/* TOKORA — система движения (к motion.js). Режим — <html data-motion>: full | reduced | off.
   Классы на <html> ставит motion.js: .m-on — full (всё движение), .m-live — full или reduced,
   .m-low — слабое устройство. Без JS страница полная: скрытые начальные состояния — только под
   .js / .m-on (у первого экрана — с аварийным показом через 3 с). Режим off и системное
   «уменьшение движения» гасит блок в конце site.css.
   Пространства имён: mi- — заставка и первый экран, ms- — прокрутка, tx- — отклики на ввод. */

/* ---------- Токены: общие кривые, длительности, ритм и язык свечения ---------- */
:root {
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); /* появления и отклики */
  --ease-in-out-quart: cubic-bezier(0.76, 0, 0.24, 1); /* шторки, прорисовки линий */
  --ease-in-expo: cubic-bezier(0.7, 0, 0.84, 0); /* уходы */
  --ease-snap: cubic-bezier(0.3, 0, 0.2, 1); /* мягкие проявления фона первого экрана */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* пружина; точнее — linear() ниже */
  --dur-fast: 250ms; /* мелкие отклики: подсветка, появление подписи */
  --dur-base: 550ms; /* ответ на ввод: скобки, линии фокуса, пружины */
  --dur-slow: 620ms; /* подъём карточки при появлении (содержимое на месте за ~300 мс) */
  --dur-scan: 450ms; /* луч сканера по карточке (как по штрихкоду посылки) и развёртка фото */
  --stagger: 90ms; /* шаг «лесенки» у соседей, вошедших вместе (как у [data-reveal] в site.css) */
  --hot: #fff3e8; /* светлое ядро: кромки, отметки, головки линий */
  --glow-line: 0 0 14px 1px rgba(var(--accent-rgb), 0.85);
}
@supports (transition-timing-function: linear(0, 1)) {
  :root {
    /* Пружина с перелётом ~9 %. */
    --ease-spring: linear(0, 0.038, 0.134, 0.263, 0.408, 0.551, 0.685, 0.802, 0.898, 0.973, 1.028, 1.064, 1.085, 1.094,
      1.093, 1.086, 1.075, 1.062, 1.048, 1.035, 1.023, 1.013, 1.005, 0.999, 0.995, 0.993, 0.991, 0.991, 1);
  }
}

/* Координаты свечения карточки (.card, .quote в site.css) — без наследования, чтобы запись на каждом кадре
   не пересчитывала стили всего содержимого карточки. */
@property --mx {
  syntax: '<length-percentage>';
  inherits: false;
  initial-value: 50%;
}
@property --my {
  syntax: '<length-percentage>';
  inherits: false;
  initial-value: -30%;
}

@property --tx-brk {
  syntax: '<length>';
  inherits: false;
  initial-value: 12px;
}


/* =====================================================================
   1. Заставка и первый экран (mi-)
   ===================================================================== */

/* ---------- Заставка: накладная, счётчик, маршрут разрезает экран ---------- */
/* Заслонка до загрузки motion.js; сама уходит через 1 с, если скрипт не пришёл (заставку он тогда не начнёт). */
html.mi-intro::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9998;
  background: var(--bg);
  animation: mi-cover-out 0.3s 1s forwards;
}
@keyframes mi-cover-out { to { opacity: 0; visibility: hidden; } }

.mi-intro {
  position: fixed;
  inset: 0;
  z-index: 9999;
  overflow: hidden;
  contain: strict;
  cursor: progress;
}
.mi-intro.is-open { pointer-events: none; }
.mi-intro.is-split .mi-intro__scan { display: none; }

/* Бланк накладной: тёплая бумага в темноте — тонкая миллиметровка и мягкое пятно света. */
.mi-intro__half {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(70vmax 50vmax at 50% 55%, rgba(var(--accent-rgb), 0.06), transparent 70%),
    linear-gradient(rgba(255, 236, 220, 0.03) 1px, transparent 1px) 50% 50% / 64px 64px,
    linear-gradient(90deg, rgba(255, 236, 220, 0.03) 1px, transparent 1px) 50% 50% / 64px 64px,
    var(--bg);
  will-change: transform;
}
.mi-intro__half--b { visibility: hidden; }
.mi-intro.is-split .mi-intro__half--b { visibility: visible; }

.mi-intro__in {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: clamp(20px, 4vh, 40px) var(--gutter);
  color: var(--muted);
  font: 500 0.66rem/1.6 var(--f-mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.mi-intro__in > :not(.mi-intro__frame) { opacity: 0; transition: opacity 0.22s; }
.mi-intro.is-ready .mi-intro__in > * { opacity: 1; }
.mi-intro__frame { position: absolute; inset: clamp(10px, 2vh, 18px); }
.mi-intro__frame::after { --o: 0px; --c: rgba(var(--accent-rgb), 0.5); }
.mi-intro__row { display: flex; align-items: center; justify-content: space-between; gap: 12px 24px; }
.mi-intro__row > * { min-width: 0; }

/* «Печать» моноширинного текста: обрезка по символам (--n — длина строки). */
.mi-intro__type {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  vertical-align: bottom;
  color: var(--text);
  animation: mi-type 0.42s steps(var(--n, 20)) 0.06s both;
}
@keyframes mi-type { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 -1ch 0 0); } }

.mi-intro__sys { display: flex; align-items: center; justify-content: flex-end; gap: 14px; text-align: right; }
/* Штрихкод накладной: полосы разной ширины, проявляются слева направо. */
.mi-intro__code {
  flex: none;
  width: 92px;
  height: 18px;
  background:
    linear-gradient(90deg,
      currentColor 0 2px, transparent 2px 4px, currentColor 4px 5px, transparent 5px 8px, currentColor 8px 11px,
      transparent 11px 12px, currentColor 12px 13px, transparent 13px 16px, currentColor 16px 18px, transparent 18px 19px,
      currentColor 19px 20px, transparent 20px 23px) 0 0 / 23px 100%;
  opacity: 0.55;
  animation: mi-code 0.5s var(--ease-out-expo) 0.2s both;
}
@keyframes mi-code { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0); } }

.mi-intro__center {
  display: grid;
  place-self: center;
  justify-items: center;
  gap: clamp(14px, 2.4vh, 22px);
  width: min(620px, 100%);
}
.mi-intro__count {
  display: flex;
  align-items: flex-start;
  color: var(--text);
  font: 700 clamp(5.5rem, 24vw, 13rem)/0.8 var(--f-num);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.mi-intro__count span { display: inline-block; min-width: 1.62em; text-align: center; white-space: nowrap; } /* цифры разной ширины — без сдвигов */
.mi-intro__count small { margin: 0.06em 0 0 0.08em; color: var(--accent-text); font-size: 0.26em; line-height: 1; }
/* Полоса — пунктир трассы, заливка идёт по нему; посылка — на её конце. */
.mi-intro__bar {
  position: relative;
  width: 100%;
  height: 2px;
  background: repeating-linear-gradient(90deg, var(--line-2) 0 6px, transparent 6px 12px);
}
.mi-intro__bar i {
  position: absolute;
  inset: 0;
  background: var(--accent);
  box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.6);
  transform: scaleX(0);
  transform-origin: left;
}
.mi-intro__bar b { position: absolute; inset: 0; }
.mi-intro__bar b::after {
  content: '';
  position: absolute;
  left: -5px;
  top: -4px;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  background: var(--accent);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.18), 0 0 14px rgba(var(--accent-rgb), 0.55);
}
.mi-intro.is-online .mi-intro__bar b { opacity: 0; transition: opacity 0.3s; }
.mi-intro__meta { display: flex; justify-content: space-between; gap: 16px; width: 100%; }
.mi-intro__status { transition: color 0.2s; }
.mi-intro.is-online .mi-intro__status { color: var(--accent-text); }
.mi-intro__log { display: grid; gap: 2px; }
.mi-intro__log li { opacity: 0; transform: translateY(4px); transition: opacity 0.16s, transform 0.3s var(--ease-out-expo); }
.mi-intro__log li.is-on { opacity: 1; transform: none; }
.mi-intro__log b { color: var(--accent-text); font-weight: 500; }
.mi-intro__skip { color: var(--dim); text-align: right; }

