/* Hallmark · genre: modern-minimal · macrostructure: Split Studio · theme: custom (signal blue on ink)
 * hero: H2 Split Diptych · nav: N5 Floating pill · footer: Ft5 Statement · features: F4 Step sequence
 * enrichment: Tier B — hand-built SVG wordmark with CSS-animated run cycle
 * pre-emit critique: P5 H5 E4 S5 R4 V5
 */

/* tokens.css подключается ссылкой в <head>, а не отсюда. @import стоил одного
   круга сети на каждой загрузке: браузер узнаёт о втором файле только после
   того, как скачал и разобрал первый. Замер 07.08.2026 на боевом сайте:
   styles.css завершался на 930 мс, tokens.css СТАРТОВАЛ на 932, шрифты — на
   1391. Три круга подряд перед первой отрисовкой.
   Ставит ссылку scripts/link-tokens-css.py, стережёт check-site.py. */

/* ============ база ============ */

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  overflow-x: clip;
}

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Трекинг и интерлиньяж идут ПАРОЙ с размером, а не задаются раз на все заголовки.
   Значения ниже — дефолт для заголовка среднего кегля (h3, h4); крупные кегли
   перекрывают его своим трекингом рядом с font-size. Почему так, а не одним
   числом на всё, — в шапке шкалы в tokens.css. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 700;
  letter-spacing: var(--track-lg);
  line-height: var(--lead-lg);
  margin: 0;
  overflow-wrap: anywhere;
  min-width: 0;
  /* Строки заголовка выравниваются по длине. Без этого перенос идёт «как влезет»:
     H1 главной на 1440 px давал «Из Китая — через» / «одного» / «оператора.» —
     вторая строка вчетверо короче первой, и заголовок читается как обрубленный.
     Свойство работает до шести строк, дальше браузер молча переходит к обычному
     переносу, — для заголовков этого хватает с запасом. */
  text-wrap: balance;
}

p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img, svg { max-width: 100%; }

a {
  color: inherit;
  text-decoration: none;
}

/* Ссылка внутри текста обязана быть видна ссылкой. Подчёркивание снято глобально
   строкой выше — это верно для кнопок, пунктов меню и карточек-ссылок, у которых
   своя форма. Но в абзаце оно снималось тоже, и «Калькулятор считает обе схемы
   рядом» выглядело сплошным предложением: ни цвета, ни линии, ни курсора-руки до
   наведения. На тёмной полосе это заметнее всего — там даже оттенка нет.

   Отбираются ссылки БЕЗ собственного класса: у всякой ссылки-элемента (.btn,
   .nav__links a, .route a) класс есть, а текстовая ссылка пишется голым тегом.
   Признак держится сам собой — новая ссылка в тексте получит вид без правки CSS.

   Подчёркивание тонкое и отодвинуто от букв: линия вплотную режет нижние выносные
   у «р», «у», «д». WCAG 1.4.1 — различие не должно держаться на одном цвете.

   Навигация исключена целиком: `:not(nav a)` отсекает потомков любого <nav> —
   и шапки, и подвала. Первая редакция правила этого не делала, и пункты меню
   («Белый ввоз», «Направления», «Услуги») приехали подчёркнутыми: они лежат
   в <li> и класса не имеют, то есть под условие подходили полностью. У пункта
   меню свой указатель — акцентная линия снизу по наведению; вторая линия рядом
   с ней читается как сбой стилей. Поймано на скриншоте первого экрана. */
:where(p, li, dd, dt, td, figcaption) a:not([class]):not(nav a) {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in oklch, currentColor 45%, transparent);
  text-underline-offset: 0.18em;
  transition: text-decoration-color var(--dur-micro) var(--ease-out),
              color var(--dur-micro) var(--ease-out);
}
:where(p, li, dd, dt, td, figcaption) a:not([class]):not(nav a):hover {
  color: var(--color-accent-deep);
  text-decoration-color: var(--color-accent-deep);
}
.band--deep :where(p, li, dd, dt, td) a:not([class]):not(nav a):hover {
  color: var(--color-accent);
  text-decoration-color: var(--color-accent);
}

:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* Пропуск навигации. Мышью не видна никогда, по Tab выезжает первой:
   иначе до первого предложения текста двадцать нажатий, и так на каждой
   из сорока четырёх страниц. WCAG 2.4.1, уровень A.

   Не display:none и не visibility:hidden — так её не найдёт и клавиатура.
   Приём стандартный: элемент размером в пиксель, вынесенный за край экрана,
   возвращается на место по фокусу. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 0.7rem 1.1rem;
  background: var(--color-deep);
  color: var(--color-ink-invert);
  border-radius: 0 0 var(--radius-sm) 0;
  font-size: var(--text-sm);
  text-decoration: none;
  /* Без этого «Перейти к содержанию» выезжает в две строки узкой плашкой:
     absolute-элемент в углу ужимается по доступной ширине. Проверено живьём
     08.08.2026 — было 118×66 вместо одной строки. */
  white-space: nowrap;
}
.skip-link:focus {
  left: 0;
}

.wrap {
  max-width: 76rem;
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-muted);
}

.lede {
  font-size: var(--text-md);
  color: var(--color-muted);
  max-width: var(--measure);
}

.num { font-variant-numeric: tabular-nums; }

/* ============ навигация · N5 floating pill ============ */

.nav {
  position: fixed;
  top: var(--space-sm);
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-nav);
  display: inline-flex;
  align-items: center;
  gap: var(--space-md);
  padding: 0.4rem 0.4rem 0.4rem 0.9rem;
  /* плотность 93 %, а не 80: пилюля проезжает над тёмными полосами и на них мутнеет */
  background: color-mix(in oklch, var(--color-paper) 93%, transparent);
  backdrop-filter: blur(16px) saturate(130%);
  -webkit-backdrop-filter: blur(16px) saturate(130%);
  border: var(--rule-hair) solid var(--color-rule);
  border-radius: var(--radius-pill);
  box-shadow: 0 10px 30px -18px oklch(20% 0.02 258 / 0.5);
  max-width: calc(100% - 2rem);
}

/* Марка не сжимается. Прежний значок был узким (22px), и flex молча ужимал
   коробку до 84px при содержимом на 108 — текст «Delivery Pro» наезжал на
   первый пункт меню. С горизонтальной птицей это вылезло сразу; лечится не
   размером картинки, а запретом сжимать. */
.nav__mark {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-sm);
  letter-spacing: -0.02em;
  white-space: nowrap;
}

/* Марка — ФАЙЛ, а не инлайн. Контуры логотипа весят 7 КБ; инлайном они
   легли бы на каждую из 67 страниц, то есть 460 КБ вместо одного
   закешированного запроса. Цвета внутри файла зашиты намеренно: логотип
   не перекрашивается темой, для тёмных подложек лежит своя копия. */
.nav__mark img.nav__glyph { width: 26px; height: 16px; display: block; flex-shrink: 0; }

.nav__links {
  display: flex;
  gap: var(--space-md);
  font-size: var(--text-sm);
  color: var(--color-muted);
}

.nav__links a {
  white-space: nowrap;
  padding-block: 0.25rem;
  border-bottom: 2px solid transparent;
  transition: color var(--dur-micro) var(--ease-out),
              border-color var(--dur-micro) var(--ease-out);
}

.nav__links a:hover { color: var(--color-ink); border-bottom-color: var(--color-accent); }

/* ---- мобильное меню ----
   Раньше на узком экране список разделов просто прятался, и одиннадцать страниц
   становились недостижимы с телефона. Теперь список раскрывается кнопкой. */
/* Кнопка меню и переключатель языка — единственные органы управления в шапке на
   телефоне, и оба были меньше пальца: 40 и 36 точек при рекомендованных 44. Размер
   рамки оставлен прежним, растёт только область касания — иначе шапка поедет.
   Замерено в браузере на 375 px 09.08.2026, скриптами такое не ловится. */
.nav__burger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  min-width: 44px;
  min-height: 44px;
  border: var(--rule-hair) solid var(--color-rule);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-ink);
  cursor: pointer;
}
.nav__burger:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.nav__burger svg { width: 1.1rem; height: 1.1rem; }
.nav__burger .nav__x { display: none; }
.nav__burger[aria-expanded="true"] .nav__bars { display: none; }
.nav__burger[aria-expanded="true"] .nav__x { display: block; }

/* ГРАНИЦА 56rem ВЗЯТА ЗАМЕРОМ, А НЕ НА ГЛАЗ (21.08.2026).
   Пилюля не переносится и не сжимается, поэтому её собственная ширина и есть
   граница. Замер в браузере на трёх языках: ru 838 px, ua 850 px, en 815 px,
   плюс 2rem боковых отступов — украинской нужно 882 px.
   Пока порог стоял на 52rem (832 px), полоса от 833 до 871 px показывала
   пилюлю, в которую содержимое не влезает: кнопка «Рассчитать» вылезала за
   её скруглённый край на 31 px при 833 px и на 4 px при 860 px — то есть
   висела снаружи пилюли на КАЖДОЙ странице сайта.
   56rem (896 px) — это 882 плюс запас на то, что шрифт на чужой машине
   нарисуется чуть шире. Цена размена названа: полоса шириной 63 px получает
   вместо пилюли обычную шапку — ту же, что и все экраны уже, и рабочую.
   ГРАНИЦА ЖИВЁТ В ТРЁХ МЕДИАЗАПРОСАХ (шапка, язык, тень при прокрутке) и
   обязана совпадать во всех: разъехавшись, они дадут шапку-полосу с тенью от
   пилюли. Совпадение сверяет `scripts/check-site.py`. */
