/* ============================================================
   СЛОЙ ДВИЖЕНИЯ — версия 2 (site-v2, черновик для просмотра)

   Отдельный файл поверх app.css: виден целиком и снимается одной строкой.

   ------------------------------------------------------------
   ГЛАВНОЕ ПРАВИЛО, ради которого всё переписано.

   Раньше здесь стоял запрет: появление по прокрутке двигает только
   transform, потому что `animation-timeline` стоит на месте, пока до
   элемента не домотали, — и всё, завязанное на прозрачность, маску или
   размытие, осталось бы невидимым.

   Запрет снимается заменой заливки. С `fill: both` анимация применяет
   начальный кадр ещё до входа в диапазон — отсюда и прятался текст.
   С `fill: forwards` до диапазона она не применяется вовсе: элемент
   показан своими обычными стилями. А диапазон начинается с `entry 0%` —
   это момент, когда низ элемента только показался из-за нижнего края
   экрана. Прятать в этот момент нечего: элемента и так не видно.

   Поэтому здесь везде `forwards`, и поэтому можно маски, размытие и
   прозрачность. `both` не использовать ни в одной прокруточной анимации.
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   1. ЗАСТАВКА
   ------------------------------------------------------------ */
@property --count{syntax:'<integer>';inherits:false;initial-value:0}

.intro{
  position:fixed;inset:0;z-index:999;pointer-events:none;overflow:hidden;
  background:var(--bg);
  display:grid;place-items:center;
  animation:intro-lift 1.15s cubic-bezier(.76,0,.24,1) 1.75s both;
}
@keyframes intro-lift{
  0%{transform:translateY(0)}
  100%{transform:translateY(-101%)}
}
/* Светлая кромка бежит по нижнему краю полотна — видно, что это штора. */
.intro::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:linear-gradient(90deg,transparent,var(--line-hi) 30%,var(--ink) 50%,var(--line-hi) 70%,transparent);
}
/* Мягкое пятно света за знаком — полотно не выглядит плоской заливкой. */
.intro::before{
  content:"";position:absolute;left:50%;top:50%;width:min(900px,120vw);aspect-ratio:1;
  transform:translate(-50%,-50%);pointer-events:none;
  background:radial-gradient(circle,var(--surface-hi) 0%,transparent 62%);
  animation:intro-glow 2s ease-out both;
}
@keyframes intro-glow{
  from{opacity:0;transform:translate(-50%,-50%) scale(.7)}
  to{opacity:1;transform:translate(-50%,-50%) scale(1)}
}

.intro-inner{
  position:relative;display:flex;flex-direction:column;align-items:center;gap:24px;
  animation:intro-fade .34s ease-in 1.5s both;
}
@keyframes intro-fade{to{opacity:0;transform:translateY(-12px)}}

.intro-mark{
  width:72px;height:72px;background:var(--ink);
  -webkit-mask:var(--q-shape) center/contain no-repeat;
  mask:var(--q-shape) center/contain no-repeat;
  animation:intro-mark 1.25s cubic-bezier(.16,1,.3,1) both;
}
@keyframes intro-mark{
  0%{opacity:0;transform:scale(.6) rotate(-40deg)}
  55%{opacity:1}
  100%{opacity:1;transform:none}
}

.intro-name{
  font-family:var(--font-display);font-size:20px;letter-spacing:.03em;color:var(--ink);
  display:flex;gap:.02em;
}
/* Буквы поднимаются по очереди. Номер приходит из разметки. */
.intro-name i{
  font-style:normal;display:inline-block;
  animation:intro-letter .55s cubic-bezier(.16,1,.3,1) both;
  animation-delay:calc(.3s + var(--i) * .045s);
}
@keyframes intro-letter{
  from{opacity:0;transform:translateY(18px) rotate(6deg)}
  to{opacity:1;transform:none}
}

.intro-line{display:flex;align-items:center;gap:14px}
.intro-bar{width:148px;height:2px;border-radius:2px;overflow:hidden;background:var(--line)}
.intro-bar i{
  display:block;height:100%;background:var(--ink);
  transform-origin:left;transform:scaleX(0);
  animation:intro-fill 1.4s cubic-bezier(.65,0,.35,1) .2s both;
}
@keyframes intro-fill{to{transform:scaleX(1)}}

/* Счётчик 0→100 без единой строчки скрипта: анимируется
   зарегистрированное число, а выводится через счётчик CSS. */
.intro-pct{
  font-size:12px;letter-spacing:.14em;color:var(--muted);min-width:42px;text-align:right;
  counter-reset:pct var(--count);
  animation:intro-count 1.4s cubic-bezier(.65,0,.35,1) .2s both;
}
.intro-pct::after{content:counter(pct) "%"}
@keyframes intro-count{from{--count:0}to{--count:100}}

/* ------------------------------------------------------------
   2. ПЕРВЫЙ ЭКРАН
   Анимации по времени — здесь прозрачность безопасна, они доигрывают
   сами по часам документа.
   ------------------------------------------------------------ */

/* Строка заголовка: маска снаружи, текст выезжает изнутри. */
.hl{display:block;overflow:hidden;padding-bottom:.09em;margin-bottom:-.09em}
.hl-i{display:block}
.hero h1 .hl-i{animation:line-up 1.1s cubic-bezier(.16,1,.3,1) both}
.hero h1 .hl:nth-child(1) .hl-i{animation-delay:2.02s}
.hero h1 .hl:nth-child(2) .hl-i{animation-delay:2.14s}
@keyframes line-up{
  from{transform:translateY(108%) rotate(2deg)}
  to{transform:none}
}