/* Маршрут (в пикселях окна): пунктир плана, линия и посылка; кромка разреза — в каждой половине. */
.mi-intro__route,
.mi-intro__edge {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.mi-intro__route path,
.mi-intro__edge path { fill: none; stroke-linecap: round; }
.mi-intro__plan { opacity: 0; stroke: rgba(255, 236, 220, 0.22); stroke-width: 1.5px; stroke-dasharray: 3 9; }
.mi-intro__line {
  stroke: var(--accent);
  stroke-width: 2px;
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
  filter: drop-shadow(0 0 6px rgba(var(--accent-rgb), 0.6));
}
.mi-intro__parcel { transform: translate(-40px, -40px); }
.mi-intro__parcel circle { fill: rgba(var(--accent-rgb), 0.14); stroke: rgba(var(--accent-rgb), 0.45); stroke-width: 1px; }
.mi-intro__parcel rect { fill: var(--accent); stroke: var(--hot); stroke-width: 1px; }
.mi-intro__edge { opacity: 0; filter: drop-shadow(0 0 6px rgba(var(--accent-rgb), 0.7)); }
.mi-intro__edge path { stroke: var(--accent); stroke-width: 2px; vector-effect: non-scaling-stroke; }
/* Луч сканера проходит бланк сверху вниз — один раз. */
.mi-intro__scan {
  position: absolute;
  inset: 0 0 auto;
  height: 28vh;
  background: linear-gradient(to bottom, transparent, rgba(var(--accent-rgb), 0.03) 85%, rgba(var(--accent-rgb), 0.12));
  animation: mi-scan 1.1s cubic-bezier(0.5, 0, 0.5, 1) both;
}
@keyframes mi-scan { from { transform: translateY(-100%); } to { transform: translateY(100vh); } }

@media (max-width: 599px) {
  .mi-intro__sys,
  .mi-intro__skip { display: none; }
}

/* ---------- Первый экран: до старта анимации (только с JS; аварийный показ через 3 с) ---------- */
/* Статичный глобус SVG — первый кадр и вид без JS / reduced / off: его не прячем. */
html.js[data-motion="full"] .main > .hero:not(.mi-hero) :is(.hero__badge, .hero__line, .hero__lead, .hero__text > .btns, .hcard, .hero__grid, .hero__glow),
html.js[data-motion="reduced"] .main > .hero:not(.mi-hero) :is(.hero__badge, .hero__line, .hero__lead, .hero__text > .btns, .hcard) {
  opacity: 0;
  animation: mi-failsafe 0.6s 3s forwards;
}
@keyframes mi-failsafe { to { opacity: 1; } }

/* ---------- Кинетичный заголовок ---------- */
.mi-hero .hero__title { position: relative; }
.mi-word { display: inline-block; }
.mi-ch { display: inline-block; transform-origin: 50% 100%; }
.mi-type-ch { border-radius: 1px; }

/* Контурная строка: временный SVG-оверлей, контур каждой буквы прорисовывается за посылкой. */
.mi-ink {
  position: absolute;
  left: 0;
  top: 0;
  overflow: visible;
  pointer-events: none;
}
.mi-ink g {
  fill: none;
  stroke: var(--accent);
  stroke-linejoin: round;
}
.mi-ink.is-glow { filter: drop-shadow(0 0 8px rgba(var(--accent-rgb), 0.55)); }

/* Маршрут под контурным словом: пунктир трассы, посылка на конце, отметка доставки. */
.mi-route {
  position: absolute;
  height: 0;
  pointer-events: none;
}
.mi-route > span { position: absolute; left: 0; top: 0; }
.mi-route > .mi-route__trail {
  right: 0;
  top: -1px;
  height: 2px;
  background: repeating-linear-gradient(90deg, rgba(var(--accent-rgb), 0.9) 0 8px, transparent 8px 15px);
}
.mi-route__dot {
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: 3px;
  background: var(--accent);
  box-shadow: 0 0 0 4px rgba(var(--accent-rgb), 0.18), 0 0 16px rgba(var(--accent-rgb), 0.6);
}
.mi-route__ping {
  width: 22px;
  height: 22px;
  margin: -11px 0 0 -11px;
  border: 1.5px solid var(--accent);
  border-radius: 50%;
  opacity: 0;
}

/* ---------- Карточка первого экрана ----------
   Раскрытие — то же, что у карточек ниже (.ms-card.ms-in: подъём, луч, скобки); здесь — только своё. */
.mi-hero .hcard.mi-wait { opacity: 0; } /* ниже первого окна (мобильные) — ждёт появления в окне */
.m-on .mi-card-go .hcard__value::after {
  transform-origin: left;
  animation: mi-underline 0.8s var(--ease-out-expo) var(--mi-line, 0s) both;
}
@keyframes mi-underline { from { transform: scaleX(0); } }
.m-on .mi-card-go .hcard__status { transform-origin: 60% 50%; }

/* Кнопка: одноразовый блик после появления. */
.btn--primary > .mi-shine {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(110deg, transparent 30%, rgba(255, 255, 255, 0.4) 50%, transparent 70%);
}

/* ---------- Глобус первого экрана: живой холст (motion-sky.js) поверх статичного SVG ----------
   SVG — первый кадр и вид без JS, в reduced и off. Холст проявляется только после своего первого кадра
   (.mi-globe-on), SVG за то же время гаснет: смена без скачка. Ниже full класс снимается — снова SVG. */
/* Слабое устройство: не размывать каждый кадр холста под карточкой — без размытия она плотнее (как до стекла). */
.m-low .mi-sky-on .hcard { -webkit-backdrop-filter: none; backdrop-filter: none; background-color: rgba(17, 15, 13, 0.84); }
.mi-sky-on .hero__glow { animation: mi-breathe 9s ease-in-out infinite alternate; }
@keyframes mi-breathe { from { scale: 0.97; } to { scale: 1.05; } }

.mi-sky,
.mi-gridlit { position: absolute; inset: 0; pointer-events: none; }
.mi-sky {
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 1.4s var(--ease-out-expo, ease-out);
}
.mi-sky-on .hero__globe { transition: opacity 1.4s var(--ease-out-expo, ease-out); }
.mi-globe-on .hero__globe { opacity: 0; }
.mi-globe-on .mi-sky { opacity: 1; }
/* На узком глобус приглушён за заголовком — та же прозрачность и тот же порог, что у .hero__globe в site.css. */
@media (max-width: 999px) {
  .mi-globe-on .mi-sky { opacity: 0.6; }
}

/* Подсветка сетки вокруг Москвы при отправке (позиция — --lx/--ly, яркость — мягкая волна opacity из JS). */
.mi-gridlit {
  opacity: 0;
  background-image:
    linear-gradient(rgba(var(--accent-rgb), 0.38) 1px, transparent 1px),
    linear-gradient(90deg, rgba(var(--accent-rgb), 0.38) 1px, transparent 1px);
  background-size: 64px 64px;
  background-position: center top;
  -webkit-mask-image: radial-gradient(circle var(--lr, 300px) at var(--lx, 50%) var(--ly, 50%), #000, rgba(0, 0, 0, 0.3) 45%, transparent);
  mask-image: radial-gradient(circle var(--lr, 300px) at var(--lx, 50%) var(--ly, 50%), #000, rgba(0, 0, 0, 0.3) 45%, transparent);
}

/* Мягкое зарево отправки у Москвы: двигается transform, яркость — opacity (волна 2.6 с, без пиков). */
.mi-dispatch {
  position: absolute;
  left: 0;
  top: 0;
  opacity: 0;
  pointer-events: none;
  border-radius: 50%;
  will-change: transform, opacity;
  width: 640px;
  height: 640px;
  margin: -320px 0 0 -320px;
  background: radial-gradient(closest-side, rgba(var(--accent-rgb), 0.22), rgba(var(--accent-rgb), 0.06) 45%, transparent);
}

/* Импульс по маршруту навигации: пунктирная «колонна» сигнала бежит сверху вниз (pulseRoutes в motion.js).
   Тоньше и тусклее заливки .ms-charge и лежит под ней — не выглядит как заливка, ушедшая вперёд посылки.
   Сумма штрихов до разрыва (0.064) = PULSE_HEAD в motion.js.
   Без non-scaling-stroke: с ним Chrome меряет штрихи pathLength в пикселях экрана, а не в долях пути.
   Толщина — в единицах viewBox: --ms-u (единиц на пиксель) ставит initCharge по замеру. */
.mi-route-pulse {
  fill: none;
  stroke: rgba(var(--accent-rgb), 0.55);
  stroke-width: calc(1px * var(--ms-u, 1));
  stroke-linecap: round;
  stroke-dasharray: 0.004 0.012 0.006 0.012 0.03 1.3;
  stroke-dashoffset: 0.064;
  vector-effect: none;
  opacity: 0;
  filter: drop-shadow(0 0 2px rgba(var(--accent-rgb), 0.45));
}

/* Первый экран (или любой блок, .ms-away) вне окна, вкладка скрыта — бесконечные циклы на паузе.
   Пульс точек внутри первого экрана с анимацией от прокрутки иначе будит главный поток каждый кадр. */
.mi-idle .hero__glow,
.mi-idle .dot,
.mi-idle .dot::after,
.ms-away .hero__glow,
.ms-away .dot,
.ms-away .dot::after,
.ms-away .ticker__track,
.is-paused .dot::after { animation-play-state: paused; }

/* =====================================================================
   2. Хореография прокрутки (ms-)
   ===================================================================== */

/* Подъёмы карточек и въезды сбоку не расширяют документ (на телефоне окно иначе «отъезжает»).
   clip, а не hidden: не создаёт контейнер прокрутки — sticky и view() работают как прежде. */
.m-on .main,
.m-on .ftr { overflow-x: clip; }

/* ---------- Вставленные декоративные элементы: без .m-on не видны и не влияют на раскладку ---------- */
.ms-num,
.ms-progress,
.ms-charge,
.ms-parcel,
.ms-fill,
.ms-fill-edge,
.ms-scan { display: none; }

/* Одометр (показатели, число карточки): окно ровно в строку — призрак-цифра держит раскладку,
   поля ±0.3em с отрицательными отступами только дают место мягкой маске краёв. Строки барабана
   разнесены на 1lh + 0.8em: соседняя цифра никогда не заглядывает в окно. По окончании — обычный текст. */
.ms-odo__col {
  position: relative;
  display: inline-block;
  margin-block: -0.3em;
  padding-block: 0.3em;
  overflow: clip;
  -webkit-mask-image: linear-gradient(transparent, #000 0.3em, #000 calc(100% - 0.3em), transparent);
  mask-image: linear-gradient(transparent, #000 0.3em, #000 calc(100% - 0.3em), transparent);
}
.ms-odo__ghost { visibility: hidden; }
.ms-odo__reel {
  position: absolute;
  top: -0.1em; /* 0.3em поля окна − 0.4em поля строки */
  right: 0;
  left: 0;
  text-align: center;
  transform: translateY(calc((1 - 1 / var(--n, 1)) * -100%));
}
.ms-odo__reel > span { display: block; padding-block: 0.4em; }
/* ---------- Утилита «прокрутки»: fallback = пауза + задержка от --p; при поддержке — таймлайн ---------- */
.m-on .ms-scrub {
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-fill-mode: both;
  animation-play-state: paused;
  animation-delay: calc(var(--p, 0) * -1s);
}

@supports (animation-timeline: view()) {
  .m-on .ms-scrub {
    animation-duration: auto;
    animation-play-state: running;
    animation-delay: 0s;
  }
}

/* =====================================================================
   1. Заголовки секций
   ===================================================================== */
.m-on .ms-head .ms-w {
  display: inline-block;
  clip-path: inset(-0.35em -0.25em -0.14em);
}
.m-on .ms-head .ms-wi { display: inline-block; transform-origin: 0 100%; }
.m-on .ms-head.ms-pending .ms-wi { transform: translateY(135%) skewY(11deg); }
.m-on .ms-head.ms-in .ms-wi {
  animation: ms-line-in 0.7s var(--ease-out-expo) backwards;
  animation-delay: calc(var(--ms-d, 0ms) + 40ms + var(--ln, 0) * 70ms);
}
.m-on .ms-head.ms-done .ms-w { clip-path: none; }

@keyframes ms-line-in {
  from { transform: translateY(135%) skewY(11deg); }
}

.m-on .ms-head .ms-sw { display: inline-block; }
.m-on .ms-head.ms-pending .ms-sw { opacity: 0; }
.m-on .ms-head.ms-in .ms-sw {
  animation: ms-word-in 0.6s var(--ease-out-expo) backwards;
  animation-delay: calc(var(--ms-d, 0ms) + var(--ms-sub, 190ms) + var(--wi, 0) * 12ms);
}
.m-on.m-low .ms-head.ms-in .ms-sw { animation-name: ms-word-in-lite; }

@keyframes ms-word-in {
  from { opacity: 0; transform: translateY(0.75em); filter: blur(6px); }
}
@keyframes ms-word-in-lite {
  from { opacity: 0; transform: translateY(0.75em); }
}

/* Черта у подписи рисуется, текст подписи «дешифруется» из JS */
.m-on .ms-head .eyebrow::before { transform-origin: 0 50%; }
.m-on .ms-head.ms-pending .eyebrow::before { transform: scaleX(0); }
.m-on .ms-head.ms-in .eyebrow::before { animation: ms-dash 0.5s var(--ease-in-out-quart) var(--ms-d, 0ms) backwards; }
.m-on .ms-head.ms-pending .ms-eb { opacity: 0; }

@keyframes ms-dash {
  from { transform: scaleX(0); }
}

/* =====================================================================
   7. Глубина: огромный контурный номер секции за заголовком (параллакс)
   ===================================================================== */
.m-on :where(.ms-has-num) { position: relative; }
.m-on .ms-has-num { isolation: isolate; view-timeline: --ms-head block; view-timeline-inset: 0; }
.m-on .ms-num {
  display: block;
  position: absolute;
  z-index: -1;
  top: 50%;
  right: 0;
  translate: 0 -50%;
  /* Оттиск градиентом, а не контур: обводка Unbounded показывает «швы» пересечений внутри цифр, а заливка
     цветом фона (как у .hero__line--outline) видна тёмным пятном на подсвеченных блоках. Тот же приём —
     у знака в подвале (.ftr__mark). body переносит слова где угодно — номер нет. */
  color: transparent;
  background: linear-gradient(180deg, rgba(var(--accent-rgb), 0.15), rgba(var(--accent-rgb), 0.035) 70%, transparent);
  -webkit-background-clip: text;
  background-clip: text;
  font: 700 clamp(7.5rem, 24cqi, 17rem)/0.8 var(--f-num);
  letter-spacing: -0.03em;
  white-space: nowrap;
  overflow-wrap: normal;
  pointer-events: none;
  user-select: none;
  transition: opacity 1.6s ease 0.25s;
  animation-name: ms-num;
  animation-timeline: --ms-head;
  animation-range: cover 0% cover 100%;
}
.m-on .ms-head.ms-pending .ms-num { opacity: 0; }
/* Узкая липкая шапка FAQ: номер скромнее, чтобы не вылезал за колонку */
.m-on .faq--split .ms-num { font-size: clamp(6rem, 18cqi, 12rem); }

@keyframes ms-num {
  from { transform: translateY(42%); }
  to { transform: translateY(-42%); }
}

/* Сетка страницы плывёт медленнее контента (бесшовно: сдвиг кратен шагу сетки) */
.m-on .page-fx__grid { background: none; }
.m-on .page-fx__grid::before {
  content: '';
  position: absolute;
  inset: 0 0 -56px;
  background-image:
    linear-gradient(rgba(255, 236, 220, 0.028) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 236, 220, 0.028) 1px, transparent 1px);
  background-size: 56px 56px;
  animation: ms-grid 1s linear both paused;
  animation-iteration-count: var(--ms-grid-n, 24);
  animation-delay: calc(var(--p, 0) * var(--ms-grid-n, 24) * -1s);
}

@supports (animation-timeline: view()) {
  .m-on .page-fx__grid::before {
    animation-duration: auto;
    animation-play-state: running;
    animation-delay: 0s;
    animation-timeline: scroll(root block);
  }
}

@keyframes ms-grid {
  to { transform: translateY(-56px); }
}

/* Первый экран: фон уходит медленнее, содержимое — «в глубину» */
.m-on .ms-hero { view-timeline: --ms-hero block; view-timeline-inset: 0; }
.m-on .ms-hero > .hero__bg {
  animation-name: ms-hero-bg;
  animation-timeline: --ms-hero;
  animation-range: exit 0% exit 100%;
}
@keyframes ms-hero-bg {
  to { transform: translateY(32%); }
}

/* Только transform: opacity у предка сделала бы его backdrop root и сломала размытие под .hcard */
@media (min-width: 900px) {
  .m-on .ms-hero > .hero__wrap {
    transform-origin: 50% 0;
    animation-name: ms-hero-out;
    animation-timeline: --ms-hero;
    animation-range: exit 0% exit 100%;
  }
  /* Затемнение уходящего экрана — отдельным слоем поверх */
  .m-on .ms-hero::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    background: var(--bg);
    opacity: 0;
    pointer-events: none;
    animation-name: ms-hero-dim;
    animation-duration: 1s;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-play-state: paused;
    animation-delay: calc(var(--p, 0) * -1s);
  }
}
@supports (animation-timeline: view()) {
  @media (min-width: 900px) {
    .m-on .ms-hero::after {
      animation-duration: auto;
      animation-play-state: running;
      animation-delay: 0s;
      animation-timeline: --ms-hero;
      animation-range: exit 0% exit 100%;
    }
  }
}
@keyframes ms-hero-out {
  to { transform: translateY(18%) scale(0.94); }
}
@keyframes ms-hero-dim {
  to { opacity: 0.75; }
}

/* =====================================================================
   2. Карточки, тарифы, отзывы, показатели: луч сканера + подъём в 3D
   ===================================================================== */
/* Содержимое на месте за ~300 мс (видно уже через ~60 мс); дольше живёт только оформление:
   луч, скобки, планка. Без clip-path: ничего не прячется под лучом. */
.m-on .ms-card.ms-pending { opacity: 0; }
.m-on .ms-card.ms-in {
  transform-origin: 50% 100%;
  animation: ms-card-in var(--dur-slow) var(--ease-out-expo) var(--ms-d, 0ms) backwards;
}

@keyframes ms-card-in {
  0% { opacity: 0; transform: perspective(1100px) translate3d(0, 36px, 0) rotateX(9deg) scale(0.985); }
  25% { opacity: 1; }
}
/* Касание: без наклона, только подъём */
@media (pointer: coarse) {
  @keyframes ms-card-in {
    0% { opacity: 0; transform: translate3d(0, 28px, 0); }
    25% { opacity: 1; }
  }
}

/* Луч сканера проходит по карточке, как по накладной, пока она встаёт на место */
.m-on .ms-scan {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  animation: ms-scan var(--dur-scan) linear var(--ms-d, 0ms) both;
}
.ms-scan::before {
  content: '';
  position: absolute;
  top: -3px;
  right: -18px;
  left: -18px;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent) 12%, var(--hot) 50%, var(--accent) 88%, transparent);
  box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.6), 0 -4px 18px rgba(var(--accent-rgb), 0.25);
}
.ms-scan::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: 100%;
  left: 0;
  height: 120px;
  background: linear-gradient(to top, rgba(var(--accent-rgb), 0.14), rgba(var(--accent-rgb), 0.03) 40%, transparent);
}