@media (max-width: 56rem) {
  /* Пилюля по центру рассчитана на одну строку. На узком экране в неё не помещаются
     логотип, кнопка и меню разом, а перенос превращает её в бесформенную каплю —
     поэтому здесь шапка становится обычной полосой во всю ширину. */
  .nav {
    top: 0;
    left: 0;
    right: 0;
    transform: none;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    max-width: none;
    width: 100%;
    border-radius: 0;
    border-inline: 0;
    border-top: 0;
    box-shadow: 0 6px 20px -18px oklch(20% 0.02 258 / 0.6);
    padding: 0.5rem var(--space-md);
    row-gap: 0;
    gap: var(--space-sm);
  }
  .nav__mark { order: 1; }
  .nav__burger { display: inline-flex; order: 2; margin-left: auto; flex: 0 0 auto; }
  /* Два класса в селекторе, а не один: ниже по файлу, уже вне медиазапроса, стоит
     `.nav .btn--fill { order: 4 }` — та же специфичность, но позже, и она забирала
     верх. Порядок 3 не применялся, и при ЗАКРЫТОМ меню это незаметно (список скрыт,
     кнопка всё равно последняя в строке), а при открытом кнопка «Рассчитать»
     уезжала на 281 px вниз, под весь список разделов. Замер 08.08.2026. */
  .nav > .btn.btn--fill { order: 3; flex: 0 0 auto; padding-inline: 0.9rem; white-space: nowrap; }
  .nav__links {
    display: none;
    order: 4;
    flex-basis: 100%;
    flex-direction: column;
    gap: 0;
    margin: 0;
    padding: var(--space-xs) 0 var(--space-sm);
    border-top: var(--rule-hair) solid var(--color-rule);
  }
  .nav__links[data-open="true"] { display: flex; }
  .nav__links a { display: block; padding-block: 0.5rem; border-bottom: 0; white-space: nowrap; }

  /* Полоса перекрывает начало страницы — возвращаем контенту место. */
  .hero { padding-top: var(--space-2xl); }
  .crumbs { padding-top: calc(var(--space-lg) + 2.5rem); }
}

/* На самых узких экранах подпись логотипа уступает место кнопке, знак остаётся. */
@media (max-width: 26rem) {
  .nav__mark { font-size: 0; gap: 0; }
  .nav__mark img.nav__glyph { width: 32px; height: 20px; }
}

/* ============ кнопки ============ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  white-space: nowrap;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  /* Межстрочный задаётся ЯВНО, иначе высота кнопки зависит от тега. Замер
     14.08.2026: <a class="btn btn--accent btn--lg"> в герое — 55 px, <button> с тем же
     набором классов в форме — 47. Причина не в стилях кнопки: ссылка наследует
     line-height: 1.6 от body, а форменным элементам браузер ставит `normal`, и
     наследование до них не доходит. Один класс, две высоты — читается как небрежная
     вёрстка, хотя разметка в обоих местах верная.
     Ступеней высоты две и обе названы: 44 px обычная (нижняя граница тач-зоны),
     52 px крупная. Прежние 44/47/55 разницей в три пикселя не читались как решение. */
  line-height: 1.25;
  min-height: 44px;
  padding: 0.65rem 1.1rem;
  border-radius: var(--radius-pill);
  border: var(--rule-hair) solid transparent;
  cursor: pointer;
  transition: transform var(--dur-micro) var(--ease-out),
              background-color var(--dur-micro) var(--ease-out),
              border-color var(--dur-micro) var(--ease-out),
              color var(--dur-micro) var(--ease-out);
}

/* НА УЗКОМ ЭКРАНЕ ДЛИННАЯ КНОПКА ПЕРЕНОСИТСЯ, А НЕ ВЫЛЕЗАЕТ (21.08.2026).
   `white-space: nowrap` выше стоит правильно: короткие подписи не должны
   ломаться на две строки посреди ряда кнопок. Но подписи бывают и длинные —
   «Рассчитать доставку в Казахстан» это 264 px вместе с отступами, — и на
   экране 280 px такая кнопка упиралась в самый край, теряя правый отступ, а
   ниже 296 px вылезала за него.
   Разрешение переноса НИЧЕГО не меняет для тех кнопок, что помещаются:
   `normal` не заставляет переносить, а лишь позволяет — там, где строка не
   влезает. То есть правка касается ровно тех случаев, ради которых написана.
   Порог 30rem — телефоны; на планшете и шире ряд кнопок остаётся ровным. */
@media (max-width: 30rem) {
  .btn { white-space: normal; max-width: 100%; }
}

.btn--fill {
  background: var(--color-ink);
  color: var(--color-ink-invert);
}
.btn--fill:hover,
.btn--fill:focus-visible { background: var(--color-deep-2); transform: translateY(-1px); }
.btn--fill:active { transform: scale(0.97); }

.btn--line {
  background: transparent;
  color: var(--color-ink);
  border-color: var(--color-rule);
}
.btn--line:hover,
.btn--line:focus-visible { border-color: var(--color-ink); transform: translateY(-1px); }
.btn--line:active { transform: scale(0.97); }

/* та же кнопка на тёмной полосе: без этого текст цвета ink сливается с фоном */
.band--deep .btn--line {
  color: var(--color-ink-invert);
  border-color: var(--color-deep-rule);
}
.band--deep .btn--line:hover,
.band--deep .btn--line:focus-visible { border-color: var(--color-accent); }

/* Имя по РОЛИ, а не по цвету. До 19.08.2026 класс звался `btn--lime`, и
   после смены бренда на синий это была бы прямая ложь в разметке шести
   страниц — а класс, который врёт, следующий заход «починит» не туда.
   Текст на заливке — чернила, и на синем тоже: белый даёт 2,6, чернила
   6,66. Проверяет пара «deep на accent» в scripts/check-contrast.py. */
.btn--accent {
  background: var(--color-accent);
  color: var(--color-deep);
}
.btn--accent:hover,
.btn--accent:focus-visible { transform: translateY(-1px); }
.btn--accent:active { transform: scale(0.97); }

.btn[disabled] { opacity: 0.5; cursor: not-allowed; transform: none; }
.btn--lg { font-size: var(--text-base); padding: 0.85rem 1.5rem; min-height: 52px; }

/* ============ герой · H2 split diptych ============ */

.hero {
  position: relative;
  isolation: isolate;
  padding-block: calc(var(--space-3xl) + 1rem) var(--space-2xl);
}

/* Первый экран стоял на голой бумаге, и вся его композиция держалась на одном
   тёмном прямоугольнике справа. Подложка ниже добавляет глубины, ничего не
   загораживая: разметочная сетка того же шага, что на тёмных полосах (страница
   получает один общий «пол»), и тёплое пятно света за карточкой логотипа.

   Гасится к низу маской, поэтому граница с соседней полосой остаётся чистой —
   без маски виден шов ровно по кромке секции. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(38rem 26rem at 78% 32%, oklch(63.9% 0.117 250 / 0.09) 0%, transparent 68%),
    repeating-linear-gradient(90deg,
      oklch(20% 0.016 258 / 0.035) 0 1px, transparent 1px var(--space-2xl)),
    repeating-linear-gradient(0deg,
      oklch(20% 0.016 258 / 0.028) 0 1px, transparent 1px var(--space-2xl));
  -webkit-mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, oklch(0% 0 0) 55%, transparent 100%);
          mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, oklch(0% 0 0) 55%, transparent 100%);
  pointer-events: none;
}

.hero__grid {
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: var(--space-2xl);
  align-items: center;
}

@media (max-width: 60rem) {
  .hero__grid { grid-template-columns: minmax(0, 1fr); gap: var(--space-xl); }
}

.hero h1 {
  font-size: var(--text-display);
  letter-spacing: var(--track-display);
  line-height: var(--lead-display);
  max-width: 14ch;
  margin-block: var(--space-md) var(--space-md);
}

.hero h1 .accent { color: var(--color-accent-deep); }

.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}

/* На узком экране кнопки первого экрана вставали друг под друга, но каждая по
   своему тексту: «Рассчитать доставку» шире «Смотреть направления» на четверть.
   Две кнопки разной длины в столбик читаются как сбитая вёрстка, а не как выбор
   из двух действий. Растягиваем обе на всю ширину — заодно растёт зона нажатия.
   Порог 34rem, а не общий 52rem: на планшете они помещаются в строку и там их
   растягивать не надо. */
@media (max-width: 34rem) {
  .hero__cta .btn { flex: 1 1 100%; }
}

.hero__routes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-md);
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: var(--rule-hair) solid var(--color-rule);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-neutral);
}

/* ---- логотип-иллюстрация ---- */

/* Карточка логотипа поднята над бумагой: тень плюс акцентный контур в один
   пиксель. Контур — не рамка ради рамки, он даёт краю карточки свет и не
   позволяет тёмному прямоугольнику слипнуться с собственной тенью. */
.mark {
  position: relative;
  background:
    radial-gradient(120% 80% at 50% 0%, var(--color-deep-2) 0%, var(--color-deep) 62%);
  border-radius: var(--radius-lg);
  padding: var(--space-lg);
  overflow: hidden;
  display: grid;
  place-items: center;
  min-height: 22rem;
  box-shadow: var(--shadow-lg), var(--glow-accent);
}