.hero .eyebrow{animation:soft-up .85s cubic-bezier(.16,1,.3,1) 1.9s both}
.hero .lead{animation:soft-blur 1s cubic-bezier(.16,1,.3,1) 2.34s both}
.hero-cta{animation:soft-up .9s cubic-bezier(.16,1,.3,1) 2.44s both}
.hero .apps{animation:soft-up .9s cubic-bezier(.16,1,.3,1) 2.54s both}
@keyframes soft-up{
  from{opacity:0;transform:translateY(20px)}
  to{opacity:1;transform:none}
}
/* Наводка на резкость: текст «проявляется», а не просто всплывает. */
@keyframes soft-blur{
  from{opacity:0;transform:translateY(16px);filter:blur(7px)}
  to{opacity:1;transform:none;filter:blur(0)}
}

.hero-visual{animation:visual-in 1.7s cubic-bezier(.16,1,.3,1) 1.95s both}
@keyframes visual-in{
  from{opacity:0;transform:translateY(46px) scale(.9) rotate(-4deg)}
  to{opacity:1;transform:none}
}
.hero-chips .chip{animation:soft-up .75s cubic-bezier(.16,1,.3,1) both,bob 5.2s ease-in-out 3.6s infinite}
.hero-chips .chip:nth-child(1){animation-delay:2.7s,3.6s}
.hero-chips .chip:nth-child(2){animation-delay:2.79s,4s}
.hero-chips .chip:nth-child(3){animation-delay:2.88s,4.4s}

header .logo,.nav-links a,.nav-right>*{animation:soft-up .75s cubic-bezier(.16,1,.3,1) both}
header .logo{animation-delay:1.82s}
.nav-links a:nth-child(1){animation-delay:1.88s}
.nav-links a:nth-child(2){animation-delay:1.93s}
.nav-links a:nth-child(3){animation-delay:1.98s}
.nav-links a:nth-child(4){animation-delay:2.03s}
.nav-right>*:nth-child(1){animation-delay:2.08s}
.nav-right>*:nth-child(2){animation-delay:2.13s}

/* Подсказка о прокрутке. */
.hero{position:relative}
.scroll-hint{
  position:absolute;left:50%;bottom:26px;transform:translateX(-50%);
  display:flex;flex-direction:column;align-items:center;gap:9px;
  font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
  animation:soft-up .8s ease 3s both;
  transition:opacity .4s ease;pointer-events:none;
}
html.scrolled .scroll-hint{opacity:0}
.scroll-hint b{display:block;width:1px;height:38px;background:var(--line);position:relative;overflow:hidden}
.scroll-hint b::after{
  content:"";position:absolute;left:0;top:0;width:100%;height:14px;
  background:var(--ink);animation:spark 2s ease-in-out infinite;
}
@keyframes spark{
  0%{transform:translateY(-16px)}
  100%{transform:translateY(40px)}
}
@media(max-width:900px){.scroll-hint{display:none}}

/* ------------------------------------------------------------
   3. ПРОКРУТКА
   Всюду `forwards` — см. пояснение вверху файла.
   ------------------------------------------------------------ */
@supports (animation-timeline: view()){

  /* --- заголовки разделов выезжают из-под маски --- */
  .head h2 .hl-i,.final h2 .hl-i{
    animation:line-up-scroll linear forwards;
    animation-timeline:view();
    animation-range:entry 8% entry 52%;
  }
  @keyframes line-up-scroll{
    from{transform:translateY(105%)}
    to{transform:none}
  }
  /* Плашка и подпись — с наводкой на резкость. */
  .head .eyebrow{animation:focus-in-s linear forwards;animation-timeline:view();animation-range:entry 2% entry 40%}
  .head p{animation:focus-in-s linear forwards;animation-timeline:view();animation-range:entry 14% entry 60%}
  @keyframes focus-in-s{
    from{opacity:0;transform:translateY(16px);filter:blur(6px)}
    to{opacity:1;transform:none;filter:blur(0)}
  }

  /* --- карточки: подъём, лёгкий разворот и наводка на резкость ---
     transform не трогаем напрямую: у карточек он собран из переменных
     в app.css, прямая запись его затрёт. Двигаем переменную. */
  .grid>.card,.plans>.plan,.stats-stage .stat,.faq details{
    animation:card-rise linear forwards;
    animation-timeline:view();
    animation-range:entry 0% entry 58%;
  }
  @keyframes card-rise{
    from{--rev:56px;opacity:0;filter:blur(5px)}
    to{--rev:0px;opacity:1;filter:blur(0)}
  }
  /* Волна по ряду: каждой следующей диапазон сдвинут. */
  .grid>.card:nth-child(3n+2){animation-range:entry 5% entry 66%}
  .grid>.card:nth-child(3n+3){animation-range:entry 10% entry 74%}
  .plans>.plan:nth-child(2){animation-range:entry 5% entry 64%}
  .plans>.plan:nth-child(3){animation-range:entry 10% entry 70%}
  .plans>.plan:nth-child(4){animation-range:entry 15% entry 76%}
  .faq details:nth-child(2n){animation-range:entry 4% entry 62%}
  .faq details:nth-child(3n){animation-range:entry 8% entry 68%}

  /* Пункты списка в тарифе появляются по одному. */
  .plan-list li{
    animation:li-in linear forwards;animation-timeline:view();
    animation-range:entry 10% entry 70%;
  }
  .plan-list li:nth-child(2){animation-range:entry 13% entry 73%}
  .plan-list li:nth-child(3){animation-range:entry 16% entry 76%}
  .plan-list li:nth-child(4){animation-range:entry 19% entry 79%}
  .plan-list li:nth-child(5){animation-range:entry 22% entry 82%}
  .plan-list li:nth-child(6){animation-range:entry 25% entry 85%}
  @keyframes li-in{
    from{opacity:0;transform:translateX(-14px)}
    to{opacity:1;transform:none}
  }

  /* --- лента стран разворачивается из перспективы --- */
  .marquee{animation:marq-in linear forwards;animation-timeline:view();animation-range:entry 0% entry 70%}
  @keyframes marq-in{
    from{opacity:.2;transform:perspective(900px) rotateX(12deg) scale(.95)}
    to{opacity:1;transform:none}
  }

  /* --- финальный экран собирается ступенями --- */
  .final .eyebrow{animation:focus-in-s linear forwards;animation-timeline:view();animation-range:entry 0% entry 40%}
  .final p{animation:focus-in-s linear forwards;animation-timeline:view();animation-range:entry 10% entry 56%}
  .final-cta{animation:focus-in-s linear forwards;animation-timeline:view();animation-range:entry 16% entry 64%}
  .final-orb{animation:orb-in linear forwards;animation-timeline:view();animation-range:entry 8% entry 78%}
  @keyframes orb-in{
    from{opacity:0;transform:translateX(-50%) translateY(30px) scaleX(.8)}
    to{opacity:1;transform:translateX(-50%)}
  }

  /* --- подвал --- */
  .foot-card{animation:card-rise-plain linear forwards;animation-timeline:view();animation-range:entry 0% entry 56%}
  @keyframes card-rise-plain{
    from{opacity:0;transform:translateY(46px);filter:blur(5px)}
    to{opacity:1;transform:none;filter:blur(0)}
  }
}