@keyframes ms-scan {
  0% { transform: translateY(0); opacity: 0; animation-timing-function: cubic-bezier(0.3, 0.55, 0.25, 1); }
  6% { opacity: 1; }
  82% { transform: translateY(100%); opacity: 1; }
  100% { transform: translateY(100%); opacity: 0; }
}

/* Скобки по углам «защёлкиваются», акцентная планка прорисовывается */
.m-on .ms-card.ms-in::after,
.m-on .member.ms-in .member__media::after {
  animation: ms-lock 0.5s var(--ease-out-expo) calc(var(--ms-d, 0ms) + 200ms) backwards;
}
.m-on .ms-card.ms-in::before {
  transform-origin: 0 50%;
  animation: ms-bar 0.5s var(--ease-in-out-quart) calc(var(--ms-d, 0ms) + 120ms) backwards;
}

@keyframes ms-lock {
  0% { opacity: 0; scale: 1.16; }
  40% { opacity: 1; }
}
@keyframes ms-bar {
  from { transform: scaleX(0); }
}

/* Команда: карточка просто поднимается, а медиа раскрывается сканирующим лучом (фото на месте за ~300 мс) */
.m-on .member.ms-card.ms-in { animation-name: ms-rise-card; }
.m-on .member.ms-in .member__media {
  animation: ms-media var(--dur-scan) linear calc(var(--ms-d, 0ms) + 30ms) backwards;
}
.m-on .member.ms-in .ms-scan { animation-delay: calc(var(--ms-d, 0ms) + 30ms); }
.ms-scan--media::after {
  height: 100%;
  background:
    repeating-linear-gradient(180deg, rgba(var(--accent-rgb), 0.12) 0 1px, transparent 1px 4px),
    linear-gradient(to top, rgba(var(--accent-rgb), 0.22), transparent 60%);
}
.m-on .member.ms-in :is(.member__initials, .member__glyph) {
  animation: ms-flicker 0.5s linear calc(var(--ms-d, 0ms) + 180ms) backwards;
}
.m-on .member.ms-in .member__img {
  animation: ms-develop 0.6s var(--ease-out-expo) calc(var(--ms-d, 0ms) + 30ms) backwards;
}
.m-on .member.ms-in .member__body > * {
  animation: ms-rise-soft 0.5s var(--ease-out-expo) backwards;
  animation-delay: calc(var(--ms-d, 0ms) + 60ms);
}
.m-on .member.ms-in .member__body > :nth-child(2) { animation-delay: calc(var(--ms-d, 0ms) + 100ms); }
.m-on .member.ms-in .member__body > :nth-child(3) { animation-delay: calc(var(--ms-d, 0ms) + 140ms); }
.m-on .member.ms-in .member__body > :nth-child(n + 4) { animation-delay: calc(var(--ms-d, 0ms) + 180ms); }

@keyframes ms-rise-card {
  from { opacity: 0; transform: translateY(32px); }
}
@keyframes ms-media {
  0% { clip-path: inset(0 0 100% 0); animation-timing-function: cubic-bezier(0.3, 0.55, 0.25, 1); }
  82%, 100% { clip-path: inset(0 0 0 0); }
}
/* Подпись не исчезает совсем: имя читается с первого кадра */
@keyframes ms-rise-soft {
  from { opacity: 0.35; transform: translateY(14px); }
}
/* Мерцание «включения»: не больше двух вспышек, малая площадь и низкий контраст */
@keyframes ms-flicker {
  0% { opacity: 0; }
  18% { opacity: 0.55; }
  30% { opacity: 0.12; }
  52% { opacity: 0.85; }
  62% { opacity: 0.45; }
  100% { opacity: 1; }
}
@keyframes ms-develop {
  from { opacity: 0.55; transform: scale(1.06); }
}
@keyframes ms-rise {
  from { opacity: 0; transform: translateY(22px); }
}

/* Отзывы: звёзды загораются по очереди */
.m-on .quote.ms-in .quote__stars .i { animation: ms-pop 0.4s var(--ease-out-expo) backwards; }
.m-on .quote.ms-in .quote__stars .i:nth-child(1) { animation-delay: calc(var(--ms-d, 0ms) + 140ms); }
.m-on .quote.ms-in .quote__stars .i:nth-child(2) { animation-delay: calc(var(--ms-d, 0ms) + 180ms); }
.m-on .quote.ms-in .quote__stars .i:nth-child(3) { animation-delay: calc(var(--ms-d, 0ms) + 220ms); }
.m-on .quote.ms-in .quote__stars .i:nth-child(4) { animation-delay: calc(var(--ms-d, 0ms) + 260ms); }
.m-on .quote.ms-in .quote__stars .i:nth-child(5) { animation-delay: calc(var(--ms-d, 0ms) + 300ms); }
.m-on .quote.ms-in .quote__mark { animation: ms-pop 0.5s var(--ease-out-expo) calc(var(--ms-d, 0ms) + 100ms) backwards; }