/* Та же разметочная сетка, что на тёмных полосах, — карточка принадлежит
   одному миру с ними, а не живёт отдельной плашкой. */
.mark::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(90deg,
      oklch(100% 0 0 / 0.03) 0 1px, transparent 1px var(--space-lg)),
    repeating-linear-gradient(0deg,
      oklch(100% 0 0 / 0.024) 0 1px, transparent 1px var(--space-lg));
  -webkit-mask-image: radial-gradient(80% 70% at 50% 40%, oklch(0% 0 0) 0%, transparent 100%);
          mask-image: radial-gradient(80% 70% at 50% 40%, oklch(0% 0 0) 0%, transparent 100%);
  pointer-events: none;
}

.mark__ground {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 22%;
  height: 1px;
  /* Земля под бегущим страусом: линия ярче в центре и тает к краям — так она
     читается как освещённый участок пола, а не как разделитель карточки. */
  background: linear-gradient(90deg,
    transparent 0%, var(--color-deep-rule) 18%,
    oklch(63.9% 0.117 250 / 0.5) 50%,
    var(--color-deep-rule) 82%, transparent 100%);
}

/* Марка героя — файл, а не инлайн: те же 7 КБ контуров, что и в шапке, и тот же
   довод. Здесь берётся СВЕТЛАЯ копия: карточка тёмная, чёрный корпус на ней
   исчез бы. `aspect-ratio` вместо `height:auto` — иначе до загрузки файла блок
   имеет нулевую высоту и первый экран дёргается. */
.mark__svg {
  width: min(100%, 21rem);
  height: auto;
  aspect-ratio: 879 / 543;
  position: relative;
  z-index: var(--z-base);
}

/* Полужирный в тексте. Без этого правила <b> и <strong> просят у браузера вес 700,
   которого в наборе нет, и он рисует синтетический жирный: буквы утолщаются
   механически и выглядят грубее остального текста. Берём вес, который реально
   загружен. */
b,
strong {
  font-weight: 600;
}

.mark__word {
  position: relative;
  z-index: var(--z-base);
  margin-top: var(--space-md);
  text-align: center;
  font-family: var(--font-display);
  /* 700, а не 800: восьмисотое начертание применялось на всём сайте ровно здесь,
     и ради одного слова в подвале браузер тянул 32 КБ отдельного файла — 13 %
     веса страницы. Разницу между 700 и 800 на одном слове не видно, экономию видно. */
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.03em;
  color: var(--color-ink-invert);
  font-size: var(--text-xl);
}

.mark__word span {
  display: block;
  font-size: var(--text-sm);
  font-family: var(--font-mono);
  font-weight: 400;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--color-accent);
  margin-top: 0.5rem;
  text-indent: 0.4em;
}

/* бег: корпус подпрыгивает, ноги качаются, линии скорости уходят назад.
   transform-box: view-box — чтобы transform-origin считался в координатах viewBox, а не bbox элемента */
.ostrich, .leg-a, .leg-b, .rider, .speed { transform-box: view-box; }

.ostrich { animation: bob      620ms var(--ease-in-out) infinite alternate; transform-origin: 126px 192px; }
.leg-a   { animation: stride-a 620ms var(--ease-in-out) infinite;           transform-origin: 112px 144px; }
.leg-b   { animation: stride-b 620ms var(--ease-in-out) infinite;           transform-origin: 138px 144px; }
.rider   { animation: rider    620ms var(--ease-in-out) infinite alternate; transform-origin: 118px 98px; }
.speed   { animation: dash     620ms linear infinite; transform-origin: 40px 180px; }

@keyframes bob      { from { transform: translateY(0) }        to { transform: translateY(-7px) } }
@keyframes rider    { from { transform: rotate(-2.5deg) }      to { transform: rotate(2deg) } }
@keyframes stride-a { 0%,100% { transform: rotate(26deg) }     50% { transform: rotate(-24deg) } }
@keyframes stride-b { 0%,100% { transform: rotate(-24deg) }    50% { transform: rotate(26deg) } }
@keyframes dash     { from { transform: translateX(14px); opacity: 0 } 40% { opacity: 1 } to { transform: translateX(-42px); opacity: 0 } }

@media (prefers-reduced-motion: reduce) {
  .ostrich, .leg-a, .leg-b, .rider, .speed { animation: none; }
  .speed { opacity: 0.45; }
}

/* ============ полосы и секции ============ */

.band { padding-block: var(--space-2xl); }
.band--tight { padding-block: var(--space-xl); }

/* Тёмная полоса — не просто заливка, а «складской свет»: разметочная сетка на
   полу и мягкое акцентное зарево у верхнего края. Обе детали держатся на
   ползёрна контраста и по отдельности не читаются — работает суммарное
   ощущение объёма. Без них тёмная полоса выглядела вырезанным прямоугольником:
   на скриншоте это самое заметное отличие плоского макета от собранного.

   Сетка нарисована градиентом, а не картинкой: ноль запросов, ноль килобайт,
   и шаг сетки живёт в тех же токенах, что и остальные отступы. */
.band--deep {
  position: relative;
  isolation: isolate;
  background: var(--color-deep);
  color: var(--color-ink-invert);
  padding-block: var(--space-3xl);
  overflow: hidden;
}

.band--deep::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    repeating-linear-gradient(90deg,
      oklch(100% 0 0 / 0.028) 0 1px, transparent 1px var(--space-2xl)),
    repeating-linear-gradient(0deg,
      oklch(100% 0 0 / 0.022) 0 1px, transparent 1px var(--space-2xl));
  /* Сетка гаснет к низу — иначе она читается как обои, а не как уходящий пол. */
  -webkit-mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, transparent 78%);
          mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, transparent 78%);
}

/* Зарево. Радиус в vw, а не в px: на широком экране пятно обязано остаться
   пятном, а не полосой во всю ширину. */
.band--deep::after {
  content: "";
  position: absolute;
  z-index: -1;
  top: calc(var(--space-3xl) * -1);
  left: 50%;
  width: min(70rem, 120vw);
  aspect-ratio: 2 / 1;
  transform: translateX(-50%);
  background: radial-gradient(50% 50% at 50% 50%,
    oklch(63.9% 0.117 250 / 0.11) 0%, transparent 70%);
  pointer-events: none;
}

.band--deep .lede,
.band--deep .eyebrow { color: var(--color-muted-invert); }

/* Чередование светлых полос. Ровный белый на всю страницу лишает её ритма:
   глазу не за что зацепиться, и восемь секций подряд читаются как одна
   бесконечная. Оттенок --color-paper-2 отличается от бумаги на 2,7 % светлоты —
   осознанно не воспринимается, но границу секции обозначает. */
.band--alt { background: var(--color-paper-2); }

/* Шапка секции — редакционная сетка: заголовок слева, пояснение справа.
   До 14.08.2026 здесь стоял один столбец в 46ch. На широком экране это оставляло
   пустой правую половину полосы, а пояснение из 145 слов уходило в двенадцать
   строк узкой колонкой — стена текста рядом с пустотой. Замер на 1440 px: занято
   490 px из 1104. Две колонки убирают и дыру, и стену: тот же текст ложится в
   шесть строк. Ниже 64rem колонки схлопываются — на планшете заголовок в 5fr
   становится нечитаемо узким. */
.section-head { margin-bottom: var(--space-xl); }
.section-head h2 { font-size: var(--text-3xl); margin-block: var(--space-xs) var(--space-sm); letter-spacing: var(--track-3xl); line-height: var(--lead-3xl); }
.section-head > :where(p, ul, ol) { max-width: var(--measure); }

/* Заголовок секции БЕЗ пояснения. Раньше в этих трёх местах стоял тот же класс
   section-head — прямо на самом h2, — и это работало лишь потому, что класс не
   делал ничего, кроме размера шрифта. С появлением сетки такой h2 стал бы гридом
   из собственного текста и сжался бы до 5/12 ширины. Разные вещи — разные имена. */
.section-title {
  font-size: var(--text-3xl);
  letter-spacing: var(--track-3xl);
  line-height: var(--lead-3xl);
  margin-block: var(--space-xs) var(--space-md);
  max-width: 24ch;
}

@media (min-width: 64rem) {
  .section-head {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: var(--space-2xl);
    align-items: start;
  }
  /* Заголовок и надзаголовок держатся первой колонки, всё прочее уходит во вторую.
     Правило написано через grid-column, а не обёрткой в разметке: обёртка потребовала
     бы правки девяти мест в index.html и ещё стольких же в каждой новой секции. */
  .section-head > .eyebrow { grid-column: 1; }
  .section-head > h2 { grid-column: 1; margin-top: 0; }
  .section-head > :not(.eyebrow):not(h2) { grid-column: 2; }
  /* Второй и следующие элементы правой колонки встают друг под другом, а не
     каждый в свою строку сетки. */
  .section-head > :not(.eyebrow):not(h2) ~ :not(.eyebrow):not(h2) { margin-top: var(--space-sm); }
}

.rule-thick { height: var(--rule-thick); background: var(--color-ink); border: 0; margin: 0; }

