/* ---------- reset ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  /* держит место под скроллбар всегда — иначе при overflow:hidden на
     модалке (см. main.js) скроллбар пропадает, и страница дёргается вбок */
  scrollbar-gutter: stable;
  /* нативный скроллбар подстраивается под тему ОС/браузера; сама страница
     остаётся светлой — это не переключает тему сайта, только системные
     элементы, которые мы явно не перекрасили своим CSS */
  color-scheme: light dark;
  /* плавный переход по якорям меню */
  scroll-behavior: smooth;
}

/* Якорь не должен заезжать под липкую шапку. :where() обнуляет
   специфичность селектора, поэтому отдельная секция переопределяет отступ
   обычным классом, без утяжеления (см. .process дальше по файлу). */
:where(section[id]) {
  scroll-margin-top: calc(var(--header-h) + var(--anchor-gap));
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

body {
  margin: 0;
  font-family: var(--font-base);
  color: var(--color-ink);
  background: var(--color-bg);
  font-size: var(--fs-body);
  line-height: var(--lh-normal);
}

img {
  display: block;
  max-width: 100%;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

h1,
h2,
h3,
p {
  margin: 0;
}

h1,
h2 {
  font-family: var(--font-heading);
}

/* ---------- layout ---------- */
.container {
  /* padding must sit OUTSIDE the 1280px content zone, not eat into it —
     so max-width includes the padding on both sides */
  max-width: calc(var(--container-max) + var(--container-pad) * 2);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: var(--radius-sm);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  padding: 14px 24px;
  font-size: var(--fs-sm);
  transition: box-shadow 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
}

.btn--primary {
  background: var(--color-primary-2);
  color: var(--color-white);
  box-shadow: var(--shadow-btn);
}

.btn--primary:hover {
  box-shadow: var(--shadow-btn-hover);
}

.btn--secondary {
  background: transparent;
  color: var(--color-ink);
  border: 1.5px solid var(--color-ink);
}

.btn--secondary:hover {
  background: rgba(11, 27, 74, 0.04);
}

.btn--lg {
  font-size: var(--fs-body-lg);
  padding: clamp(14px, 1vw, 15px) clamp(20px, 2vw, 24px);
}

.btn--block {
  width: 100%;
}

/* ---------- cta glow (авто-проигрывающийся акцент, не по ховеру) ----------
   Готовая реализация — светящаяся змейка из круглых точек на offset-path
   (каждая точка садится на путь центром, поэтому углы проходятся идеально,
   в отличие от жёсткой полосы/дэша, которая на скруглении срезает угол и
   торчит наружу). Настройки и вся логика (профиль яркости, вспышка,
   пересчёт под реальный периметр кнопки через ResizeObserver) — из
   готового файла, только: убраны дублирующие фон/паддинги/тень кнопки
   (это уже даёт наш .btn/.btn--primary), селектор с .btn-glow переведён на
   уже применённый в разметке .btn--cta-glow, --btn-radius подхватывает
   реальный border-radius кнопки на каждом брейкпоинте (см. ниже и JS). */
.btn--cta-glow {
  --btn-radius: 8px;

  --dur: 5s; /* время одного круга */
  --dot: 3px; /* толщина следа = weight обводки в макете */
  --overlap: 0.3; /* шаг между точками как доля толщины */
  --bloom: 12px; /* ореол = два drop shadow с обводки в макете */
  --intensity: 2.2; /* яркость поверх нормировки, см. JS */
  --flash-at: -0.05; /* момент вспышки в долях круга от прохода головы через низ */

  position: relative;
  isolation: isolate;
}

.btn--cta-glow:active {
  transform: scale(0.98);
}

@container (min-width: 900px) {
  .final-cta__btn.btn--cta-glow {
    --btn-radius: 12px; /* .final-cta__btn сам переключается на var(--radius-md) на этом брейкпоинте */
  }
}

.btn-glow__snake {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  isolation: isolate;
  /* размытие привязано к ШАГУ между точками, а не к их размеру: гасить
     надо именно рябь с периодом в шаг. drop shadow дают ореол */
  filter: blur(calc(var(--smooth, 1px) * 0.8)) drop-shadow(0 0 calc(var(--bloom) * 0.4) rgba(255, 255, 255, 0.9))
    drop-shadow(0 0 var(--bloom) rgba(150, 205, 255, 0.7)) drop-shadow(0 0 calc(var(--bloom) * 2.4) rgba(90, 150, 255, 0.45));
}

.btn-glow__snake i {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  /* толщина одинаковая у всех точек, гаснет только яркость: неоновый
     след — это свет вдоль трубки, а не капля */
  width: var(--dot);
  height: var(--dot);
  border-radius: 50%;
  background: radial-gradient(
    circle closest-side,
    rgba(255, 255, 255, 1) 0%,
    rgba(255, 255, 255, 0.82) 22%,
    rgba(255, 255, 255, 0.45) 48%,
    rgba(255, 255, 255, 0.15) 72%,
    rgba(255, 255, 255, 0) 100%
  );
  opacity: calc(var(--a, 0) * var(--intensity, 1));
  mix-blend-mode: screen;
  /* обводка Inside — путь утоплен внутрь на половину толщины, радиус на
     столько же меньше */
  offset-path: rect(
    calc(var(--dot) / 2) calc(100% - var(--dot) / 2) calc(100% - var(--dot) / 2) calc(var(--dot) / 2) round
      max(0px, calc(var(--btn-radius) - var(--dot) / 2))
  );
  offset-rotate: 0deg;
  offset-distance: calc(var(--start, 0%) - (1 - var(--off, 0)) * 100%);
  animation: glow-run var(--dur) linear infinite;
  animation-delay: calc((var(--off, 0) - 1) * var(--dur));
}

@supports (mix-blend-mode: plus-lighter) {
  .btn-glow__snake i {
    mix-blend-mode: plus-lighter;
  }
}

@keyframes glow-run {
  from {
    offset-distance: var(--start, 0%);
  }
  to {
    offset-distance: calc(var(--start, 0%) - 100%);
  }
}

.btn-glow__flash {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.8), inset 0 0 calc(var(--bloom) * 0.8) rgba(190, 225, 255, 0.5),
    0 0 calc(var(--bloom) * 1.4) rgba(150, 205, 255, 0.7), 0 0 calc(var(--bloom) * 3.5) rgba(90, 150, 255, 0.45);
  animation: glow-flash var(--dur) linear infinite;
  animation-delay: calc((var(--flash-at, 0) - 1) * var(--dur));
}

@keyframes glow-flash {
  0% {
    opacity: 0;
    transform: scale(1);
    animation-timing-function: cubic-bezier(0.2, 0.85, 0.35, 1);
  }
  5% {
    opacity: 1;
    transform: scale(1.008);
    animation-timing-function: cubic-bezier(0.25, 0, 0.45, 1);
  }
  38% {
    opacity: 0;
    transform: scale(1.022);
  }
  100% {
    opacity: 0;
    transform: scale(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .btn-glow__snake,
  .btn-glow__snake i,
  .btn-glow__flash {
    animation: none !important;
  }

  .btn-glow__snake {
    opacity: 0.55;
  }
}

/* ---------- tag ---------- */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  background: var(--color-primary-soft);
  color: var(--color-primary-tag);
  font-size: clamp(0.6875rem, 0.65rem + 0.15vw, 0.75rem);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.tag__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-primary-tag);
  flex-shrink: 0;
}

/* ---------- header ---------- */
.header {
  border-bottom: 1px solid var(--color-border);
  background: var(--color-bg);
  position: sticky;
  top: 0;
  z-index: 40;
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(1rem, 3vw, 2rem);
  padding-block: clamp(0.75rem, 1vw, 1rem);
}

.header__logo img {
  width: clamp(68px, 6vw, 82px);
  height: auto;
}

.nav__list {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 2rem);
}

.nav__list a {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--color-text);
  white-space: nowrap;
}

.nav__list a:hover {
  color: var(--color-ink);
}

.header__actions {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2vw, 1.5rem);
}

.header__phone {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-ink);
  white-space: nowrap;
}


.burger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 24px;
  height: 24px;
  padding: 0;
}

.burger span {
  display: block;
  width: 100%;
  height: 2px;
  background: var(--color-ink);
  border-radius: 2px;
}

/* до 900px — бургер. Порог тот же, на котором секции переходят на
   десктопные отступы (--section-py), поэтому шапка и контент
   перестраиваются в одной точке, а не в двух соседних */
@media (max-width: 899px) {
  .nav,
  .header__phone,
  .header__login {
    display: none;
  }

  .burger {
    display: flex;
  }
}

/* ---------- mobile menu ----------
   Открытие: панель проявляется, следом лесенкой выезжает содержимое —
   шапка, пункты по очереди, нижний блок. Закрытие быстрое, одной
   заливкой, без лесенки: задержки навешаны только на .is-open.

   hidden снимается на один кадр раньше класса (см. js/main.js): между
   «ещё не отрисовано» и «открыто» интерполировать нечего, и переход
   схлопнулся бы в одну точку. Тот же приём, что у модалки. */
.mobile-menu {
  --menu-ease: cubic-bezier(0.16, 1, 0.3, 1);

  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--color-white);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 24px 24px 40px;
  overflow-y: auto;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.mobile-menu.is-open {
  opacity: 1;
}

/* панель остаётся в потоке ещё ~300мс после закрытия, пока догасает, и всё
   это время невидимой перекрывала бы всю страницу кликам */
.mobile-menu:not(.is-open) {
  pointer-events: none;
}

.mobile-menu[hidden] {
  display: none;
}

/* Базовое состояние = состояние закрытия, поэтому длительность здесь
   короткая: при снятии .is-open содержимое должно уехать вниз ЗАОДНО с
   заливкой панели, а не тянуться дольше неё. Раньше тут стояли те же
   0.45s, что и на открытии, панель гасла за 0.28s и увозила содержимое
   недоигранным — со стороны это выглядело как «просто пропало». */
.mobile-menu__header,
.mobile-menu__nav a,
.mobile-menu__bottom {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.22s ease-in, transform 0.22s ease-in;
}

.mobile-menu.is-open .mobile-menu__header,
.mobile-menu.is-open .mobile-menu__nav a,
.mobile-menu.is-open .mobile-menu__bottom {
  opacity: 1;
  transform: none;
  transition: opacity 0.45s var(--menu-ease), transform 0.45s var(--menu-ease);
}

.mobile-menu.is-open .mobile-menu__header {
  transition-delay: 0.05s;
}
.mobile-menu.is-open .mobile-menu__nav a:nth-child(1) {
  transition-delay: 0.1s;
}
.mobile-menu.is-open .mobile-menu__nav a:nth-child(2) {
  transition-delay: 0.155s;
}
.mobile-menu.is-open .mobile-menu__nav a:nth-child(3) {
  transition-delay: 0.21s;
}
.mobile-menu.is-open .mobile-menu__nav a:nth-child(4) {
  transition-delay: 0.265s;
}
.mobile-menu.is-open .mobile-menu__nav a:nth-child(5) {
  transition-delay: 0.32s;
}
.mobile-menu.is-open .mobile-menu__bottom {
  transition-delay: 0.38s;
}

@media (prefers-reduced-motion: reduce) {
  .mobile-menu,
  .mobile-menu__header,
  .mobile-menu__nav a,
  .mobile-menu__bottom {
    transition-duration: 0.01ms;
    transition-delay: 0s;
  }
}

.mobile-menu__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: 8px;
}

.mobile-menu__logo {
  font-size: 22px;
  font-weight: 800;
  color: var(--color-ink-2);
}

.mobile-menu__close {
  width: 24px;
  height: 24px;
}

.mobile-menu__nav {
  display: flex;
  flex-direction: column;
  margin-top: 40px;
}

.mobile-menu__nav a {
  padding-block: 21px;
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-ink-2);
  border-bottom: 1px solid var(--color-border);
}

.mobile-menu__nav a:last-child {
  border-bottom: 0;
}