@keyframes ms-pop {
  from { opacity: 0; transform: scale(0.4); }
}

/* О нас: год основания «вытирается» слева направо со светящейся кромкой */
.m-on .about__hl.ms-in .about__year {
  position: relative;
  animation: ms-wipe 0.55s var(--ease-in-out-quart) calc(var(--ms-d, 0ms) + 120ms) backwards;
}
.m-on .about__hl.ms-in .about__year::after {
  content: '';
  position: absolute;
  inset: -4% auto -4% 0;
  width: 100%;
  background: linear-gradient(90deg, transparent calc(100% - 3px), var(--hot) calc(100% - 3px));
  filter: drop-shadow(0 0 10px rgba(var(--accent-rgb), 0.9));
  pointer-events: none;
  animation: ms-wipe-edge 0.55s var(--ease-in-out-quart) calc(var(--ms-d, 0ms) + 120ms) both;
}

@keyframes ms-wipe {
  0% { clip-path: inset(-90px 100% -90px -90px); }
  90% { clip-path: inset(-90px 0% -90px -90px); }
  100% { clip-path: inset(-90px -90px -90px -90px); }
}
@keyframes ms-wipe-edge {
  0% { transform: translateX(-100%); opacity: 1; }
  90% { transform: translateX(0); opacity: 1; }
  100% { transform: translateX(0); opacity: 0; }
}

/* Одометры: один проход 0 → d, разряды справа стартуют на 40 мс позже; в движении барабан размыт
   (в долях em — нечитаемо при любом кегле), к остановке резкость возвращается: промежуточные числа не читаются */
.m-on .ms-odo:not(.ms-roll) .ms-odo__reel { transform: none; }
.m-on .ms-odo.ms-roll .ms-odo__reel {
  transition: transform var(--odo-ms, 620ms) cubic-bezier(0.35, 0.15, 0.15, 1) calc(var(--j, 0) * 40ms);
  animation: ms-odo-blur var(--odo-ms, 620ms) linear calc(var(--j, 0) * 40ms) both;
}
@keyframes ms-odo-blur {
  0% { filter: blur(0); }
  12%, 70% { filter: blur(0.08em); }
  100% { filter: blur(0); }
}

/* Цены (тариф, число карточки с валютой): не крутятся — итоговая строка «вытирается» слева направо
   со светящейся кромкой. Задержка — --wipe-d (у тарифа — от лесенки карточек). */
.m-on .plan.ms-in .plan__amount { --wipe-d: calc(var(--ms-d, 0ms) + 60ms); }
.m-on :is(.plan.ms-in .plan__amount, .ms-wipe) {
  position: relative;
  animation: ms-price 460ms var(--ease-in-out-quart) var(--wipe-d, 0ms) backwards;
}
.m-on :is(.plan.ms-in .plan__amount, .ms-wipe)::after {
  content: '';
  position: absolute;
  inset: -6% auto -6% 0;
  width: 100%;
  background: linear-gradient(90deg, transparent calc(100% - 2px), var(--hot) calc(100% - 2px));
  filter: drop-shadow(0 0 8px rgba(var(--accent-rgb), 0.9));
  pointer-events: none;
  animation: ms-price-edge 460ms var(--ease-in-out-quart) var(--wipe-d, 0ms) both;
}
.m-on .plan .plan__amount { justify-self: start; } /* рамка по тексту: кромка не уходит за цену */
@keyframes ms-price {
  from { clip-path: inset(-20% 100% -20% -10%); }
  to { clip-path: inset(-20% -10% -20% -10%); }
}
@keyframes ms-price-edge {
  0% { transform: translateX(-100%); opacity: 1; }
  85% { transform: translateX(0); opacity: 1; }
  100% { transform: translateX(0); opacity: 0; }
}

/* FAQ: вопросы въезжают справа, под каждым пробегает акцентная линия */
.m-on .ms-faq { position: relative; }
.m-on .ms-faq.ms-pending { opacity: 0; }
.m-on .ms-faq.ms-in { animation: ms-slide-in 0.6s var(--ease-out-expo) var(--ms-d, 0ms) backwards; }
.m-on .ms-faq::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  height: 1px;
  background: linear-gradient(90deg, var(--accent), rgba(var(--accent-rgb), 0));
  box-shadow: var(--glow-line);
  transform-origin: 0 50%;
  opacity: 0;
  pointer-events: none;
}
.m-on .ms-faq.ms-in::after { animation: ms-underline 0.9s var(--ease-in-out-quart) calc(var(--ms-d, 0ms) + 80ms) both; }

@keyframes ms-slide-in {
  from { opacity: 0; transform: translateX(40px); }
}
@keyframes ms-underline {
  0% { transform: scaleX(0); opacity: 1; }
  55% { transform: scaleX(1); opacity: 1; }
  100% { transform: scaleX(1); opacity: 0; }
}

/* Призыв: панель раскрывается шторкой */
.m-on .ms-panel.ms-pending { opacity: 0; }
.m-on .ms-panel.ms-in { animation: ms-panel-in 0.65s var(--ease-in-out-quart) var(--ms-d, 0ms) backwards; }
.m-on .ms-panel.ms-in :is(.cta__body, .cta__btns) {
  animation: ms-rise 0.55s var(--ease-out-expo) calc(var(--ms-d, 0ms) + 160ms) backwards;
}
.m-on .ms-panel.ms-in .cta__btns { animation-delay: calc(var(--ms-d, 0ms) + 230ms); }

@keyframes ms-panel-in {
  0% { opacity: 0; clip-path: inset(0 100% 0 0); }
  10% { opacity: 1; }
  100% { opacity: 1; clip-path: inset(-20px -20px -20px -20px); }
}

/* =====================================================================
   3. Бегущая строка — CSS-лента из site.css; JS при прокрутке меняет её скорость (playbackRate)
   и наклон (--ms-skew), затем засыпает
   ===================================================================== */
.m-on .ms-ticker .ticker__group { transform: skewX(var(--ms-skew, 0deg)); }

/* =====================================================================
   4. Полоса прогресса, маршрут боковой навигации заполняется, активный пункт — как на табло
   ===================================================================== */
.m-on .ms-progress {
  display: block;
  position: fixed;
  top: calc(var(--header-h) - 1px);
  right: 0;
  left: 0;
  z-index: 51;
  height: 2px;
  pointer-events: none;
  container-type: inline-size;
  transition: opacity 0.3s;
}
.m-on.menu-open .ms-progress { opacity: 0; }
.ms-progress__bar {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(var(--accent-rgb), 0.15), var(--accent) 70%, #ffd9c4);
  box-shadow: var(--glow-line);
  transform-origin: 0 50%;
  animation-name: ms-grow-x;
  animation-timeline: scroll(root block);
}
.ms-progress__head {
  position: absolute;
  top: 50%;
  left: 0;
  animation-name: ms-travel-x;
  animation-timeline: scroll(root block);
}
.ms-progress__head::before {
  content: '';
  position: absolute;
  top: -7px;
  left: -12px;
  width: 24px;
  height: 14px;
  border-radius: 50%;
  background: radial-gradient(closest-side, #fff4ec, rgba(var(--accent-rgb), 0.6) 45%, transparent);
}

@keyframes ms-grow-x {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}
@keyframes ms-travel-x {
  0% { transform: translateX(0); opacity: 0; }
  3% { opacity: 1; }
  100% { transform: translateX(100cqw); opacity: 1; }
}

.m-on .ms-layout { view-timeline: --ms-layout block; view-timeline-inset: 0; }
/* Исходный маршрут — приглушённый план; по нему же ритм отправок пускает мягкий импульс (pulseRoutes). */
.m-on .sidenav__route.ms-dim :is(.route__line, .route__glow) { stroke-opacity: 0.32; }
.m-on .sidenav__route.ms-dim .route__stop { opacity: 0.45; }
/* Копия поверх: заливка по длине пути (pathLength=1) от прогресса раскладки. */
.m-on .ms-charge {
  display: block;
  pointer-events: none;
  filter: drop-shadow(0 0 4px rgba(var(--accent-rgb), 0.55));
}
/* Без non-scaling-stroke (site.css): с ним Chrome откладывает штрихи pathLength в пикселях экрана, и заливка
   уходит от остановок и посылки на величину масштаба SVG (вперёд на низком окне, назад — на высоком).
   Толщину держим постоянной на экране сами: --ms-u — единиц viewBox на пиксель (initCharge, по замеру). */
.m-on .ms-charge :is(.route__line, .route__glow) {
  vector-effect: none;
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
  animation-name: ms-route-fill;
  animation-timeline: --ms-layout;
  animation-range: contain 0% contain 100%;
}
.m-on .ms-charge .route__line { stroke: var(--accent); stroke-opacity: 1; stroke-width: calc(1.5px * var(--ms-u, 1)); }
.m-on .ms-charge .route__glow { stroke: rgba(var(--accent-rgb), 0.35); stroke-width: calc(1.25px * var(--ms-u, 1)); }
@keyframes ms-route-fill { to { stroke-dashoffset: 0; } }

/* Остановки загораются, когда заливка их проходит (класс — из motion.js). */
.m-on .ms-charge .route__stop {
  fill: var(--accent);
  opacity: 0;
  transform: scale(0.3);
  transform-box: fill-box;
  transform-origin: center;
  transition: opacity 0.35s, transform 0.6s var(--ease-spring);
}
.m-on .ms-charge .route__stop.is-lit { opacity: 1; transform: none; }

/* Посылка на конце заливки: коробка = коробка SVG (замер), позиция — доли коробки (cqw/cqh). */
.m-on .ms-parcel:not([hidden]) {
  display: block;
  position: absolute;
  container-type: size;
  pointer-events: none;
}
.ms-parcel__dot {
  position: absolute;
  top: 0;
  left: 0;
}
.ms-parcel__dot::before,
.ms-parcel__dot::after {
  content: '';
  position: absolute;
}
/* Ореол — круг, сама посылка — квадрат со скруглением */
.ms-parcel__dot::before {
  top: -13px;
  left: -13px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(var(--accent-rgb), 0.35), transparent);
  opacity: 0;
  transition: opacity 0.4s;
}
.ms-parcel__dot::after {
  top: -4px;
  left: -4px;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--bg), 0 0 10px rgba(var(--accent-rgb), 0.7);
  transform: scale(0.6);
  transition: transform 0.4s var(--ease-spring);
}
.ms-parcel.is-moving .ms-parcel__dot::before { opacity: 1; }
.ms-parcel.is-moving .ms-parcel__dot::after { transform: none; }