/* ============ схема направлений ============
   Линии рисуются от склада к точкам назначения, когда схема попадает на экран.
   Приём — штриховка длиной во весь путь, сдвинутая за его край и подтянутая
   обратно. Длина пути при этом не считается скриптом: атрибут pathLength="1"
   в разметке переводит штриховку в доли, и весь путь всегда равен единице,
   какой бы кривой он ни был.

   Порядок появления — сверху вниз, задержка растёт с номером линии. Одномоментный
   старт всех пяти читается как мигание, поочерёдный — как отправка. */

.schema {
  margin: 0 0 var(--space-2xl);
}

.schema svg {
  width: 100%;
  height: auto;
  display: block;
}

.schema__line {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1100ms var(--ease-out);
}
.schema__line--air  { stroke: var(--color-accent); stroke-width: 3; }
.schema__line--road { stroke: oklch(63.9% 0.117 250 / 0.42); stroke-width: 2; }

.schema[data-shown="true"] .schema__line { stroke-dashoffset: 0; }
.schema__line:nth-child(2) { transition-delay: 90ms; }
.schema__line:nth-child(3) { transition-delay: 180ms; }
.schema__line:nth-child(4) { transition-delay: 270ms; }
.schema__line:nth-child(5) { transition-delay: 360ms; }

/* Без JS и при выключенном движении линии обязаны быть на месте: схема без
   линий — это пять подписей в пустоте, а не «менее нарядная схема». */
html:not([data-motion="on"]) .schema__line { stroke-dashoffset: 0; }

.schema__origin circle { fill: var(--color-accent); }
.schema__targets circle { fill: var(--color-accent); }

/* Точка склада дышит: она смысловой центр схемы, всё расходится от неё.
   Круг растёт и тает — это второе кольцо поверх первого, а не мигание самой
   точки: мигающий элемент интерфейса читается как ошибка. */
.schema__pulse {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 2;
  transform-origin: 150px 150px;
  transform-box: view-box;
  animation: schema-pulse 2600ms var(--ease-out) infinite;
}
@keyframes schema-pulse {
  0%   { transform: scale(1);   opacity: 0.55; }
  70%  { transform: scale(2.4); opacity: 0; }
  100% { transform: scale(2.4); opacity: 0; }
}

.schema__name {
  fill: var(--color-ink-invert);
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 700;
  letter-spacing: var(--track-lg);
}
.schema__note {
  fill: var(--color-muted-invert);
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.02em;
}

/* Схема — резюме карточек, которые идут следом, и на узком экране она проигрывает
   им во всём: подписи ужимаются до нечитаемого, а данные в ней те же. Поэтому
   ниже 52rem её нет. Информация при этом не теряется — карточки на месте. */
@media (max-width: 52rem) {
  .schema { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .schema__pulse { animation: none; opacity: 0; }
  .schema__line { transition: none; stroke-dashoffset: 0; }
}

/* ============ направления ============ */

.routes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--space-md);
}

.route {
  position: relative;
  border: var(--rule-hair) solid var(--color-deep-rule);
  border-radius: var(--radius-md);
  padding: var(--space-lg) var(--space-md) var(--space-md);
  background: var(--color-deep-2);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  transition: transform var(--dur-short) var(--ease-out),
              border-color var(--dur-short) var(--ease-out);
}

.route:hover { transform: translateY(-3px); border-color: var(--color-accent); }

/* Соседние карточки выравнивают внутренние строки: код, заголовок, описание, список,
   сноска и ссылка встают на одни линии у всех карточек ряда.
   До 14.08.2026 карточка была колонкой flex, а список прижимался вниз через
   margin-top:auto. Из-за этого при описании разной длины список «плавал»: замер на
   1440 px давал 201 px у Украины против 163 у России в одном ряду и 206 против 185
   во втором — глаз читает это как съехавшую вёрстку.
   Строк ровно шесть, столько же детей у каждой карточки; появится седьмой блок —
   поднимать span, иначе он вывалится в собственную строку.
   Под @supports, потому что при отсутствии subgrid карточка обязана остаться
   колонкой flex, а не рассыпаться на неявные строки. */
@supports (grid-template-rows: subgrid) {
  .route {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 6;
    /* Собственный gap здесь снимается намеренно. Строки субсетки рассчитаны родителем
       с ЕГО зазором (20 px), а карточка со своим (12 px) раскладывала содержимое по
       другому шагу — линии родителя и содержимое ребёнка расходились, и выравнивание
       работало наполовину: замер после первой правки давал 179 против 163 вместо
       общей линии. Зазор обязан быть один и тот же, иначе subgrid бессмыслен. */
    row-gap: inherit;
  }
  /* Список больше не всплывает: его место задаёт строка сетки, общая для ряда. */
  .route__list { margin-top: 0; }
}

/* первая карточка шире — сетка не должна читаться как три равные колонки */
.route--wide { grid-column: span 2; }
@media (max-width: 60rem) { .route--wide { grid-column: auto; } }

.route h3 { font-size: var(--text-xl); letter-spacing: var(--track-xl); line-height: var(--lead-xl); }
.route p { color: oklch(76% 0.012 258); font-size: var(--text-sm); }

.route__code {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.18em;
  color: var(--color-accent);
}

/* Без margin-top:auto. Он прижимал список к низу карточки, и при описаниях разной
   длины списки соседних карточек стояли на разной высоте — вёрстка читалась как
   съехавшая. Низ карточки держит последняя строка (ссылка), у неё свой auto. */
.route__list { display: grid; gap: 0.35rem; padding-top: var(--space-sm); }
.route__list li {
  font-size: var(--text-sm);
  color: oklch(80% 0.012 258);
  padding-left: 1.1rem;
  position: relative;
}
.route__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 6px;
  height: 6px;
  background: var(--color-accent);
  border-radius: 1px;
}

/* Сноска карточки набирается основным шрифтом, а не моноширинным. Моно на сайте
   несёт роль метки — код направления, надзаголовок, перечень стран в подвале: там
   это два-три слова, и разрядка работает. Здесь же два полноценных предложения
   («T1 оплачивается отдельно, считается от стоимости инвойса…»), и моноширинный
   набор с разрядкой 0,18em читается как вывод терминала, а не как примечание.
   Размер поднят с xs до sm по той же причине: это текст, а не подпись. */
/* Цвет здесь НЕ задаётся: соседнее правило `.route p` специфичнее (класс + тег
   против одного класса) и всё равно выигрывает. Стоявший тут oklch(62%…) не
   применялся ни разу с момента написания — сноска всегда рисовалась цветом
   описания, и это верно: разный цвет у двух соседних абзацев одной карточки
   выглядел бы как ошибка. Вернуть цвет можно только вместе с селектором
   `p.route__meta`, и тогда его надо прогнать через check-contrast.py. */
.route__meta {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  border-top: var(--rule-hair) solid var(--color-deep-rule);
  padding-top: var(--space-sm);
  margin-top: var(--space-sm);
}

/* ============ услуги — диптих ============ */

.diptych {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: var(--space-2xl);
  align-items: start;
}
.diptych--flip { grid-template-columns: 7fr 5fr; }

/* ЗАГОЛОВОК РАЗДЕЛА ИДЁТ ПЕРВЫМ В РАЗМЕТКЕ, А НА ЭКРАНЕ ОСТАЁТСЯ СПРАВА.
   Раздел «Как проходит поставка» был собран так, что его h2 стоял в разметке
   ПОСЛЕ пяти h3 своих же шагов: колонка с шагами шире и потому шла первой.
   Экранный диктор и поисковый робот читают разметку, а не сетку, и видели
   пять подзаголовков без раздела, к которому те относятся (аудит 21.08.2026).
   Порядок в разметке исправлен, вид сохранён перестановкой средствами сетки.
   Только на широком экране: в одну колонку заголовок обязан идти первым — так
   он и идёт, потому что стоит первым в разметке. */
@media (min-width: 60.0625rem) {
  .diptych--flip > *:first-child { order: 2; }
  .diptych--flip > *:last-child { order: 1; }
}
@media (max-width: 60rem) {
  .diptych, .diptych--flip { grid-template-columns: minmax(0, 1fr); gap: var(--space-lg); }
}

.services { display: grid; gap: 0; }

.service {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-md);
  align-items: baseline;
  padding-block: var(--space-md);
  border-top: var(--rule-hair) solid var(--color-rule);
}
.service:last-child { border-bottom: var(--rule-hair) solid var(--color-rule); }

.service__key {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-accent-deep);
  letter-spacing: 0.1em;
}
.service h3 { font-size: var(--text-md); font-weight: 700; margin-bottom: 0.2rem; }
.service p { color: var(--color-muted); font-size: var(--text-sm); }

/* ============ преимущества ============ */

.edges { display: grid; gap: var(--space-md); grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); }

.edge {
  border-left: var(--rule-hair) solid var(--color-rule);
  padding: var(--space-xs) 0 var(--space-md) var(--space-md);
}
.edge:first-child { border-left-color: var(--color-accent); }
.edge h3 { font-size: var(--text-lg); margin-bottom: var(--space-xs); letter-spacing: var(--track-lg); line-height: var(--lead-lg); }
.edge p { color: var(--color-muted); font-size: var(--text-sm); }

/* второй ряд смещён — сетка не читается как ровный четырёхблочник */
.edges--offset { margin-top: var(--space-md); }
@media (min-width: 60rem) { .edges--offset { padding-left: var(--space-2xl); } }

/* ============ шаги · F4 ============ */