.mobile-menu__bottom {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.mobile-menu__phone {
  padding-left: 4px;
  font-size: 1rem;
  font-weight: 500;
  color: var(--color-ink-2);
}

.mobile-menu__login {
  border-radius: var(--radius-md);
  height: 48px;
}

/* ---------- modal (общая форма заявки) ----------
   Один модальный блок на весь сайт (partials/modal.html) — заголовок
   передаётся не через дублирование разметки на каждую кнопку, а через
   data-modal-title на самой кнопке-триггере (js/main.js читает атрибут и
   подставляет текст в .modal__title перед открытием). */
.modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.modal[hidden] {
  display: none;
}

/* открытие управляется классом .is-open, а не [hidden] — [hidden] снимается
   до начала анимации и возвращается только после её конца (см. main.js),
   иначе display:none обнулял бы transition мгновенно, без анимации */
.modal__overlay {
  position: absolute;
  inset: 0;
  background: rgba(3, 18, 58, 0.4);
  opacity: 0;
  transition: opacity 0.25s ease;
}

.modal.is-open .modal__overlay {
  opacity: 1;
}

.modal__panel {
  position: relative;
  width: 100%;
  max-width: 460px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 24px 20px;
  border-radius: var(--radius-lg);
  background: var(--color-white);
  box-shadow: 0px 16px 16px rgba(3, 18, 58, 0.07);
  opacity: 0;
  transform: translateY(12px) scale(0.97);
  transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.2, 0.8, 0.3, 1);
}

.modal.is-open .modal__panel {
  opacity: 1;
  transform: translateY(0) scale(1);
}

@media (prefers-reduced-motion: reduce) {
  .modal__overlay,
  .modal__panel {
    transition: none;
  }
}