/* Активный пункт перелистывается вниз, как строка на табло вылетов: без сдвигов и разрывов. */
.m-on .sidenav__link.ms-flip .sidenav__label {
  display: inline-block;
  transform-origin: 50% 0;
  animation: ms-flip 0.55s var(--ease-out-expo);
}
.m-on .sidenav__link.ms-flip .sidenav__bar { animation: ms-bar-on 0.6s ease-out; }
.m-on .sidenav__link.ms-flip .sidenav__num { animation: ms-num-on 0.6s ease-out; }

@keyframes ms-flip {
  0% { transform: perspective(240px) rotateX(-88deg); opacity: 0.2; color: var(--accent-text); }
  55% { transform: perspective(240px) rotateX(10deg); opacity: 1; }
  100% { transform: none; }
}
@keyframes ms-bar-on {
  0% { box-shadow: 0 0 14px 1px rgba(var(--accent-rgb), 0.7); }
}
@keyframes ms-num-on {
  0% { color: var(--accent-text); }
}

/* =====================================================================
   6. Шаги — маршрут с остановками: линия прокладывается синхронно с прокруткой, остановки отмечаются по очереди
   Диапазон: начало, когда верх списка на (1 - r0)·vh, конец — низ списка на r1·vh.
   ===================================================================== */
.m-on .ms-steps { view-timeline: --ms-steps block; view-timeline-inset: 0; --ms-r0: 0.2; --ms-r1: 0.45; }

@container blk (min-width: 900px) {
  .m-on .ms-steps { --ms-r0: 0.08; --ms-r1: 0.68; }
}

.m-on .ms-steps .step::before {
  transform-origin: 50% 0;
  animation-name: ms-draw-y;
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-fill-mode: both;
  animation-play-state: paused;
  animation-delay: calc(clamp(0, var(--p, 0) * var(--n, 1) - var(--si, 0), 1) * -1s);
}

@supports (animation-timeline: view()) {
  .m-on .ms-steps .step::before {
    animation-duration: auto;
    animation-play-state: running;
    animation-delay: 0s;
    animation-timeline: --ms-steps;
    animation-range:
      cover calc(var(--ms-r0) * 100vh + (100% - (var(--ms-r0) + var(--ms-r1)) * 100vh) * var(--si) / var(--n))
      cover calc(var(--ms-r0) * 100vh + (100% - (var(--ms-r0) + var(--ms-r1)) * 100vh) * (var(--si) + 1) / var(--n));
  }
}

@container blk (min-width: 900px) {
  .m-on .ms-steps .step::before { transform-origin: 0 50%; animation-name: ms-draw-x; }
}

@keyframes ms-draw-x {
  from { transform: scaleX(0); }
}
@keyframes ms-draw-y {
  from { transform: scaleY(0); }
}

.m-on .ms-steps .step__num {
  border-color: var(--line-2);
  color: var(--dim);
  box-shadow: 0 0 0 4px var(--bg);
  transition: border-color 0.5s, color 0.5s, box-shadow 0.6s, background-color 0.3s;
}
.m-on .ms-steps .step.is-lit .step__num {
  border-color: rgba(var(--accent-rgb), 0.6);
  color: var(--accent-text);
  box-shadow: 0 0 0 4px var(--bg), 0 0 18px rgba(var(--accent-rgb), 0.22);
  animation: ms-stop-on 0.9s var(--ease-out-expo);
}
.m-on .ms-steps .step:hover .step__num { background: var(--accent); color: var(--on-accent); }

/* Остановка отмечена: кольцо расходится от номера, сам номер чуть подрастает и садится. */
@keyframes ms-stop-on {
  0% { transform: scale(0.92); box-shadow: 0 0 0 4px var(--bg), 0 0 0 4px rgba(var(--accent-rgb), 0.45); }
  30% { transform: scale(1.06); }
  100% { transform: none; box-shadow: 0 0 0 4px var(--bg), 0 0 0 14px rgba(var(--accent-rgb), 0); }
}

/* Текст шагов появляется обычным образом (лесенкой), а у отмеченной остановки заголовок на миг — акцентом */
.m-on .ms-step.ms-pending { opacity: 0; }
.m-on .ms-step.ms-in :is(.step__title, .step__text, .step__meta) {
  animation: ms-rise 0.55s var(--ease-out-expo) backwards;
  animation-delay: calc(var(--ms-d, 0ms) + 40ms);
}
.m-on .ms-step.ms-in .step__text { animation-delay: calc(var(--ms-d, 0ms) + 80ms); }
.m-on .ms-step.ms-in .step__meta { animation-delay: calc(var(--ms-d, 0ms) + 120ms); }
.m-on .ms-steps .step.is-lit .step__title { animation: ms-title-flash 1.1s ease-out; }
.m-on .ms-steps .step.is-lit .step__meta .i { animation: ms-pop 0.6s var(--ease-out-expo) 0.1s backwards; }

@keyframes ms-title-flash {
  0%, 20% { color: var(--accent-text); }
}

/* =====================================================================
   8. Призыв: кромка авиаконверта и точечная сетка едут с прокруткой, заголовок заливается слева направо
   ===================================================================== */
.m-on .ms-cta { view-timeline: --ms-cta block; view-timeline-inset: 0; }
/* Та же точечная сетка, что в site.css (.cta__fx), но на ::before — плывёт под неподвижной маской поля */
.m-on .ms-cta .cta__fx { background: none; overflow: hidden; }
.m-on .ms-cta .cta__fx::before {
  content: '';
  position: absolute;
  inset: -48px;
  background: radial-gradient(circle, rgba(var(--accent-rgb), 0.28) 1px, transparent 1.7px) 0 0 / 16px 16px;
}
.m-on .ms-cta::before,
.m-on .ms-cta .cta__fx::before,
.m-on .ms-fill,
.m-on .ms-fill-edge {
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-fill-mode: both;
  animation-play-state: paused;
  animation-delay: calc(var(--p, 0) * -1s);
}
.m-on .ms-cta::before { animation-name: ms-airmail; }
.m-on .ms-cta .cta__fx::before { animation-name: ms-dots; }

/* До заливки — бледный оттиск, а не контур: обводка Unbounded показывает «швы» пересечений внутри букв */
.m-on .ms-cta .cta__title {
  position: relative;
  color: rgba(255, 236, 220, 0.16);
}
.m-on .ms-cta .cta__title em.accent { color: inherit; }
.m-on .ms-fill {
  display: block;
  position: absolute;
  inset: 0;
  color: var(--text);
  -webkit-text-stroke-width: 0;
  pointer-events: none;
  user-select: none;
  animation-name: ms-fill;
}
.m-on .ms-fill em.accent { color: var(--accent-text); }
.m-on .ms-fill-edge {
  display: block;
  position: absolute;
  top: -6%;
  bottom: -6%;
  left: 0;
  width: 100%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent calc(100% - 90px), rgba(var(--accent-rgb), 0.16) calc(100% - 2px), var(--hot) calc(100% - 2px));
  animation-name: ms-fill-edge;
}
/* Заливка идёт на отрезке 20–55 % прохода блока через экран */
.m-on .ms-fill,
.m-on .ms-fill-edge { animation-delay: calc(clamp(0, (var(--p, 0) - 0.2) / 0.35, 1) * -1s); }

@supports (animation-timeline: view()) {
  .m-on .ms-cta::before,
  .m-on .ms-cta .cta__fx::before,
  .m-on .ms-fill,
  .m-on .ms-fill-edge {
    animation-duration: auto;
    animation-play-state: running;
    animation-delay: 0s;
    animation-timeline: --ms-cta;
    animation-range: cover 0% cover 100%;
  }
  .m-on .ms-fill,
  .m-on .ms-fill-edge { animation-range: cover 20% cover 55%; }
}

/* Полосы авиаконверта по краю призыва едут вместе с прокруткой */
@keyframes ms-airmail {
  from { background-position: 0 0; }
  to { background-position: 340px 0; }
}
/* Двигаем точки, а не поле: маска поля остаётся на месте; сдвиг меньше запаса inset (48px) */
@keyframes ms-dots {
  from { transform: translate(-40px, 16px); }
  to { transform: translate(40px, -16px); }
}
@keyframes ms-fill {
  from { clip-path: inset(-20% 100% -30% 0); }
  to { clip-path: inset(-20% -6% -30% 0); }
}
@keyframes ms-fill-edge {
  0% { transform: translateX(-100%); opacity: 0; }
  6% { opacity: 1; }
  90% { opacity: 1; }
  100% { transform: translateX(0); opacity: 0; }
}

/* Подвал: буквы знака поднимаются и заполняются снизу, как шкала загрузки */
/* overflow: hidden делает подвал контейнером прокрутки, и view() считал бы видимость внутри него */
.m-on .ftr:has(.ms-mark) { overflow: clip; }
.m-on .ms-mark {
  view-timeline: --ms-mark block;
  view-timeline-inset: 0;
  background: none;
}
.m-on .ms-mark .ms-ch {
  display: inline-block;
  /* Нижняя половина фона — «жидкость» с яркой кромкой; сдвиг фона поднимает уровень */
  background:
    linear-gradient(180deg, transparent 47.2%, rgba(255, 196, 160, 0.85) 49.7%, rgba(var(--accent-rgb), 0.5) 50.2%,
      rgba(var(--accent-rgb), 0.2) 62%, rgba(var(--accent-rgb), 0.03) 100%) 0 0 / 100% 200% no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  animation-name: ms-letter;
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-fill-mode: both;
  animation-play-state: paused;
  animation-delay: calc(clamp(0, (var(--p, 0) - var(--i, 0) / var(--n, 1) * 0.3) / 0.42, 1) * -1s);
}

@supports (animation-timeline: view()) {
  .m-on .ms-mark .ms-ch {
    animation-duration: auto;
    animation-play-state: running;
    animation-delay: 0s;
    animation-timeline: --ms-mark;
    animation-range:
      entry calc(var(--i) / var(--n) * 30%)
      entry calc(42% + var(--i) / var(--n) * 30%);
  }
}

@keyframes ms-letter {
  0% { transform: translateY(105%) skewY(6deg); background-position: 0 0; }
  55% { transform: none; }
  100% { transform: none; background-position: 0 100%; }
}

/* =====================================================================
   3. Отклики на ввод: курсор, магнит, наклон, отметки клика, формы (tx-)
   ===================================================================== */