/* Поставка — это последовательность, и выглядеть она должна последовательностью.
   Раньше здесь стоял ряд одинаковых строк, разделённых горизонтальными линейками:
   такая разметка сообщает «семь равноправных пунктов», хотя смысл — «одно за
   другим, слева направо по времени».

   Горизонтальные линейки убраны и заменены вертикальной линией с узлами: она и
   разделяет шаги, и показывает их порядок. Двух приёмов разделения сразу быть не
   должно — линия плюс рамки читаются как таблица, у которой поехала вёрстка. */
.steps { display: grid; gap: 0; counter-reset: step; }

.step {
  position: relative;
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr);
  gap: var(--space-md);
  padding-block: var(--space-md);
  align-items: start;
}

/* Отрезок линии от своего узла к следующему. У последнего шага его нет: линия,
   уходящая в пустоту, обещает продолжение, которого не будет. */
.step:not(:last-child)::before {
  content: "";
  position: absolute;
  left: calc(1.35rem - 1px);
  top: 2.9rem;
  bottom: -0.6rem;
  width: 2px;
  background: linear-gradient(180deg,
    var(--color-accent) 0%,
    color-mix(in oklch, var(--color-accent) 30%, var(--color-rule)) 100%);
}

.step__n {
  display: grid;
  place-items: center;
  width: 2.7rem;
  height: 2.7rem;
  border-radius: 50%;
  border: 2px solid var(--color-accent);
  /* Заливка непрозрачная и того же цвета, что полоса: узел обязан перекрывать
     линию, иначе она просвечивает сквозь цифру. */
  background: var(--color-paper);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--color-accent-deep);
  font-variant-numeric: tabular-nums;
  position: relative;
  z-index: var(--z-base);
}

.step h3 { font-size: var(--text-md); margin-bottom: 0.2rem; padding-top: 0.35rem; }
.step p { color: var(--color-muted); font-size: var(--text-sm); max-width: var(--measure); }

/* На узком экране колонка номера схлопывается, и вести линию не от чего:
   узел встаёт над текстом, а не слева от него. Возвращается разделительная
   линейка — единственный приём, который в одну колонку работает. */
@media (max-width: 30rem) {
  .step {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-xs);
    border-top: var(--rule-hair) solid var(--color-rule);
  }
  .step:last-child { border-bottom: var(--rule-hair) solid var(--color-rule); }
  .step:not(:last-child)::before { display: none; }
  .step h3 { padding-top: 0; }
}

/* ============ FAQ ============ */

.faq { display: grid; gap: 0; max-width: 60rem; }

.qa { border-top: var(--rule-hair) solid var(--color-rule); }
.qa:last-child { border-bottom: var(--rule-hair) solid var(--color-rule); }

.qa summary {
  cursor: pointer;
  list-style: none;
  padding-block: var(--space-md);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-md);
  letter-spacing: -0.02em;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-md);
  transition: color var(--dur-micro) var(--ease-out);
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary:hover,
.qa summary:focus-visible { color: var(--color-accent-deep); }

.qa summary::after {
  content: "";
  flex: none;
  width: 12px;
  height: 12px;
  border-right: 2px solid var(--color-neutral);
  border-bottom: 2px solid var(--color-neutral);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--dur-short) var(--ease-out);
}
.qa[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }

.qa__body { padding-bottom: var(--space-md); color: var(--color-muted); font-size: var(--text-sm); max-width: var(--measure); }
.qa__body p + p { margin-top: var(--space-sm); }

/* ============ калькулятор ============ */

.calc {
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: var(--space-2xl);
  align-items: start;
}
@media (max-width: 60rem) { .calc { grid-template-columns: minmax(0, 1fr); gap: var(--space-lg); } }

.calc__form { display: grid; gap: var(--space-md); }

.calc__set { border: 0; padding: 0; margin: 0; display: grid; gap: 0.35rem; min-width: 0; }
.calc__set legend {
  padding: 0;
  font-size: var(--text-sm);
  color: var(--color-muted-invert);
}
.calc__dims {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-sm);
}

/* поля на тёмной полосе: рамка и подпись поднимаются по светлоте */
.band--deep .field label { color: var(--color-muted-invert); }
.band--deep .field input,
.band--deep .field select {
  background: var(--color-deep-2);
  color: var(--color-ink-invert);
  /* Было --color-deep-rule: 1,35 против тёмной карточки. Стало 3,40. */
  border-color: var(--color-field-rule-deep);
}
.band--deep .field input::placeholder { color: var(--color-field-hint-deep); }
/* Наведение обязано делать границу ЗАМЕТНЕЕ покоя, а не тусклее: разбор
   значений — в комментарии к --color-field-rule-deep-hover. */
.band--deep .field input:hover,
.band--deep .field select:hover { border-color: var(--color-field-rule-deep-hover); }
.band--deep .field input:focus-visible,
.band--deep .field select:focus-visible { border-color: var(--color-accent); }
.band--deep .form__status[data-state="error"] { color: var(--color-error-invert); }

.calc__out {
  display: grid;
  gap: var(--space-md);
  background: var(--color-deep-2);
  border: var(--rule-hair) solid var(--color-deep-rule);
  border-radius: var(--radius-md);
  padding: var(--space-lg);
  min-width: 0;
}
.calc__out[hidden] { display: none; }

.calc__metric {
  display: grid;
  gap: var(--space-2xs);
  padding-bottom: var(--space-sm);
  border-bottom: var(--rule-hair) solid var(--color-deep-rule);
}
.calc__metric:last-of-type { border-bottom: 0; padding-bottom: 0; }

.calc__label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: oklch(62% 0.010 258);
}
.calc__value {
  font-size: var(--text-md);
  overflow-wrap: anywhere;
}
.calc__value b { font-family: var(--font-display); font-size: var(--text-xl); font-weight: 700; letter-spacing: var(--track-xl); line-height: var(--lead-xl); }
.calc__value--verdict {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  letter-spacing: var(--track-xl);
  line-height: var(--lead-xl);
  font-weight: 700;
  color: var(--color-accent);
}

.calc__note {
  font-size: var(--text-sm);
  color: oklch(74% 0.012 258);
  margin: 0;
}

/* Калькулятор на светлой полосе: подписи, рассчитанные на тёмный фон, тонут в бумаге.
   Карточка результата остаётся тёмной — она и должна читаться как отдельный блок. */
.calc--light .calc__set legend { color: var(--color-muted); }
.calc--light .calc__note { color: oklch(80% 0.012 258); }

.calc__disclaimer {
  margin-top: var(--space-xl);
  font-size: var(--text-sm);
  color: oklch(66% 0.011 258);
  max-width: var(--measure);
}

/* ============ заявка ============ */

.lead {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: var(--space-2xl);
  align-items: start;
}
@media (max-width: 60rem) { .lead { grid-template-columns: minmax(0, 1fr); gap: var(--space-lg); } }

.form { display: grid; gap: var(--space-md); }
.form__row { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); gap: var(--space-md); }

.field { display: grid; gap: 0.35rem; }
.field label { font-size: var(--text-sm); color: var(--color-muted); }

.field input,
.field select,
.field textarea {
  font: inherit;
  font-size: var(--text-base);
  color: var(--color-ink);
  background: var(--color-paper);
  /* Не --color-rule: граница поля — элемент интерфейса, ей нужно 3:1 против
     фона (WCAG 1.4.11), а декоративной линейке — нет. Замер 08.08.2026. */
  border: var(--rule-hair) solid var(--color-field-rule);
  border-radius: var(--radius-sm);
  padding: 0.7rem 0.85rem;
  width: 100%;
  /* Высота задаётся явно, иначе поля одной формы стоят разной высоты. Замер
     14.08.2026: input 50 px, select «Направление» 49, select «Как ввозите сегодня»
     47 — три размера в одном столбце. У select высота собирается из содержимого
     опций и системной метрики, у input — из line-height; ни то ни другое мы не
     задавали, и разница вылезала на глаз ступенькой правого края. */
  line-height: 1.4;
  min-height: 50px;
  transition: border-color var(--dur-micro) var(--ease-out);
}
.field textarea { resize: vertical; min-height: 5.5rem; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--color-neutral); }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible { border-color: var(--color-focus); }
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"] { border-color: var(--color-error-rule); }

.form__note { font-size: var(--text-xs); color: var(--color-neutral); max-width: 46ch; }
.form__status { font-size: var(--text-sm); min-height: 1.4em; }
.form__status[data-state="error"] { color: var(--color-error); }
.form__status[data-state="ok"] { color: var(--color-accent-deep); }

.contact { display: grid; gap: var(--space-sm); align-content: start; }
.contact__line { display: flex; align-items: baseline; gap: var(--space-sm); font-size: var(--text-sm); }
.contact__line dt { color: var(--color-neutral); min-width: 6.5rem; font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase; }
.contact__line dd { margin: 0; }
.contact__line a { border-bottom: 1px solid var(--color-rule); transition: border-color var(--dur-micro) var(--ease-out); }
.contact__line a:hover { border-bottom-color: var(--color-accent); }

.chips { display: flex; flex-wrap: wrap; gap: var(--space-xs); margin-top: var(--space-sm); }

/* ============ подвал · Ft5 statement ============ */