/* ------------------------------------------------------------
   4. ЗАКРЕПЛЁННАЯ СЦЕНА С ШАГАМИ
   Высокая секция, внутри неё сцена во весь экран прилипает к верху,
   и пока прокручиваешь — шаги едут вбок. Главный приём референса.

   Включается только там, где есть и поддержка таймлайнов, и место:
   на узких экранах остаётся обычная сетка.
   ------------------------------------------------------------ */
@supports (animation-timeline: view()){
  @media(min-width:1100px){
    .steps-stage{position:relative;height:320vh;view-timeline-name:--steps}
    .steps-pin{
      position:sticky;top:0;height:100vh;display:flex;align-items:center;
      overflow:hidden;
    }
    .steps-pin .steps{
      display:flex;flex-wrap:nowrap;gap:26px;width:max-content;
      padding-inline:max(24px,calc((100vw - 1240px) / 2));
      animation:steps-slide linear forwards;
      animation-timeline:--steps;
      animation-range:contain 0% contain 100%;
    }
    .steps-pin .step{width:min(380px,32vw);flex:none}
    @keyframes steps-slide{
      to{transform:translateX(calc(-100% + 100vw - max(48px,calc(100vw - 1240px))))}
    }
    /* Полоса хода сцены — видно, сколько шагов осталось. */
    .steps-track{
      position:absolute;left:50%;bottom:12vh;transform:translateX(-50%);
      width:min(360px,40vw);height:2px;background:var(--line);border-radius:2px;overflow:hidden;
    }
    .steps-track i{
      display:block;height:100%;background:var(--ink);transform-origin:left;transform:scaleX(0);
      animation:steps-progress linear forwards;
      animation-timeline:--steps;animation-range:contain 0% contain 100%;
    }
    @keyframes steps-progress{to{transform:scaleX(1)}}
  }
}
/* Без поддержки и на узких экранах полоса хода не нужна. */
.steps-track{display:none}
@supports (animation-timeline: view()){
  @media(min-width:1100px){.steps-track{display:block}}
}

/* ------------------------------------------------------------
   5. УКАЗАТЕЛЬ РАЗДЕЛА
   Столбик точек сбоку: видно, где ты на странице.
   ------------------------------------------------------------ */
.rail{
  position:fixed;right:26px;top:50%;transform:translateY(-50%);z-index:60;
  display:flex;flex-direction:column;gap:14px;align-items:flex-end;
  opacity:0;transition:opacity .4s ease;
}
html.scrolled .rail{opacity:1}
.rail a{display:flex;align-items:center;gap:10px;color:var(--muted);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase}
.rail span{opacity:0;transform:translateX(6px);transition:opacity .3s ease,transform .3s ease}
.rail a:hover span,.rail a.here span{opacity:1;transform:none}
.rail i{
  display:block;width:7px;height:7px;border-radius:50%;background:var(--line-hi);
  transition:transform .3s cubic-bezier(.34,1.56,.64,1),background-color .3s ease;
}
.rail a.here i{background:var(--ink);transform:scale(1.5)}
@media(max-width:1240px){.rail{display:none}}

/* ------------------------------------------------------------
   6. МЕЛОЧИ
   ------------------------------------------------------------ */
/* Кнопка тянется к курсору. Сдвиг задаёт скрипт, максимум 7px. */
.btn{--pull-x:0px;--pull-y:0px}
.btn-primary{transform:translate(var(--pull-x),var(--pull-y))}
.btn-primary:active{transform:translate(var(--pull-x),var(--pull-y)) scale(.985)}


/* ------------------------------------------------------------
   7. СИСТЕМНАЯ НАСТРОЙКА «МЕНЬШЕ ДВИЖЕНИЯ»
   ------------------------------------------------------------ */