/* ---------- Прожектор: мягкий свет и подсвеченная сетка под курсором ---------- */
.tx-spot,
.tx-cursor,
.tx-pings {
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
}
.tx-spot {
  z-index: -1; /* над .page-fx, под содержимым */
  width: 560px;
  height: 560px;
  opacity: 0;
  background: radial-gradient(closest-side, rgba(var(--accent-rgb), 0.13), rgba(var(--accent-rgb), 0.045) 55%, transparent);
  transition: opacity 0.6s;
  will-change: transform;
  contain: strict;
}
.tx-spot.is-on { opacity: 1; }
.tx-spot__mask {
  position: absolute;
  inset: 0;
  overflow: hidden;
  -webkit-mask-image: radial-gradient(closest-side, #000 0%, rgba(0, 0, 0, 0.45) 45%, transparent 100%);
  mask-image: radial-gradient(closest-side, #000 0%, rgba(0, 0, 0, 0.45) 45%, transparent 100%);
}
.tx-spot__grid {
  --p: 56px;
  position: absolute;
  top: 0;
  left: 0;
  width: calc(100% + var(--p));
  height: calc(100% + var(--p));
  background-image:
    radial-gradient(circle at 0.5px 0.5px, rgba(255, 226, 200, 0.75) 1px, transparent 1.6px),
    linear-gradient(rgba(var(--accent-rgb), 0.34) 1px, transparent 1px),
    linear-gradient(90deg, rgba(var(--accent-rgb), 0.34) 1px, transparent 1px);
  background-size: var(--p) var(--p);
  transition: opacity 0.45s;
  will-change: transform;
}
.tx-spot__grid--hero,
.tx-spot.is-hero .tx-spot__grid:not(.tx-spot__grid--hero) { opacity: 0; }
.tx-spot.is-hero .tx-spot__grid--hero { opacity: 1; }
body:not(.fx-grid) .tx-spot__grid { display: none; }

/* ---------- Кольцо курсора (системный курсор остаётся на месте) ---------- */
.tx-cursor {
  z-index: 90;
  width: 0;
  height: 0;
  will-change: transform;
}
.tx-cursor > span { position: absolute; }
/* Обёртка кольца: скрипт вытягивает её вдоль скорости, а состояния масштабируют само кольцо. */
.tx-cursor__body {
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  transition: opacity 0.3s;
}
.tx-cursor__ring {
  position: absolute;
  left: -18px;
  top: -18px;
  width: 36px;
  height: 36px;
  border: 1px solid rgba(var(--accent-rgb), 0.75);
  border-radius: 50%;
  transition: transform 0.5s var(--ease-spring), opacity 0.3s, background-color 0.3s, border-color 0.3s;
}
/* Риски компаса по четырём сторонам */
.tx-cursor__ring::before {
  content: '';
  position: absolute;
  inset: -7px;
  background:
    linear-gradient(rgba(var(--accent-rgb), 0.9) 0 0) top center / 1px 5px no-repeat,
    linear-gradient(rgba(var(--accent-rgb), 0.9) 0 0) bottom center / 1px 5px no-repeat,
    linear-gradient(rgba(var(--accent-rgb), 0.9) 0 0) left center / 5px 1px no-repeat,
    linear-gradient(rgba(var(--accent-rgb), 0.9) 0 0) right center / 5px 1px no-repeat;
  transition: opacity 0.3s;
}
.tx-cursor__lock {
  --c: rgba(var(--accent-rgb), 0.85);
  left: -21px;
  top: -21px;
  width: 42px;
  height: 42px;
  opacity: 0;
  transform: scale(1.8) rotate(45deg);
  background:
    linear-gradient(var(--c) 0 0) top left / 8px 1.5px no-repeat,
    linear-gradient(var(--c) 0 0) top left / 1.5px 8px no-repeat,
    linear-gradient(var(--c) 0 0) top right / 8px 1.5px no-repeat,
    linear-gradient(var(--c) 0 0) top right / 1.5px 8px no-repeat,
    linear-gradient(var(--c) 0 0) bottom left / 8px 1.5px no-repeat,
    linear-gradient(var(--c) 0 0) bottom left / 1.5px 8px no-repeat,
    linear-gradient(var(--c) 0 0) bottom right / 8px 1.5px no-repeat,
    linear-gradient(var(--c) 0 0) bottom right / 1.5px 8px no-repeat;
  transition: transform var(--dur-base) var(--ease-spring), opacity var(--dur-fast);
}
.tx-cursor__pill {
  left: 16px;
  top: 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px 8px 12px;
  border: 1px solid rgba(var(--accent-rgb), 0.7);
  background: rgba(11, 10, 9, 0.88);
  color: var(--accent-text);
  font: 600 0.66rem/1 var(--f-mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  white-space: nowrap;
  box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.9), 0 0 18px -6px rgba(var(--accent-rgb), 0.6);
  opacity: 0;
  clip-path: inset(0 100% 0 0);
  transform: translate(-6px, -4px);
  transition: clip-path 0.4s var(--ease-out-expo), opacity 0.2s, transform 0.4s var(--ease-out-expo);
}
.tx-cursor__arrow {
  display: inline-block;
  font-size: 0.82rem;
  letter-spacing: 0;
  transition: transform 0.35s var(--ease-out-expo);
}
.tx-cursor[data-dir='down'] .tx-cursor__arrow { transform: rotate(90deg); }
.tx-cursor[data-dir='up'] .tx-cursor__arrow { transform: rotate(-90deg); }
.tx-cursor[data-dir='out'] .tx-cursor__arrow { transform: rotate(-45deg); }
.tx-cursor.is-flip .tx-cursor__pill { left: auto; right: 16px; clip-path: inset(0 0 0 100%); transform: translate(6px, -4px); }

.tx-cursor.is-hidden > span { opacity: 0 !important; }
.tx-cursor.is-scrolling .tx-cursor__pill { opacity: 0; transition-duration: 0.12s; }
.tx-cursor.is-link .tx-cursor__ring {
  transform: scale(1.55);
  border-color: var(--accent);
  background: rgba(var(--accent-rgb), 0.1);
}
.tx-cursor.is-link .tx-cursor__ring::before { opacity: 0; }
.tx-cursor.is-pill .tx-cursor__ring {
  transform: scale(0.28);
  border-color: var(--accent);
  background: var(--accent);
}
.tx-cursor.is-pill .tx-cursor__ring::before,
.tx-cursor.is-lock .tx-cursor__ring::before { opacity: 0; }
.tx-cursor.is-pill .tx-cursor__pill {
  opacity: 1;
  clip-path: inset(0 0 0 0);
  transform: none;
}
.tx-cursor.is-lock .tx-cursor__ring { transform: scale(0.16); opacity: 1; background: var(--accent); }
.tx-cursor.is-lock .tx-cursor__lock { opacity: 1; transform: none; }
.tx-cursor.is-text .tx-cursor__ring { transform: scale(0.2); opacity: 0; }
.tx-cursor.is-on-accent .tx-cursor__ring { border-color: rgba(11, 10, 9, 0.7); background: rgba(11, 10, 9, 0.06); }
.tx-cursor.is-on-accent.is-pill .tx-cursor__ring { background: rgba(11, 10, 9, 0.85); }
.tx-cursor.is-down .tx-cursor__ring { transform: scale(0.78); }
.tx-cursor.is-down.is-link .tx-cursor__ring { transform: scale(1.25); }
.tx-cursor.is-down .tx-cursor__lock { transform: scale(0.86); }

/* ---------- Отметки клика: кольца и точки (canvas поверх страницы, пока есть что рисовать) ---------- */
.tx-pings {
  z-index: 85;
  width: 100%;
  height: 100%;
}

/* ---------- Импульс по фону: тонкое кольцо сигнала за содержимым ---------- */
.tx-wave {
  position: fixed;
  top: 0;
  left: 0;
  z-index: -1; /* как .tx-spot: над фоном страницы, под содержимым */
  width: 520px;
  height: 520px;
  opacity: 0;
  pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(closest-side, transparent 70%, rgba(var(--accent-rgb), 0.05) 84%,
    rgba(var(--accent-rgb), 0.26) 95%, rgba(255, 228, 208, 0.32) 97.5%, transparent 100%);
  will-change: transform, opacity;
}
/* Второе кольцо внутри — тоньше и отстаёт, как повтор сигнала. */
.tx-wave > span {
  position: absolute;
  inset: 22%;
  border-radius: 50%;
  background: radial-gradient(closest-side, transparent 86%, rgba(var(--accent-rgb), 0.2) 96%, transparent 100%);
}

/* ---------- Кнопки: магнит, блик ---------- */
.m-on .btn.tx-magnet { z-index: 1; }
.m-on .btn--ghost::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, transparent 30%, rgba(var(--accent-rgb), 0.22) 50%, transparent 70%);
  transform: translateX(-120%);
  transition: transform 0.7s var(--ease);
  pointer-events: none;
}
.m-on .btn--ghost:hover::before { transform: translateX(120%); }
.m-on .btn--ghost > * { position: relative; }
.m-on .btn--primary::before {
  background: linear-gradient(110deg, transparent 32%, rgba(255, 255, 255, 0.18) 44%, rgba(255, 255, 255, 0.55) 50%, rgba(255, 255, 255, 0.18) 56%, transparent 68%);
}

/* ---------- 3D-наклон карточек: блик и раздвигающиеся уголки ---------- */
.m-on .tx-tilting {
  transition-property: border-color, box-shadow, --glow, filter;
  will-change: transform;
}
.m-on .card.tx-tilting { transform-style: preserve-3d; }
.m-on .card.tx-tilting .card__icon { transform: translateZ(26px); }
.m-on .card.tx-tilting .card__top .chip { transform: translateZ(18px); }

.tx-glare {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.5s;
}
.tx-glare > span {
  position: absolute;
  top: -260px;
  left: -260px;
  width: 520px;
  height: 520px;
  background: radial-gradient(closest-side, rgba(255, 244, 232, 0.12), rgba(var(--accent-rgb), 0.07) 45%, transparent 72%);
}
.tx-hot > .tx-glare { opacity: 1; }

.m-on :is(.card, .plan, .quote, .member__media).brk::after {
  --s: var(--tx-brk);
  transition: --tx-brk var(--dur-base) var(--ease-out-expo), transform var(--dur-base) var(--ease-out-expo);
}
.m-on :is(.card, .plan, .quote, .member__media).brk--4::after { --tx-brk: 16px; }
.m-on :is(.card, .plan, .quote, .member__media).brk.tx-hot::after {
  --tx-brk: 30px;
  transform: scale(1.02);
}

/* ---------- Навигация разделов: акцентный скан по подписи ---------- */
.m-on :is(.sidenav__label, .menu__label) { position: relative; }
.tx-navscan {
  position: absolute;
  inset: 0;
  color: var(--accent-text);
  text-shadow: 0 0 10px rgba(var(--accent-rgb), 0.7);
  clip-path: inset(0 0 0 100%);
  pointer-events: none;
}
html:not(.m-on) .tx-navscan { display: none; }