.foot {
  background: var(--color-deep);
  color: var(--color-ink-invert);
  padding: var(--space-2xl) 0 var(--space-lg);
}
.foot__line {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.75rem, 4.4vw, 3rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  max-width: 22ch;
}
.foot__line em { font-style: normal; color: var(--color-accent); }
.foot__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  justify-content: space-between;
  align-items: baseline;
  margin-top: var(--space-xl);
  padding-top: var(--space-md);
  border-top: var(--rule-hair) solid var(--color-deep-rule);
  font-size: var(--text-xs);
  color: oklch(66% 0.012 258);
}
.foot__meta a { border-bottom: 1px solid var(--color-deep-rule); }
.foot__meta a:hover { border-bottom-color: var(--color-accent); }
.foot__nav { display: flex; flex-wrap: wrap; gap: var(--space-md); }
.foot__nav a { white-space: nowrap; }

/* Тач-зоны на телефоне. Текстовые ссылки в подвале и в карточках направлений
   имели высоту 18–20 px — ниже порога 24 px, при котором в них перестают промахиваться.
   Увеличиваем саму зону нажатия, не трогая ни размер шрифта, ни ритм списка: padding
   компенсируется отрицательным margin, поэтому визуально ничего не сдвигается. */
@media (max-width: 52rem) {
  .foot__nav a,
  .route a,
  .dir-cta a:not(.btn) {
    display: inline-block;
    padding-block: 0.4rem;
    margin-block: -0.4rem;
  }

  /* Ссылки, которые сами по себе являются действием, а не словом внутри фразы:
     знак в шапке, заголовок карточки услуги, телефон и мессенджер в контактах.
     Замер на 375 px 14.08.2026: 28, 23 и 19 px по высоте — в телефон и в телеграм
     промахиваются пальцем, а это два способа с нами связаться.

     Зона растягивается псевдоэлементом, а НЕ отступами. Приём выше (padding плюс
     отрицательный margin) требует знать высоту строки заранее: одно и то же число
     даёт разную зону у заголовка в 23 px и у контакта в 19. Здесь высота считается
     от фактической — `calc((100% - 44px) / 2)` — и поток не меняется вовсе, ни на
     пиксель, потому что псевдоэлемент вынут из потока.

     Ссылки внутри предложений намеренно не трогаются: их 31 на главной, они идут
     подряд в тексте, и растянутые зоны накладывались бы друг на друга — нажатие
     стало бы попадать не туда, куда целится палец. WCAG 2.5.8 такие ссылки из
     требования к размеру исключает именно поэтому. */
  /* Строки контактов разводятся до 46 px по шагу. Без этого растянутые зоны
     накладываются: замер дал шаг 33 px при зоне 44, то есть 11 px пересечения —
     палец, метящий в телефон, открывает телеграм. Зона нажатия, заходящая на
     соседнюю ссылку, хуже маленькой: маленькая заставляет прицелиться, а эта
     уверенно срабатывает не туда. */
  .contact { gap: 0; }
  .contact__line { min-height: 46px; align-items: center; }

  /* Кнопки-близнецы на телефоне — во всю ширину, а не по своему тексту. «Написать в
     WhatsApp» и «Написать в Telegram» давали 185 и 177 px: два одинаковых по смыслу
     действия вставали лесенкой из-за разницы в длине слова. Ширина по содержимому
     осмысленна там, где кнопка одна среди текста; в столбце одинаковых действий она
     превращается в рваный край. На широком экране правило не действует — там кнопки
     стоят в строку, и растягивать их не на что. */
  .chips > .btn { flex: 1 1 100%; }

  .nav__mark,
  h3 > a:only-child,
  th > a:only-child,
  .contact__line dd > a:only-child {
    position: relative;
  }
  .nav__mark::after,
  h3 > a:only-child::after,
  th > a:only-child::after,
  .contact__line dd > a:only-child::after {
    content: "";
    position: absolute;
    inset: min(0px, calc((100% - 44px) / 2)) 0;
  }
}

/* Переключатель языка. Намеренно не флаг: флаг обозначает страну, а не язык,
   и украиноязычный клиент из Польши читает его как «доставка в Польшу». */
.nav__lang {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  color: var(--color-muted);
  padding: 0.35rem 0.5rem;
  border: var(--rule-hair) solid var(--color-rule);
  /* Пилюля, а не скруглённый прямоугольник: в шапке этот переключатель стоит между
     круглой кнопкой меню и кнопкой-пилюлей «Рассчитать». Три разные формы в ряду
     читаются как три разных по важности органа управления, хотя все три — кнопки. */
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.nav__lang:hover,
.nav__lang:focus-visible { color: var(--color-ink); border-color: var(--color-neutral); }
/* Соседи в шапке расставлены через order, поэтому переключателю тоже нужен свой:
   без него он уезжает в начало строки и встаёт левее логотипа. */
.nav__lang { order: 3; }
.nav .btn--fill { order: 4; }
@media (max-width: 56rem) { .nav__lang { padding: 0.45rem 0.55rem; } }

/* ============ полоса фактов под героем ============ */

.proof {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 0;
  border-block: var(--rule-hair) solid var(--color-rule);
}
/* Цифра — главный графический элемент этой полосы, а не подпись к тексту.
   Была на кегль 2xl вровень с заголовками секций и терялась среди них; акцентный
   штрих слева задаёт колонке начало и работает вместо второй вертикальной
   линейки. Поэтому же убрана правая граница у последней ячейки — ряд теперь
   держится левыми штрихами, а не клеткой. */
.proof__cell {
  position: relative;
  padding: var(--space-md) var(--space-md) var(--space-md) var(--space-md);
  border-right: var(--rule-hair) solid var(--color-rule);
}
.proof__cell::before {
  content: "";
  position: absolute;
  left: 0;
  top: var(--space-md);
  width: 3px;
  height: 1.6rem;
  border-radius: 2px;
  background: var(--color-accent);
}
.proof__cell:last-child { border-right: 0; }
.proof__n {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  letter-spacing: var(--track-3xl);
  font-weight: 700;
  line-height: 1;
  color: var(--color-ink);
  /* Цифры одной ширины: без этого счётчик при пересчёте 0→99 дёргает всю строку,
     а в статике «13» и «50» стоят на разной ширине и ряд выглядит неровным. */
  font-variant-numeric: tabular-nums;
}
/* Единица измерения — не часть числа: тот же вес, но мельче и приглушённее,
   чтобы «$/кг» не спорил с самой цифрой. */
.proof__n small {
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--color-neutral);
  letter-spacing: var(--track-md);
}
.proof__cap {
  display: block;
  margin-top: 0.4rem;
  font-size: var(--text-sm);
  color: var(--color-muted);
  max-width: 22ch;
}
@media (max-width: 40rem) {
  .proof__cell { border-right: 0; border-bottom: var(--rule-hair) solid var(--color-rule); padding-right: 0; }
  .proof__cell:last-child { border-bottom: 0; }
}

/* ============ сравнительная таблица ============ */

.cmp-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.cmp {
  width: 100%;
  min-width: 34rem;
  border-collapse: collapse;
  font-size: var(--text-sm);
  text-align: left;
}
.cmp caption {
  text-align: left;
  padding-bottom: var(--space-sm);
  font-size: var(--text-sm);
  color: var(--color-muted);
}
.cmp th, .cmp td {
  padding: var(--space-sm) var(--space-md) var(--space-sm) 0;
  border-bottom: var(--rule-hair) solid var(--color-rule);
  vertical-align: top;
}
.cmp thead th {
  font-family: var(--font-display);
  font-size: var(--text-base);
  font-weight: 700;
  border-bottom: var(--rule-thick) solid var(--color-ink);
}
.cmp tbody th { font-weight: 500; color: var(--color-muted); width: 30%; }
.cmp td:last-child { padding-right: 0; }
.cmp .cmp--us { color: var(--color-ink); font-weight: 500; }

/* Та же таблица на тёмной полосе. Стоит ДО узкоэкранного блока намеренно:
   медиазапрос не добавляет веса селектору, а `.band--deep .cmp tbody th`
   внутри него и снаружи весят одинаково. Пока эти пять правил лежали ПОСЛЕ
   блока, они его и перебивали — то есть мобильное правило не применялось
   никогда, и на телефоне заголовок строки рисовался приглушённым #a0a5ac
   вместо задуманного светлого. Поймано разбором 20.08.2026; поменяете
   порядок обратно — дефект вернётся молча, потому что на широком экране всё
   выглядит правильно. */
.band--deep .cmp th, .band--deep .cmp td { border-bottom-color: var(--color-deep-rule); }
.band--deep .cmp thead th { border-bottom-color: var(--color-accent); color: var(--color-ink-invert); }
.band--deep .cmp tbody th { color: oklch(72% 0.012 258); }
.band--deep .cmp td { color: oklch(84% 0.010 258); }
.band--deep .cmp .cmp--us { color: var(--color-ink-invert); }

/* На узком экране таблица разворачивается в карточки: сравнение — ключевой блок
   страницы, и листать его вбок пальцем никто не станет. */
@media (max-width: 40rem) {
  .cmp-scroll { overflow-x: visible; }
  .cmp, .cmp tbody, .cmp tr, .cmp th, .cmp td { display: block; min-width: 0; }
  .cmp thead { display: none; }
  .cmp tr {
    padding-block: var(--space-md);
    border-bottom: var(--rule-hair) solid var(--color-rule);
  }
  .cmp tbody th {
    width: auto;
    padding: 0 0 var(--space-xs);
    border: 0;
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--color-ink);
  }
  .cmp td { padding: 0.35rem 0 0 0; border: 0; }
  .cmp td::before {
    content: attr(data-col) ": ";
    color: var(--color-neutral);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    display: block;
  }
  .band--deep .cmp tbody th { color: var(--color-ink-invert); }
  .band--deep .cmp tr { border-bottom-color: var(--color-deep-rule); }
}