.modal__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.modal__header-text {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.modal__title {
  font-size: 1.25rem; /* 20px */
  font-weight: 700;
  color: var(--color-ink-2);
}

.modal__desc {
  font-size: 0.8125rem; /* 13px */
  color: var(--color-text-muted);
}

.modal__close {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #f5f7fa;
}

.modal__form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.modal-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.modal-field__label {
  font-size: 0.75rem; /* 12px */
  font-weight: 600;
  color: var(--color-ink-2);
}

.modal-field__input {
  height: 44px;
  width: 100%;
  padding: 0 14px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: #f5f7fa;
  font-family: inherit;
  font-size: 0.875rem; /* 14px */
  color: var(--color-ink-2);
  transition: border-color 0.15s ease;
}

.modal-field__input::placeholder {
  color: var(--color-text-muted);
}

.modal-field__input:focus {
  outline: none;
  border-color: var(--color-primary);
}

.modal__footer {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 4px;
}

.modal__consent {
  font-size: 0.6875rem; /* 11px */
  line-height: 1.4;
  color: var(--color-text-muted);
}

.modal__consent a {
  color: var(--color-primary);
  text-decoration: underline;
}

@media (min-width: 900px) {
  .modal__panel {
    gap: 24px;
    padding: 32px;
  }

  .modal__title {
    font-size: 1.375rem; /* 22px */
  }

  .modal__desc {
    font-size: 0.875rem; /* 14px */
  }

  .modal__close {
    width: 36px;
    height: 36px;
  }

  .modal__form {
    gap: 16px;
  }

  .modal-field__label {
    font-size: 0.8125rem; /* 13px */
  }

  .modal-field__input {
    height: 48px;
    border-radius: var(--radius-sm);
    padding: 0 16px;
  }

  .modal__footer {
    gap: 12px;
  }

  .modal__consent {
    font-size: 0.75rem; /* 12px */
  }
}

/* ---------- hero ---------- */
.hero {
  /* query container for everything below — must live on an ANCESTOR of
     the elements whose layout switches (.hero__inner, .hero__actions),
     never on the switching element itself: an element cannot be resized
     by a query against the containment context it establishes */
  container-type: inline-size;
  padding-block: var(--section-py);
}

.hero__inner {
  display: flex;
  flex-direction: column;
  gap: clamp(2rem, 4vw, 3.75rem);
  /* выше .hero-glow, который лежит абсолютом в той же секции */
  position: relative;
  z-index: 1;
}

@container (min-width: 960px) {
  .hero__inner {
    flex-direction: row;
    align-items: center;
  }

  .hero__left {
    /* flex-basis 0, not auto — with auto, the long .hero__desc sentence's
       unwrapped max-content width was winning as the "preferred" size and
       crushing .hero__right down to its min-width floor even at 1440px */
    flex: 1 1 0%;
    /* NOT 0 — a 0-basis flex item takes zero weight in the shrink formula,
       so .hero__right (which has a real basis) absorbed 100% of any deficit
       down to ITS floor before .hero__left gave up a single pixel. With no
       floor of its own, .hero__left had nowhere to shrink TO and just
       overflowed. 500px keeps the title reading as 2 comfortable lines
       ("Размещайте задания. Находите" / "исполнителей.") at the 960px
       threshold instead of cramming into 3-4 with mid-word breaks. */
    min-width: 500px;
  }

  .hero__right {
    /* 608px per the Figma frame (was wrongly 560 — squeezed the stats
       cards below their min-content and forced a label to wrap) */
    flex: 0 1 608px;
    /* low floor on purpose: .dashboard-mock crops its own stats-row via
       overflow: hidden (see that section), so .hero__right is free to
       actually shrink here instead of staying rigid at 608 and starving
       .hero__left — that rigidity was what squeezed the title/tag into
       an ugly wrap around 1000-1150px container width */
    min-width: min(100%, 320px);
  }
}

.hero__left {
  display: flex;
  flex-direction: column;
}

.hero__tag {
  align-self: flex-start;
}

.hero__title {
  margin-top: 1rem;
  font-size: var(--fs-h1);
  font-weight: 800;
  line-height: 1.2;
  color: var(--color-ink-2);
  /* safety net: if a single word is ever still wider than .hero__left's
     240px floor (very large font + narrow column), break it instead of
     overflowing past the column into .hero__right */
  overflow-wrap: break-word;
}

.hero__desc {
  margin-top: clamp(1rem, 1.5vw + 0.65rem, 2rem);
  font-size: var(--fs-body-lg);
  line-height: var(--lh-normal);
  color: var(--color-text-muted);
}

.hero__actions {
  margin-top: clamp(2rem, 1.5vw + 1.65rem, 3rem);
  display: flex;
  flex-direction: column;
  gap: clamp(0.75rem, 0.38vw + 0.66rem, 1rem);
  width: 100%;
  max-width: 335px;
}

.hero__actions .btn {
  flex: 1;
  /* literal Figma sizes, not .btn--lg's fluid clamp — 16px mobile frame,
     15px desktop frame (see @container override below); padding is
     already correct as-is, both frames agree on 14px 24px */
  font-size: 1rem; /* 16px */
}

/* must come AFTER the base rule above: same specificity (0,2,0), so with
   this @container block placed earlier in the file the plain rule below
   would win by source order regardless of width and silently eat the
   desktop override — that's exactly what happened before this comment */
@container (min-width: 960px) {
  .hero__actions .btn {
    font-size: 0.9375rem; /* 15px, desktop Figma frame */
  }
}

@container (min-width: 480px) {
  .hero__actions {
    flex-direction: row;
    flex-wrap: wrap;
    max-width: none;
    width: auto;
  }

  .hero__actions .btn {
    flex: none;
  }
}

/* ---------- hero: появление при загрузке ----------
   Чистый CSS, ни строчки JS. Это главное свойство блока, а не сама
   анимация.

   Было: заголовок резался скриптом на строки, каждая выезжала из маски,
   и до прихода скрипта весь первый экран приходилось прятать. Отсюда
   тянулась вся цепочка проблем — зависимость от метрики шрифта,
   перерезка при ресайзе, пустой блок на медленной сети и три отдельных
   предохранителя, чтобы контент не остался скрытым.

   Стало: текст проявляется целым блоком из лёгкого размытия. Приём взят
   с attio.com, там первый экран сделан так же — блок целиком, blur 1.5px
   плюс прозрачность, никакой разбивки на строки. Выглядит так же дорого,
   а стоит ноль килобайт скрипта.

   animation-fill-mode: both держит элемент в начальном состоянии во время
   своей задержки, поэтому отдельное «спрятать до старта» не нужно —
   состояние задаёт сама анимация. Задержки намеренно короткие: пока
   элемент полностью прозрачен, он не считается кандидатом на LCP, и
   каждая лишняя десятая доля секунды здесь прямо портит метрику. */
.hero {
  --in-ease: cubic-bezier(0.16, 1, 0.3, 1); /* expo-out */
  position: relative;
}

.hero__tag {
  animation: hero-in-fade 0.7s var(--in-ease) 0.04s both;
}

.hero__title {
  animation: hero-in-text 0.85s var(--in-ease) 0.1s both;
}

.hero__desc {
  animation: hero-in-text 0.85s var(--in-ease) 0.2s both;
}

.hero__actions .btn:nth-child(1) {
  animation: hero-in-fade 0.7s var(--in-ease) 0.34s both;
}

.hero__actions .btn:nth-child(2) {
  animation: hero-in-fade 0.7s var(--in-ease) 0.4s both;
}

/* Размытие небольшое, 2px. У attio 1.5px — при большем значении текст на
   старте читается не как «проявляется», а как «расфокусирован».
   Снимается оно раньше, чем заканчивается движение: к середине анимации
   буквы уже чёткие, и хвост доигрывает только сдвиг. */
@keyframes hero-in-text {
  from {
    opacity: 0;
    transform: translateY(14px);
    filter: blur(2px);
  }
  55% {
    filter: blur(0);
  }
  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

@keyframes hero-in-fade {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---- правая панель ----
   Лёгкий наклон по X, распрямляющийся в ноль: панель как будто ложится на
   плоскость экрана, а не просто всплывает. */
.hero__right {
  animation: hero-in-panel 1.1s var(--in-ease) 0.24s both;
}

@keyframes hero-in-panel {
  from {
    opacity: 0;
    transform: perspective(1400px) rotateX(9deg) translateY(52px) scale(0.965);
  }
  to {
    opacity: 1;
    transform: perspective(1400px) rotateX(0deg) translateY(0) scale(1);
  }
}

/* ---- содержимое панели ---- */
.dashboard-mock__title {
  animation: hero-in-card 0.7s var(--in-ease) 0.46s both;
}
.metric-card:nth-child(1) {
  animation: hero-in-card 0.7s var(--in-ease) 0.54s both;
}
.metric-card:nth-child(2) {
  animation: hero-in-card 0.7s var(--in-ease) 0.62s both;
}
.metric-card:nth-child(3) {
  animation: hero-in-card 0.7s var(--in-ease) 0.7s both;
}
.task-card:nth-child(1) {
  animation: hero-in-card 0.7s var(--in-ease) 0.78s both;
}
.task-card:nth-child(2) {
  animation: hero-in-card 0.7s var(--in-ease) 0.86s both;
}

@keyframes hero-in-card {
  from {
    opacity: 0;
    transform: translateY(20px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---- блик по панели, один раз ----
   .dashboard-mock уже режет себя по overflow, поэтому блик не вылезет за
   скруглённые углы. */
.hero-sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    105deg,
    transparent 38%,
    rgba(255, 255, 255, 0.55) 50%,
    transparent 62%
  );
  animation: hero-in-sheen 1.1s cubic-bezier(0.4, 0, 0.2, 1) 0.9s both;
}

@keyframes hero-in-sheen {
  from {
    transform: translateX(-130%);
    opacity: 0;
  }
  25% {
    opacity: 1;
  }
  to {
    transform: translateX(130%);
    opacity: 0;
  }
}

/* ---- мягкое пятно света за панелью ---- */
.hero-glow {
  position: absolute;
  /* справа строго 0, без выноса за секцию: у .hero нет overflow, и любой
     отрицательный отступ по горизонтали тут же даёт горизонтальную
     прокрутку всей страницы. По вертикали выносить можно */
  inset: -12% 0 -20% 30%;
  pointer-events: none;
  background: radial-gradient(
    60% 60% at 60% 40%,
    rgba(23, 53, 245, 0.1) 0%,
    rgba(23, 53, 245, 0) 70%
  );
  animation: hero-in-glow 1.5s var(--in-ease) 0.26s both;
}

@keyframes hero-in-glow {
  from {
    opacity: 0;
    transform: scale(0.9);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Ветка scripting: none больше не нужна — здесь нет ни одного правила,
   которое зависело бы от скрипта. */
@media (prefers-reduced-motion: reduce) {
  .hero__tag,
  .hero__title,
  .hero__desc,
  .hero__actions .btn,
  .hero__right,
  .dashboard-mock__title,
  .metric-card,
  .task-card,
  .hero-glow {
    animation: none;
  }

  .hero-sheen {
    animation: none;
    opacity: 0;
  }
}


/* ---------- dashboard mock ----------
   Fixed px straight off each Figma frame (375 / 1440), no vw clamp() in
   here: .dashboard-mock's own width isn't continuously fluid the way the
   page is — it's 100% of .hero__right in column mode, then hard-capped at
   608px once row mode kicks in (see .hero__right) — so a clamp() would
   keep drifting past the point where the box itself stopped growing, and
   never actually land on either frame's real numbers. Base rules below are
   the mobile (375) frame; the @container block at the end of this section
   overrides to the desktop (1440) frame, on the same 960px breakpoint
   .hero__inner already switches on — not a new one. */
.dashboard-mock {
  width: 100%;
  /* якорь для .hero-sheen, блика при появлении первого экрана */
  position: relative;
  background: #f7f8fc;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  /* matches Figma's own "overflow-clip" on this node: .stats-row below is a
     fixed 3-up row that never reflows, so on narrow widths it's meant to be
     cropped here rather than stack — designer's call, not a bug */
  overflow: hidden;
}

.dashboard-mock__title {
  /* omitted in the mobile Figma frame to save vertical space; shown only
     once .hero__inner switches to the row layout, see @container below */
  display: none;
  font-weight: 700;
  font-size: var(--fs-body);
  color: var(--color-ink-2);
}

/* fixed 3 columns, never reflows to 2+1 — see .dashboard-mock's
   overflow: hidden. minmax(122px, 1fr): 122px is the mobile Figma card
   width acting as a hard floor; 1fr lets all 3 grow evenly to fill
   whatever room .dashboard-mock actually has above that, so card width
   tracks the real available space instead of jumping between two guessed
   breakpoint numbers */
.stats-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(122px, 1fr));
  gap: 12px;
}

.metric-card {
  min-width: 0;
  background: linear-gradient(to right, var(--color-white), var(--metric-tint, #f8faff));
  border: 1px solid var(--color-border-2);
  border-radius: var(--radius-md);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.metric-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}

.metric-card__accent {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 40%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(to right, var(--accent-from), var(--accent-to));
}

.metric-card__accent img {
  width: 55%;
  height: 55%;
}

.metric-card__trend {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 7px;
  border-radius: var(--radius-pill);
  background: var(--metric-trend-bg, #eff6ff);
  font-family: var(--font-metric);
  font-size: 0.625rem;
  font-weight: 600;
  color: var(--metric-trend-color, #1d4ed8);
  white-space: nowrap;
}

.metric-card__trend img {
  width: 9px;
  height: 9px;
}

.metric-card__content {
  display: flex;
  align-items: center;
  gap: 6px;
}

.metric-card__value {
  font-family: var(--font-metric);
  font-size: 1.1875rem; /* 19px */
  font-weight: 700;
  color: var(--color-ink);
  line-height: 1.2;
}

.metric-card__label {
  min-width: 0;
  overflow: hidden;
  color: var(--color-text-muted);
  font-family: var(--font-metric);
  font-size: 0.5rem; /* 8px, grows to 10px desktop — see @container below */
  font-weight: 600;
  line-height: 15.29px;
  letter-spacing: 0.08px;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.metric-card--blue {
  --metric-tint: #f8faff;
  --accent-from: #3b82f6;
  --accent-to: #1d4ed8;
  --metric-trend-bg: #eff6ff;
  --metric-trend-color: #1d4ed8;
}

.metric-card--green {
  --metric-tint: #ecfdf5;
  --accent-from: #10b981;
  --accent-to: #059669;
  --metric-trend-bg: #ecfdf5;
  --metric-trend-color: #059669;
}

.metric-card--amber {
  --metric-tint: #fffbeb;
  --accent-from: #f59e0b;
  --accent-to: #d97706;
  --metric-trend-bg: #fffbeb;
  --metric-trend-color: #d97706;
}

.job-cards-row {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.task-card {
  background: var(--color-white);
  border: 1px solid var(--color-border-2);
  border-radius: var(--radius-md);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.task-card__badge-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.task-card__price {
  font-weight: 700;
  color: var(--color-primary-tag);
  font-size: var(--fs-sm);
}

.task-tag {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 8px;
  border-radius: 4px;
  border: 1px solid;
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
}

.task-tag--blue {
  background: #ecf1ff;
  border-color: #91caff;
  color: var(--color-primary);
}

.task-tag--green {
  background: #e0faeb;
  border-color: #33c77d;
  color: #178c57;
}

.task-card__details {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.task-card__title {
  font-weight: 700;
  font-size: var(--fs-body);
  color: var(--color-ink);
}

.task-card__meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-xs);
  color: var(--color-text-muted);
}

.task-card__meta img {
  width: 12px;
  height: 12px;
}

/* dashboard-mock component tree: desktop (1440) frame values, see the
   comment at the top of the section above */
@container (min-width: 960px) {
  .dashboard-mock {
    gap: 16px;
  }

  .dashboard-mock__title {
    display: block;
  }

  .metric-card {
    padding: 20px;
    gap: 10px;
  }

  .metric-card__accent {
    width: 27px;
    height: 27px;
  }

  .metric-card__value {
    font-size: 1.4375rem; /* 23px */
  }

  .metric-card__label {
    font-size: 0.625rem; /* 10px */
  }

  .job-cards-row {
    gap: 15px;
  }

  .task-card {
    padding: 20px;
    gap: 16px;
  }
}

/* ---------- shared section pieces ---------- */
.section {
  padding-block: var(--section-py);
}

.kicker {
  display: inline-flex;
  align-items: center;
  width: fit-content;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  background: var(--color-primary-soft);
  color: var(--color-primary-tag);
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* ---------- product value (how-it-works-v2) ----------
   Same rule-9 approach as the Hero dashboard-mock: fixed px per Figma
   frame (375 / 1440), switched on 900px — this section's own existing
   column⇄row breakpoint, not the Hero's 960. .product-value__layout and
   .product-value__grid keep their clamp()s below since those genuinely
   track the full container width continuously and their two bounds
   already land exactly on both frames' real numbers. */
.product-value {
  container-type: inline-size;
  background: #f7f8fc;
  padding-block: var(--section-py);
}

.product-value__layout {
  display: flex;
  flex-direction: column;
  gap: clamp(2rem, 4vw, 6rem);
}

@container (min-width: 900px) {
  .product-value__layout {
    flex-direction: row;
    /* NOT center — Figma top-aligns the sidebar with the grid, it doesn't
       vertically center against the taller 2x2 card column */
    align-items: flex-start;
  }

  .product-value__grid-wrap {
    order: 1;
    flex: 2 1 480px;
  }

  .product-value__sidebar {
    order: 2;
    flex: 1 1 405px;
    max-width: 480px;
  }
}

.product-value__sidebar {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.product-value__title {
  font-size: 1.75rem; /* 28px */
  font-weight: 700;
  line-height: 1.21;
  color: var(--color-ink-2);
  /* mobile: uniform 12px from .product-value__sidebar's gap. Desktop
     frame splits into two DIFFERENT gaps (badge->title 32px, title->desc
     20px) instead of one uniform value, so it's margin-top here rather
     than the parent's gap — see @container override below */
}

.product-value__desc {
  max-width: 480px;
  color: var(--color-text-muted);
  font-size: 0.9375rem; /* 15px */
  line-height: 1.47; /* 22px */
}

/* desktop (1440) overrides — MUST come after every base rule they touch:
   same specificity (0,1,0 / 0,2,0), so a rule wrapped in @container placed
   earlier in the file loses the cascade tiebreak to a plain rule that
   comes later, regardless of which container width actually matches (see
   the .hero__actions .btn fix earlier for the same bug). .feature-card's
   own overrides are further down, right after ITS base rule, for the
   same reason. */
@container (min-width: 900px) {
  .product-value__sidebar {
    gap: 0;
  }

  .product-value__title {
    font-size: 2.5rem; /* 40px */
    line-height: 1.15;
    margin-top: 32px;
  }

  .product-value__desc {
    font-size: 1rem; /* 16px */
    margin-top: 20px;
  }
}

.product-value__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: clamp(1rem, 1.6vw, 1.5rem);
}

.feature-card {
  background: var(--color-white);
  border: 1px solid var(--color-border-2);
  border-radius: var(--radius-lg);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: clamp(0.75rem, 0.38vw + 0.66rem, 1rem);
  box-shadow: 0 2px 4px rgba(15, 23, 42, 0.04);
}

.feature-card__icon {
  width: clamp(3rem, 2.82rem + 0.75vw, 3.5rem);
  height: clamp(3rem, 2.82rem + 0.75vw, 3.5rem);
  border-radius: var(--radius-md);
  background: var(--color-primary-soft);
  display: flex;
  align-items: center;
  justify-content: center;
}

.feature-card__icon img {
  width: 24px;
  height: 24px;
}

.feature-card__title {
  font-size: var(--fs-card-title);
  font-weight: 700;
  color: var(--color-ink);
}

.feature-card__desc {
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--color-text-muted);
}

@container (min-width: 900px) {
  .feature-card {
    padding: 24px;
    border-radius: var(--radius-xl);
  }

  .feature-card__icon {
    border-radius: var(--radius-lg);
  }

  .feature-card__icon img {
    width: 28px;
    height: 28px;
  }
}

/* ---------- fns trust block ----------
   Fixed px per Figma frame (375 / 1440), switched at 900px — same
   threshold as product-value, this section's own column/row content
   switch. Content and desc copy are identical in both frames here, no
   drift to reconcile (unlike product-value). No divider line on mobile —
   present in DOM, hidden until the row layout, same pattern as
   .dashboard-mock__title in Hero. */
.fns-trust {
  container-type: inline-size;
  border-block: 1px solid var(--color-border);
  padding-block: var(--section-py);
}

.fns-trust__inner {
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.fns-trust__content {
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.fns-trust__text {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.fns-trust__title {
  font-size: 1.75rem; /* 28px */
  font-weight: 700;
  line-height: 1.214;
  color: var(--color-ink-2);
}

.fns-trust__desc {
  font-size: 0.9375rem; /* 15px */
  line-height: 1.467;
  color: var(--color-text-muted);
}

.fns-trust__divider {
  display: none;
  border: 0;
  border-top: 1px solid var(--color-border);
  margin: 0;
  width: 100%;
}

.fns-trust__pills {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
}

.fns-pill {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 14px;
  background: #f8fafc;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  font-size: 0.8125rem; /* 13px */
  font-weight: 600;
  color: var(--color-ink);
}

.fns-pill__icon {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #dcfce7;
  display: flex;
  align-items: center;
  justify-content: center;
}

.fns-pill__icon img {
  width: 11px;
  height: 11px;
}

.fns-trust__seal {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}

.fns-trust__seal img {
  width: 114px;
  height: auto;
  display: block;
}

@container (min-width: 900px) {
  .fns-trust__inner {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }

  .fns-trust__content {
    /* grow: 0 — with 1 it ate all the leftover row space via
       justify-content: space-between and stretched past 694px */
    flex: 0 1 697px;
    min-width: 320px;
    gap: 32px;
  }

  .fns-trust__text {
    gap: 18px;
  }

  .fns-trust__title {
    font-size: 2.5rem; /* 40px */
    line-height: 1.2;
  }

  .fns-trust__desc {
    font-size: 1rem; /* 16px */
    line-height: 1.625;
  }

  .fns-trust__divider {
    display: block;
  }

  .fns-trust__pills {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 16px;
    width: auto;
  }

  .fns-pill {
    width: auto;
    padding: 10px 16px;
    gap: 10px;
    font-size: 0.875rem; /* 14px */
    color: var(--color-ink-2);
  }

  .fns-pill__icon {
    width: 20px;
    height: 20px;
  }

  .fns-pill__icon img {
    width: 12px;
    height: 12px;
  }

  .fns-trust__seal {
    flex: 0 1 260px;
    min-width: 140px;
    width: auto;
  }

  .fns-trust__seal img {
    width: 100%;
  }
}
/* ---------- process (закреплённый блок с переключением шагов) ----------
   Блок залипает на весь экран, а прокрутка внутри секции переключает шаги.
   .process__track — трек прокрутки высотой 100vh + 3 × --p-step-scroll,
   .process__pin — то, что видит пользователь.

   wheel НЕ перехватывается: прокрутка остаётся родной (трекпад, тач,
   клавиатура, полоса прокрутки, поиск по странице работают как обычно).
   JS только читает, насколько трек уже прокручен, и раскладывает это
   в 0..3.

   scroll-snap здесь БЫЛ и был убран намеренно. Точки притяжения стояли
   через --p-step-scroll, а proximity подтягивает к БЛИЖАЙШЕЙ точке по
   окончании жеста, то есть порог — половина шага, и считается он за один
   непрерывный жест, а не суммарно. Мышь с мелкой дельтой (Windows «1
   строка за щелчок», ~33px) этот порог одним щелчком не берёт, и каждый
   раз откатывалась назад: секция не листалась вообще. Mandatory делает
   хуже — Chrome считает точку назначения от дельты и прилипает к
   ближайшей, при мелкой дельте это всегда текущая. Без snap каждый
   пиксель честно двигает прогресс на любом устройстве, а непрерывная
   заливка линии между шагами даёт обратную связь сразу.

   Брейкпоинт здесь @media, а не @container как в остальном файле:
   закрепление зависит от ВЫСОТЫ вьюпорта (весь блок должен помещаться в
   экран), а container queries её не видят. Два порога, не один: две
   колонки — от 1024px ширины (см. ниже); залипание/pin — от 1100px
   ширины И 620px высоты одновременно (см. дальше по файлу). Между
   1024 и 1100 — уже два столбца, но переключение шагов ещё кликом,
   без scroll-pin. */
.process {
  /* без отступа под шапку, в отличие от остальных секций: закрепление
     начинается ровно от верха трека, и любой отступ оставил бы блок
     недоехавшим до точки залипания. Шапку блок учитывает сам —
     см. padding-top у .process__pin */
  scroll-margin-top: 0;

  /* тот же замер, что и у отступа якорей: было отдельное число 73px,
     то есть второй источник правды для одной и той же высоты */
  --p-header-h: var(--header-h, 73px);
  /* Прокрутка на один шаг. Фиксированные пиксели, а НЕ vh: щелчок колеса
     тоже меряется в пикселях (Windows по умолчанию ~100px), и одинаковыми
     все три перехода получаются только при кратной величине. На 32vh при
     экране 950px шаг выходил 304px, то есть 3.04 щелчка: первый переход
     требовал 4 щелчка, следующие по 3 за счёт накопленного перелёта.
     200px — ровно два щелчка на переход, без разнобоя и без зависимости
     от высоты окна. Ниже ~170px становится дёргано: один мах трекпадом
     это 300-800px, то есть два-четыре шага за один жест. */
  --p-step-scroll: 200px;
  --p-ease: cubic-bezier(0.22, 1, 0.36, 1);

  --p-num: clamp(32px, 8.5vw, 44px);
  --p-num-lh: 1.27;
  --p-title-a: 1.0625rem; /* 17px */
  --p-title-i: 1rem; /* 16px */
  --p-pad-x: 20px;
  --p-pad-a: 20px;
  --p-pad-i: 14px;
  --p-connector: 24px;
  --p-rail-x: 44px;
  --p-media-h: clamp(240px, 62vw, 420px);

  padding-block: var(--section-py);
}

/* <1024px: простой список (см. .process__mobile ниже) вместо
   интерактивного трека — те же карточки/бейджи, без scroll-pin и без
   активного/неактивного состояния шагов */
.process__track {
  display: none;
  position: relative;
}

.process__mobile {
  display: block;
}

/* эта копия .process__header не участвует в scroll-reveal (.process.is-inview
   в main.css применяется дальше, завязан на десктопный .process__pin) —
   просто всегда видима, без анимации, как и весь .process__mobile */
.process__mobile .process__header > * {
  opacity: 1;
}

.process__mobile-steps {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.process-mobile-step {
  display: flex;
  flex-direction: column;
  gap: 16px;
  /* lets the badges below read real available width via cqw, so they
     retreat inward smoothly instead of overhanging past the page edge */
  container-type: inline-size;
}

.process-mobile-step__text {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.process-mobile-step__head {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Inter, не var(--font-heading) — в этом мобильном узле Figma сам
   использует Inter Extra Bold/Bold для номера и заголовка шага, не
   Outfit (тот включается только для крупных H1/H2 по правилу проекта,
   а эта надпись — мелкая инлайновая, 14px) */
.process-mobile-step__num {
  font-weight: 800;
  font-size: 0.875rem; /* 14px */
  color: var(--color-ink-2);
}

.process-mobile-step__title {
  font-weight: 700;
  font-size: 0.875rem; /* 14px */
  color: var(--color-ink-2);
}

.process-mobile-step__desc {
  font-size: 0.8125rem; /* 13px */
  line-height: 1.385; /* 18px */
  color: var(--color-text-muted);
}

/* тот же стретч-баг, что уже был у .kicker (см. п.11 гайда) — flex-колонка
   по умолчанию растягивает детей на всю ширину; картинке нужна её
   собственная (588-640px), а не вся ширина .process-mobile-step */
.process__card {
  width: fit-content;
}

.process-mobile-step .process__card {
  align-self: center;
}

@media (min-width: 1024px) {
  .process__mobile {
    display: none;
  }

  .process__track {
    display: block;
  }
}

/* width, а не растягивание грид-элемента: у .container есть
   margin-inline: auto, а авто-поля отменяют stretch — без этого блок
   ужимался до max-content (940px вместо 1360px) */
.process__inner {
  width: 100%;
}

.process__header {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-bottom: 32px;
}

.process__title {
  font-size: 1.75rem; /* 28px */
  font-weight: 700;
  line-height: 1.15;
  color: var(--color-ink-2);
}

.process__desc {
  font-size: 0.9375rem; /* 15px */
  line-height: 1.5;
  color: var(--color-text-muted);
}

.process__columns {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.process__steps {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.process-step {
  display: flex;
  align-items: center;
  gap: 20px;
  width: 100%;
  padding: var(--p-pad-i) var(--p-pad-x);
  border-radius: var(--radius-lg);
  background: transparent;
  text-align: left;
  transition: background-color 0.4s var(--p-ease), padding-block 0.4s var(--p-ease);
}

.process-step:not(.is-active):hover {
  background: rgba(11, 27, 74, 0.03);
}

.process-step:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.process-step.is-active {
  padding-block: var(--p-pad-a);
  background: #f8f9fb;
}

.process-step__num {
  flex-shrink: 0;
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: var(--p-num);
  line-height: var(--p-num-lh);
  color: #cbd5e1;
  transition: color 0.4s var(--p-ease);
}

.process-step.is-active .process-step__num {
  color: var(--color-primary);
}

.process-step__body {
  flex: 1 1 0%;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.process-step__title {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--p-title-i);
  line-height: 1.28;
  color: #94a3b8;
  transition: color 0.4s var(--p-ease), font-size 0.4s var(--p-ease);
}

.process-step.is-active .process-step__title {
  font-size: var(--p-title-a);
  line-height: 1.4;
  color: var(--color-ink-2);
}

/* grid-rows 0fr -> 1fr: высота до auto без замера контента в JS */
.process-step__desc-wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.4s var(--p-ease);
}

.process-step.is-active .process-step__desc-wrap {
  grid-template-rows: 1fr;
}

.process-step__desc {
  overflow: hidden;
  min-height: 0;
  display: block;
  padding-top: 8px;
  font-size: 0.9375rem; /* 15px */
  line-height: 1.47;
  color: var(--color-text-muted);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.35s var(--p-ease), transform 0.35s var(--p-ease);
}

.process-step.is-active .process-step__desc {
  opacity: 1;
  transform: none;
  transition-delay: 0.1s;
}

.process-step__connector {
  position: relative;
  display: block;
  flex: 0 0 var(--p-connector);
  width: 1px;
  margin-left: var(--p-rail-x);
  background: var(--color-border);
  overflow: hidden;
}

.process-step__connector-fill {
  position: absolute;
  inset: 0;
  background: var(--color-primary);
  transform-origin: top center;
  transform: scaleY(var(--fill, 0));
  transition: transform 0.4s var(--p-ease);
}

.process__showcase-media {
  position: relative;
  height: var(--p-media-h);
}

.process__slide {
  position: absolute;
  inset: 0;
  /* centers .process__image, which is sized to its own intrinsic aspect
     ratio (see below) rather than stretched — a flex-centered auto-sized
     child, not object-fit:contain on a stretched box */
  display: flex;
  align-items: center;
  justify-content: center;
  /* lets the badges below read real available width via cqw, so they
     retreat inward smoothly instead of overhanging past the page edge */
  container-type: inline-size;
  opacity: 0;
  transform: scale(0.96) translateY(16px);
  transition: opacity 0.45s var(--p-ease), transform 0.6s var(--p-ease);
}

.process.is-inview .process__slide.is-active {
  opacity: 1;
  transform: none;
}

/* уходящий слайд (картинка + её бейджи) отъезжает в другую сторону —
   читается как смена кадра, а не как мигание одного и того же */
.process__slide.is-leaving {
  opacity: 0;
  transform: scale(1.03) translateY(-14px);
}

.process__image {
  /* auto, not width/height: 100% — each of the 4 exports has its own
     aspect ratio (534-602px tall on a 588-640px-wide canvas), and a
     forced 100%/100% box + object-fit:contain left empty letterboxed
     margin INSIDE the element's own box that a border/box-shadow would
     then hug instead of the visible card. Auto-sizing within max-w/h
     makes the element's box equal the visible content exactly */
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  pointer-events: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-card);
}

/* .process__card shrinks to the image's own auto size (flex child,
   align-items: center on .process__slide means it isn't stretched) and
   gives .process-badge a positioning root that's the actual card edges —
   not .process__showcase-media's shared box, which is wider/taller than
   any single card and differs per slide */
.process__card {
  position: relative;
}

/* бейджи — свёрстаны кодом, не куски картинки (см. пункт про экспорт
   карточек без плавающих бейджей выше). Офсеты — пиксели, измеренные
   вручную по месту на каждом слайде, не формула — компоновка бейджей
   не подчиняется одному правилу между слайдами */
.process-badge {
  position: absolute;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-radius: 12px;
  background: var(--color-white);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-card);
  font-size: 0.875rem; /* 14px */
  font-weight: 600;
  color: var(--color-ink-2);
  white-space: nowrap;
  pointer-events: none;
}

.process-badge--tint {
  background: var(--color-primary-soft);
  border-color: transparent;
  color: var(--color-primary);
}

/* top/bottom stay % of the card's own box (unaffected by this, no edge
   risk there — vertical page scroll is normal). right/left that OVERHANG
   the card (negative values) use clamp()+cqw instead of a fixed % or px:
   (100cqw - CARD_WIDTHpx) / 2 is the real margin between the centered
   card and its container's edge; clamp(0px, margin, MAX_OVERHANG) can't
   go negative (no overhang once margin hits 0 — badge sits flush with
   the card) and can't exceed MAX_OVERHANG (the figma-measured value)
   once there's plenty of room. No breakpoint needed — it tracks actual
   available space continuously. Requires container-type: inline-size on
   the real parent (.process__slide desktop / .process-mobile-step
   mobile), not .process__card itself — cqw has to read the SURROUNDING
   space, not the fit-content card's own width. */
.process-badge--1-top {
  top: 7.1%;
  right: calc(-1 * clamp(0px, (100cqw - 588px) / 2, 54px));
  transform: rotate(1.5deg);
}

.process-badge--1-bottom {
  bottom: 13.46%;
  left: calc(-1 * clamp(0px, (100cqw - 588px) / 2, 59px));
  transform: rotate(-2deg);
}

.process-badge--2-top {
  top: 10.07%;
  right: 3.91%;
  transform: rotate(1.5deg);
}

.process-badge--2-bottom {
  bottom: -6.41%;
  left: calc(-1 * clamp(0px, (100cqw - 640px) / 2, 32px));
  transform: rotate(-2deg);
}

/* только мобилка — там снизу карточки мало места, вылет наезжал на
   следующий шаг; на десктопе -6.41% (см. базовое правило) верны как есть */
.process__mobile .process-badge--2-bottom {
  bottom: 0;
}

.process-badge--3-top {
  top: 6.01%;
  right: calc(-1 * clamp(0px, (100cqw - 640px) / 2, 28px));
  transform: rotate(-3deg);
}

.process-badge--4-top {
  top: 6.81%;
  right: 3.91%;
  transform: rotate(2deg);
  color: var(--color-success);
}

.process-badge--4-bottom {
  bottom: 17.94%;
  left: calc(-1 * clamp(0px, (100cqw - 640px) / 2, 31px));
  transform: rotate(-2deg);
  color: var(--color-primary);
}

.process-badge__icon {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
}

/* галочка и точка-индикатор — кодом (border-trick / круг), а не SVG:
   единственная разница между зелёным/синим вариантом — цвет заливки */
.process-badge__icon--check {
  position: relative;
  border-radius: 50%;
}

.process-badge__icon--check::after {
  content: "";
  position: absolute;
  left: 5px;
  top: 3px;
  width: 5px;
  height: 8px;
  border: solid var(--color-white);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.process-badge__icon--green {
  background: var(--color-success);
}

.process-badge__icon--blue {
  background: var(--color-primary);
}

.process-badge__icon--dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-primary);
}

/* появление секции. Именно @keyframes, а не transition: лесенка задержек
   на transition висела бы и на смене активного шага — фон карточки
   переключался бы с задержкой до 0.5s */
@keyframes process-rise {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.process__header > *,
.process-step,
.process-step__connector {
  opacity: 0;
}

.process.is-inview .process__header > *,
.process.is-inview .process-step,
.process.is-inview .process-step__connector {
  animation: process-rise 0.65s var(--p-ease) both;
}

.process.is-inview .process__header > *:nth-child(2) {
  animation-delay: 0.06s;
}
.process.is-inview .process__header > *:nth-child(3) {
  animation-delay: 0.12s;
}
.process.is-inview .process-step:nth-of-type(1) {
  animation-delay: 0.18s;
}
.process.is-inview .process-step__connector:nth-of-type(1) {
  animation-delay: 0.24s;
}
.process.is-inview .process-step:nth-of-type(2) {
  animation-delay: 0.28s;
}
.process.is-inview .process-step__connector:nth-of-type(2) {
  animation-delay: 0.34s;
}
.process.is-inview .process-step:nth-of-type(3) {
  animation-delay: 0.38s;
}
.process.is-inview .process-step__connector:nth-of-type(3) {
  animation-delay: 0.44s;
}
.process.is-inview .process-step:nth-of-type(4) {
  animation-delay: 0.48s;
}

/* is-inview ставит JS — без него контент не должен остаться невидимым */
@media (scripting: none) {
  .process__header > *,
  .process-step,
  .process-step__connector,
  .process__slide.is-active {
    opacity: 1;
    transform: none;
  }
}

/* ---- две колонки (только ширина) ---- */
@media (min-width: 1024px) {
  .process {
    /* размеры по макету 1440×998 (см. Figma node 41689:10274), но с
       привязкой к vh: закреплённый блок обязан помещаться в экран, а
       макет нарисован под 998px высоты */
    --p-num: clamp(38px, 6.2vh, 56px);
    --p-title-a: clamp(1.0625rem, 2.2vh, 1.25rem); /* 17 → 20px */
    --p-title-i: clamp(1rem, 2vh, 1.125rem); /* 16 → 18px */
    --p-pad-x: 24px;
    --p-pad-a: clamp(16px, 2.7vh, 24px);
    --p-pad-i: clamp(10px, 1.8vh, 16px);
    --p-connector: clamp(16px, 3.5vh, 32px);
    --p-rail-x: 52px;
    --p-media-h: clamp(280px, 59vh, 534px);
  }

  .process__header {
    /* коэффициент по высоте снижен с 7vh: на экране 625px это давало
       44px отступа при дефиците всего в 13px */
    margin-bottom: clamp(20px, 4vh, 64px);
  }

  .process__title {
    /* 40px по макету на 1440 и шире, но к 1024 плавно уходит к 36px:
       на 40px строка «От задачи до выплаты…» требует 1012px, а в
       контейнере там 929px, и она переносится на вторую строку. Одна
       лишняя строка заголовка — это 46px, ровно та высота, из-за
       которой закреплённый блок переставал помещаться в экран. */
    font-size: clamp(2.25rem, 1.634rem + 0.96vw, 2.5rem);
  }

  .process__desc {
    font-size: 1.0625rem; /* 17px */
  }

  .process__columns {
    flex-direction: row;
    align-items: center;
    gap: 80px;
  }

  .process__steps {
    /* реальный минимум, не 0 — рядом сосед со своим basis */
    flex: 0 1 420px;
    min-width: 320px;
  }

  .process__showcase {
    /* 640px — реальная ширина карточек сейчас, не 780 (та рамка с
       бейджами внутри, которой в разметке больше нет, см. .process__card).
       Пол ниже, чем у Hero-мокапа: там overflow:hidden прятал лишнее,
       здесь плоский PNG-скриншот — при слишком сильном сжатии текст на
       нём просто станет нечитаемым, не переносится как HTML */
    flex: 1 1 640px;
    min-width: 300px;
  }
}

/* ---- закрепление ----
   Условие составное, через запятую (это ИЛИ), потому что требуемая высота
   зависит от ширины: чем уже экран, тем больше строк занимают заголовок
   секции и описания шагов, и тем выше получается блок. Пороги взяты из
   замеров, а не на глаз — при меньших значениях низ блока срезается, и
   доскроллить до него нельзя, прокрутка в этот момент управляет шагами. */
@media (min-width: 1200px) and (min-height: 620px),
  (min-width: 1024px) and (min-height: 740px) {
  .process {
    padding-block: 0;
  }

  .process__track {
    height: calc(100vh + 3 * var(--p-step-scroll));
  }

  .process__pin {
    position: sticky;
    top: 0;
    height: 100vh;
    display: grid;
    align-content: center;
    /* шапка сайта sticky и перекрывает верх экрана */
    padding-top: var(--p-header-h);
  }
}

@media (prefers-reduced-motion: reduce) {
  .process *,
  .process *::before,
  .process *::after {
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    animation: none !important;
  }

  .process__header > *,
  .process-step,
  .process-step__connector,
  .process__slide.is-active {
    opacity: 1;
    transform: none;
  }
}

/* ---------- professions categories (bento) ----------
   Desktop is 3 independent flex rows with different width ratios per
   row (652/290/290, then 411/411/411, then 290/290/652) — not one CSS
   grid, since a single grid shares column tracks across every row and
   can't express three different splits. Mobile is a plain uniform 2-col
   grid instead. Same DOM serves both: .bento-row is `display: contents`
   on mobile (unwraps itself so its cards become direct grid items,
   auto-flowing 2-per-row) and a real flex row only once the @container
   breakpoint switches .bento-grid itself to column-stacked flex. */
.professions-categories {
  container-type: inline-size;
  background: #f7f8fc;
}

.professions-categories__header {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 32px;
}

.professions-categories__title {
  font-size: 1.75rem; /* 28px */
  font-weight: 700;
  line-height: 1.214;
  color: var(--color-ink-2);
}

/* два экземпляра в DOM (как .mobile-menu дублирует .nav) — на мобилке
   это обычный чип под заголовком, на десктопе floating-бейдж, свисающий
   с угла первой плитки; position:absolute должен считаться от ближайшего
   позиционированного предка, так что десктопный экземпляр физически лежит
   внутри .bento-card--wide, а не под заголовком, где он на мобилке */
.today-chip {
  width: fit-content;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  background: var(--color-white);
  border: 1px solid var(--color-border);
  font-size: 0.75rem; /* 12px */
  font-weight: 600;
  color: var(--color-ink-2);
}

.today-chip--desktop {
  display: none;
}

.today-chip__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-primary);
  flex-shrink: 0;
}

.bento-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}

/* совсем узко — 2 колонки уже не помещаются, схлопываем в одну */
@container (max-width: 374px) {
  .bento-grid {
    grid-template-columns: 1fr;
  }
}

.bento-row {
  display: contents;
}

.bento-card,
.bento-cta {
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.bento-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.bento-card__icon {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: var(--color-primary-soft);
  display: flex;
  align-items: center;
  justify-content: center;
}

.bento-card__icon img {
  /* max, не фикс — иконки разного нативного соотношения сторон (тег
     32×24, велосипед 29×18, гаечный ключ 15.7×24...), фиксированный
     квадрат их растягивал/сплющивал каждую по-своему */
  width: auto;
  height: auto;
  max-width: 16px;
  max-height: 16px;
}

.bento-card__count {
  font-size: 0.625rem; /* 10px */
  font-weight: 600;
  color: var(--color-text-muted);
  white-space: nowrap;
}

.bento-card__title {
  font-weight: 700;
  font-size: 0.875rem; /* 14px */
  color: var(--color-ink-2);
}

/* ---------- bento-card: ховер ----------
   Четыре слоя, все на transform/opacity/color — плитку не пересчитывает
   ни одна из анимаций:
     1) пятно света, едущее за курсором (--mx/--my ставит js/main.js),
     2) подъём карточки с мягкой синей тенью и подкраской рамки,
     3) плашка иконки заливается синим, сама иконка становится белой,
     4) заголовок уходит в синий и подаётся вправо.

   Всё внутри @media (hover: hover): на тач-устройствах ховер «залипает»
   после тапа и состояние остаётся висеть, пока не тапнешь мимо. */
.bento-card {
  position: relative;
  /* своя область наложения, чтобы пятно с z-index:-1 не ушло за карточку */
  isolation: isolate;
  /* overflow здесь НЕ нужен и вреден: пятно лежит в inset: 0 со скруглением
     по карточке и за её границы не выйдет само по себе, а вот чип «Доступны
     сегодня» у широкой плитки намеренно вынесен наружу (right: -110px,
     bottom: -11px) — обрезка съедала его */
  transition: transform 0.35s var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)),
    border-color 0.35s ease, box-shadow 0.35s ease;
}

/* Порядок перекрытия. Раньше позиционированной была только широкая плитка,
   поэтому она одна попадала в слой позиционированных элементов и рисовалась
   поверх соседних — вместе со своим вынесенным наружу чипом. Теперь
   позиционированы все плитки, и они рисуются в порядке разметки: соседняя
   карточка накрывала чип. Задаём порядок явно.

   Широкая выше наведённой: чип маленький, а перекрытая тень у соседа
   заметнее, чем срезанный угол чипа. */
.bento-card--wide {
  z-index: 2;
}

.bento-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s ease;
  background: radial-gradient(
    circle 140px at var(--mx, 50%) var(--my, 0%),
    rgba(23, 53, 245, 0.12),
    rgba(23, 53, 245, 0) 70%
  );
}

.bento-card__icon {
  transition: background-color 0.35s ease, transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.bento-card__icon img {
  transition: filter 0.35s ease;
}

.bento-card__title {
  transition: color 0.35s ease, transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

.bento-card__count {
  transition: color 0.35s ease;
}

@media (hover: hover) {
  .bento-card:hover {
    /* поднимаем над соседями, иначе их фон срезает тень наведённой плитки */
    z-index: 1;
    transform: translateY(-4px);
    border-color: rgba(23, 53, 245, 0.35);
    box-shadow: 0 14px 30px -12px rgba(23, 53, 245, 0.28);
  }

  .bento-card:hover::before {
    opacity: 1;
  }

  .bento-card:hover .bento-card__icon {
    background: var(--color-primary);
    transform: scale(1.1);
  }

  /* иконки двухцветные (#01123E и #1735F5) и лежат в <img>, поэтому
     currentColor до них не достаёт — на залитой синим плашке уводим их
     в чистый белый фильтром */
  .bento-card:hover .bento-card__icon img {
    filter: brightness(0) invert(1);
  }

  .bento-card:hover .bento-card__title {
    color: var(--color-primary);
    transform: translateX(3px);
  }

  .bento-card:hover .bento-card__count {
    color: var(--color-ink-2);
  }
}

@media (prefers-reduced-motion: reduce) {
  .bento-card,
  .bento-card::before,
  .bento-card__icon,
  .bento-card__icon img,
  .bento-card__title,
  .bento-card__count {
    transition-duration: 0.01ms;
  }

  .bento-card:hover,
  .bento-card:hover .bento-card__icon,
  .bento-card:hover .bento-card__title {
    transform: none;
  }
}

.bento-cta {
  grid-column: 1 / -1;
  background: var(--color-ink);
  border: 0;
  gap: 16px;
}

.bento-cta__text {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.bento-cta__title {
  font-weight: 700;
  font-size: 1.125rem; /* 18px */
  color: var(--color-white);
}

.bento-cta__desc {
  font-size: 0.8125rem; /* 13px */
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.7);
}

.bento-cta__btn {
  width: 100%;
}

@container (min-width: 900px) {
  .professions-categories__header {
    margin-bottom: 56px;
  }

  .professions-categories__title {
    font-size: 2.5rem; /* 40px */
    line-height: 1.2;
  }

  /* бейдж теперь физически внутри .bento-card--wide (первая плитка),
     позиционируется от её собственного края — никакой cqw-математики
     не нужно, карточка сама меняет размер, бейдж просто едет с ней */
  .bento-row:nth-of-type(1) .bento-card--wide {
    position: relative;
  }

  .today-chip--mobile {
    display: none;
  }

  .today-chip--desktop {
    display: inline-flex;
    position: absolute;
    bottom: -11px;
    right: -110px;
    transform: rotate(3deg);
  }

  .bento-grid {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 24px;
  }

  .bento-row {
    display: flex;
    gap: 24px;
  }

  .bento-row:nth-of-type(1) .bento-card--wide {
    flex: 652 1 0%;
  }
  .bento-row:nth-of-type(1) .bento-card:not(.bento-card--wide) {
    flex: 290 1 0%;
  }

  .bento-row--even .bento-card {
    flex: 411 1 0%;
  }

  .bento-row:nth-of-type(3) .bento-card {
    flex: 290 1 0%;
  }
  .bento-row:nth-of-type(3) .bento-cta {
    flex: 652 1 0%;
  }

  .bento-card,
  .bento-cta {
    padding: 28px;
    border-radius: var(--radius-xl);
    justify-content: space-between;
    box-shadow: var(--shadow-card);
  }

  .bento-card {
    height: 180px;
  }

  /* min-height, не height: если тексту с кнопкой не хватает ширины в
     ряд, .bento-cta ниже переносит кнопку на вторую строку сама (flex-wrap,
     без брейкпоинта) — жёсткая высота обрезала бы перенесённый контент */
  .bento-cta {
    min-height: 180px;
  }

  .bento-card__icon {
    width: 48px;
    height: 48px;
    border-radius: var(--radius-md);
  }

  .bento-card__icon img {
    width: auto;
    height: auto;
    max-width: 24px;
    max-height: 24px;
  }

  .bento-card__count {
    padding: 6px 12px;
    border-radius: var(--radius-pill);
    background: #f1f5f9;
    font-size: 0.8125rem; /* 13px */
  }

  .bento-card__title {
    font-size: 1.375rem; /* 22px */
  }

  .bento-cta {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
  }

  .bento-cta__text {
    flex: 1 1 260px;
    max-width: 340px;
  }

  .bento-cta__desc {
    color: rgba(255, 255, 255, 0.6);
  }

  .bento-cta__btn {
    width: auto;
    border-radius: var(--radius-pill);
  }
}

/* ---------- when we needed (3 карточки: тёмная hero + 2 обычные) ----------
   Мобилка — колонка, десктоп — ряд из трёх равных по ширине карточек
   (все flex: 1 1 0, в отличие от bento с разными долями). Высоту рядов
   не фиксируем в px — flex-row со стретчем по умолчанию сам выравнивает
   карточки по высоте самой высокой. */
.when-we-needed {
  container-type: inline-size;
  background: #f7f8fc;
  border-top: 1px solid var(--color-border);
}

.when-we-needed__header {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 32px;
}

.when-we-needed__title {
  font-family: var(--font-heading);
  font-size: 1.75rem; /* 28px */
  font-weight: 700;
  line-height: 1.214;
  color: var(--color-ink-2);
}

.when-we-needed__desc {
  font-size: 0.9375rem; /* 15px */
  line-height: 1.467;
  color: var(--color-text);
}

.when-we-needed__grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.wwn-card {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 28px;
  padding: 24px;
  border-radius: var(--radius-lg);
  background: var(--color-white);
  border: 1px solid var(--color-border);
}

.wwn-card--hero {
  background-color: var(--color-ink);
  background-image: url("../assets/icons/when-we-needed/wave-bg.svg");
  background-repeat: no-repeat;
  background-position: bottom center;
  background-size: 110%;
  border: 0;
}

.wwn-card__top {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.wwn-card__badge {
  width: fit-content;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  background: var(--color-primary-soft);
  color: var(--color-primary);
  font-size: 0.625rem; /* 10px */
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.wwn-card--hero .wwn-card__badge {
  background: rgba(255, 255, 255, 0.12);
  color: var(--color-white);
}

.wwn-card__title {
  font-size: 1.375rem; /* 22px */
  font-weight: 700;
  line-height: 1.2;
  color: var(--color-ink);
}

.wwn-card--hero .wwn-card__title {
  color: var(--color-white);
}

.wwn-card__desc {
  font-size: 0.875rem; /* 14px */
  line-height: 1.43;
  color: var(--color-text);
}

.wwn-card--hero .wwn-card__desc {
  color: rgba(255, 255, 255, 0.85);
}

.wwn-card__icon {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-pill);
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f8f9ff;
  border: 1px solid #e5e9fe;
}

.wwn-card--hero .wwn-card__icon {
  background: #243684;
  border: 0;
}

.wwn-card__icon img {
  /* max, не фикс — тот же приём, что и у иконок профессий (п. в гайде):
     сохраняем нативное соотношение сторон вместо принудительного квадрата */
  width: auto;
  height: auto;
  max-width: 24px;
  max-height: 24px;
}

/* молоток на мобилке крупнее остальных иконок этого блока — так в макете */
.wwn-card--tool .wwn-card__icon img {
  max-width: 32px;
  max-height: 32px;
}

@container (min-width: 900px) {
  .when-we-needed__header {
    margin-bottom: 64px;
  }

  .when-we-needed__title {
    font-size: 2.5rem; /* 40px */
    line-height: 1.2;
  }

  .when-we-needed__desc {
    font-size: 1.125rem; /* 18px */
    line-height: 1.556;
  }

  .when-we-needed__grid {
    flex-direction: row;
    gap: 24px;
  }

  .wwn-card {
    flex: 1 1 0%;
    height: 430px; /* точное значение из Figma-инспектора на 1280px */
    gap: 0;
    justify-content: space-between;
    padding: 32px;
    border-radius: var(--radius-xl);
  }

  .wwn-card--hero {
    background-position: -288px calc(100% - 14px);
    background-size: 792px 140px;
  }

  .wwn-card__badge {
    padding: 5px 10px;
    font-size: 0.6875rem; /* 11px */
    letter-spacing: 0.05em;
  }

  .wwn-card__title {
    font-size: 1.75rem; /* 28px */
    line-height: 1.214;
  }

  .wwn-card__desc {
    font-size: 0.9375rem; /* 15px */
    line-height: 1.467;
  }

  .wwn-card__icon {
    width: 52px;
    height: 52px;
  }

  .wwn-card--tool .wwn-card__icon img {
    max-width: 24px;
    max-height: 24px;
  }
}

/* ---------- pricing ---------- */
.pricing {
  container-type: inline-size;
}

.pricing__header {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 32px;
}

.pricing__title {
  font-family: var(--font-heading);
  font-size: 1.75rem; /* 28px */
  font-weight: 700;
  line-height: 1.214;
  color: var(--color-ink-2);
}

.pricing__grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.pricing-card {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 24px;
  border-radius: var(--radius-lg);
  background: var(--color-white);
  border: 1px solid var(--color-border);
  /* без этого длинное слово без пробелов (например, "Индивидуально" в цене)
     становится неразрывным min-content-полом — из-за него карточки в ряду
     с flex: 1 1 0% просаживаются неровно при недостатке места (см. п.12
     гайда), у каждой свой самый длинный "неразрывный" токен */
  hyphens: auto;
  overflow-wrap: break-word;
}

.pricing-card--featured {
  border: 2px solid var(--color-primary);
}

.pricing-card--dark {
  background: var(--color-ink-2);
  border: 0;
}

.pricing-card__body {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.pricing-card__head {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.pricing-card__title {
  font-size: 1.25rem; /* 20px */
  font-weight: 700;
  line-height: 1.2;
  color: var(--color-ink);
}

.pricing-card--dark .pricing-card__title {
  color: var(--color-white);
}

.pricing-card__desc {
  font-size: 0.8125rem; /* 13px */
  line-height: 1.38;
  color: var(--color-text);
}

.pricing-card--dark .pricing-card__desc {
  color: rgba(255, 255, 255, 0.75);
}

.pricing-card__price {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.pricing-card__price-value {
  font-size: 2rem; /* 32px */
  font-weight: 800;
  line-height: 1.2;
  color: var(--color-ink);
}

.pricing-card--dark .pricing-card__price-value {
  color: var(--color-white);
}

.pricing-card__price-note {
  font-size: 0.75rem; /* 12px */
  color: var(--color-text);
}

.pricing-card--dark .pricing-card__price-note {
  color: rgba(255, 255, 255, 0.6);
}

.pricing-card__features {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.pricing-card__features li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.8125rem; /* 13px */
  line-height: 1.3;
  color: var(--color-ink);
}

.pricing-card--dark .pricing-card__features li {
  color: var(--color-white);
}

.pricing-card__features img {
  flex-shrink: 0;
  width: 14px;
  height: 14px;
}

/* белая обводка на мобилке, сплошная белая заливка на десктопе (см. п.5 —
   разница между кадрами тут не дрейф, а реальный выбор дизайнера на каждом) */
.btn--secondary-light {
  background: transparent;
  color: var(--color-white);
  border: 1.5px solid var(--color-white);
}

.btn--secondary-light:hover {
  background: rgba(255, 255, 255, 0.08);
}

@container (min-width: 900px) {
  .pricing__header {
    margin-bottom: 56px;
  }

  .pricing__title {
    font-size: 2.5rem; /* 40px */
    line-height: 1.2;
  }

  .pricing__grid {
    flex-direction: row;
    gap: 24px;
  }

  .pricing-card {
    flex: 1 1 0%;
    justify-content: space-between;
    /* тянется вместе со страницей на всём диапазоне 900-1440 (эта раскладка
       не фиксируется по ширине, как п.9 карточка, а продолжает резиниться) —
       clamp() тут не костыль, а верный инструмент (см. п.1/9 гайда) */
    padding-block: clamp(25px, 2.778vw, 40px);
    padding-inline: clamp(20px, -13.333px + 3.704vw, 40px);
    border-radius: var(--radius-xl);
  }

  .pricing-card__body {
    gap: 32px;
  }

  .pricing-card__title {
    font-size: 1.5rem; /* 24px */
  }

  .pricing-card__desc {
    font-size: 0.875rem; /* 14px */
    line-height: 1.43;
  }

  .pricing-card__price-value {
    font-size: clamp(1.625rem, 0.583rem + 1.852vw, 2.25rem); /* 26px → 36px */
  }

  .pricing-card__features li {
    font-size: 0.875rem; /* 14px */
  }

  .pricing-card__features img {
    width: 16px;
    height: 16px;
  }

  .pricing-card--dark .btn--secondary-light {
    background: var(--color-white);
    color: var(--color-ink-2);
    border-color: var(--color-white);
  }
}

/* ---------- faq (аккордеон) ----------
   Высоту панели ответа НЕ задаём числом — grid-rows-приём: обёртка
   .faq-item__panel это display:grid с grid-template-rows: 0fr в закрытом
   состоянии и 1fr в открытом, transition идёт по этому свойству. Строка
   грида в 0fr буквально нулевая, а в 1fr равна высоте контента — переход
   между ними анимируется плавно без единого числа и без JS-замера
   scrollHeight. overflow:hidden на внутренней обёртке обязателен, иначе
   контент "торчит" наружу, пока трек ещё не дорос. Это сейчас более
   широко поддерживаемая техника, чем анимация через interpolate-size —
   тот пока есть только в Chromium (см. verstka-guide.md источники). */
.faq {
  container-type: inline-size;
  background: #fafbfc;
}

.faq__header {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 32px;
}

.faq__title {
  font-family: var(--font-heading);
  font-size: 1.75rem; /* 28px */
  font-weight: 700;
  line-height: 1.214;
  color: var(--color-ink-2);
}

.faq__list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}

.faq-item {
  border-radius: var(--radius-md);
  background: var(--color-white);
  border: 1px solid var(--color-border);
}

.faq-item__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  padding: 20px;
  text-align: left;
  font-size: 0.9375rem; /* 15px */
  font-weight: 700;
  color: var(--color-ink);
}

.faq-item__chevron {
  flex-shrink: 0;
  display: flex;
  transition: transform 0.25s ease;
}

.is-open .faq-item__chevron {
  transform: rotate(180deg);
}

.faq-item__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.3s ease;
}

.is-open .faq-item__panel {
  grid-template-rows: 1fr;
}

.faq-item__panel-inner {
  overflow: hidden;
  min-height: 0;
}

.faq-item__a {
  padding: 0 20px 20px;
  font-size: 0.8125rem; /* 13px */
  line-height: 1.54;
  color: var(--color-text);
}

@container (min-width: 900px) {
  .faq__header {
    margin-bottom: 48px;
  }

  .faq__title {
    font-size: 2.375rem; /* 38px, точное значение из десктоп-кадра */
    line-height: 1.21;
  }

  .faq__list {
    gap: 16px;
  }

  .faq-item {
    border-radius: var(--radius-lg);
  }

  .faq-item__q {
    padding: 24px;
    font-size: 1.125rem; /* 18px */
    color: var(--color-ink-2);
  }

  .faq-item__a {
    padding: 0 24px 24px;
    font-size: 0.875rem; /* 14px */
    line-height: 1.57;
  }
}

/* ---------- final cta ---------- */
.final-cta {
  container-type: inline-size;
  background: var(--color-ink);
}

.final-cta__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
  text-align: center;
}

.final-cta__head {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.final-cta__title {
  font-family: var(--font-heading);
  font-size: 2rem; /* 32px */
  font-weight: 700;
  line-height: 1.19;
  color: var(--color-white);
}

.final-cta__desc {
  font-size: 0.9375rem; /* 15px */
  line-height: 1.467;
  color: #f6f8fb;
}

.final-cta__actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}

.final-cta__btn {
  width: 100%;
  padding: 14px 24px;
  font-size: 1rem; /* 16px */
  border-radius: var(--radius-sm);
}

.final-cta__trust {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
}

.final-cta__badge {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 14px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 0.8125rem; /* 13px */
  font-weight: 600;
  color: var(--color-white);
}

.final-cta__badge-icon--mobile {
  width: 16px;
  height: 16px;
}

.final-cta__badge-icon--desktop {
  display: none;
}

@container (min-width: 900px) {
  .final-cta__inner {
    gap: 48px;
  }

  .final-cta__head {
    gap: 24px;
    max-width: 780px;
  }

  .final-cta__title {
    font-size: 3.5rem; /* 56px */
    line-height: 1.1;
  }

  .final-cta__desc {
    font-size: 1.25rem; /* 20px */
    line-height: 1.5;
  }

  .final-cta__actions {
    flex-direction: row;
    width: auto;
  }

  .final-cta__btn {
    width: auto;
    padding: 16px 32px;
    font-size: 1.125rem; /* 18px */
    border-radius: var(--radius-md);
  }

  .final-cta__trust {
    flex-direction: row;
    width: auto;
    gap: 24px;
  }

  .final-cta__badge {
    width: auto;
    padding: 10px 16px;
    font-size: 0.875rem; /* 14px */
  }

  .final-cta__badge-icon--mobile {
    display: none;
  }

  .final-cta__badge-icon--desktop {
    display: block;
    width: 18px;
    height: 18px;
  }
}

/* ---------- footer ---------- */
.footer {
  container-type: inline-size;
  background: var(--color-ink-2);
  padding-block: 40px;
}

.footer__inner {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.footer__columns {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.footer__col {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.footer__col--brand {
  gap: 12px;
}

.footer__logo {
  width: 82px;
  height: 27px;
}

.footer__brand-desc {
  font-size: 0.8125rem; /* 13px */
  line-height: 1.4;
  color: #9ca3af;
}

.footer__col-title {
  font-size: 0.9375rem; /* 15px */
  font-weight: 600;
  color: var(--color-white);
}

.footer__link {
  font-size: 0.875rem; /* 14px */
  color: #9ca3af;
}

.footer__separator {
  height: 1px;
  background: rgba(255, 255, 255, 0.24);
}

.footer__legal {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.footer__requisites {
  font-size: 0.75rem; /* 12px */
  line-height: 1.5;
  color: #9ca3af;
}

.footer__copyright {
  font-size: 0.75rem; /* 12px */
  color: #9ca3af;
}

@container (min-width: 900px) {
  .footer {
    padding-block: 64px;
  }

  .footer__inner {
    gap: 48px;
  }

  .footer__columns {
    flex-direction: row;
    gap: 64px;
  }

  .footer__col {
    flex: 1 1 0%;
    gap: 16px;
  }

  .footer__logo {
    width: 122px;
    height: 40px;
  }

  .footer__brand-desc {
    font-size: 0.875rem; /* 14px */
    line-height: 1.43;
  }

  .footer__col-title {
    font-size: 1rem; /* 16px */
  }

  .footer__legal {
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
  }

  .footer__requisites {
    font-size: 0.8125rem; /* 13px */
  }
}

/* ---------- calculator ----------
   Статично, без JS — значения захардкожены как в макете, дизайнер ещё
   не определился с логикой расчёта. */
.calculator {
  container-type: inline-size;
}

.calculator__header {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  margin-bottom: 20px;
}

.calculator__title {
  font-family: var(--font-heading);
  font-size: 1.75rem; /* 28px */
  font-weight: 700;
  line-height: 1.214;
  color: var(--color-ink-2);
}

.calculator__layout {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.calculator__panel {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* сегментированный тумблер (мобилка) */
.calc-tariff--desktop {
  display: none;
}

.calc-tariff__segmented {
  display: flex;
  gap: 4px;
  padding: 4px;
  border-radius: var(--radius-md);
  background: #f1f5f9;
}

.calc-tariff__segment {
  flex: 1 1 0%;
  height: 32px;
  border-radius: var(--radius-sm);
  background: var(--color-white);
  font-size: 0.8125rem; /* 13px */
  font-weight: 600;
  color: var(--color-text);
}

.calc-tariff__segment.is-active {
  background: var(--color-primary);
  font-weight: 700;
  color: var(--color-white);
}

.calc-tariff__note {
  margin-top: 6px;
  font-size: 0.75rem; /* 12px */
  line-height: 1.33;
  color: var(--color-text);
}

/* карточки-варианты тарифа (десктоп) */
.calc-tariff__option {
  flex: 1 1 0%;
  height: 72px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 12px;
  border-radius: var(--radius-md);
  background: var(--color-white);
  border: 1px solid var(--color-border);
  text-align: center;
}

.calc-tariff__option.is-active {
  background: var(--color-primary);
  border-color: transparent;
}

.calc-tariff__option-title {
  font-size: 0.875rem; /* 14px */
  font-weight: 700;
  color: var(--color-ink-2);
}

.calc-tariff__option.is-active .calc-tariff__option-title {
  color: var(--color-white);
}

.calc-tariff__option-sub {
  font-size: 0.75rem; /* 12px */
  font-weight: 500;
  color: var(--color-text);
}

.calc-tariff__option.is-active .calc-tariff__option-sub {
  color: rgba(255, 255, 255, 0.8);
}

.calc-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
}

.calc-field__label {
  font-size: 0.875rem; /* 14px */
  letter-spacing: 0.1px;
  color: var(--color-text-muted);
}

.calc-field__input {
  height: 48px;
  width: 100%;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border-2);
  background: var(--color-white);
  font-family: inherit;
  font-size: 1rem; /* 16px */
  color: var(--color-ink-2);
  transition: border-color 0.15s ease;
}

.calc-field__input:focus {
  outline: none;
  border-color: var(--color-primary);
}

/* ---------- calc-select: кастомный выпадающий список ---------- */
.calc-select {
  position: relative;
  width: 100%;
}

.calc-select__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  text-align: left;
  cursor: pointer;
}

.calc-select__value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.calc-select.is-placeholder .calc-select__value {
  color: var(--color-text-muted);
}

.calc-select__chevron {
  flex-shrink: 0;
  width: 14px;
  height: 14px;
  transition: transform 0.15s ease;
}

.calc-select__toggle[aria-expanded="true"] .calc-select__chevron {
  transform: rotate(180deg);
}

.calc-select__options {
  position: absolute;
  z-index: 5;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 240px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border-2);
  background: var(--color-white);
  box-shadow: 0px 16px 16px rgba(3, 18, 58, 0.1);
  /* открытие идёт через .is-open (см. main.js), а не мгновенный [hidden] —
     тот снимается до начала анимации и возвращается только после её конца,
     иначе display:none обнулял бы transition, как и у модалки (см. её же
     .modal__panel) */
  opacity: 0;
  transition: opacity 0.15s ease;
}

.calc-select__options.is-open {
  opacity: 1;
}

.calc-select__options[hidden] {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .calc-select__options {
    transition: none;
  }
}

/* тонкий приглушённый скролл (тот же приём — 4px, radius 2px — что в
   ruqi-smena-front) для мест, где на мелких
   экранах реально может появиться внутренний скролл, плюс липкое
   оглавление правовых страниц, где он есть всегда */
.calc-select__options,
.modal__panel,
.legal__toc {
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar-thumb) transparent;
}

.calc-select__options::-webkit-scrollbar,
.modal__panel::-webkit-scrollbar,
.legal__toc::-webkit-scrollbar {
  width: 4px;
  height: 4px;
}

.calc-select__options::-webkit-scrollbar-track,
.modal__panel::-webkit-scrollbar-track,
.legal__toc::-webkit-scrollbar-track {
  background-color: transparent;
}

.calc-select__options::-webkit-scrollbar-thumb,
.modal__panel::-webkit-scrollbar-thumb,
.legal__toc::-webkit-scrollbar-thumb {
  background-color: var(--scrollbar-thumb);
  border-radius: 2px;
}

/* подсветка на наведении есть только у webkit-псевдоэлементов:
   стандартное scrollbar-color состояний не поддерживает */
.calc-select__options::-webkit-scrollbar-thumb:hover,
.modal__panel::-webkit-scrollbar-thumb:hover,
.legal__toc::-webkit-scrollbar-thumb:hover {
  background-color: var(--scrollbar-thumb-hover);
}

.calc-select__options li {
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  font-size: 0.9375rem; /* 15px */
  color: var(--color-ink-2);
  cursor: pointer;
}

.calc-select__options li.is-highlighted {
  background: var(--color-primary-soft);
}

.calc-select__options li[aria-selected="true"] {
  font-weight: 600;
  color: var(--color-primary);
}

.calc-fields-row {
  display: contents;
}

.calc-result {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  padding: 16px;
  border-radius: var(--radius-lg);
  background: var(--color-ink-2);
  border: 1px solid var(--color-primary);
  box-shadow: 0px 12px 14px rgba(23, 53, 245, 0.2);
}

.calc-result__heading {
  font-size: 1rem; /* 16px */
  font-weight: 700;
  color: var(--color-white);
}

.calc-result__details {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--color-text-muted);
  font-size: 0.8125rem; /* 13px */
}

.calc-result__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 4px 8px;
}

.calc-result__row span:first-child {
  color: #f6f8fb;
}

.calc-result__row span:last-child {
  font-weight: 700;
  color: var(--color-white);
  /* подстраховка от переполнения — числа посчитаны из пользовательского
     ввода и в теории могут быть очень длинными (см. maxlength на инпутах,
     это первая линия защиты, а перенос строки — вторая, на случай если
     туда всё же прилетит что-то большое) */
  overflow-wrap: anywhere;
  text-align: right;
}

.calc-result__total {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.calc-result__total-label {
  font-size: 0.75rem; /* 12px */
  color: #f6f8fb;
}

.calc-result__total-value {
  font-size: 1.5rem; /* 24px */
  font-weight: 700;
  color: var(--color-white);
  overflow-wrap: anywhere;
}

@container (min-width: 900px) {
  .calculator__header {
    margin-bottom: 48px;
  }

  .calculator__title {
    font-size: 2.375rem; /* 38px, точное значение из десктоп-кадра */
    line-height: 1.21;
  }

  .calculator__layout {
    flex-direction: row;
    gap: 32px;
  }

  .calculator__panel {
    flex: 1 1 0%;
    gap: 24px;
    padding: 40px;
    border-radius: var(--radius-xl);
    background: #fafbfc;
    border: 1px solid var(--color-border);
  }

  .calc-fields-row {
    display: flex;
    gap: 16px;
  }

  .calc-result {
    flex: 0 0 420px;
    gap: 24px;
    padding: 32px;
    border: 0;
    box-shadow: none;
  }

  .calc-result__heading {
    font-size: 1.5rem; /* 24px */
    font-weight: 400;
    line-height: 1.33;
  }

  .calc-result__details {
    gap: 16px;
    padding-bottom: 20px;
    font-size: 0.9375rem; /* 15px */
  }

  .calc-result__row span:last-child {
    font-weight: 400;
  }

  .calc-result__total-value {
    font-size: 2.5rem; /* 40px */
    line-height: 1.5;
  }
}

/* переключатель тарифа держит компактный мобильный вид (сегмент-контрол)
   дольше, чем остальная панель — на 900-1023px десктопным карточкам не
   хватает ширины (см. п. в гайде про промежуточные ширины), а сегмент-
   контрол в этом диапазоне работает нормально. Только сам переключатель,
   остальной блок переключается на 900px, как обычно. */
@container (min-width: 1024px) {
  .calc-tariff--mobile {
    display: none;
  }

  .calc-tariff--desktop {
    display: flex;
    gap: 12px;
    width: 100%;
  }
}

/* ---------- правовые страницы (политика конфиденциальности) ----------
   Длинный юридический документ читают не подряд, а ищут в нём нужный
   пункт. Поэтому две вещи: оглавление, липнущее сбоку, и подсветка того
   раздела, который сейчас на экране (scroll spy в js/main.js).

   Ширина текста ограничена 68 символами: на всю ширину экрана такой
   документ читать невозможно, глаз теряет строку при возврате. */
.legal-hero {
  padding-block: clamp(32px, 6vw, 72px) clamp(28px, 4vw, 48px);
  background: linear-gradient(180deg, #f7f8fc 0%, var(--color-bg) 100%);
  border-bottom: 1px solid var(--color-border);
}

.legal-hero__inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}

.legal-hero__crumbs {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-sm);
  color: var(--color-text);
}

.legal-hero__crumbs a {
  color: var(--color-text);
}

.legal-hero__crumbs a:hover {
  color: var(--color-primary);
}

.legal-hero__crumbs span[aria-current] {
  color: var(--color-ink-2);
  font-weight: 500;
}

.legal-hero__title {
  /* без ограничения ширины: заголовок задуман на всю колонку */
  font-family: var(--font-heading);
  font-size: var(--fs-h1);
  font-weight: 800;
  line-height: var(--lh-tight);
  color: var(--color-ink-2);
}

/* ---- раскладка ---- */
.legal {
  padding-block: clamp(32px, 5vw, 64px) var(--section-py);
}

.legal__inner {
  display: grid;
  gap: clamp(28px, 4vw, 56px);
}

/* ---- оглавление ---- */
.legal__toc-title {
  margin: 0 0 12px;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text);
}

.legal__toc-nav {
  display: flex;
  flex-direction: column;
}

.legal__toc-link {
  display: flex;
  gap: 10px;
  padding: 7px 0 7px 14px;
  border-left: 2px solid var(--color-border);
  font-size: var(--fs-sm);
  line-height: 1.35;
  color: var(--color-text);
  transition: color 0.2s ease, border-color 0.2s ease;
}

.legal__toc-link:hover {
  color: var(--color-ink-2);
  border-left-color: var(--color-text);
}

/* класс ставит scroll spy в js/main.js */
.legal__toc-link.is-current {
  color: var(--color-primary);
  font-weight: 600;
  border-left-color: var(--color-primary);
}

.legal__toc-num {
  flex-shrink: 0;
  min-width: 1.4em;
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
}

.legal__toc-link.is-current .legal__toc-num {
  color: var(--color-primary);
}

/* ---- текст ---- */
.legal__body {
  min-width: 0;
  max-width: 68ch;
}

.legal__section {
  /* padding, а не margin: переход по якорю ставит верх секции вплотную под
     шапку, и без этого запаса заголовок прилипал бы к ней вплотную */
  padding-top: 28px;
}

.legal__section + .legal__section {
  margin-top: 12px;
  border-top: 1px solid var(--color-border);
}

.legal__h {
  display: flex;
  gap: 12px;
  margin: 0 0 14px;
  font-family: var(--font-heading);
  font-size: var(--fs-h3);
  font-weight: 700;
  line-height: var(--lh-snug);
  color: var(--color-ink-2);
}

.legal__h-num {
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  color: var(--color-primary);
}

.legal__p {
  margin: 0 0 12px;
  font-size: var(--fs-body-md);
  line-height: 1.7;
  color: var(--color-text-muted);
}

/* Номер пункта висит в отдельной колонке слева, а не внутри абзаца: так
   текст выравнивается по одной вертикали независимо от длины номера, и
   глаз при поиске нужного пункта скользит по прямой.

   Сетка, а не отрицательный отступ: с отступом номер вылезал бы за левый
   край колонки текста. Второй элемент сетки — сам текст: в грид-контейнере
   голый текстовый узел становится анонимным элементом и встаёт во вторую
   колонку сам. Класс-модификатор обязателен — у абзацев без номера
   единственный элемент ушёл бы в узкую первую колонку. */
.legal__p--num {
  display: grid;
  grid-template-columns: 3.4em minmax(0, 1fr);
}

.legal__num {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--color-ink-2);
}

.legal__list {
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.legal__list li {
  position: relative;
  padding-left: 20px;
  font-size: var(--fs-body-md);
  line-height: 1.7;
  color: var(--color-text-muted);
}

.legal__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.82em;
  width: 8px;
  height: 1px;
  background: var(--color-primary);
}

.legal__link {
  color: var(--color-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(23, 53, 245, 0.35);
}

.legal__link:hover {
  text-decoration-color: var(--color-primary);
}

/* ---- полоса прочитанного ----
   Ширину задаёт js/main.js через --read, ставится на :root */
.read-progress {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 45;
  height: 2px;
  width: 100%;
  transform: scaleX(var(--read, 0));
  transform-origin: left center;
  background: linear-gradient(90deg, var(--color-primary), #6f8bff);
  pointer-events: none;
}

@media (min-width: 900px) {
  .legal__inner {
    grid-template-columns: 260px minmax(0, 1fr);
    align-items: start;
  }

  .legal__toc {
    position: sticky;
    /* высоту шапки меряет скрипт, см. блок замера в js/main.js */
    top: calc(var(--header-h) + 24px);
    max-height: calc(100vh - var(--header-h) - 48px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  .legal__body {
    padding-top: 0;
  }
}

/* на узких экранах оглавление становится обычным блоком сверху */
@media (max-width: 899px) {
  .legal__toc {
    padding: 16px 18px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: #f8f9fb;
  }

  .legal__toc-link {
    padding-block: 6px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .legal__toc-link {
    transition: none;
  }
}

/* ---------- правовые страницы: оферта и соглашение ---------- */

/* Заголовок без своего номера: в этих двух документах нумерация уже вшита
   в текст заголовка («1. Предмет договора»), а приложения не нумерованы
   вовсе — свой счётчик поверх дал бы фальшивые номера */
.legal__h--plain {
  display: block;
}

.legal__sub {
  margin: 22px 0 10px;
  font-family: var(--font-heading);
  font-size: var(--fs-body-lg);
  font-weight: 700;
  color: var(--color-ink-2);
}

.legal__body em {
  font-style: italic;
  color: var(--color-ink-2);
}

/* ---- сноски-подсказки ----
   В оферте термины подчёркнуты и раскрываются по наведению. tabindex на
   элементе стоит в разметке, поэтому подсказка доступна и с клавиатуры —
   :focus-within ловит как наведение мышью, так и переход табом */
.legal__term {
  position: relative;
  color: var(--color-ink-2);
  font-weight: 500;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  text-decoration-color: rgba(23, 53, 245, 0.5);
  cursor: help;
}

/* Подсказка висит у термина и по ширине равна своему тексту.

   Горизонтальный сдвиг проставляет js/main.js: в CSS неоткуда узнать, в
   каком месте строки окажется слово после переноса, а у правого края
   колонки окошко вылезало за экран. Скрипт же ограничивает и ширину —
   колонкой текста, иначе сдвигать было бы некуда.

   Без скрипта подсказка просто выровняется по левому краю термина. */
.legal__term-note {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  z-index: 20;
  width: max-content;
  max-width: min(460px, 84vw);
  padding: 12px 14px;
  border-radius: var(--radius-md);
  background: var(--color-ink-2);
  color: var(--color-white);
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: 1.5;
  text-decoration: none;
  box-shadow: 0 12px 32px -10px rgba(3, 18, 58, 0.45);
  opacity: 0;
  visibility: hidden;
  transform: translate(var(--note-x, 0px), 4px);
  transition: opacity 0.18s ease, transform 0.18s ease, visibility 0s linear 0.18s;
}

/* Класс ставит скрипт, когда над строкой не хватает места: у верхней
   кромки экрана подсказка уходила бы под шапку */
.legal__term-note.is-below {
  bottom: auto;
  top: calc(100% + 8px);
  transform: translate(var(--note-x, 0px), -4px);
}

.legal__term:hover .legal__term-note,
.legal__term:focus-within .legal__term-note,
.legal__term:focus .legal__term-note {
  opacity: 1;
  visibility: visible;
  transform: translate(var(--note-x, 0px), 0);
  transition-delay: 0s;
}

/* ---- словарь терминов ----
   В PDF соглашения сноски стоят внизу страниц; при переносе в веб они
   собраны в один раздел в конце, иначе ломали бы чтение посреди абзаца */
.legal__terms {
  margin: 0;
}

.legal__terms dt {
  margin-top: 16px;
  font-weight: 700;
  color: var(--color-ink-2);
}

.legal__terms dd {
  margin: 4px 0 0;
  font-size: var(--fs-body-md);
  line-height: 1.7;
  color: var(--color-text-muted);
}

@media (prefers-reduced-motion: reduce) {
  .legal__term-note {
    transition: none;
  }
}