/* ---------- Заголовки: по наведению строка «перелистывается», как на табло вылетов ----------
   Акцентная копия (inert, на время отклика) открывается сверху вниз и уходит вниз; по кромке — тонкая планка. */
.m-on :is(.sec-title, .cta__title) { position: relative; }
.tx-flap {
  position: absolute;
  inset: 0;
  display: block;
  pointer-events: none;
  opacity: 0;
  color: var(--accent-text);
  -webkit-text-stroke-width: 0;
}
.tx-flap * { color: inherit !important; text-shadow: none !important; -webkit-text-stroke-width: 0 !important; }
.tx-flap--edge {
  inset: 0 -4px auto;
  height: 1px;
  background: rgba(var(--accent-rgb), 0.8);
  box-shadow: 0 0 8px rgba(var(--accent-rgb), 0.6);
}
.tx-flipping > .tx-flap { animation: tx-flap 0.64s var(--ease-in-out-quart); }
.tx-flipping > .tx-flap--edge { animation: tx-flap-edge 0.64s var(--ease-in-out-quart); }

@keyframes tx-flap {
  0% { opacity: 1; clip-path: inset(-10% -4px 100% -4px); }
  45% { opacity: 1; clip-path: inset(-10% -4px -10% -4px); }
  100% { opacity: 1; clip-path: inset(100% -4px -10% -4px); }
}
@keyframes tx-flap-edge {
  0% { opacity: 1; transform: translateY(0); }
  45% { opacity: 1; transform: translateY(var(--tx-h, 1em)); }
  100% { opacity: 0; transform: translateY(var(--tx-h, 1em)); }
}

/* ---------- Команда: сканер, монограмма, фото ---------- */
.tx-scan {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
}
.tx-scan > span {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  height: 34%;
  opacity: 0;
  background: linear-gradient(180deg, transparent, rgba(var(--accent-rgb), 0.12) 70%, rgba(var(--accent-rgb), 0.55) 97%, rgba(255, 236, 220, 0.95) 99.4%, transparent);
  transform: translateY(-100%);
}
.tx-scan::after {
  content: '';
  position: absolute;
  inset: 0;
  opacity: 0;
  background: repeating-linear-gradient(180deg, rgba(0, 0, 0, 0.22) 0 1px, transparent 1px 3px);
  transition: opacity 0.6s;
}
.member__media:hover > .tx-scan::after { opacity: 0.55; }

.m-on .member__media > .member__img.tx-color {
  position: absolute;
  inset: 0;
  filter: contrast(1.05) saturate(1.08);
}
/* Пока идёт развёртка, основное фото остаётся ч/б — цвет приносит копия. */
.m-on .member:hover .member__media > .member__img:not(.tx-color) { filter: grayscale(1) contrast(1.05) brightness(0.9); }

.tx-mono {
  position: absolute;
  inset: 0;
  overflow: visible;
  pointer-events: none;
}
.tx-mono text {
  fill: rgba(var(--accent-rgb), 0.18);
  fill-opacity: 0;
  stroke: rgba(var(--accent-rgb), 0.9);
  stroke-width: 1.5px;
  stroke-dasharray: 900;
  stroke-dashoffset: 0;
}
.member__mono.tx-has-svg .member__initials { visibility: hidden; }
.m-on .member:hover .member__mono .tx-mono text { filter: drop-shadow(0 0 18px rgba(var(--accent-rgb), 0.45)); }

/* ---------- FAQ: «+» → «×» с пружиной, акцентная направляющая ---------- */
.tx-x {
  position: relative;
  display: none;
  width: 16px;
  height: 16px;
}
.tx-x i {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 2px;
  margin-top: -1px;
  background: currentColor;
  transition: transform 0.6s var(--ease-spring);
}
.tx-x i + i { transform: rotate(90deg); }
.m-live .faq__item[open]:not(.is-closing) .faq__icon { transform: none; }
.faq__item[open]:not(.is-closing) .tx-x i { transform: rotate(225deg); }
.faq__item[open]:not(.is-closing) .tx-x i + i { transform: rotate(315deg); }
.m-live .faq__icon.tx-has-x > .i { display: none; }
.m-live .faq__icon.tx-has-x > .tx-x { display: block; }

.m-on .faq__item { position: relative; }
.m-on .faq__item::before {
  content: '';
  position: absolute;
  top: -1px;
  bottom: -1px;
  left: -14px;
  width: 2px;
  background: var(--accent);
  box-shadow: var(--glow-line);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--dur-base) var(--ease-out-expo);
}
.m-on .faq__item[open]:not(.is-closing)::before { transform: none; }
/* Узко поле страницы 16–20px: черта — у края строки, а не у края экрана */
@container blk (max-width: 599px) {
  .m-on .faq__item::before { left: -8px; }
}
.m-on .faq__item[open]:not(.is-closing) .faq__num { text-shadow: 0 0 12px rgba(var(--accent-rgb), 0.8); }

/* ---------- Форма: уголки и линия фокуса, отправка, ошибки, штамп «Принято» ---------- */
.m-on .tx-form .field { position: relative; }
.m-on .tx-form .field::before,
.m-on .tx-form .field::after {
  content: '';
  position: absolute;
  grid-row: 2 / 3; /* абсолютный элемент в сетке поля: его рамка — строка с контролом */
  grid-column: 1 / -1;
  pointer-events: none;
}
.m-on .tx-form .field::before {
  inset: -5px;
  opacity: 0;
  transform: scale(1.035);
  background:
    linear-gradient(var(--accent) 0 0) top left / 10px 2px no-repeat,
    linear-gradient(var(--accent) 0 0) top left / 2px 10px no-repeat,
    linear-gradient(var(--accent) 0 0) top right / 10px 2px no-repeat,
    linear-gradient(var(--accent) 0 0) top right / 2px 10px no-repeat,
    linear-gradient(var(--accent) 0 0) bottom left / 10px 2px no-repeat,
    linear-gradient(var(--accent) 0 0) bottom left / 2px 10px no-repeat,
    linear-gradient(var(--accent) 0 0) bottom right / 10px 2px no-repeat,
    linear-gradient(var(--accent) 0 0) bottom right / 2px 10px no-repeat;
  transition: opacity var(--dur-fast), transform 0.5s var(--ease-spring);
}
.m-on .tx-form .field::after {
  top: auto;
  right: 0;
  bottom: 0;
  left: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 60%, #fff));
  box-shadow: var(--glow-line);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-base) var(--ease-out-expo);
}
.m-on .tx-form .field:focus-within::before { opacity: 1; transform: none; }
.m-on .tx-form .field:focus-within::after { transform: none; }
.m-on .tx-form .field:has([aria-invalid='true'])::after { background: var(--danger); box-shadow: 0 0 12px rgba(255, 107, 94, 0.8); }
.m-on .tx-form .field__label { transition: color 0.25s, letter-spacing 0.4s var(--ease-out-expo); }
.m-on .tx-form .field:focus-within .field__label { color: var(--accent-text); letter-spacing: 0.24em; }

.tx-err .field__control,
.tx-err .check__box { animation: tx-err 0.7s ease-out; }
@keyframes tx-err {
  from { box-shadow: 0 0 0 4px rgba(255, 107, 94, 0.45); }
  to { box-shadow: 0 0 0 0 rgba(255, 107, 94, 0); }
}

/* Отправка: полосы бегут, как лента сортировки, и повторяется блик, пока заявка уходит */
.m-on .form.is-loading .btn--primary { filter: saturate(0.85); }
.m-on .form.is-loading .btn--primary::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: -30px;
  width: calc(100% + 60px);
  background: repeating-linear-gradient(-45deg, rgba(11, 10, 9, 0.16) 0 10px, transparent 10px 20px);
  animation: tx-stripes 0.55s linear infinite;
}
.m-on .form.is-loading .btn--primary::before { animation: tx-sweep 1.1s var(--ease) infinite; }
@keyframes tx-stripes { to { transform: translateX(28.28px); } }
@keyframes tx-sweep {
  from { transform: translateX(-120%); }
  to { transform: translateX(120%); }
}

.m-on .btn.tx-success { filter: none; }
.m-on .btn.tx-success::after,
.m-on .btn.tx-success::before { animation: none; display: none; }
.btn--primary > .tx-btn-check {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--accent);
  animation: tx-fade 0.2s both;
}
.tx-btn-check svg { width: 30px; height: 30px; }
.tx-btn-check path,
.tx-done__mark path {
  fill: none;
  stroke: var(--on-accent);
  stroke-width: 3;
  stroke-linecap: square;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: tx-draw 0.5s 0.12s var(--ease-out-expo) forwards;
}
@keyframes tx-draw { to { stroke-dashoffset: 0; } }
@keyframes tx-fade { from { opacity: 0; } }

.form-done.tx-done::before { display: none; }
.form-done.tx-done--held { align-content: center; } /* штамп — по центру рамки прежней высоты формы */
/* Штамп на накладной: двойная рамка, галочка и «Принято», чуть повёрнут. */
.tx-done__mark {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 9px 16px 9px 11px;
  border: 2px solid var(--accent);
  border-radius: 3px;
  outline: 1px solid rgba(var(--accent-rgb), 0.45);
  outline-offset: 3px;
  color: var(--accent-text);
  font: 700 0.86rem/1 var(--f-mono);
  letter-spacing: 0.26em;
  text-transform: uppercase;
  transform: rotate(-4deg);
}
.tx-done__mark b { font-weight: inherit; }
.tx-done__mark svg { flex: none; width: 22px; height: 22px; }
.tx-done__mark path { stroke: var(--accent); animation-delay: 0.3s; }
.m-live .tx-done { animation: tx-fade 0.4s both; }
.m-on .tx-done { animation: none; }
.m-on .tx-done__mark { animation: tx-stamp 0.6s var(--ease-out-expo) both; }
.m-on .tx-done > p { animation: tx-wipe 0.7s 0.15s var(--ease-out-expo) both; }
/* Штамп опускается на бумагу: крупнее и наискосок → чуть вдавливается → на месте. */
@keyframes tx-stamp {
  0% { opacity: 0; transform: scale(1.7) rotate(-12deg); }
  55% { opacity: 1; transform: scale(0.96) rotate(-4deg); }
  100% { opacity: 1; transform: rotate(-4deg); }
}
@keyframes tx-wipe {
  from { opacity: 0.2; clip-path: inset(0 100% 0 0); transform: translateX(-12px); }
  to { opacity: 1; clip-path: inset(0 0 0 0); transform: none; }
}

/* ---------- Плавающая кнопка: импульс «на связи» в покое ---------- */
.m-on .fab__btn::after {
  content: '';
  position: absolute;
  inset: -6px;
  border: 1px solid rgba(var(--accent-rgb), 0.4);
  border-radius: 50%;
  animation: ring 2.8s var(--ease) 1.4s infinite;
  pointer-events: none;
}
.m-on .fab__btn[aria-expanded='true']::after { animation: none; opacity: 0; }