/* ============ внутренние страницы: заголовок и крошки ============ */

/* H1 разделов раньше стоял инлайном с фиксированным --text-3xl: на 320 px он рвал слово
   «Официальная» пополам. Здесь размер тянется от ширины экрана, а перенос запрещён
   внутри слова — длинное слово скорее уменьшится, чем разъедется. */
.dir-h1 {
  font-size: clamp(1.75rem, 6.2vw + 0.4rem, 2.875rem);
  margin-bottom: var(--space-md);
  overflow-wrap: break-word;
  hyphens: none;
}

/* Навигация фиксированная; на мобиле она наезжала на хлебные крошки. */
/* Навигация фиксированная и центрированная — крошкам нужен зазор под неё. */
.crumbs { padding-top: calc(var(--space-xl) + 2.5rem); }
@media (max-width: 48rem) {
  .crumbs { padding-top: calc(var(--space-lg) + 2.5rem); }
}

/* ---- содержимое внутренних страниц ----
   Этот блок до 14.08.2026 лежал НЕ здесь, а в теге <style> каждой страницы: 427 строк,
   скопированных по двадцати файлам. Копии успели разъехаться на три редакции — у
   europe, kazakhstan, uzbekistan и ukraine не было ни `.dir-note`, ни поддержки
   нумерованных списков, то есть врезка, поставленная на такой странице, рисовалась
   обычным абзацем, а <ol> терял нумерацию. Ошибка такого рода не видна в разметке
   и не ловится ни одной проверкой: страница просто выглядит иначе, чем соседняя.
   Одно место — и разъехаться больше нечему. */

/* Первая полоса внутренней страницы отбивается сверху сильнее обычного: над ней
   только крошки, и без этого заголовок липнет к навигации. */
main .band:first-child { padding-top: var(--space-3xl); }

/* Заглавная полоса внутренней страницы получает ту же разметочную сетку, что
   первый экран главной. Без неё двадцать внутренних страниц открывались голой
   бумагой: заголовок, абзац и белое поле до самого низа — рядом с главной это
   читается как другой сайт, а не как его раздел.

   Пятна света здесь нет намеренно: на главной оно подсвечивает карточку
   логотипа, то есть у него есть предмет. Свет без предмета — просто градиент.

   Сетка живёт на псевдоэлементе первого блока, а не на <main>: у <main> нет
   своей высоты первого экрана, и фон растянулся бы на всю страницу целиком.

   `:first-of-type`, а НЕ `:first-child`, и разница здесь несущая. Тип считается
   по тегу: у всех страниц полосы — <section>. На внутренней странице первая
   секция и есть заглавная полоса, правило её берёт. На ГЛАВНОЙ первая секция —
   это .hero, у которого своя подложка со светом; условие «первая секция И с
   классом band» на нём не выполняется, и полоса фактов, идущая следом, второй
   сетки не получает. Заменить на `:first-child` — значит выдать главной две
   подложки подряд со швом между ними. Проверено замером на четырёх страницах. */
main > .band:first-of-type:not(.band--deep) {
  position: relative;
  isolation: isolate;
}
main > .band:first-of-type:not(.band--deep)::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    repeating-linear-gradient(90deg,
      oklch(20% 0.016 258 / 0.03) 0 1px, transparent 1px var(--space-2xl)),
    repeating-linear-gradient(0deg,
      oklch(20% 0.016 258 / 0.024) 0 1px, transparent 1px var(--space-2xl));
  -webkit-mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, transparent 92%);
          mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, transparent 92%);
  pointer-events: none;
}
/* Тёмная полоса исключена в самом селекторе, а не погашена правилом ниже: она
   рисует свою сетку ярче, и отдельное «background: none» перебило бы её —
   правило с `main >` специфичнее, чем `.band--deep::before`. */

/* Лид страницы — один класс на все виды внутренних страниц. Раньше их было три
   (.dir-lede, .faq-intro, .nf-lede) с тремя разными мерами строки при одинаковой роли. */
.dir-lede, .faq-intro, .nf-lede {
  max-width: var(--measure);
  color: var(--color-muted);
  font-size: var(--text-lg);
}
.faq-intro { font-size: var(--text-base); }

.dir-block { margin-top: var(--space-3xl); }
.faq-group { margin-top: var(--space-2xl); }

/* Вертикальный ритм внутри раздела. Базовый сброс снимает отступы у p, ul и table,
   а возвращались они точечно — списку и таблице. Абзацу не возвращались вовсе,
   поэтому текст после списка и подпись под таблицей прилипали к предыдущему блоку
   без единого пикселя зазора: два разных высказывания читались как одно.
   Соседям задаётся общий отступ, а у кого он свой — список, заголовок, врезка —
   тот перебивает правило собственной специфичностью, и его ритм не ломается. */
.dir-block > * + *,
.legal > * + * { margin-top: var(--space-md); }

/* Один размер у заголовка раздела на ВСЕХ внутренних страницах. Было три: 2xl в
   разделах, xl в вопросах и xl в оферте — при том что роль у них одна и та же,
   «начало раздела». Канон взят по большинству страниц (девятнадцать из двадцати двух). */
.dir-block > h2,
.faq-group > h2,
.legal h2 {
  font-size: var(--text-2xl);
  letter-spacing: var(--track-2xl);
  line-height: var(--lead-2xl);
  margin-bottom: var(--space-md);
}
.legal h2 { margin-top: var(--space-xl); }

/* Заголовок правовой страницы не рвётся посреди слова.
   Общее правило страницы — `overflow-wrap: anywhere` (styles.css:48): оно
   спасает длинные адреса и номера в таблицах, но заголовку даёт «Политика
   конфиденциальнос / ти» — перенос по середине слова там, где слово помещается
   на своей строке. Здесь возвращаем обычный перенос по словам и разрешаем
   расстановку переносов: язык страницы объявлен в <html lang>, поэтому браузер
   переносит по правилам своего языка, а не наугад. */
.legal h1 {
  overflow-wrap: break-word;
  hyphens: auto;
}
.dir-block > h3 { font-size: var(--text-lg); margin-block: var(--space-lg) var(--space-2xs); letter-spacing: var(--track-lg); line-height: var(--lead-lg); }

.dir-block p, .dir-block li,
.legal p, .legal li { color: var(--color-muted); max-width: var(--measure); }

/* Списки внутренних страниц. Правило было написано дважды — для .dir-block и для
   .legal — слово в слово, и в половине копий без ветки для <ol>. */
.dir-block ul, .dir-block ol,
.legal ul, .legal ol {
  padding-left: 1.2em;
  display: grid;
  gap: var(--space-2xs);
  margin-top: var(--space-sm);
}
.dir-block ul, .legal ul { list-style: disc; }
.dir-block ol, .legal ol { list-style: decimal; }
.dir-block li::marker, .legal li::marker { color: var(--color-accent-deep); }

.dir-table { width: 100%; border-collapse: collapse; margin-top: var(--space-md); }
.dir-table th, .dir-table td {
  text-align: left;
  padding: var(--space-sm) var(--space-md) var(--space-sm) 0;
  border-bottom: var(--rule-hair) solid var(--color-rule);
  vertical-align: top;
}
.dir-table th {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral);
  font-weight: 400;
}
.dir-table td:first-child { color: var(--color-ink); font-weight: 500; }
.dir-scroll { overflow-x: auto; }

.dir-steps { display: grid; gap: var(--space-md); margin-top: var(--space-md); }
.dir-step { display: grid; grid-template-columns: 2.2rem 1fr; gap: var(--space-md); align-items: start; }
.dir-step__n {
  font-family: var(--font-mono);
  color: var(--color-accent-deep);
  font-size: var(--text-sm);
  padding-top: 0.15em;
}

.dir-note {
  margin-top: var(--space-md);
  padding: var(--space-md);
  background: var(--color-paper-2);
  border-left: var(--rule-thick) solid var(--color-accent);
}
.dir-note p { max-width: none; }

/* Призыв в конце страницы — одинаковый на разделах и на вопросах. */
.dir-cta, .faq-cta {
  margin-top: var(--space-3xl);
  padding-top: var(--space-xl);
  border-top: var(--rule-hair) solid var(--color-rule);
}

.legal { max-width: var(--measure); }
.legal .updated {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral);
}

/* Страница 404: список направлений, куда можно уйти. */
.nf-links { display: grid; gap: var(--space-sm); margin-top: var(--space-xl); max-width: 34rem; }
.nf-links a {
  display: flex;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-md) 0;
  border-bottom: var(--rule-hair) solid var(--color-rule);
}
.nf-links b { font-family: var(--font-display); font-weight: 700; }
.nf-links span { color: var(--color-neutral); font-size: var(--text-sm); text-align: right; }
.nf-links a:hover b { color: var(--color-accent-deep); }

/* Таблицы страниц-разделов на узком экране разворачиваются в карточки — иначе
   ставки и сроки приходится листать вбок. */