@media(prefers-reduced-motion:reduce){
  .intro,.scroll-hint,.rail,.steps-track{display:none}
  .hero h1 .hl-i,.hero .eyebrow,.hero .lead,.hero-cta,.hero .apps,
  .hero-visual,.hero-chips .chip,
  header .logo,.nav-links a,.nav-right>*,
  .head h2 .hl-i,.final h2 .hl-i,.head .eyebrow,.head p,
  .grid>.card,.plans>.plan,.stats-stage .stat,.faq details,.plan-list li,
  .marquee,.final .eyebrow,.final p,.final-cta,.final-orb,.foot-card,
  .intro-mark,.intro-name i,.intro-bar i,.intro-pct{
    animation:none;
  }
  .btn-primary{transform:none}
  /* Сцена с шагами превращается обратно в обычную сетку. */
  .steps-stage{height:auto}
  .steps-pin{position:static;height:auto;overflow:visible}
  .steps-pin .steps{display:grid;grid-template-columns:repeat(4,1fr);width:auto;animation:none;padding-inline:0}
  .steps-pin .step{width:auto}
}

/* ------------------------------------------------------------
   8. ГЛОБУС
   Шар с нашими точками присутствия. Раздел «География» перестаёт быть
   просто бегущей строкой: сначала видно, где мы есть, потом — список.
   ------------------------------------------------------------ */