/* ---------- CTA в шапке: по наведению огонёк обходит контур кнопки ---------- */
.tx-trace { display: none; }
.m-on .btn--primary > .tx-trace {
  position: absolute;
  inset: 0;
  display: block;
  padding: 2px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  transition: opacity 0.3s;
}
.tx-trace::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 260%;
  aspect-ratio: 1;
  margin: -130% 0 0 -130%;
  background: conic-gradient(from 0deg, transparent 0 6%, rgba(255, 255, 255, 0.35) 14%, #fff 18%, transparent 20%);
  animation: tx-spin 2.2s linear infinite paused;
}
.m-on .hdr__cta:hover > .tx-trace { opacity: 1; }
.m-on .hdr__cta:hover > .tx-trace::before { animation-play-state: running; }
@keyframes tx-spin { to { transform: rotate(360deg); } }

/* ---------- Касания: рябь (вместо системной подсветки касания) ---------- */
.m-on :is(.card__btn, .clist__row, .fcard__row, .faq__q) { position: relative; }
.m-on :is(.card, .plan, .quote, .card__btn, .clist__row, .fcard__row, .faq__q) { -webkit-tap-highlight-color: transparent; }
.tx-ripples {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.tx-ripple {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(var(--accent-rgb), 0.16), rgba(var(--accent-rgb), 0.22) 62%, rgba(var(--accent-rgb), 0.6) 68%, transparent 71%);
  pointer-events: none;
  transform: scale(0);
}
.btn > .tx-ripple { position: absolute; }
.btn--primary > .tx-ripple,
.fab__btn > .tx-ripple {
  background: radial-gradient(closest-side, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.3) 62%, rgba(255, 255, 255, 0.7) 68%, transparent 71%);
}

/* =====================================================================
   4. Телефон и касания: ритм прокрутки на узком экране, нажатие, шапка, плавающая кнопка, ленты [data-rail]
   ===================================================================== */

/* ---------- Узкий экран (одна колонка): короче пути, быстрее появления ----------
   Карточки входят по одной — каждая играет сразу при входе (лесенка в motion.js ≤ 150 мс). Содержимое
   на месте за ~250 мс, оформление (луч, скобки) — до ~450 мс. Без наклона (см. «Касание» выше). */
@media (max-width: 599px) {
  :root {
    --dur-slow: 460ms; /* подъём карточки */
    --dur-scan: 380ms; /* луч сканера */
  }
  @keyframes ms-card-in {
    0% { opacity: 0; transform: translate3d(0, 18px, 0); }
    30% { opacity: 1; }
  }
  @keyframes ms-rise {
    from { opacity: 0; transform: translateY(14px); }
  }
  @keyframes ms-rise-card {
    from { opacity: 0; transform: translateY(18px); }
  }
  @keyframes ms-slide-in {
    from { opacity: 0; transform: translateX(20px); }
  }
  .m-on .ms-head.ms-in .ms-wi {
    animation-duration: 0.5s;
    animation-delay: calc(var(--ms-d, 0ms) + 30ms + var(--ln, 0) * 50ms);
  }
  .m-on .ms-head.ms-in .ms-sw {
    animation-duration: 0.45s;
    animation-delay: calc(var(--ms-d, 0ms) + var(--ms-sub, 190ms) * 0.7 + var(--wi, 0) * 8ms);
  }
  .m-on .ms-head.ms-in .eyebrow::before { animation-duration: 0.4s; }
  .m-on .ms-faq.ms-in { animation-duration: 0.45s; }
  .m-on .ms-faq.ms-in::after { animation-duration: 0.7s; }
  .m-on .ms-panel.ms-in { animation-duration: 0.5s; }
  .m-on .ms-panel.ms-in :is(.cta__body, .cta__btns) { animation-duration: 0.42s; }
  .m-on .ms-step.ms-in :is(.step__title, .step__text, .step__meta) { animation-duration: 0.42s; }
  .m-on .ms-card.ms-in::after,
  .m-on .member.ms-in .member__media::after { animation-duration: 0.4s; animation-delay: calc(var(--ms-d, 0ms) + 140ms); }
  .m-on .ms-card.ms-in::before { animation-duration: 0.4s; animation-delay: calc(var(--ms-d, 0ms) + 80ms); }
  .m-on .ms-scan::after { height: 72px; }
  /* Номер секции (.ms-num) на узком экране раскладывает site.css (шапки секций): небольшой, в строке подписи. */
}

/* ---------- Нажатие (initPress): поверхность проседает, кромка загорается акцентом ----------
   Просадку (scale) и рябь ведёт WAAPI в motion.js; здесь — только вид кромки. Слой поверх своей
   поверхности, не ловит касаний и не меняет раскладку. */
.tx-pressfx {
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), 0.75), inset 0 0 28px -10px rgba(var(--accent-rgb), 0.55);
  background: radial-gradient(120% 90% at 50% 100%, rgba(var(--accent-rgb), 0.08), transparent 70%);
}
html:not(.m-live) .tx-pressfx { display: none; }
.ms-rail-dot > .tx-pressfx { display: none; } /* у точки — только просадка */
:is(.btn--primary, .fab__btn) > .tx-pressfx {
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.35);
  background: rgba(255, 255, 255, 0.12);
}
.m-live :is(.card, .plan, .quote, .member, .stat, .menu__link, .menu__home, .sidenav__link, .mcontacts__row,
  .fcontacts__row, .burger, .btn) { -webkit-tap-highlight-color: transparent; }

/* Касание без мыши: наведение «залипает» после тапа — сдвиги от :hover снимаем, отклик даёт нажатие. */
@media (hover: none) {
  .card:hover,
  .plan:hover,
  .fab__btn:hover { transform: none; }
  .btn:hover .btn__arrow,
  .card__btn:hover .card__arrow,
  a:hover > :is(.mcontacts__go, .fcontacts__go, .fcard__go, .clist__go) { transform: none; }
  .m-on .btn--ghost:hover::before { transform: translateX(-120%); }
}

/* ---------- Шапка на узком экране: уходит при прокрутке вниз, возвращается при прокрутке вверх ----------
   Класс .tx-hdr-away ставит motion.js (initHeaderAway; никогда — у верха страницы, при открытом меню,
   панели контактов и фокусе внутри шапки). full — уезжает вверх, reduced — гаснет, off — не уходит.
   Полоса прогресса (.ms-progress) поднимается к краю окна и остаётся видна. */
@media (max-width: 899px) {
  .m-live .hdr { transition: translate 0.45s var(--ease-out-expo), opacity 0.3s, visibility 0s; }
  .m-on .hdr.tx-hdr-away {
    translate: 0 calc(-100% - 2px);
    transition: translate 0.32s var(--ease-in-out-quart), visibility 0s 0.32s;
    visibility: hidden;
  }
  html[data-motion='reduced'] .hdr.tx-hdr-away {
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s, visibility 0s 0.25s;
  }
  .m-on .ms-progress { transition: opacity 0.3s, translate 0.45s var(--ease-out-expo); }
  .m-on.tx-hdr-off .ms-progress {
    translate: 0 calc(1px - var(--header-h));
    transition: opacity 0.3s, translate 0.32s var(--ease-in-out-quart);
  }
}

/* ---------- Плавающая кнопка: возвращается пружиной (уход и затемнение — в site.css) ---------- */
.m-on .fab__btn {
  transition: transform 0.25s var(--ease), box-shadow 0.25s, opacity 0.25s, scale 0.6s var(--ease-spring),
    translate 0.6s var(--ease-spring), visibility 0s;
}

/* ---------- Ленты карточек [data-rail]: индикатор под лентой, карточка по центру, появление ----------
   .ms-rail-on — лента сейчас листается (содержимое шире её); на широком экране это сетка, индикатора нет. */
.ms-rail-bar { display: none; }
.ms-rail-bar.is-on {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 4px;
  color: var(--muted);
  font: 500 0.7rem/1 var(--f-mono);
  letter-spacing: 0.2em;
  user-select: none;
}
.ms-rail-count { font-variant-numeric: tabular-nums; }
.ms-rail-count b { color: var(--text-2); font-weight: 600; }
.ms-rail-dots { display: flex; align-items: center; margin-right: -14px; }
/* Точка — 6px, зона касания — 36×44 (пальцем, а не прицелом) */
.ms-rail-dot {
  position: relative;
  width: 36px;
  height: 44px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ms-rail-dot::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 3px;
  background: var(--line-3);
  transition: width 0.4s var(--ease-out-expo), margin 0.4s var(--ease-out-expo), background-color 0.3s, box-shadow 0.3s;
}
.ms-rail-dot.is-on::before {
  width: 20px;
  margin-left: -10px;
  background: var(--accent);
  box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.55);
}

/* Карточка по центру ленты — в полную силу, соседи тише. С view(inline) — по положению в ленте, вместе
   с пальцем (композитор); без него — класс .is-current и короткий переход. Только прозрачность, без
   масштаба: точки привязки scroll-snap браузер считает по уменьшенной коробке — карточка вставала мимо
   поля страницы. Выделенный тариф («чаще всего») не приглушается: его и надо заметить первым. */
@keyframes ms-rail-focus {
  0%, 100% { opacity: 0.66; }
  40%, 60% { opacity: 1; }
}
@keyframes ms-rail-dim {
  0%, 100% { opacity: 0.74; }
  40%, 60% { opacity: 1; }
}
.m-on .ms-rail-sda.ms-rail-on > *,
html[data-motion='reduced'] .ms-rail-sda.ms-rail-on > * {
  animation: ms-rail-focus linear both;
  animation-timeline: view(inline);
  animation-range: cover 0% cover 100%;
}
html[data-motion='reduced'] .ms-rail-sda.ms-rail-on > * { animation-name: ms-rail-dim; }
.m-live .ms-rail-on:not(.ms-rail-sda) > * { transition: opacity 0.45s; }
.m-on .ms-rail-on:not(.ms-rail-sda) > :not(.is-current) { opacity: 0.66; }
html[data-motion='reduced'] .ms-rail-on:not(.ms-rail-sda) > :not(.is-current) { opacity: 0.74; }
.m-live .ms-rail.ms-rail-on > .plan.plan--featured { animation: none; opacity: 1; }

/* Лента появляется целиком, въезжая сбоку (подсказка: листается); карточки за краем не ждут прокрутки. */
.m-on .ms-rail-in.ms-pending { opacity: 0; }
.m-on .ms-rail-in.ms-in { animation: ms-rail-in 0.55s var(--ease-out-expo) var(--ms-d, 0ms) backwards; }
@keyframes ms-rail-in {
  from { opacity: 0; translate: 44px 0; }
}