@media (max-width: 40rem) {
  .dir-scroll { overflow-x: visible; }
  .dir-table, .dir-table tbody, .dir-table tr, .dir-table td { display: block; }
  .dir-table thead { display: none; }
  .dir-table tr {
    padding-block: var(--space-md);
    border-bottom: var(--rule-hair) solid var(--color-rule);
  }
  .dir-table td { padding: 0.35rem 0 0 0; border: 0; }
  .dir-table td:first-child {
    padding-top: 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-md);
  }
  .dir-table td:not(:first-child)::before {
    content: attr(data-col) ": ";
    color: var(--color-neutral);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    display: block;
  }
}

/* ============ блок прямой речи ============ */

.honest {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--space-md);
}
.honest__item {
  padding: var(--space-md);
  background: var(--color-paper-2);
  border-top: 3px solid var(--color-accent);
}
.honest__item h3 { font-size: var(--text-md); margin-bottom: var(--space-xs); }
.honest__item p { font-size: var(--text-sm); color: var(--color-muted); }

/* ============ появление ============ */

/* ============ появление при прокрутке ============
   Скрытое состояние объявлено ТОЛЬКО под html[data-motion="on"]. Атрибут ставит
   встроенный скрипт в <head>, и он же снимает движение при prefers-reduced-motion.
   Порядок именно такой, потому что цена ошибки несимметрична: не отработала
   анимация — человек увидит статичную страницу; спрятали безусловно и сломался
   скрипт — человек увидит пустую.

   Переход, а не @keyframes: переход можно перехватить на полпути и развернуть,
   покадровая анимация начинается с нуля. Для блока, который проезжает мимо
   границы экрана туда-обратно, разница видна сразу. */
html[data-motion="on"] [data-reveal],
html[data-motion="on"] .reveal {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity var(--dur-long) var(--ease-out) calc(var(--i, 0) * 60ms),
    transform var(--dur-long) var(--ease-out) calc(var(--i, 0) * 60ms);
}

html[data-motion="on"] [data-reveal][data-shown="true"],
html[data-motion="on"] .reveal[data-shown="true"] {
  opacity: 1;
  transform: none;
}

/* Первый экран не ждёт наблюдателя: он и так на виду, а лишний кадр ожидания
   между отрисовкой и появлением читается как подвисание загрузки. */
html[data-motion="on"] .hero .reveal {
  animation: reveal var(--dur-long) var(--ease-out) calc(var(--i, 0) * 70ms) forwards;
  transition: none;
}
@keyframes reveal { to { opacity: 1; transform: none; } }

/* ============ движение интерфейса ============ */

/* Шапка получает тень только тогда, когда под неё заехало содержимое. В самом
   верху страницы тень отделяла бы пилюлю от пустоты — она там лишняя и выдаёт
   элемент, наклеенный поверх макета. Атрибут ставит motion.js. */
.nav {
  transition:
    box-shadow var(--dur-short) var(--ease-out),
    background-color var(--dur-short) var(--ease-out),
    border-color var(--dur-short) var(--ease-out);
}
html[data-motion="on"] .nav { box-shadow: none; }
html[data-motion="on"][data-scrolled="true"] .nav {
  box-shadow: var(--shadow-md);
  background: color-mix(in oklch, var(--color-paper) 96%, transparent);
}
@media (max-width: 56rem) {
  html[data-motion="on"][data-scrolled="true"] .nav {
    box-shadow: 0 6px 20px -18px oklch(20% 0.02 258 / 0.6);
  }
}

/* Раскрытие вопроса. Штатный <details> открывается рывком: браузер просто
   показывает содержимое, анимировать там нечего — до появления псевдоэлемента
   ::details-content, который и есть эта скрытая обёртка.

   Всё завёрнуто в @supports намеренно: где псевдоэлемента нет, аккордеон
   работает ровно как раньше — мгновенно. Это улучшение поверх рабочего
   поведения, а не условие работы.

   interpolate-size разрешает переход к auto: без него высота content-визуально
   прыгает с нуля на полную, и плавным остаётся только затухание. */
@supports selector(details::details-content) {
  html { interpolate-size: allow-keywords; }

  .qa::details-content {
    block-size: 0;
    overflow: clip;
    opacity: 0;
    transition:
      block-size var(--dur-short) var(--ease-out),
      opacity var(--dur-short) var(--ease-out),
      content-visibility var(--dur-short) allow-discrete;
  }
  .qa[open]::details-content {
    block-size: auto;
    opacity: 1;
  }
}

/* Карточка направления приподнимается под курсором. Тень растёт вместе со
   сдвигом — предмет, поднятый выше, отбрасывает тень дальше; сдвиг без тени
   читается как рывок текста, а не как движение карточки. */
.route {
  transition:
    transform var(--dur-short) var(--ease-out),
    border-color var(--dur-short) var(--ease-out),
    box-shadow var(--dur-short) var(--ease-out);
}

/* Указатель под курсором есть только там, где есть курсор. На сенсорном экране
   :hover залипает после касания, и карточка остаётся поднятой до тапа в
   стороне — выглядит как застрявшая анимация. */
@media (hover: hover) and (pointer: fine) {
  .route:hover { box-shadow: var(--shadow-lg); }
  .proof__cell { transition: background-color var(--dur-short) var(--ease-out); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 150ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 150ms !important;
  }
  .reveal { animation: reveal 150ms linear forwards; }
  /* Бегущий страус остановлен выше, в своём разделе: там снимается сам
     animation-name, и «animation-duration: 150ms !important» из этого правила
     ему уже безразличен — имени нет, длительность нечему применять. */
}

/* ============ печать ============
   Появление при прокрутке прячет блок заранее и показывает его по срабатыванию
   наблюдателя. На печати наблюдателя нет и прокрутки нет: страница отдаётся
   целиком, и половина текста ушла бы в бумагу прозрачной. Коммерческое
   предложение по такому маршруту распечатывают — это не редкий случай.

   Здесь же гасится фон полос: разметочная сетка и заливка тёмных секций съедают
   тонер и делают текст на них нечитаемым в чёрно-белой печати. */
/* ── согласие на аналитику ──────────────────────────────────────────────────
   Баннер стоит СПРАВА ВНИЗУ, а не по центру снизу: центр закрывает кнопки
   первого экрана, то есть главный призыв страницы. На узком экране — во всю
   ширину внизу. Цвета берутся токенами, поэтому обе темы работают сами.
   Появление гасится при prefers-reduced-motion: это служебное окно, а не
   украшение, и дёргать им человека, который просил не анимировать, незачем. */
.consent {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 90;
  width: min(24rem, calc(100vw - 2rem));
  padding: 1rem 1.125rem 1.125rem;
  background: var(--color-paper);
  color: var(--color-ink);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  animation: consent-in 0.22s ease-out;
}

@keyframes consent-in {
  from { opacity: 0; transform: translateY(0.5rem); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .consent { animation: none; }
}

.consent__text {
  margin: 0 0 0.875rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--color-muted);
}

.consent__text a {
  color: var(--color-accent);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.consent__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Обе кнопки одного размера намеренно: отказ, сделанный мельче согласия,
   согласием не считается — ни по смыслу, ни по правилам. */
.consent__btn {
  flex: 1 1 auto;
  min-height: 2.25rem;
  padding: 0 0.875rem;
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-ink);
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}

.consent__btn:hover { border-color: var(--color-accent); }
.consent__btn:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

.consent__btn--yes {
  color: var(--color-ink-invert);
  background: var(--color-ink);
  border-color: var(--color-ink);
}

.consent__btn--yes:hover {
  background: var(--color-accent);
  border-color: var(--color-accent);
}

@media (max-width: 40rem) {
  .consent { right: 0.5rem; left: 0.5rem; bottom: 0.5rem; width: auto; }
}

@media print {
  .consent { display: none; }
}

@media print {
  [data-reveal], .reveal {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
    transition: none !important;
  }
  .schema__line { stroke-dashoffset: 0 !important; }
  .schema__pulse { display: none; }

  .hero::before,
  .band--deep::before,
  .band--deep::after,
  main > .band:first-of-type:not(.band--deep)::before { display: none; }

  .band--deep {
    background: none;
    color: var(--color-ink);
  }
  .band--deep .lede,
  .band--deep .eyebrow,
  .schema__name,
  .schema__note { color: var(--color-muted); fill: var(--color-muted); }

  /* Таблица сравнения на тёмной полосе. Сброса `color` у .band--deep НЕ хватает:
     её строки объявляют цвет СВОИМИ правилами, а те весят больше (0,2,2 против
     0,1,0) и наследование до них не доходит. На белой бумаге светлые значения
     давали 1,12 у шапки и колонки «Ваш контракт», 1,63 у тела — то есть блок
     про то, кто импортёр в декларации, уходил в распечатку почти пустым. И
     ждать от печати фона нельзя: браузеры по умолчанию его не печатают вовсе,
     так что дефект воспроизводился при ЛЮБЫХ настройках. Найдено 20.08.2026. */
  .band--deep .cmp thead th,
  .band--deep .cmp tbody th,
  .band--deep .cmp td,
  .band--deep .cmp .cmp--us { color: var(--color-ink); }
  .band--deep .cmp thead th { border-bottom-color: var(--color-ink); }
  .band--deep .cmp th,
  .band--deep .cmp td { border-bottom-color: var(--color-rule); }

  .nav, .skip-link { display: none; }
}