.globe-wrap{
  position:relative;margin:10px auto 34px;
  display:flex;flex-direction:column;align-items:center;gap:18px;
}
.globe-stage{
  position:relative;width:min(620px,84vw);aspect-ratio:1;
  /* Края растворяются в фоне — шар не выглядит наклейкой на полотне. */
  -webkit-mask:radial-gradient(circle at 50% 50%,#000 62%,transparent 82%);
  mask:radial-gradient(circle at 50% 50%,#000 62%,transparent 82%);
}
.globe-canvas{display:block;width:100%;height:100%}
/* Ореол за шаром. Прошлые попытки: плотное пятно на 74% ширины —
   получался мутный диск, в котором тонул шар; узкое кольцо — читалось
   отдельной серой окружностью, как посторонняя деталь. Здесь широкое
   мягкое свечение с далёким затуханием: края у него нет, поэтому и
   вычленить его глазом не получается. */
.globe-stage::before{
  content:"";position:absolute;left:50%;top:50%;width:92%;aspect-ratio:1;
  transform:translate(-50%,-50%);border-radius:50%;pointer-events:none;z-index:-1;
  background:radial-gradient(circle,transparent 38%,var(--surface-hi) 55%,transparent 100%);
  opacity:.7;filter:blur(26px);
}

.globe-legend{
  list-style:none;margin:0;padding:0;
  display:flex;gap:26px;flex-wrap:wrap;justify-content:center;
  font-size:13.5px;color:var(--muted);
}
.globe-legend li{display:flex;align-items:center;gap:9px}
.globe-legend i{width:7px;height:7px;border-radius:50%;background:var(--ink);flex:none}
.globe-legend i.lte{width:6px;height:6px;opacity:.6}
.globe-legend i.arc{
  width:16px;height:1px;border-radius:0;
  background:repeating-linear-gradient(90deg,var(--ink) 0 4px,transparent 4px 7px);
}

@media(max-width:620px){
  .globe-stage{width:min(420px,88vw)}
  .globe-legend{gap:14px;font-size:12.5px}
}

/* Появление шара: вырастает и наводится на резкость. */
@supports (animation-timeline: view()){
  .globe-wrap{
    animation:globe-in linear forwards;
    animation-timeline:view();animation-range:entry 0% entry 62%;
  }
  @keyframes globe-in{
    from{opacity:0;transform:translateY(40px) scale(.9);filter:blur(6px)}
    to{opacity:1;transform:none;filter:blur(0)}
  }
}
@media(prefers-reduced-motion:reduce){
  .globe-wrap{animation:none}
}

/* ============================================================
   ВТОРОЙ ЗАХОД: атмосфера, чтение текста, глубина
   ============================================================ */

/* ------------------------------------------------------------
   9. АТМОСФЕРА РАЗДЕЛОВ
   Страница была ровно чёрной от начала до конца — от этого она и
   читалась скучной. Каждый раздел получает своё медленно плывущее
   пятно света: полотно перестаёт быть плоским, появляется ритм.

   Пятно живёт внутри секции, а не общим слоем на всю страницу:
   у разделов непрозрачные фоны (bg-1, bg-2), и общий слой они бы
   просто перекрыли.
   ------------------------------------------------------------ */
.section{overflow:clip}          /* пятно не должно вылезать за раздел */
.section::before{
  content:"";position:absolute;pointer-events:none;z-index:0;
  width:min(1100px,120vw);aspect-ratio:1;border-radius:50%;
  background:radial-gradient(circle,var(--surface-hi) 0%,transparent 62%);
  opacity:.55;filter:blur(30px);
  animation:ambient 26s ease-in-out infinite alternate;
}
/* Разное место и разный ход у соседних разделов — иначе виден повтор. */
.section:nth-of-type(odd)::before{left:-16%;top:-28%}
.section:nth-of-type(even)::before{right:-18%;bottom:-30%;top:auto;left:auto;animation-duration:34s;animation-delay:-9s}
@keyframes ambient{
  from{transform:translate3d(0,0,0) scale(1)}
  to{transform:translate3d(6%,4%,0) scale(1.14)}
}
/* Содержимое раздела должно быть над пятном. */
.section>.wrap,.section>.steps-stage{position:relative;z-index:1}

/* ------------------------------------------------------------
   10. ТЕКСТ ЗАЧИТЫВАЕТСЯ ПРИ ПРОКРУТКЕ
   Слова гаснут до трети яркости и по очереди набирают полную —
   взгляд идёт по строке, а не прыгает по готовому блоку.

   Диапазон у каждого слова свой, номер приходит из разметки.
   Заливка forwards: до входа в кадр слово показано обычным стилем,
   то есть полностью читаемым. Если таймлайнов нет — абзац просто
   статичный, ничего не теряется.
   ------------------------------------------------------------ */
.wd{font-style:normal}
@supports (animation-timeline: view()){
  .head p .wd,.final p .wd{
    animation:word-read linear forwards;
    animation-timeline:view();
    animation-range:entry calc(8% + var(--i) * 1.1%) entry calc(30% + var(--i) * 1.1%);
  }
  @keyframes word-read{
    from{opacity:.28}
    to{opacity:1}
  }
}

/* ------------------------------------------------------------
   11. ГЛУБИНА ПЕРВОГО ЭКРАНА
   Пока герой уходит вверх, текст и логотип двигаются с разной
   скоростью — появляется расстояние между планами.
   Диапазон exit: пока экран целиком в кадре, ничего не смещено.
   ------------------------------------------------------------ */
@supports (animation-timeline: view()){
  .hero-copy{
    animation:hero-drift linear forwards;
    animation-timeline:view();animation-range:exit 0% exit 100%;
  }
  @keyframes hero-drift{
    from{transform:none;opacity:1}
    to{transform:translateY(-64px);opacity:.25}
  }
  /* Логотип уходит дальше и разворачивается — он ближе к зрителю. */
  .q-stage{
    animation:hero-drift-far linear forwards;
    animation-timeline:view();animation-range:exit 0% exit 100%;
  }
  @keyframes hero-drift-far{
    from{transform:none}
    to{transform:translateY(-136px) scale(.82) rotate(7deg)}
  }
  .hero-chips{
    animation:hero-drift-near linear forwards;
    animation-timeline:view();animation-range:exit 0% exit 100%;
  }
  @keyframes hero-drift-near{
    from{transform:none;opacity:1}
    to{transform:translateY(-34px);opacity:.2}
  }
}

/* ------------------------------------------------------------
   12. ИЛЛЮСТРАЦИИ В КАРТОЧКАХ ПРОЯВЛЯЮТСЯ
   Раньше рисунок оживал только под курсором — при обычной прокрутке
   карточки выглядели статичными картинками. Теперь рисунок
   раскрывается шторкой слева направо, пока карточка въезжает.
   ------------------------------------------------------------ */
@supports (animation-timeline: view()){
  .card-visual svg{
    animation:visual-wipe linear forwards;
    animation-timeline:view();animation-range:entry 10% entry 64%;
  }
  @keyframes visual-wipe{
    from{clip-path:inset(0 100% 0 0)}
    to{clip-path:inset(0 0 0 0)}
  }
  /* Значок в углу выскакивает следом за рисунком. */
  .card-badge{
    animation:badge-pop linear forwards;
    animation-timeline:view();animation-range:entry 34% entry 70%;
  }
  @keyframes badge-pop{
    from{transform:translateY(-50%) scale(0)}
    to{transform:translateY(-50%) scale(1)}
  }
}

/* ------------------------------------------------------------
   13. КРОМКА РАЗДЕЛА
   Тонкая линия расходится от середины, когда раздел входит в кадр:
   переход между блоками перестаёт быть просто стыком.
   ------------------------------------------------------------ */
.section::after{
  content:"";position:absolute;left:50%;top:0;z-index:1;
  width:min(1240px,92vw);height:1px;pointer-events:none;
  transform:translateX(-50%) scaleX(0);
  background:linear-gradient(90deg,transparent,var(--line-hi) 35%,var(--ink) 50%,var(--line-hi) 65%,transparent);
  opacity:.6;
}
@supports (animation-timeline: view()){
  .section::after{
    animation:edge-draw linear forwards;
    animation-timeline:view();animation-range:entry 0% entry 42%;
  }
  @keyframes edge-draw{
    from{transform:translateX(-50%) scaleX(0)}
    to{transform:translateX(-50%) scaleX(1)}
  }
}

/* ------------------------------------------------------------
   14. ВОПРОСЫ ПОЛУЧАЮТ НОМЕРА
   Список перестаёт быть однородной стопкой: глаз цепляется за
   порядковый номер и понимает объём раздела.
   ------------------------------------------------------------ */
.faq{counter-reset:вопрос}
.faq details summary{position:relative}
.faq details summary::before{
  counter-increment:вопрос;
  content:counter(вопрос,decimal-leading-zero);
  margin-right:14px;
  font-family:var(--font-display);font-size:12.5px;letter-spacing:.04em;
  color:var(--muted);opacity:.7;
  transition:color .3s ease,opacity .3s ease;
}
.faq details[open] summary::before,.faq details:hover summary::before{color:var(--ink);opacity:1}

/* ------------------------------------------------------------
   15. КРУПНОЕ ИМЯ В ПОДВАЛЕ
   Финальный аккорд: имя во всю ширину карточки. Декоративное,
   поэтому в разметке помечено aria-hidden.
   ------------------------------------------------------------ */
.foot-word{
  /* ⚠️ Было "line-height:.82" вместе с "overflow:hidden" и отрицательным
     нижним отступом -18px. Строчный ящик при таком межстрочном ниже
     самих букв, поэтому обрезка срезала им верх и низ, а следующий блок
     со своей верхней границей затягивался прямо на слово — линия шла
     сквозь буквы. Межстрочный 1, обрезки нет, отступ обычный: слово
     видно целиком, разделитель идёт под ним. */
  margin:30px 0 20px;pointer-events:none;user-select:none;
  font-family:var(--font-display);font-weight:500;
  font-size:clamp(42px,11.4vw,168px);line-height:1;letter-spacing:-.05em;
  color:var(--ink);opacity:.055;white-space:nowrap;text-align:center;
}
@supports (animation-timeline: view()){
  .foot-word{
    animation:word-grow linear forwards;
    animation-timeline:view();animation-range:entry 0% entry 90%;
  }
  @keyframes word-grow{
    from{transform:scale(.86);opacity:0}
    to{transform:scale(1);opacity:.055}
  }
}
@media(max-width:620px){.foot-word{margin:22px 0 14px}}

/* ------------------------------------------------------------
   16. СВЕТ ПО РЯДУ ТАРИФОВ
   Полоса света проходит по ряду, пока он въезжает: ряд читается как
   одно целое, а не как четыре отдельные карточки.
   ------------------------------------------------------------ */
.plans{position:relative}
.plans::before{
  content:"";position:absolute;top:-6%;bottom:-6%;width:38%;left:0;z-index:0;
  pointer-events:none;opacity:0;
  background:linear-gradient(90deg,transparent,var(--surface-hi),transparent);
  filter:blur(24px);
}
@supports (animation-timeline: view()){
  .plans::before{
    animation:row-sweep linear forwards;
    animation-timeline:view();animation-range:entry 0% entry 86%;
  }
  @keyframes row-sweep{
    0%{opacity:0;transform:translateX(-40%)}
    30%{opacity:1}
    80%{opacity:1}
    100%{opacity:0;transform:translateX(300%)}
  }
}

/* ------------------------------------------------------------
   17. «МЕНЬШЕ ДВИЖЕНИЯ» — добавка ко второму заходу
   ------------------------------------------------------------ */
@media(prefers-reduced-motion:reduce){
  .section::before,.section::after,.plans::before{animation:none}
  .section::after{transform:translateX(-50%) scaleX(1)}
  .head p .wd,.final p .wd{animation:none;opacity:1}
  .hero-copy,.q-stage,.hero-chips,.card-visual svg,.card-badge,.foot-word{animation:none}
  .card-visual svg{clip-path:none}
  .foot-word{opacity:.055;transform:none}
}

/* ============================================================
   ТРЕТИЙ ЗАХОД: закреплённые сцены и поведение шапки

   Структура референса разобрана: у него вся страница — чередование
   закреплённых сцен по три-четыре экрана. Внутри сцены кадр стоит на
   месте, а содержимое проматывается прокруткой. Причём закреплений
   бывает два, на разной высоте (top:0 и top:50%), и разница между ними
   даёт параллакс внутри одного кадра.

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

@property --step{syntax:'<integer>';inherits:false;initial-value:1}

/* ------------------------------------------------------------
   18. ЗАКРЕПЛЁННАЯ СЦЕНА С ГЛОБУСОМ
   Секция высотой в два с половиной экрана. Кадр прилипает к верху, шар
   в это время вырастает, доходит до полного размера и снова отступает,
   а подписи легенды выходят по одной.

   Включается только там, где есть и поддержка таймлайнов, и место.
   Ниже 900px и без поддержки остаётся обычный блок — глобус просто
   стоит в потоке, как раньше.
   ------------------------------------------------------------ */
@supports (animation-timeline: view()){
  @media(min-width:900px){
    .globe-scene{position:relative;height:250vh;view-timeline-name:--globe}
    .globe-pin{
      position:sticky;top:0;height:100vh;
      display:flex;align-items:center;justify-content:center;
    }
    .globe-pin .globe-wrap{margin:0}

    .globe-wrap{
      animation:globe-scene linear forwards;
      animation-timeline:--globe;
      animation-range:contain 0% contain 100%;
    }
    /* Приход, стояние, уход — три состояния в одном проходе. */
    @keyframes globe-scene{
      0%{opacity:.35;transform:scale(.8) translateY(46px);filter:blur(6px)}
      26%{opacity:1;transform:scale(1) translateY(0);filter:blur(0)}
      74%{opacity:1;transform:scale(1.05) translateY(-8px);filter:blur(0)}
      100%{opacity:.3;transform:scale(.92) translateY(-44px);filter:blur(5px)}
    }

    /* Подписи выходят по одной, пока шар стоит в кадре. */
    .globe-legend li{
      animation:legend-in linear forwards;
      animation-timeline:--globe;
    }
    .globe-legend li:nth-child(1){animation-range:contain 12% contain 26%}
    .globe-legend li:nth-child(2){animation-range:contain 20% contain 34%}
    .globe-legend li:nth-child(3){animation-range:contain 28% contain 42%}
    @keyframes legend-in{
      from{opacity:0;transform:translateY(16px)}
      to{opacity:1;transform:none}
    }
  }
}

/* ------------------------------------------------------------
   19. НОМЕР ШАГА В ЗАКРЕПЛЁННОЙ СЦЕНЕ
   Крупная цифра меняется по мере прокрутки: видно, на каком шаге ты
   находишься и сколько осталось.

   Число не считает скрипт: анимируется зарегистрированное целое с
   пошаговым сглаживанием `steps(4, jump-none)`, а выводится через
   счётчик CSS. Четыре ступени дают ровно 01, 02, 03, 04.
   ------------------------------------------------------------ */
.steps-count{display:none}
@supports (animation-timeline: view()){
  @media(min-width:1100px){
    .steps-count{
      display:block;position:absolute;z-index:0;pointer-events:none;
      left:max(24px,calc((100vw - 1240px) / 2));top:12vh;
      font-family:var(--font-display);font-weight:500;
      font-size:clamp(56px,7.4vw,124px);line-height:1;letter-spacing:-.05em;
      color:var(--ink);opacity:.07;
      counter-reset:шаг var(--step);
      animation:step-count steps(4,jump-none) forwards;
      animation-timeline:--steps;
      animation-range:contain 0% contain 100%;
    }
    .steps-count::after{content:"0" counter(шаг) " / 04"}
    @keyframes step-count{from{--step:1}to{--step:4}}
  }
}

/* ------------------------------------------------------------
   20. ШАПКА УХОДИТ И ВОЗВРАЩАЕТСЯ
   Вниз — прячется и не мешает читать, вверх — сразу возвращается.
   Класс ставит скрипт; без него шапка просто всегда на месте.
   ------------------------------------------------------------ */
header{transition:transform .42s cubic-bezier(.215,.61,.355,1)}
html.nav-hidden header{transform:translateY(-100%)}

/* ------------------------------------------------------------
   21. «МЕНЬШЕ ДВИЖЕНИЯ» — добавка к третьему заходу
   ------------------------------------------------------------ */
@media(prefers-reduced-motion:reduce){
  .globe-wrap,.globe-legend li,.steps-count{animation:none}
  .globe-scene{height:auto}
  .globe-pin{position:static;height:auto}
  header{transition:none}
  html.nav-hidden header{transform:none}
}

/* ============================================================
   ЧЕТВЁРТЫЙ ЗАХОД: закреплённый первый экран

   У референса первый экран растянут на три экрана прокрутки и всё это
   время стоит закреплённым, а содержимое внутри расходится по планам.
   Здесь то же, но на 2.5 экрана: столько нужно, чтобы движение успело
   прочитаться, и при этом человек быстрее добирается до цен.

   ⚠️ Пока экран закреплён, его собственная коробка неподвижна
   относительно окна — значит, `view()` на нём самом встал бы намертво,
   и прежний параллакс по диапазону `exit` перестал бы работать. Поэтому
   всё внутри сцены переведено на именованный таймлайн `--hero`, который
   висит на подвижной обёртке, а не на закреплённом кадре.
   ============================================================ */
@supports (animation-timeline: view()){
  @media(min-width:900px){
    .hero-scene{position:relative;height:250vh;view-timeline-name:--hero}
    .hero{
      position:sticky;top:0;height:100vh;
      display:flex;align-items:center;
      padding:0;
    }
    .hero>.wrap{width:100%}

    /* Текст держится почти половину сцены, потом уходит вверх. */
    .hero-copy{
      animation:hero-copy-scene linear forwards;
      animation-timeline:--hero;animation-range:contain 0% contain 100%;
    }
    @keyframes hero-copy-scene{
      0%,26%{transform:none;opacity:1}
      100%{transform:translateY(-96px);opacity:.1}
    }

    /* Логотип — ближний план: сперва вырастает, потом уходит дальше всех. */
    .q-stage{
      animation:hero-q-scene linear forwards;
      animation-timeline:--hero;animation-range:contain 0% contain 100%;
    }
    @keyframes hero-q-scene{
      0%,20%{transform:none;opacity:1}
      54%{transform:scale(1.16) rotate(-5deg) translateY(-12px);opacity:1}
      100%{transform:scale(.7) rotate(9deg) translateY(-128px);opacity:.18}
    }

    /* Плашки расходятся и гаснут раньше остальных. */
    .hero-chips{
      animation:hero-chips-scene linear forwards;
      animation-timeline:--hero;animation-range:contain 0% contain 100%;
    }
    @keyframes hero-chips-scene{
      0%,24%{transform:none;opacity:1}
      100%{transform:translateY(-64px) scale(.9);opacity:0}
    }

    /* Подсказка о прокрутке уходит сразу, как тронулись. */
    .scroll-hint{
      animation:soft-up .8s ease 3s both,hint-out linear forwards;
      animation-timeline:auto,--hero;
      animation-range:normal,contain 0% contain 14%;
    }
    @keyframes hint-out{
      from{opacity:1}
      to{opacity:0}
    }
  }
}

/* ------------------------------------------------------------
   22. «МЕНЬШЕ ДВИЖЕНИЯ» — добавка к четвёртому заходу
   Сцена схлопывается обратно в обычный экран.
   ------------------------------------------------------------ */
@media(prefers-reduced-motion:reduce){
  .hero-scene{height:auto}
  .hero{position:static;height:auto;padding:64px 0 92px}
  .hero-copy,.q-stage,.hero-chips,.scroll-hint{animation:none}
}

/* ============================================================
   ПЯТЫЙ ЗАХОД: связка страниц и нумерация разделов
   ============================================================ */

/* ------------------------------------------------------------
   23. ШТОРА ПРИ ПЕРЕХОДЕ
   Переход на другую страницу перестаёт быть мгновенной подменой: полотно
   поднимается снизу, и только потом браузер уходит по адресу. Сайт
   читается как одно целое, а не как набор отдельных документов.

   ⚠️ Безопасность здесь важнее эффекта. Переход назначается таймером
   ДО того, как ставится класс анимации: даже если стили не применятся
   или скрипт споткнётся следующей строкой, человек всё равно попадёт
   куда шёл. А если скрипт не выполнится вовсе — ссылки работают как
   обычные, без всякой шторы.
   ------------------------------------------------------------ */
.curtain{
  position:fixed;inset:0;z-index:998;pointer-events:none;
  background:var(--bg);
  transform:translateY(100%);
}
html.leaving .curtain{
  transform:translateY(0);
  transition:transform .42s cubic-bezier(.76,0,.24,1);
}
/* Светлая кромка бежит по верхнему краю шторы — та же деталь, что и у
   заставки: видно, что это полотно, а не заливка. */
.curtain::before{
  content:"";position:absolute;left:0;right:0;top:0;height:1px;
  background:linear-gradient(90deg,transparent,var(--line-hi) 30%,var(--ink) 50%,var(--line-hi) 70%,transparent);
}
/* Знак в середине — короткая пауза перед сменой страницы. */
.curtain i{
  position:absolute;left:50%;top:50%;width:52px;height:52px;
  transform:translate(-50%,-50%) scale(.7);opacity:0;
  background:var(--ink);
  -webkit-mask:var(--q-shape) center/contain no-repeat;
  mask:var(--q-shape) center/contain no-repeat;
}
html.leaving .curtain i{
  transform:translate(-50%,-50%) scale(1);opacity:1;
  transition:transform .38s cubic-bezier(.16,1,.3,1) .1s,opacity .3s ease .1s;
}

/* ------------------------------------------------------------
   24. НОМЕРА РАЗДЕЛОВ
   Плашка над заголовком получает порядковый номер — длинная страница
   обретает счёт, видно, сколько глав пройдено.
   ------------------------------------------------------------ */
body{counter-reset:раздел}
.section .head .eyebrow{counter-increment:раздел}
.section .head .eyebrow::before{
  content:counter(раздел,decimal-leading-zero) " · ";
  opacity:.5;
}

/* ------------------------------------------------------------
   25. «МЕНЬШЕ ДВИЖЕНИЯ» — добавка к пятому заходу
   ------------------------------------------------------------ */
@media(prefers-reduced-motion:reduce){
  .curtain{display:none}
  html.leaving .curtain,html.leaving .curtain i{transition:none}
}

/* ------------------------------------------------------------
   10. СТРАНИЦЫ ДОКУМЕНТАЦИИ
   На /docs и /routers движения не было вовсе: рядом с главной они
   выглядели мёртвыми. Здесь ровно столько, чтобы вести взгляд по
   длинному тексту, и ни каплей больше — читать это будут подолгу.

   ⚠️ Везде `forwards`, НИКОГДА `both`. При `both` браузер применяет
   начальный кадр ещё до входа в диапазон, и текст инструкции остаётся
   невидимым, пока до него не доскроллят. Для страницы, где человек ищет
   ответ поиском по странице, это провал.
   ------------------------------------------------------------ */
@supports (animation-timeline: view()){
  @media(min-width:900px) and (prefers-reduced-motion: no-preference){

    /* Заголовок раздела чуть подаётся вперёд при подходе. */
    .docs-body section > h2,
    .docs-body section > h1{
      animation:docs-head linear forwards;
      animation-timeline:view();
      animation-range:entry 2% entry 30%;
    }
    @keyframes docs-head{
      from{opacity:.35;transform:translateY(14px)}
      to{opacity:1;transform:none}
    }

    /* Абзацы и списки — тем же движением, но слабее: текст не должен
       мельтешить, пока его читают. */
    .docs-body section > p,
    .docs-body section > ul,
    .docs-body section > ol,
    .docs-body section > .rt-table,
    .docs-body section > pre{
      animation:docs-body-in linear forwards;
      animation-timeline:view();
      animation-range:entry 0% entry 22%;
    }
    @keyframes docs-body-in{
      from{opacity:.5;transform:translateY(9px)}
      to{opacity:1;transform:none}
    }

    /* Врезки заметнее прочего: это предупреждения, их и надо замечать. */
    .docs-body .callout{
      animation:docs-callout linear forwards;
      animation-timeline:view();
      animation-range:entry 0% entry 26%;
    }
    @keyframes docs-callout{
      from{opacity:.4;transform:translateY(12px) scale(.985)}
      to{opacity:1;transform:none}
    }

    /* Шаги нумерованного списка проявляются по очереди — видно, что это
       последовательность, а не набор пунктов. */
    .docs-body .steps-num li{
      animation:docs-step linear forwards;
      animation-timeline:view();
      animation-range:entry 0% entry 30%;
    }
    @keyframes docs-step{
      from{opacity:.45;transform:translateX(-10px)}
      to{opacity:1;transform:none}
    }
  }
}

/* Кружок с номером шага наливается при наведении на пункт. */
.docs-body .steps-num li::before{
  transition:border-color .3s ease,background-color .3s ease,color .3s ease,transform .35s cubic-bezier(.34,1.56,.64,1);
}
.docs-body .steps-num li:hover::before{
  border-color:var(--line-hi);background:var(--ink);color:var(--bg);transform:scale(1.08);
}

/* Строка таблицы совместимости подсвечивается — по ней ведут пальцем. */
.rt-row{transition:background-color .25s ease}
.rt-row:not(.rt-head):hover{background:var(--surface-hi)}

/* Пункт бокового меню слегка отъезжает — понятно, что он нажимаемый. */
.docs-nav a{transition:background .25s ease,color .25s ease,transform .25s cubic-bezier(.215,.61,.355,1)}
.docs-nav a:hover{transform:translateX(3px)}

@media(prefers-reduced-motion: reduce){
  .docs-body section > h1,.docs-body section > h2,
  .docs-body section > p,.docs-body section > ul,.docs-body section > ol,
  .docs-body section > pre,.docs-body .callout,.docs-body .steps-num li,
  .docs-body section > .rt-table{
    animation:none;opacity:1;transform:none;
  }
  .docs-nav a:hover{transform:none}
}
