/*
  Палитра снята с самого мини-аппа Upscale (app/content/media/screen_start.jpg,
  screen_rules.jpg, screen_payout.jpg): почти чёрный фон, один тёплый оранжевый
  акцент, фиолетовый — только на второстепенном. Смысл прямой: страница должна
  выглядеть продолжением приложения, в которое человек сейчас перейдёт.

  Зелёный и красный не входят в палитру страницы. Они живут только внутри
  симулятора просадки и означают там ровно одно — жив счёт или закрыт. Цвет,
  который где-то ещё значит «хорошо» или «плохо», перестаёт значить это здесь.

  Чего здесь нет и не должно появиться: свечений и ореолов, парящих частиц,
  неона, размытых цветных пятен, градиентов из фиолетового в синий, стеклянных
  панелей с блюром поверх всего. Это набор, по которому страница читается как
  сгенерированная, и он убивает ровно то доверие, ради которого писались
  честные тексты.
*/

:root {
  --bg:        #0a0a0c;
  --surface:   #141417;
  --raised:    #1b1b1f;
  --line:      #26262b;
  --line-soft: #1e1e22;

  --text:      #f2f2f4;
  /* Серые — от 4.5:1 к любому фону (D-117): --muted 7.0–8.4, --dim 4.9–5.8. */
  --muted:     #a8a8b2;
  --dim:       #8a8a94;

  --accent:      #f5a55e;   /* кнопка CHOOSE CHALLENGE в мини-аппе */
  --accent-ink:  #17110a;   /* текст на оранжевом */
  --accent-tint: #241a10;   /* заливка выбранной вкладки там же */
  --accent-line: #4a3016;

  --violet:    #b85bd6;     /* только плашка партнёрства */

  --ok:        #3fb950;     /* только симулятор */
  --danger:    #e5484d;     /* только симулятор */
  --danger-bg: #2a1114;

  --radius:    14px;
  --wrap:      1200px;
  --pad:       20px;
}

/* Вариативный файл на оба начертания: 27 КБ на всю типографику.
   Plus Jakarta Sans — геометрический, как шрифт мини-аппа, и спроектирован
   для Джакарты. `swap`, чтобы текст был виден раньше шрифта. */
/* `optional`, а не `swap`. Со `swap` шрифт приезжал под симулированной сетью
   Lighthouse на 1731-й миллисекунде и переверстывал текст: строка теряла
   высоту, всё ниже уезжало на 27 px, CLS 0.0041 тремя прогонами подряд —
   видно в трейсе по узлам, которые сдвигались на 4-5 px по горизонтали и
   меняли ширину на пару пикселей. Это подмена шрифта, а не раскладка.

   `optional` означает: не успел к первой отрисовке — эта загрузка идёт
   системным шрифтом, а сам файл остаётся в кэше и работает со следующей.
   Прыжка не бывает никогда, по определению свойства. Файл лежит рядом, отдан
   тем же соединением и объявлен в `<link rel=preload>`, так что на живом
   соединении он успевает; жертвуем мы редким первым визитом по плохому
   мобильному каналу — тем самым, которому прыгающая страница вредит больше
   всего. */
@font-face {
  font-family: "Plus Jakarta Sans";
  src: url("/fonts/plusjakartasans-latin.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: optional;
}

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

html {
  -webkit-text-size-adjust: 100%;
  background: var(--bg);
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: transparent;
  color: var(--text);
  font-family: "Plus Jakarta Sans", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

.skip, .topbar, main, .sticky { position: relative; z-index: 1; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  /* Вырез камеры в альбомной ориентации съедает край: поля берут максимум из
     обычного отступа и системного. */
  padding-left: max(var(--pad), env(safe-area-inset-left));
  padding-right: max(var(--pad), env(safe-area-inset-right));
}

section { padding: 44px 0; border-top: 1px solid var(--line-soft); }
section.hero { border-top: 0; }

/* ------------------------------------------------------------ типографика */

h1 {
  font-size: clamp(28px, 7.4vw, 34px);
  line-height: 1.12;
  letter-spacing: -0.022em;
  font-weight: 700;
  margin: 0 0 14px;
  text-wrap: balance;
}

/* Заголовок первого экрана переносится по-разному на двух языках, и на смене
   языка блок под ним подпрыгивает. В CLS это не попадает — сдвиги в пределах
   500 мс после клика из метрики исключены, — но глазами видно.
   Промерено на живой странице по всем ширинам с шагом 10 px: расходятся только
   узкие полосы, где индонезийский берёт три строки, а английский две.
     375…409 px    id 3 / en 2   ← сюда попадает iPhone 12/13/14 (390)
     1024…1063 px  id 3 / en 2
     1244…1303 px  id 3 / en 2
   Везде остальное строки совпадают, и резервировать там нечего: лишняя строка
   пустоты хуже прыжка. 3.36em — это три строки при line-height 1.12; в em,
   а не в пикселях, потому что кегль внутри полосы плывёт по vw. */
@media (min-width: 375px) and (max-width: 409px) { h1 { min-height: 3.36em; } }
@media (min-width: 1024px) and (max-width: 1063px) { h1 { min-height: 3.36em; } }
@media (min-width: 1244px) and (max-width: 1303px) { h1 { min-height: 3.36em; } }
h2, h3 { text-wrap: balance; }

h2 {
  font-size: clamp(20px, 5.2vw, 26px);
  line-height: 1.2;
  letter-spacing: -0.015em;
  font-weight: 700;
  margin: 0 0 16px;
}
h3 {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.008em;
  margin: 0 0 6px;
}
p { margin: 0 0 14px; }
p:last-child { margin-bottom: 0; }
b { font-weight: 700; }

.muted { color: var(--muted); }
.fine  { color: var(--dim); font-size: 13.5px; line-height: 1.5; }
.lede  { font-size: 17.5px; color: var(--muted); margin-bottom: 24px; }
.lead-line { margin-bottom: 24px; }

/* --------------------------------------------------------------- шапка */

.topbar { padding: 14px 0 0; }
/* Единственное, что осталось в шапке, — переключатель языка, и он справа.
   Текстовая метка «Challenge $1.000» отсюда убрана: она слово в слово
   повторяла первую строку H1 двумя сантиметрами ниже и читалась как чужой
   заголовок, случайно попавший в шапку. */
.topbar-in { display: flex; align-items: center; justify-content: flex-end; }

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

   Вертикальные поля, а не высота: тап-цель обязана быть 44 px, а выглядеть
   строка должна строкой, а не кнопкой. */
.tg-alt {
  /* `block` с шириной по содержимому, а не `inline-block`: на десктопе кнопка
     не растянута во всю колонку, и инлайновая ссылка вставала рядом с ней —
     то есть выглядела вторым равноправным действием. */
  display: block;
  width: fit-content;
  margin-top: 2px;
  padding: 12px 2px;
  color: var(--muted);
  font-size: 13.5px;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color .18s ease, border-color .18s ease;
}
.card .tg-alt, .seq-body .tg-alt { margin-top: 0; }

/* Три факта под кнопкой (D-117): пилюли, не кнопки. */
.hero-facts {
  list-style: none; margin: 12px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 6px 8px;
}
.hero-facts li {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 10px 5px 8px;
  border-radius: 999px; border: 1px solid var(--accent-line); background: var(--accent-tint);
  color: var(--text); font-size: 13px; font-weight: 600; line-height: 1.2;
}
.hero-facts li::before { content: "✓"; color: var(--accent); font-weight: 700; }

.skip { position: absolute; left: -9999px; background: var(--accent); color: var(--accent-ink); padding: 10px 16px; border-radius: 8px; text-decoration: none; }
.skip:focus { left: 20px; top: 12px; z-index: 40; }

/* -------------------------------------------------------------- кнопки */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 52px; padding: 14px 24px;
  border-radius: var(--radius);
  font: inherit; font-weight: 700; font-size: 16px; letter-spacing: -0.005em;
  text-decoration: none; text-align: center; cursor: pointer;
  border: 1px solid transparent;
  transition: transform .14s ease, background-color .16s ease, border-color .16s ease;
}
.btn-lg { min-height: 56px; font-size: 17px; }
.btn-primary { background: var(--accent); color: var(--accent-ink); width: 100%; }
.btn-ghost { background: transparent; color: var(--text); border-color: var(--line); width: 100%; }

/* Подъём на пиксель и усиление фона — ровно столько, чтобы кнопка отвечала
   на курсор и не отвечала на него шоу. */

/* На телефоне ховера нет — есть нажатие, и оно обязано быть заметным. */
.btn:active { scale: .97; }
.btn-primary:active { background: color-mix(in srgb, var(--accent) 86%, #000); }
.btn-ghost:active { background: var(--raised); }

/* Заперто — не значит мертво. Кнопка отвечает на тап: уводит к шагу 1 и
   подсвечивает его. Кнопка, которая молчит, читается как поломка. */
.btn.is-locked { background: var(--raised); color: var(--dim); border-color: var(--line); }
.btn.is-locked:hover { background: var(--raised); transform: none; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }

/* -------------------------------------------------------- первый экран */

.hero { padding-top: 30px; padding-bottom: 48px; }
/* Обязательная строка раскрытия. Она короткая, но не декоративная:
   читаемость важнее приглушённости. */
.hero-copy .fine { margin-top: 14px; color: var(--muted); }

/* Корпус телефона. Пропорция берётся у самого скриншота: картинка стоит на
   натуральной высоте, а рамка показывает её верх и обрезает низ маской.
   Ни сжатия, ни полей по бокам — экран выглядит продолжающимся за край.
   Рамка 3 px, скругление 8% ширины, ни одной тени с размытием. */
.phone {
  --phone-w: 214px;
  /* Единица панелей. Всё внутри рамки меряется в ней, поэтому панель растёт
     вместе с рамкой, а не остаётся мелкой картинкой в большом окне. */
  --u: calc(var(--phone-w) / 214);
  --phone-h: 296px;
  width: var(--phone-w);
  margin: 30px auto 0;
  border: 3px solid var(--raised);
  border-radius: calc(var(--phone-w) * 0.08 + 3px);
  background: #000;
}
.phone-screen {
  position: relative;
  width: 100%;
  height: var(--phone-h);
  overflow: hidden;
  border-radius: calc(var(--phone-w) * 0.08);
  background: var(--bg);
}
.shot {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  height: auto;
  opacity: 0;
  transition: opacity .45s ease;
}
.shot.is-on { opacity: 1; }
/* Мягкое затухание к фону страницы: низ экрана не обрублен, а уходит. */
.phone-screen::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 26%;
  background: linear-gradient(to bottom, rgba(10, 10, 12, 0), var(--bg));
  pointer-events: none;
}

.device-note { margin-top: 14px; text-align: center; color: var(--dim); font-size: 13.5px; }

/* ------------------------------------------- чат: карточка в раскладке

   Раньше чат был плавающей панелью: разметку строил скрипт, стили приезжали
   отдельным файлом после первой отрисовки, окно всплывало поверх страницы.
   Теперь это обычный блок, и всё отсюда следует.

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

   Высота карточки задана числом и не зависит ни от переписки, ни от длины
   подписей. Это единственная причина, по которой ответ модели не двигает
   страницу: расти внутри он может сколько угодно, наружу — нет. */

.hero-ask { margin-top: 26px; }

/* Две кривые на всё движение в чате. Появление — быстрый старт и мягкая
   посадка; движение уже видимого на месте — симметричное. `ease-in` не
   используется нигде: начало, которое медлит, читается как задержка. */
.chat {
  --ease-in-view: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-place: cubic-bezier(0.77, 0, 0.175, 1);
  --bubble-it: #1d1d22;
  --online: #34d399;
  /* Аватар в ленте и отступ от него до пузыря. */
  --ava: 28px;
  --ava-gap: 8px;
  position: relative;
  display: flex; flex-direction: column;
  /* Мобильная высота, верх полосы 320–380 из брифа. Два пузыря приветствия
     и чипы в два ряда обязаны влезать целиком: чип, ушедший под срез, —
     это клик мимо (найдено 2026-09-23: нажатие попадало в поле ввода).

     D-117: высота — по содержимому, пока разговора нет (380 px с прижатым к
     низу приветствием уводили чипы за край экрана iPhone). `is-open` —
     ~60svh с первым сообщением; `--chat-h0` — высота до роста, ниже неё
     карточка не сжимается. */
  height: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  overflow: hidden;
}
.chat[hidden] { display: none; }
.chat.is-open { height: clamp(var(--chat-h0, 320px), 60svh, 600px); }
/* Вернувшийся с перепиской — открыта с первой отрисовки (resume.v2.js). */
.chat-resume .chat { height: clamp(320px, 60svh, 600px); }

.chat-head {
  flex: none;
  display: flex; align-items: center; gap: 10px;
  padding: 6px 14px;
  border-bottom: 1px solid var(--line-soft);
}
/* Знак, а не лицо. Ассистент — ИИ и так себя и называет; лицо, пусть
   сгенерированное, обещало бы человека (D-106, D-109). */
.chat-face { position: relative; width: 40px; height: 40px; flex: none; }
.chat-face-img { display: block; width: 40px; height: 40px; border-radius: 50%; }
/* «Онлайн» — справа снизу на аватаре: 12 px вместе с кольцом цвета панели,
   кольцо отделяет точку от градиента. */
.chat-online {
  position: absolute; right: -1px; bottom: -1px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--online); border: 2.5px solid var(--surface);
}
.chat-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.chat-title { font-size: 14px; font-weight: 600; letter-spacing: -.01em; }
.chat-sub { color: var(--muted); font-size: 11.5px; margin-top: 1px; }

.chat-log {
  position: relative;
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
  overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  /* Прокруткой управляет скрипт: к началу нового ответа, а не в самый низ.
     Браузерная привязка прокрутки спорила бы с ним. */
  overflow-anchor: none;
  padding: 12px;
  /* Мягкий край вместо обреза: сообщение уходит под шапку и под поле ввода
     затуханием в 12 px. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 24px, #000 calc(100% - 12px), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 24px, #000 calc(100% - 12px), transparent 100%);
}

/* Полоса прокрутки: 6 px, дорожки нет, ползунок проявляется при наведении и
   во время прокрутки (класс `is-scrolling` ставит скрипт и снимает через
   ~800 мс тишины).

   Две ветки, и не случайно. Chrome с 121 версии и Firefox понимают
   стандартные `scrollbar-width` / `scrollbar-color`, и если у элемента они
   не `auto`, Chrome молча выключает `::-webkit-scrollbar` (MDN). А только
   `::-webkit-scrollbar` умеет ширину 6 px, отступ 2 px и полное скругление.
   Поэтому стандартные свойства получает лишь тот, у кого псевдоэлемента нет
   вовсе, — Firefox; у него `thin` без отступа — ближе нельзя. */
/* Место под полосу зарезервировано там, где она классическая, — на десктопе
   с мышью. Иначе она появлялась, как только лента переполнялась, сужала
   содержимое на 10 px, и пузыри человека, прижатые вправо, дёргались вбок
   через секунды после ввода — смещение вёрстки, которое CLS засчитывает
   (найдено тестом 2026-09-23). На телефоне полоса накладная и места не
   занимает; резерв там только отнял бы ширину у пузырей. */
@media (hover: hover) and (pointer: fine) {
  .chat-log { scrollbar-gutter: stable; }
}
@supports selector(::-webkit-scrollbar) {
  .chat-log { scrollbar-width: auto; scrollbar-color: auto; }
  .chat-log::-webkit-scrollbar { width: 10px; height: 10px; }
  .chat-log::-webkit-scrollbar-track { background: transparent; }
  .chat-log::-webkit-scrollbar-button { display: none; }
  .chat-log::-webkit-scrollbar-thumb {
    background-color: transparent;
    border: 2px solid transparent; background-clip: padding-box;
    border-radius: 999px;
  }
  .chat-log.is-scrolling::-webkit-scrollbar-thumb { background-color: rgba(255, 255, 255, .14); }
  @media (hover: hover) {
    .chat-log:hover::-webkit-scrollbar-thumb { background-color: rgba(255, 255, 255, .14); }
    .chat-log::-webkit-scrollbar-thumb:hover { background-color: rgba(255, 255, 255, .28); }
  }
}
@supports not selector(::-webkit-scrollbar) {
  .chat-log { scrollbar-width: thin; scrollbar-color: transparent transparent; }
  .chat-log.is-scrolling { scrollbar-color: rgba(255, 255, 255, .14) transparent; }
  @media (hover: hover) {
    .chat-log:hover { scrollbar-color: rgba(255, 255, 255, .14) transparent; }
  }
}

.chat-flow { display: flex; flex-direction: column; gap: 10px; }
/* До первого сообщения содержимое стоит внизу — пустота уходит вверх, под
   шапку. С первым действием человека скрипт меняет отступ на равный ему
   `transform` в том же кадре: визуально ничего не сдвигается, а дальше поток
   держится у низа сдвигом, а не раскладкой. Сдвиг — не смещение вёрстки, и
   каждый новый пузырь, подтягивающий переписку вверх, CLS не добавляет.
   `margin-top`, а не `justify-content`: переполненный флекс с прижатием к
   низу обрезает содержимое сверху, и доскроллить до него нельзя. */
.chat-log:not([data-started]) .chat-flow { margin-top: auto; }

/* Реплики ассистента — группа пузырей с аватаром у последнего, как в
   мессенджере: 4 px между пузырями, 8 px от аватара. */
.chat-turn {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  padding-left: calc(var(--ava) + var(--ava-gap));
}
.chat-ava {
  position: absolute; left: 0; bottom: 0;
  display: block; width: var(--ava); height: var(--ava);
  border-radius: 50%;
}
/* У живой группы аватар стоит сверху и едет к последнему пузырю сдвигом:
   переставлять его раскладкой значило бы смещать вёрстку на каждый пузырь. */
.chat-turn.is-live .chat-ava { top: 0; bottom: auto; }

.chat-b {
  max-width: 94%;
  padding: 7px 11px;
  font-size: 14.5px; line-height: 1.4;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
/* Угол со стороны аватара — 6 px у каждого пузыря группы; верхний — 18 px
   только у первого. */
.chat-b.it {
  background: var(--bubble-it);
  border-radius: 18px 18px 18px 6px;
  transform-origin: 0 100%;
}
.chat-b.it + .chat-b.it, .chat-b.it + .chat-dots-b { border-top-left-radius: 6px; }
.chat-b.me {
  align-self: flex-end;
  background: var(--accent-tint); border: 1px solid var(--accent-line);
  border-radius: 18px 18px 6px 18px;
  transform-origin: 100% 100%;
}

/* Появление и скольжение ленты — `element.animate()` в скрипте чата (D-116),
   все числа там, в объекте `MOTION`. Здесь — только точка, от которой растёт
   появляющееся: у Nara снизу слева, у человека снизу справа. */
.chat-cta, .chat-dots-b { transform-origin: 0 100%; }

/* Вернувшийся с живой перепиской (класс ставит resume.v2.js в <head> до
   первой отрисовки, D-113): приветствие и чипы не рисуются, их место остаётся
   пустым той же высоты — CLS ноль, — и его заполняет чат. Скрипт чата снимает
   класс, как только восстановит переписку. Не загрузился — через 3 с
   приветствие проявляется само: пустой карточки навсегда не бывает. */
.chat-resume #chatFlow > .chat-turn:first-child,
.chat-resume #chatChips { visibility: hidden; animation: chat-reveal 0s linear 3s forwards; }
@keyframes chat-reveal { to { visibility: visible; } }

/* Уходящее — чипы и три точки — уезжает копией поверх карточки, а сам
   элемент покидает раскладку сразу: иначе его место схлопнулось бы через
   160 мс, и всё ниже прыгнуло бы. */
.chat-ghost { position: absolute; margin: 0; pointer-events: none; z-index: 1; }

/* Чипы живут до первого сообщения. */
.ask-chips { display: flex; flex-wrap: wrap; gap: 6px; }
/* Узкие телефоны: на 360 приветствие с чипами иначе не влезает на 11 px, а
   это две трети андроидного рынка. Полпикселя шрифта — и всё на месте. */
@media (max-width: 380px) {
  .chat { --ava: 24px; }
  .chat-log { padding: 10px; }
  .chat-flow { gap: 8px; }
  .chat-b { font-size: 14px; padding: 6px 10px; }
  .ask-chip { font-size: 13px; padding: 0 11px; }
}
.ask-chip {
  min-height: 34px; padding: 0 12px;
  border-radius: 999px; border: 1px solid var(--line); background: var(--raised);
  color: var(--text); font: inherit; font-size: 13.5px; cursor: pointer;
  position: relative;
  transition: transform 120ms var(--ease-in-view);
}
/* Цель нажатия добирается невидимой областью, как у сегментированного
   контрола: 34 + 5 + 5 = 44. */
.ask-chip::before { content: ""; position: absolute; inset: -5px 0; }
.ask-chip:active { transform: scale(.97); }
.ask-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Три точки — в пузыре, на месте будущего ответа. */
.chat-dots-b { background: var(--bubble-it); border-radius: 18px 18px 18px 6px; padding: 7px 11px; }
.chat-dots { display: inline-flex; align-items: center; gap: 5px; height: 20px; }
.chat-dots i {
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
  animation: chatdot 1.05s var(--ease-in-place) infinite;
}
.chat-dots i:nth-child(2) { animation-delay: .16s; }
.chat-dots i:nth-child(3) { animation-delay: .32s; }
@keyframes chatdot {
  0%, 80%, 100% { opacity: .3; transform: translateY(0); }
  40% { opacity: 1; transform: translateY(-3px); }
}

/* Кнопка внутри ответа — карточка действия по содержимому, а не плита во всю
   ширину: оранжевая плита в первом экране уже есть, и она одна. */
.chat-cta {
  align-self: flex-start; max-width: 100%;
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: 4px;
  padding: 9px 13px; border-radius: 12px;
  background: var(--accent-tint); border: 1px solid var(--accent-line);
  color: var(--text); text-decoration: none;
  font-size: 14px; font-weight: 600; line-height: 1.3;
}
.chat-cta .btn-arrow { color: var(--accent); font-weight: 700; }
.chat-cta:active { transform: scale(.97); transition: transform 120ms var(--ease-in-view); }

/* Карточка со схемой экрана (D-117): до 260 px, слайд 168 px и край
   следующего — видно, что ленту листают пальцем. */
.chat-card {
  align-self: flex-start;
  width: min(260px, 100%);
  margin-top: 2px;
  transform-origin: 0 100%;
}
.cc-track {
  display: flex; gap: 8px;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.cc-track::-webkit-scrollbar { display: none; }
.cc-slide { flex: none; width: 168px; margin: 0; scroll-snap-align: start; }
.chat-card.is-single .cc-slide { width: 190px; }
.cc-slide .phone { --phone-w: 168px; width: 100%; margin: 0; }
.chat-card.is-single .cc-slide .phone { --phone-w: 190px; }
/* Ниже, чем кадр телефона: у панелей низ пустой, а карточка — часть ответа. */
.cc-slide .phone-screen { height: auto; aspect-ratio: 6 / 7; }
.cc-slide .phone-screen::after { content: none; }
.cc-cap { margin-top: 6px; color: var(--muted); font-size: 12.5px; line-height: 1.35; }
.cc-foot { display: flex; align-items: center; gap: 10px; margin-top: 6px; color: var(--muted); font-size: 12px; }
.chat-card.is-single .cc-foot { display: none; }
.chat-card.is-empty { display: none; }
.cc-count { font-variant-numeric: tabular-nums; }
.cc-dots { display: inline-flex; gap: 5px; }
.cc-dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--line); transition: background-color .2s ease; }
.cc-dots i.is-on { background: var(--accent); }
/* Кнопка копирования — только в карточках с кодом. */
.chat-copy {
  display: none;
  width: 100%; min-height: 44px; margin-top: 8px; padding: 8px 12px;
  border-radius: 12px; border: 1px solid var(--accent); background: var(--accent);
  color: var(--accent-ink); font: inherit; font-size: 14px; font-weight: 700; cursor: pointer;
}
.chat-card.has-copy .chat-copy { display: block; }
.chat-copy.is-done { background: var(--accent-tint); color: var(--text); border-color: var(--accent-line); }
.chat-copy:active { transform: scale(.97); }
/* Быстрый ответ под ответом Nara — тот же чип, что под приветствием. */
.chat-quick { align-self: flex-start; padding-left: calc(var(--ava) + var(--ava-gap)); }

.chat-form {
  flex: none; display: flex; gap: 8px;
  padding: 10px 12px 12px;
  border-top: 1px solid var(--line-soft);
}
.chat-form input {
  flex: 1; min-width: 0; min-height: 44px; padding: 0 13px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 12px;
  color: var(--text); font: inherit;
}
.chat-form input::placeholder { color: var(--dim); }
.chat-send {
  width: 44px; height: 44px; flex: none; border: 0; border-radius: 12px;
  background: var(--accent); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: transform 120ms var(--ease-in-view);
}
.chat-send svg {
  width: 16px; height: 16px; fill: none; stroke: var(--accent-ink);
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.chat-send:active { transform: scale(.97); }

/* Телефон с графиком в секции «что можно торговать». Рамка не «похожая» на
   ту, что в инструкции, а буквально та же: те же токены ширины и высоты,
   тот же бордюр, то же скругление. Это проверяется замером в браузере —
   две рамки одного вида, разошедшиеся на пару пикселей, читаются как
   небрежность быстрее, чем как две рамки. */
.trade-device { display: flex; flex-direction: column; align-items: center; }
.trade-device .phone { margin: 0; }
.trade-device .device-note { margin-top: 10px; font-size: 12.5px; }

/* --------------------------------------------------- что такое Upscale */

/* Сетка фактов (D-117): 2×2 на телефоне, четыре в ряд на десктопе. */
.facts-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
}
.fact {
  padding: 14px 13px 15px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.fact-ic {
  display: block; width: 26px; height: 26px; margin-bottom: 8px;
  fill: none; stroke: var(--accent); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.fact h3 { font-size: 15px; margin-bottom: 4px; }
.fact p { color: var(--muted); font-size: 13.5px; line-height: 1.45; margin: 0; }

/* ------------------------------------- «бесплатно»: полоса во всю ширину */

/* Единственный блок с другим фоном и во всю ширину экрана. Это главный ход
   на доверие, и он обязан читаться как заявление, а не как ещё один абзац. */
.band {
  position: relative;
  background: rgb(24, 24, 29);
  padding: 52px 0;
}
/* Кромки — градиентные, оранж .5 в центре и ноль к краям: так полоса не
   заканчивается прямой линией, а растворяется. */
.band::before, .band::after {
  content: "";
  position: absolute; left: 0; right: 0; height: 1px;
  pointer-events: none;
  background: linear-gradient(to right,
    rgba(245, 165, 94, 0), rgba(245, 165, 94, .5) 50%, rgba(245, 165, 94, 0));
}
.band::before { top: 0; }
.band::after { bottom: 0; }
.band-grid { display: grid; gap: 26px; }
.band-lead { display: flex; flex-direction: column; }
.amount-value {
  font-size: clamp(52px, 15vw, 88px);
  font-weight: 700; letter-spacing: -0.035em; line-height: 1;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  /* Статичная тень — ключевая цифра страницы светится. В кадрах её нет. */
  text-shadow: 0 0 24px rgba(245, 165, 94, .35);
}
.band-caption { margin-top: 10px; color: var(--text); font-size: 16px; font-weight: 600; }
.band-body p { color: var(--muted); }
.band-body .quote { color: var(--text); }
.band-body .fine { color: var(--muted); }
/* Путь к выплате — три шага с номерами, как в инструкции ниже. */
.path { list-style: none; margin: 0 0 6px; padding: 0; display: grid; gap: 12px; }
.path li { display: flex; gap: 12px; align-items: flex-start; }
.path-num {
  flex: none; width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-tint); border: 1px solid var(--accent-line); color: var(--accent);
  font-size: 13.5px; font-weight: 700;
}
.path-text { padding-top: 3px; color: var(--text); font-size: 16px; line-height: 1.5; }

.quote { border-left: 2px solid var(--accent); padding: 2px 0 2px 16px; margin: 22px 0; }

/* --------------------------------------------------------------- факты */

.facts { list-style: none; margin: 0 0 14px; padding: 0; }
.facts li { position: relative; padding: 0 0 0 18px; margin-bottom: 12px; color: var(--muted); }
.facts li::before {
  content: ""; position: absolute; left: 0; top: 10px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
}
.facts li:last-child { margin-bottom: 0; }

/* ------------------------------ инструкция: шаги управляют телефоном */

/* Телефон в разметке стоит раньше шагов — на узком экране он над ними и
   липнет к верху, иначе переключение экрана было бы не видно. */
.guide { display: grid; gap: 18px; margin-bottom: 22px; }
.guide-phone { position: sticky; top: 10px; z-index: 2; }
/* Рамка инструкции — тот же телефон, что в первом экране: пропорция,
   скругление и рамка общие, потому что компонент один. Внутри не картинки,
   а панели из разметки, поэтому высота не зависит ни от какого кадра —
   она просто равна рамке в шапке на той же ширине. */
.guide-phone .phone { margin-top: 0; }
/* Затухание внизу нужно там, где кадр обрывается посреди содержимого. Панель
   нарисована целиком, у неё есть свой низ. */
.guide-phone .phone-screen::after { content: none; }

/* ── обвязка: где человек находится ──────────────────────────────────────
   Панели у двух путей общие — экраны Upscale одни и те же. Разное только то,
   откуда на них смотрят, и отвечает на это обвязка: у веб-пути пилюля
   адресной строки, у телеграмного — шапка мини-аппа и полоса ввода. Она
   схематична: ни логотипа Telegram, ни иконок конкретного браузера, только
   форма. Стоит снаружи панелей и переключается вместе с вкладкой, поэтому
   видна на каждом шаге, а не только на первом. */
.chrome { position: absolute; left: 0; right: 0; z-index: 1; pointer-events: none; }
.phone-screen[data-chrome="web"] { --chrome-top: calc(30 * var(--u)); --chrome-bottom: 0px; }
.phone-screen[data-chrome="telegram"] { --chrome-top: calc(28 * var(--u)); --chrome-bottom: calc(34 * var(--u)); }
.phone-screen[data-chrome="web"] [data-chrome-for="telegram"],
.phone-screen[data-chrome="telegram"] [data-chrome-for="web"] { display: none; }

/* Веб: нейтральный серый, как шапка браузера. */
.chrome-web {
  top: 0; display: flex; align-items: center;
  height: calc(30 * var(--u)); padding: 0 calc(8 * var(--u));
  background: var(--raised); border-bottom: 1px solid var(--line);
}
.ch-pill {
  display: flex; align-items: center; gap: calc(5 * var(--u));
  width: 100%; padding: calc(3 * var(--u)) calc(8 * var(--u));
  border-radius: 999px; background: var(--bg); border: 1px solid var(--line);
  font-size: calc(8.5 * var(--u)); color: var(--muted);
}
.ch-lock { width: calc(8 * var(--u)); height: calc(8 * var(--u)); flex: none; fill: none; stroke: var(--dim); stroke-width: 1.3; }
.ch-url { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Телеграм: тот же тёмный, но холоднее — синеватый вместо нейтрального.
   Оттенок, а не бренд: логотипа здесь нет и быть не должно. */
.chrome-tg { top: 0; bottom: 0; display: flex; flex-direction: column; justify-content: space-between; }
.ch-bar {
  display: flex; align-items: center; gap: calc(7 * var(--u));
  height: calc(28 * var(--u)); padding: 0 calc(9 * var(--u));
  background: #171d25; border-bottom: 1px solid #232c38;
  font-size: calc(9.5 * var(--u)); font-weight: 600; color: var(--muted);
}
.ch-x { width: calc(10 * var(--u)); height: calc(10 * var(--u)); flex: none; fill: none; stroke: var(--dim); stroke-width: 1.4; stroke-linecap: round; }
.ch-input {
  display: flex; align-items: center;
  height: calc(34 * var(--u)); padding: 0 calc(9 * var(--u));
  background: #171d25; border-top: 1px solid #232c38;
}
.ch-input .bar { background: #2a3441; }

/* ── панели инструкции ───────────────────────────────────────────────────
   Схема экрана, а не подделка скриншота, и читаться должна именно так:
   палитра и шрифт лендинга, полоски вместо текста. Настоящие только подписи
   кнопок и то, что само является оффером (1,000 USD). Все размеры — в
   единицах `--u`: на телефоне это пиксель, на десктопе рамка шире, и панель
   растёт вместе с ней, а не остаётся мелкой картинкой в большом окне. */
.panel {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  padding: calc(var(--chrome-top, 0px) + 10 * var(--u)) calc(11 * var(--u))
           calc(var(--chrome-bottom, 0px) + 10 * var(--u));
  font-size: calc(10.5 * var(--u)); line-height: 1.25;
  color: var(--text);
  opacity: 0;
  transition: opacity .3s ease;
}
.panel.is-on { opacity: 1; }
.pn-top { display: flex; align-items: center; gap: calc(7 * var(--u)); margin-bottom: calc(14 * var(--u)); }
.pn-logo { width: calc(14 * var(--u)); height: calc(14 * var(--u)); border-radius: 4px; background: var(--accent); flex: none; }
.pn-avatar { width: calc(16 * var(--u)); height: calc(16 * var(--u)); border-radius: 50%; background: var(--line); flex: none; }
.pn-body { display: flex; flex-direction: column; gap: calc(9 * var(--u)); flex: 1; min-height: 0; }
.pn-center { justify-content: center; align-items: center; padding-bottom: calc(24 * var(--u)); }
.pn-chat { justify-content: flex-start; }
.pn-bottom { margin-top: auto; }
/* Полоска-заглушка. Ширина в процентах от строки: полоска не притворяется
   словом, у неё нет ни длины слова, ни его ритма. */
.bar { display: block; height: calc(6 * var(--u)); border-radius: 999px; background: var(--line); }
.w20 { width: 20%; } .w30 { width: 30%; } .w40 { width: 40%; } .w50 { width: 50%; }
.w60 { width: 60%; } .w70 { width: 70%; } .w80 { width: 80%; } .w90 { width: 90%; }
.pn-title { display: block; font-weight: 700; font-size: calc(12.5 * var(--u)); letter-spacing: -.01em; }
.pn-name { font-weight: 600; }
.pn-btn {
  display: flex; align-items: center; justify-content: center;
  width: 100%; min-height: calc(30 * var(--u));
  border-radius: calc(8 * var(--u));
  font-weight: 700; font-size: calc(10 * var(--u)); letter-spacing: .02em;
  border: 1px solid var(--line); color: var(--muted);
}
.pn-btn.ghost { padding: 0 calc(24 * var(--u)); }
/* Подсветка — ровно того элемента, который называет шаг. Кнопка — заливкой
   акцентом, как настоящие кнопки на странице; список или карточка — кольцом. */
.pn-btn.hl { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.ring { position: relative; }
.ring::after {
  content: ""; position: absolute; inset: calc(-4 * var(--u));
  border: 1.5px solid var(--accent); border-radius: calc(11 * var(--u));
  pointer-events: none;
}
.pn-bubble {
  display: flex; flex-direction: column; gap: calc(6 * var(--u));
  width: 78%; padding: calc(8 * var(--u)) calc(9 * var(--u));
  border-radius: calc(10 * var(--u)) calc(10 * var(--u)) calc(10 * var(--u)) calc(3 * var(--u));
  background: var(--surface); border: 1px solid var(--line-soft);
}
.pn-pills { display: flex; gap: calc(5 * var(--u)); }
.pn-pill {
  flex: 1; text-align: center;
  padding: calc(6 * var(--u)) 0; border-radius: 999px;
  border: 1px solid var(--line); color: var(--muted); font-size: calc(9 * var(--u)); font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pn-pill.is-on { background: var(--accent-tint); border-color: var(--accent); color: var(--text); }
.pn-list { display: flex; flex-direction: column; gap: calc(6 * var(--u)); }
.pn-row {
  display: flex; align-items: center; justify-content: space-between; gap: calc(8 * var(--u));
  padding: calc(8 * var(--u)) calc(9 * var(--u));
  border-radius: calc(8 * var(--u)); background: var(--surface); border: 1px solid var(--line-soft);
}
.pn-row .bar { flex: none; }
.pn-card {
  display: flex; flex-direction: column; gap: calc(8 * var(--u));
  padding: calc(10 * var(--u)); border-radius: calc(10 * var(--u));
  background: var(--surface); border: 1px solid var(--line);
}
.pn-card .pn-row { background: none; border: 0; padding: 0; }
.pn-card.dim { opacity: .55; }
.pn-modal { justify-content: flex-end; }
.pn-sheet {
  display: flex; flex-direction: column; gap: calc(10 * var(--u));
  padding: calc(12 * var(--u)) calc(11 * var(--u)) calc(14 * var(--u));
  margin: 0 calc(-11 * var(--u)) calc(-10 * var(--u));
  border-radius: calc(14 * var(--u)) calc(14 * var(--u)) 0 0;
  background: var(--raised); border-top: 1px solid var(--line);
}
/* Пять ячеек — как в модалке приложения; пятая в фокусе, буква уже введена. */
.pn-cells { display: grid; grid-template-columns: repeat(5, 1fr); gap: calc(5 * var(--u)); }
.pn-cell {
  aspect-ratio: 142 / 132;
  display: flex; align-items: center; justify-content: center;
  border-radius: calc(7 * var(--u)); border: 1px solid var(--line); background: var(--surface);
  font-weight: 700; font-size: calc(13 * var(--u));
}
.pn-cell.is-focus { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.pn-sum { font-weight: 700; font-size: calc(14 * var(--u)); letter-spacing: -.01em; }
.pn-badge {
  padding: calc(3 * var(--u)) calc(7 * var(--u)); border-radius: 999px;
  background: var(--accent-tint); border: 1px solid var(--accent-line); color: var(--accent);
  font-size: calc(8.5 * var(--u)); font-weight: 700; white-space: nowrap;
}

.guide-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.gstep {
  display: flex; gap: 14px; align-items: flex-start;
  width: 100%; min-height: 44px; padding: 15px 16px;
  text-align: left; font: inherit; color: var(--text); cursor: pointer;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  transition: border-color .18s ease, background-color .18s ease;
}
.gstep.is-on { border-color: var(--accent); background: var(--accent-tint); }
.gstep-num {
  flex: none; display: grid; place-items: center;
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--raised); color: var(--dim); border: 1px solid var(--line);
  font-size: 13px; font-weight: 700;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
}
.gstep.is-on .gstep-num { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.gstep-body { display: block; min-width: 0; }
.gstep-title { display: block; font-weight: 700; margin-bottom: 3px; }
.gstep-text { display: block; color: var(--muted); font-size: 14.5px; line-height: 1.5; }

.guide-note { margin-top: 4px; }

/* --------------------------------------- что можно торговать: два экрана */

.trade { margin-top: 28px; display: grid; gap: 18px; }
.trade-copy p { color: var(--muted); font-size: 15px; margin: 0; }
/* На телефоне — стопкой: список инструментов во всю ширину, под ним рамка с
   графиком. Двумя колонками они вставали по 134 px на узком экране, и это
   уже не кадр, а иконка. */
.trade-shots { display: grid; grid-template-columns: 1fr; gap: 16px; justify-items: center; }
/* Только список инструментов: правило `img` цепляло и график в телефоне, и
   под ним была чёрная пустота (D-117). Правый край затухает — обрез «Fundin»
   читается как прокручиваемый ряд. */
.trade-shots > img {
  display: block; width: 100%;
  height: clamp(250px, 70vw, 320px);
  object-fit: cover; object-position: top;
  border: 1px solid var(--line); border-radius: var(--radius);
  -webkit-mask-image: linear-gradient(to right, #000 74%, transparent 99%), linear-gradient(to bottom, #000 82%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to right, #000 74%, transparent 99%), linear-gradient(to bottom, #000 82%, transparent 100%);
  mask-composite: intersect;
}


/* -------------------------------------- промокод и переход: два шага */

.sequence { list-style: none; margin: 0; padding: 0; max-width: 520px; }
.seq { position: relative; display: flex; gap: 14px; padding: 0 0 26px; }
.seq:last-child { padding-bottom: 0; }
.seq:not(:last-child)::after {
  content: ""; position: absolute; left: 15px; top: 38px; bottom: 12px;
  width: 1px; background: var(--line);
}
.seq-num {
  flex: none; width: 31px; height: 31px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--raised); color: var(--dim); border: 1px solid var(--line);
  font-size: 14px; font-weight: 700;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
  z-index: 1;
}
.seq.is-done .seq-num { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.seq.is-live .seq-num { border-color: var(--accent); color: var(--accent); }
.seq-body { flex: 1; min-width: 0; }
.seq-body .btn { margin-top: 4px; }
.seq-body .fine { margin-top: 10px; }

/* Пять ячеек той же геометрии, что в модалке приложения: обмеряно по
   assets/app_screens/app_promo.jpg — ячейка 142x132 при ширине экрана 1179,
   зазор 25. Человек видит здесь ровно тот элемент, который встретит через
   минуту, и незнакомый интерфейс перестаёт быть незнакомым. */
/* Главный момент страницы. Пятно света за ячейками — статичный градиент,
   дышит только его opacity: .14 ↔ .22 за шесть секунд.

   Пятно шире ячеек на 40 px с каждой стороны, и на телефоне его левый край
   уходит за экран. `overflow-x: clip` на секции режет его по краю страницы,
   не превращая секцию в прокручиваемый контейнер: без этого страница
   получала 20 px горизонтальной прокрутки на любой ширине. */
#kode { overflow-x: clip; }
.cells::before {
  content: "";
  position: absolute; inset: -34px -40px;
  pointer-events: none;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%, var(--accent), rgba(245, 165, 94, 0) 70%);
  opacity: .18;
  animation: breathe 6s ease-in-out infinite alternate;
}
@keyframes breathe { from { opacity: .14; } to { opacity: .22; } }
.cells.is-copied .cell, .cells.is-just-copied .cell, .cells.is-nudged .cell {
  box-shadow: inset 0 0 0 1px var(--accent);
}
.cells {
  position: relative;
  display: flex;
  gap: clamp(7px, 2.2vw, 11px);
  width: 100%; max-width: 316px;
  margin: 12px 0 0;
  background: none; border: 0; cursor: pointer;
  /* Нажимают по кнопке целиком, а не по ячейке. Вертикальные поля держат
     цель не ниже 44 px даже на 320 px, где ячейка ужимается до 38 —
     задавать высоту самой ячейке нельзя, `aspect-ratio` тогда растянет её
     по ширине и строка вылезет за экран. */
  padding: 5px 0;
  min-height: 48px;
  align-items: center;
}
.cell {
  flex: 1 1 0; max-width: 62px;
  aspect-ratio: 142 / 132;
  display: grid; place-items: center;
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 11%;
  background: #16161a;
  font-size: clamp(17px, 4.6vw, 21px); font-weight: 700; color: var(--text);
  transition: border-color .2s ease, color .2s ease, background-color .2s ease;
}
.cells:hover .cell { border-color: rgba(255, 255, 255, .38); }

/* Буквы загораются по очереди и гаснут, оставляя ячейки отмеченными. */
@keyframes cellLit {
  0%   { border-color: rgba(255, 255, 255, .22); color: var(--text); background: #16161a; }
  28%  { border-color: var(--accent); color: var(--accent); background: var(--accent-tint); }
  100% { border-color: var(--accent-line); color: var(--text); background: #16161a; }
}
/* Порядковый номер ячейки — в стилях, а не в атрибуте `style` разметки.
   CSP на домене задаёт `style-src 'self'`, и инлайновый стиль там просто не
   применяется: на localhost без CSP подсветка работала, на боевом домене
   `--i` оставался пустым и все пять букв загорались разом. */
.cell:nth-child(1) { --i: 0; }
.cell:nth-child(2) { --i: 1; }
.cell:nth-child(3) { --i: 2; }
.cell:nth-child(4) { --i: 3; }
.cell:nth-child(5) { --i: 4; }

.cells.is-copied .cell { animation: cellLit .62s ease calc(var(--i) * .09s) both; }

.code-hint { margin: 10px 0 0; font-size: 13.5px; color: var(--muted); }
#codeHint.is-copied { color: var(--accent); }
.hint-click { display: none; }
@media (hover: hover) {
  #codeHint:not(.is-copied) { display: none; }
  .hint-click { display: inline; }
  #codeHint.is-copied ~ .hint-click { display: none; }
}

@keyframes nudge {
  0%, 100% { transform: translateX(0); }
  22% { transform: translateX(-5px); }
  62% { transform: translateX(5px); }
}
.cells.is-nudged { animation: nudge .32s ease; }
.cells.is-nudged .cell { border-color: var(--accent); }

/* ------------------------------------------------- симулятор просадки */

.split { display: grid; gap: 28px; }

.sim {
  padding: 20px 18px 18px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
/* Переход в красное — резкий. Правило срабатывает мгновенно, и ощущение
   должно быть таким же; плавность здесь была бы враньём про механику. */
.sim, .sim-big, .sim-verdict { transition: none; }
.sim.is-dead { border-color: var(--danger); background: var(--danger-bg); }
.sim h3 { margin-bottom: 16px; }

.sim-readout { display: flex; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.sim-right { text-align: right; }
.sim-label { display: block; font-size: 12px; letter-spacing: .04em; text-transform: uppercase; color: var(--dim); }
.sim-big { display: block; margin-top: 2px; font-size: 26px; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.sim.is-dead .sim-big { color: var(--danger); }

#simCanvas { display: block; width: 100%; height: 128px; }

.sim-slider { display: block; margin: 8px 0 14px; }
.sim-slider .sim-label { margin-bottom: 10px; }

/* Высота 44 px — цель нажатия на телефоне не может быть меньше.
   Дорожка при этом остаётся тонкой: её рисует ::-webkit-slider-runnable-track. */
input[type="range"] { -webkit-appearance: none; appearance: none; width: 100%; height: 44px; background: transparent; cursor: pointer; margin: 0; }
input[type="range"]::-webkit-slider-runnable-track { height: 4px; border-radius: 2px; background: var(--line); }
input[type="range"]::-moz-range-track { height: 4px; border-radius: 2px; background: var(--line); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 26px; height: 26px; margin-top: -11px; border-radius: 50%;
  background: var(--accent); border: 3px solid var(--bg); box-shadow: 0 0 0 1px var(--accent);
}
input[type="range"]::-moz-range-thumb { width: 22px; height: 22px; border-radius: 50%; background: var(--accent); border: 3px solid var(--bg); }
.sim.is-dead input[type="range"]::-webkit-slider-thumb { background: var(--danger); box-shadow: 0 0 0 1px var(--danger); }
.sim.is-dead input[type="range"]::-moz-range-thumb { background: var(--danger); }

.sim-verdict { font-weight: 700; margin: 0 0 12px; color: var(--ok); }
.sim.is-dead .sim-verdict { color: var(--danger); }

/* ------------------------------------------------------------ развилка */

.fork-section { padding: 56px 0 64px; }
.fork-in { text-align: center; }
.fork-in h2 { margin-bottom: 24px; }
.fork { display: grid; gap: 14px; max-width: 760px; margin: 0 auto; text-align: left; }
.card { padding: 22px 20px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); }
.card p { color: var(--muted); font-size: 15px; }
.card .btn { margin-top: 4px; }
/* Последний экран — единственный, где основное действие выделено заливкой. */
.card-ready { border-color: var(--accent-line); background: var(--accent-tint); }
/* Второй цвет бренда получает смысл: оранжевый — действие, фиолетовый —
   разговор. Кромка 1 px, .6 слева → 0 справа. Статика. */
.card { position: relative; }
.card::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 1px;
  border-radius: var(--radius) var(--radius) 0 0;
  pointer-events: none;
}
.card-ready::before { background: linear-gradient(to right, rgba(245, 165, 94, .85), rgba(245, 165, 94, 0)); }
.card-ask::before { background: linear-gradient(to right, rgba(184, 91, 214, .95), rgba(184, 91, 214, 0)); }

/* -------------------------------------------------------------- подвал */

footer { padding: 40px 0 48px; border-top: 1px solid var(--line-soft); }

/* Две строки мелким шрифтом, обычным текстом: ни модалки, ни спойлера. */
.foot-line { color: var(--dim); font-size: 13px; line-height: 1.6; margin: 0 0 4px; }
.foot-line:last-child { margin-bottom: 0; }

/* ------------------------------------------------------ липкая кнопка */

/* ~56 px плюс безопасная зона (D-117). */
.sticky {
  position: fixed; inset: auto 0 0 0; z-index: 30;
  display: flex; align-items: center; gap: 12px;
  padding: 6px var(--pad) calc(6px + env(safe-area-inset-bottom));
  background: var(--bg);
  border-top: 1px solid var(--line);
  transform: translateY(110%);
  transition: transform .22s ease;
}
.sticky.is-shown { transform: translateY(0); }
.sticky .btn { flex: 1; min-height: 44px; padding: 8px 16px; font-size: 15px; }
.sticky-alt {
  flex: none; display: inline-flex; align-items: center;
  min-height: 44px; padding: 0 6px;
  color: var(--muted); font-size: 14px; font-weight: 700; text-decoration: none;
}
.sticky-alt:hover { color: var(--text); }

/* Телефон: первый экран плотнее (D-117) — под офферное добавились факты, и
   чат уехал вниз. Подзаголовок 16 px, отступы меньше; тап-цели не трогаем. */
@media (max-width: 767px) {
  .topbar { padding-top: 10px; }
  .hero { padding-top: 18px; }
  .lede { font-size: 16px; line-height: 1.5; margin-bottom: 18px; }
  .hero-facts { margin-top: 10px; }
  .hero-ask { margin-top: 14px; }
}

/* ═══ порядок на телефоне и планшете (D-117): чат → «Cara ambilnya» → $1.000 →
   факты → рынки. `order`, а не разметка: десктоп и краулер — как раньше. */
@media (max-width: 1023px) {
  main { display: flex; flex-direction: column; }
  main > .hero { order: 0; }
  main > .ticker { order: 1; }
  main > #ambil { order: 2; }
  main > #kode { order: 3; }
  main > #free { order: 4; }
  main > #what { order: 5; }
  main > #rules { order: 6; }
  main > .fork-section { order: 7; }
  main > footer { order: 8; }
}

/* ══════════════════════════════════════════════════ планшет: 768px+ */

@media (min-width: 768px) {
  :root { --pad: 32px; }
  .facts-grid { grid-template-columns: repeat(4, 1fr); gap: 14px; }
  .fact { padding: 18px 16px; }
  .fork { grid-template-columns: 1fr 1fr; }
}

/* ══════════════════════════════ десктоп: отдельная раскладка, 1024px+ */

@media (min-width: 1024px) {
  .price-line { top: 12rem; height: 16rem; }
  section { padding: 76px 0; }
  .hero { padding-top: 56px; padding-bottom: 84px; }

  h1 { font-size: clamp(38px, 3.6vw, 50px); }
  h2 { font-size: clamp(26px, 2.2vw, 32px); }

  /* Сетка 12 столбцов, контейнер 1200. Первый экран — две колонки:
     слева текст на шесть столбцов, справа телефон на пять. */
  .hero-grid {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 40px;
    align-items: center;
  }
  /* Две колонки, а не двенадцать: правая — карточка чата, и её ширина
     задана самой колонкой, а не долей сетки. 420–480 — полоса, в которой
     ответ модели читается без переносов по два слова и при этом остаётся
     место под заголовок и кнопку. */
  .hero-grid { grid-template-columns: minmax(0, 1fr) clamp(420px, 33vw, 480px); gap: 48px; }
  /* Верхом: заголовок не едет вслед за растущим чатом (D-117). */
  .hero-grid { align-items: start; }
  .hero-ask { margin-top: 0; }
  .chat.is-open { height: clamp(var(--chat-h0, 320px), 60svh, 560px); }
  .chat-resume .chat { height: clamp(320px, 60svh, 560px); }

  .btn-primary, .btn-ghost { width: auto; min-width: 240px; }

  /* Полоса «бесплатно»: сумма слева, текст справа. */
  .band { padding: 84px 0; }
  .band-grid { grid-template-columns: repeat(12, 1fr); gap: 40px; align-items: start; }
  .band-lead { grid-column: 1 / span 4; position: sticky; top: 40px; }
  .band-body { grid-column: 6 / span 7; }

  /* Правила слева, симулятор справа и крупно. */
  .split { grid-template-columns: repeat(12, 1fr); gap: 40px; align-items: start; }
  .split-a { grid-column: 1 / span 5; }
  .split-b { grid-column: 7 / span 6; }
  .sim { padding: 26px 24px 24px; }
  #simCanvas { height: 160px; }
  .sim-big { font-size: 32px; }

  /* Шаги слева, телефон справа. Рамка — ровно та же, что в первом экране,
     300×428: компонент один, и на странице он один и тот же на глаз, а не
     «похожий». Липнет обёртка: колонка растянута на высоту ряда и центрирует
     телефон, пока ряд короче вьюпорта; когда ряд длиннее, телефон прилипает и
     стоит по центру экрана — «на уровне шагов» на любой высоте. */
  .guide { grid-template-columns: minmax(0, 1fr) minmax(300px, 380px); gap: 48px; align-items: stretch; }
  .guide-steps { grid-column: 1; grid-row: 1; gap: 12px; }
  .guide-phone {
    grid-column: 2; grid-row: 1;
    position: static; top: auto;
    align-self: stretch;
    display: flex; flex-direction: column; justify-content: center;
  }
  .guide-stick { position: sticky; top: max(40px, calc((100dvh - 434px) / 2)); }
  .guide-phone .phone { --phone-w: 300px; --phone-h: 428px; margin: 0 auto; }

  /* Кадр слева, рамка справа, обе высотой 428: рамка на десктопе ровно та
     же, что в инструкции — 300×428, — и подгонять под неё надо кадр, а не
     наоборот. Разная высота у соседей читается как две разные мысли. */
  .trade { grid-template-columns: repeat(12, 1fr); gap: 40px; align-items: center; }
  .trade-copy { grid-column: 1 / span 5; }
  .trade-shots {
    grid-column: 7 / span 6;
    grid-template-columns: minmax(0, 1fr) auto; gap: 20px; align-items: start;
  }
  .trade-shots img { height: 428px; }
  .trade-device .phone { --phone-w: 300px; --phone-h: 428px; }


  .fork-section { padding: 96px 0 104px; }
  .fork { gap: 20px; }
  .card { padding: 28px 26px; }
  .card .btn { width: 100%; }

  /* Липкая кнопка — механика узкого экрана. На десктопе кнопки и так видны. */
  .sticky { display: none; }
}

@media (min-width: 1440px) {
  :root { --pad: 40px; }
}

/* ------------------------------------------------------------ движение */

/* Первый экран: заголовок, подзаголовок, кнопка и строка — по 60 мс друг за
   другом. */
.enter { opacity: 0; transform: translateY(12px); animation: rise .42s cubic-bezier(.22,.7,.3,1) forwards; }
.enter-2 { animation-delay: .06s; }
.enter-3 { animation-delay: .12s; }
.enter-4 { animation-delay: .18s; }
@keyframes rise { to { opacity: 1; transform: none; } }

.reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .42s cubic-bezier(.22, .61, .36, 1), transform .42s cubic-bezier(.22, .61, .36, 1);
}
.reveal.is-in { opacity: 1; transform: none; }

/* Стаггер — только через :nth-child. Индекс в атрибуте `style` заблокировала
   бы CSP (`style-src 'self'`), и это уже случалось с ячейками промокода. */
.guide-steps li:nth-child(2) { transition-delay: .06s; }
.guide-steps li:nth-child(3) { transition-delay: .12s; }
.guide-steps li:nth-child(4) { transition-delay: .18s; }

/* Без JS видно всё: краулер Meta скрипты не выполняет, и страница, чей текст
   появляется только после скрипта, приезжает на модерацию пустой. */
.no-js .reveal, .no-js .enter { opacity: 1; transform: none; animation: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  /* Коннектор доезжает сразу и целиком: у scroll-timeline нет длительности,
     которую можно обнулить универсальным правилом выше. */
  .guide-steps::before { animation: none; scale: 1 1; }
  .guide-steps::after { display: none; }
  .gstep.is-on::before { display: block; }
  .cells::before { animation: none; opacity: .18; }
  .enter { opacity: 1; transform: none; }
  .reveal { opacity: 1; transform: none; }
  #bg { animation: none; }
  /* Чат при reduced-motion: скрипт сам оставляет только прозрачность. */
  .chat .ask-chip:active, .chat .chat-send:active, .chat .chat-cta:active { transform: none; }
  /* Страховка проявления — не движение, и её задержку общее правило выше
     обнулять не должно. */
  .chat-resume #chatFlow > .chat-turn:first-child,
  .chat-resume #chatChips { animation-delay: 3s !important; }
  .sticky { transform: translateY(0); }
  .sticky:not(.is-shown) { display: none; }
}

/* ---------------------------- передача во встроенном браузере соцсети */

/* Экран, который видит человек из ленты Facebook: страница t.me внутри
   WebView заканчивалась бы кнопкой «OPEN IN TELEGRAM» на английском, а здесь
   он видит своё и один тап. Разметку отдаёт app/api/landing.py. */
.handoff {
  max-width: 460px;
  margin: 0 auto;
  /* dvh, а не vh: на Android при скрытии адресной строки vh пересчитывается
     и блок подпрыгивает. */
  padding: 20dvh 24px 40px;
  text-align: center;
}
.handoff h1 { font-size: 26px; margin-bottom: 10px; }
.handoff p { color: var(--muted); margin-bottom: 26px; }
.handoff .btn { width: 100%; }
.handoff .btn + .btn { margin-top: 12px; }

/* Появление знака в счётчике: разряд встаёт на место, уже набранное молчит. */
.amount-value .pop { display: inline-block; animation: popIn .26s ease both; }
@keyframes popIn { from { opacity: 0; transform: translateY(.18em); } }

/* ══════════════════════════════════════ первый экран: фон и движение */

/* Декорации лежат под контентом и не участвуют в раскладке: LCP-элемент —
   заголовок — рисуется сразу из HTML и на входе не анимируется вовсе. */
/* Один слой на всю страницу вместо свечения, принадлежащего секции.
   Раньше пятна жили внутри `section.hero` с `overflow: hidden`, и граница
   секции резала их прямым краем поперёк экрана. Такой край не маскируется —
   его можно только не создавать.

   `fixed`, а не `absolute` во всю высоту документа: слой размером с вьюпорт
   не перерисовывается при прокрутке и не зависит от того, сколько на странице
   контента. */
.fx {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  contain: strict;
}
.hero-grid { position: relative; z-index: 1; }

/* Два пятна. Размытие ЗАПЕЧЕНО в сам градиент — `filter: blur` на движущемся
   элементе пересчитывается каждый кадр и съедает телефон. */
/* Пороги видимости — правило, не вкус: любой декор на #0a0a0c обязан
   отличаться от фона не меньше чем на 6 % яркости. Проверка — скриншот при
   половинной яркости: не нашёлся глазами за секунду — его нет. Отсюда все
   числа ниже. */
.aura {
  position: absolute;
  width: 46rem; height: 46rem;
  border-radius: 50%;
}
.aura-1 {
  top: -18rem; left: -12rem;
  background: radial-gradient(circle closest-side, rgba(245, 165, 94, .30), rgba(245, 165, 94, .09) 55%, rgba(245, 165, 94, 0) 74%);
  animation: aura1 26s ease-in-out infinite alternate;
}
/* Второе пятно тоже привязано к верху, а не к низу. Привязка к `bottom`
   стоила 0.02 CLS: высота первого экрана дорастает после подмены шрифта, и
   пятно на 46rem уезжало вместе с нижней границей. Смещения не видно —
   но площадь у пятна огромная, и в метрику оно попадало целиком. */
.aura-2 {
  top: 22rem; right: -14rem;
  background: radial-gradient(circle closest-side, rgba(184, 91, 214, .24), rgba(184, 91, 214, .08) 55%, rgba(184, 91, 214, 0) 74%);
  animation: aura2 31s ease-in-out infinite alternate;
}
@keyframes aura1 { to { transform: translate3d(6rem, 3rem, 0); } }
@keyframes aura2 { to { transform: translate3d(-5rem, -3rem, 0); } }

/* Линия цены. Никаких данных с претензией на котировки и никаких осей:
   это форма, а не график. Рисуется один раз, дальше очень медленно едет. */
/* Привязка к верху и абсолютная высота, а не `bottom: 8%` и `height: 42%`.
   Проценты считались от высоты первого экрана, а она у нас не постоянна —
   и линия на 200% ширины уезжала вместе с ней. Lighthouse ловил ровно это:
   0.0162 CLS, три прогона подряд, всегда один и тот же элемент. Ауру то же
   самое лечило тем же способом. Числа взяты с домена: на 390 px линия стояла
   на 22.4rem высотой 18.8rem, на 1440 px — 19.1rem и 16.0rem. */
.price-line {
  position: absolute;
  left: 0; top: 14rem;
  width: 200%; height: 19rem;
  opacity: 1;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0, 0, 0, 0) 88%);
  mask-image: linear-gradient(to bottom, #000 0%, rgba(0, 0, 0, 0) 88%);
  animation: lineDrift 90s linear infinite;
}
.price-line path {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.5;
  stroke-linecap: round;
  opacity: .55;
  stroke-dasharray: 1400;
  stroke-dashoffset: 1400;
  animation: drawLine 1.2s cubic-bezier(.22, .61, .36, 1) .15s forwards;
}
.price-line .glow { stroke-width: 6; opacity: .12; }
/* Телефон: линия ниже, за карточкой чата, и прозрачнее — текст не пересекает
   (D-117). `svh` не меняется при скрытии панели браузера. */
@media (max-width: 1023px) {
  .price-line { top: calc(100svh - 7.5rem); height: 7rem; opacity: .5; }
}
@keyframes drawLine { to { stroke-dashoffset: 0; } }
@keyframes lineDrift { to { transform: translate3d(-50%, 0, 0); } }

/* ═══════════════════════════════ полоса прокрутки и линии между секциями */

/* Единственные две вещи на scroll-timeline: у обеих смысл — прогресс.
   Поддержки нет — полосы просто нет, и это нормально. */
.progress {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  z-index: 50;
  pointer-events: none;
}
@supports (animation-timeline: scroll()) {
  .progress {
    animation: scaleIn linear both;
    animation-timeline: scroll(root block);
  }
}
@keyframes scaleIn { to { transform: scaleX(1); } }

section { position: relative; }
/* Линия рисуется от центра при входе секции. Без поддержки она просто есть. */
section::before {
  content: "";
  position: absolute;
  top: -1px; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--line) 22%, var(--line) 78%, transparent);
}
section.hero::before, .band::before { content: none; }
@supports (animation-timeline: view()) {
  section::before {
    transform: scaleX(0);
    animation: scaleIn linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 16%;
  }
}

/* ══════════════════════════════════════════ бегущая строка инструментов */

.ticker {
  overflow: hidden;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
  padding: 12px 0;
  /* Место зарезервировано: строка не сдвигает ничего при появлении. */
  height: 46px;
}
.ticker-track {
  display: flex;
  width: max-content;
  gap: 2.5rem;
  animation: marquee 40s linear infinite;
  will-change: transform;
}
.ticker:hover .ticker-track { animation-play-state: paused; }
.ticker-item {
  display: inline-flex; align-items: center; gap: .55rem;
  color: var(--muted);
  font-size: 13.5px; font-weight: 700; letter-spacing: .04em;
  white-space: nowrap;
}
.ticker-item::after {
  content: "";
  width: 4px; height: 4px; border-radius: 50%;
  background: var(--accent);
  opacity: .5;
}
@keyframes marquee { to { transform: translate3d(-50%, 0, 0); } }

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

/* ══════════════════════════════ сегментированный переключатель ×2 */

/* Один контрол на два применения: язык в шапке и путь получения в
   инструкции. Общее — капсула, подложка, ячейка, цель нажатия. Разное —
   роль (radiogroup выбирает значение, tablist показывает панель) и то, что
   лежит внутри ячейки: флаг или подпись. Второй такой контрол не пишем: две
   одинаковые на вид капсулы с разным поведением — это уже два разных
   контрола, и человек об это спотыкается. */

/* Одна капсула на две ячейки. `1fr 1fr`, а не `auto auto`: ячейки обязаны
   быть равны, иначе подложка, которая ездит ровно на свою ширину, промахнётся
   мимо второй — подписи `ID` и `EN` одинаковы сегодня и не обязаны быть
   одинаковыми завтра. */
.seg {
  position: relative;
  display: inline-grid;
  grid-template-columns: 1fr 1fr;
  padding: 3px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .045);
  border: 1px solid var(--line);
}

/* Снимок кроссфейда языкового переключателя не касается: он анимируется сам,
   подложкой. Без своего имени он попал бы в снимок root и проиграл бы обе
   анимации сразу — свою и чужую. Имя принадлежит только шапке: двух
   одинаковых `view-transition-name` в документе быть не может, второй отменил
   бы переход целиком. */
.langs { view-transition-name: langs; }

/* Подложка. Позиция и масштаб едут по РАЗНЫМ свойствам — `translate` и
   `scale`, а не два `transform` на одном элементе: второй transform затирает
   первый целиком, и либо подложка не едет, либо не пружинит. */
.seg-thumb {
  position: absolute;
  inset: 3px 50% 3px 3px;
  border-radius: 999px;
  background: var(--accent-tint);
  border: 1px solid var(--accent);
  pointer-events: none;
  translate: 0 0;
  /* Перелёт в конце (1.56 по второй контрольной точке) — это и есть ощущение
     пружины. Без него подложка просто доезжает. */
  transition: translate .32s cubic-bezier(.34, 1.56, .64, 1);
}
/* Правая ячейка. Селектор на каждый контрол свой, объявление одно: атрибут
   называет выбранное ЗНАЧЕНИЕ, а не его номер, — по имени его подменяет
   сборка английской страницы, и общий числовой индекс сломал бы там
   `_replace_once`. */
.langs[data-lang-active="en"] .seg-thumb,
.guide-tabs[data-tab-active="telegram"] .seg-thumb { translate: 100% 0; }
/* Сплющивание на ходу. Отдельным свойством, поэтому с `translate` не спорит. */
.seg-thumb.is-moving { animation: thumbSquash .32s cubic-bezier(.34, 1.56, .64, 1); }
@keyframes thumbSquash { 50% { scale: 1.08 .94; } }

.seg-btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  background: none; border: 0; color: var(--dim);
  font: inherit; font-size: 13px; font-weight: 700;
  border-radius: 999px; padding: 0 14px; min-height: 38px;
  cursor: pointer;
  transition: color .18s ease, scale .09s ease;
}
/* Цель нажатия — 46 px по высоте, при том что капсула не раздувается:
   площадь добирается невидимой областью кнопки, а не её видимым размером. */
.seg-btn::before { content: ""; position: absolute; inset: -4px 0; }
/* Две роли — два атрибута: `aria-checked` у radiogroup, `aria-selected` у
   tablist. Вид один, поэтому правило одно. Ключ на атрибуте, а не на классе:
   класс пришлось бы синхронизировать с ARIA вручную, и он бы разъехался. */
.seg-btn[aria-checked="true"],
.seg-btn[aria-selected="true"] { color: var(--text); }
.seg-btn:active { scale: .96; }
.seg-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.lang-code, .seg-label { line-height: 1; }
/* Подпись длиннее ячейки не расталкивает капсулу: трек `minmax(0, 1fr)`
   ужимается ниже min-content, подпись обрезается. Без этого `Lewat Telegram`
   на 320 px растянул бы капсулу шире `.wrap` и дал бы горизонтальную
   прокрутку. */
.seg-label { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ── путь получения: тот же контрол над списком шагов ─────────────────── */

/* Во всю ширину колонки, но не шире 340 px: подписи здесь словами, а не кодом
   языка, и капсула на всю страницу читалась бы как панель, а не как выбор из
   двух. Влево, по оси заголовка и списка шагов. */
.guide-tabs {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  width: 100%; max-width: 340px;
  margin: 0 0 18px;
}
/* Поля уже, чем у языкового: там в ячейке две буквы, здесь два слова. */
.guide-tabs .seg-btn { padding: 0 10px; }

/* Скрытая панель прячется атрибутом `hidden`, но `display: grid` у списка
   шагов сильнее UA-правила `[hidden] { display: none }` — без этой строки
   обе панели остались бы на экране одновременно. */
.guide-steps[hidden] { display: none; }

/* ═══════════════════════════════════════════ флаги в переключателе языка */

/* Инлайновый SVG, не эмодзи: у Windows нет глифов флагов, и вместо флага он
   рисует две буквы регионального индикатора — «ID» вместо флага Индонезии. */
.lang-flag {
  display: block;
  width: 16px; height: 12px;
  border-radius: 2px;
  flex: none;
  /* Единственный `filter` на странице. Он разовый, 180 мс, на элементе 16×12
     и вне скролл-цикла — в кадры его не тащим. */
  transition: opacity .18s ease, filter .18s ease;
}
.lang[aria-checked="false"] .lang-flag { opacity: .45; filter: saturate(.3); }
.lang[aria-checked="true"] .lang-flag { opacity: 1; filter: saturate(1); }
.lang-flag.is-popped { animation: flagPop .26s ease; }
@keyframes flagPop { 50% { scale: 1.14; } }

/* ══════════════════════════════════════════ подложки нижних секций */

/* Сетка — фон графика, а не украшение ради украшения. Один тайл через
   repeating-linear-gradient, ноль байт JS, контраст на пределе видимости.
   Маска гасит её к краям секции: без маски у сетки был бы прямоугольный
   контур, то есть та же прямая линия, от которой мы уходим.

   Достаётся не каждой секции: полоса, промокод и развилка остаются голыми.
   Однородно украшенная страница читается как шумная, а не как богатая. */
.grid-bg { position: relative; }
.grid-bg::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: -1;
  background-image:
    repeating-linear-gradient(to right, rgba(255, 255, 255, .13) 0 1px, rgba(255, 255, 255, 0) 1px 72px),
    repeating-linear-gradient(to bottom, rgba(255, 255, 255, .13) 0 1px, rgba(255, 255, 255, 0) 1px 72px);
  -webkit-mask-image: radial-gradient(115% 75% at 50% 50%, #000 30%, rgba(0, 0, 0, 0) 100%);
  mask-image: radial-gradient(115% 75% at 50% 50%, #000 30%, rgba(0, 0, 0, 0) 100%);
}

/* Уровень цены на графике: одна горизонтальная линия коротким пунктиром на
   38 % высоты. Статика, ноль анимации. */
.grid-bg::after {
  content: "";
  position: absolute; left: 0; right: 0; top: 38%; height: 1px;
  pointer-events: none;
  z-index: -1;
  background: repeating-linear-gradient(to right,
    rgba(245, 165, 94, .42) 0 6px, rgba(245, 165, 94, 0) 6px 14px);
  -webkit-mask-image: linear-gradient(to right, rgba(0, 0, 0, 0), #000 12%, #000 88%, rgba(0, 0, 0, 0));
  mask-image: linear-gradient(to right, rgba(0, 0, 0, 0), #000 12%, #000 88%, rgba(0, 0, 0, 0));
}

/* Правила — не вторая копия сетки: горизонтальные линии-леджер, таблица на
   линейке. Маска та же радиальная. */
.ledger-bg { position: relative; }
.ledger-bg::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: -1;
  background-image: repeating-linear-gradient(to bottom,
    rgba(255, 255, 255, .15) 0 1px, rgba(255, 255, 255, 0) 1px 48px);
  -webkit-mask-image: radial-gradient(115% 75% at 50% 50%, #000 30%, rgba(0, 0, 0, 0) 100%);
  mask-image: radial-gradient(115% 75% at 50% 50%, #000 30%, rgba(0, 0, 0, 0) 100%);
}

/* ── четыре шага: линия-коннектор и крупные номера ──────────────────── */

.guide-steps { position: relative; counter-reset: step; }
/* Линия проходит по центру кружков с номерами: 1 px рамки карточки + 16 px
   её padding + половина кружка 28 px. */
.guide-steps::before {
  content: "";
  position: absolute;
  left: 31px; top: 24px; bottom: 24px; width: 1px;
  background: rgba(245, 165, 94, .55);
  scale: 1 0;
  transform-origin: top center;
  transition: scale .7s ease;
}
.reveal.is-in .guide-steps::before { scale: 1 1; }
@supports (animation-timeline: view()) {
  .guide-steps::before {
    transition: none;
    animation: connector linear both;
    animation-timeline: view();
    animation-range: entry 25% cover 55%;
  }
}
@keyframes connector { to { scale: 1 1; } }

/* Точка Ø8 на коннекторе едет вниз по мере прокрутки — «прогресс» буквально.
   Псевдоэлемент растянут на всю длину линии, а точка нарисована в его верхнем
   краю: тогда `translate: 0 calc(100% - 8px)` — это ровно длина линии, какой
   бы ни была высота списка, и ни одного пикселя считать не надо. Двигается
   только translate. */
.guide-steps::after {
  content: "";
  position: absolute;
  left: 27px; top: 24px; bottom: 24px; width: 8px;
  pointer-events: none;
  background: radial-gradient(circle at 4px 4px, var(--accent) 3.4px, rgba(245, 165, 94, 0) 4.2px) top / 8px 8px no-repeat;
  translate: 0 0;
  display: none;
}
@supports (animation-timeline: view()) {
  .guide-steps::after {
    display: block;
    animation: dotRide linear both;
    animation-timeline: view();
    animation-range: entry 25% cover 55%;
  }
}
@keyframes dotRide { to { translate: 0 calc(100% - 8px); } }
/* Фолбэк без scroll-timeline: та же точка стоит у активного шага. Под reduce
   — тоже она, а едущая скрыта: точка обязана быть неподвижной. */
.gstep.is-on::before {
  content: "";
  position: absolute; left: 26px; top: 25px; width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--accent);
  display: none;
}
@supports not (animation-timeline: view()) {
  .gstep.is-on::before { display: block; }
}

.guide-steps li { counter-increment: step; }
/* Номер стоит за содержимым карточки: только типографика, никакой графики. */
.gstep::after {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  right: 10px; top: -14px;
  font-size: clamp(120px, 12vw, 150px); font-weight: 700; letter-spacing: -.05em; line-height: 1;
  color: rgba(245, 165, 94, .14);
  pointer-events: none;
  z-index: 0;
}
.gstep { position: relative; overflow: hidden; }
.gstep-num, .gstep-body { position: relative; z-index: 1; }

/* ═════════════════════════════════════════════════ микровзаимодействия */

/* Нажатие — вне hover-медиазапроса намеренно. На телефоне нет ни курсора, ни
   наведения, и это единственная тактильная реакция, которую увидит вся
   индонезийская аудитория. Всё остальное ниже — премия тем, у кого мышь. */
.btn-ghost:active, .sticky-alt:active { scale: .98; }
.gstep:active, .card:active { scale: .99; }
.btn, .btn-ghost, .sticky-alt, .gstep, .card {
  transition: translate .2s ease, scale .09s ease, color .18s ease,
    background-color .18s ease, border-color .2s ease;
}
/* Отступ вручную: кнопка — inline-flex, и пробел между текстом и стрелкой
   в разметке схлопывается как межэлементный. */
.btn-arrow { display: inline-block; margin-left: .26em; transition: translate .2s ease; }

/* Иконка копирования. Обводкой, а не заливкой: пятнадцать пикселей заливки
   на тёмном превращаются в пятно. */
.copy-ic {
  width: 15px; height: 15px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
  transition: rotate .3s ease;
}
.code-hint { display: inline-flex; align-items: center; gap: 7px; }

@keyframes sheen {
  from { translate: -120% 0; opacity: 0; }
  25% { opacity: 1; }
  to { translate: 120% 0; opacity: 0; }
}
@keyframes wobble { 30% { rotate: -6deg; } 70% { rotate: 6deg; } }

/* ── смена языка целиком ──────────────────────────────────────────────── */

/* 200 мс: короче — мигание, длиннее — заметная пауза перед тем, как текст
   снова можно читать. */
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 200ms; }

/* Переключатель из кроссфейда вынут. Гасить приходится вчетвером: у группы
   своя анимация геометрии, у пары изображений — изоляция под `plus-lighter`,
   у старого и нового снимков — свои fade-out и fade-in из UA-таблицы. Оставить
   что-то одно значит получить либо двойную засветку, либо старый снимок
   поверх нового. */
::view-transition-group(langs) { animation: none; }
::view-transition-image-pair(langs) { isolation: auto; }
::view-transition-old(langs) { animation: none; opacity: 0; }
::view-transition-new(langs) { animation: none; opacity: 1; mix-blend-mode: normal; }

/* Фолбэк там, где View Transitions нет, — а это ровно встроенные браузеры
   соцсетей, через которые пойдёт весь платный трафик. Гасим, подменяем текст,
   поднимаем обратно с четырьмя пикселями подъёма. */
.lang-swap-out { opacity: 0; transition: opacity 90ms ease; }
.lang-swap-in { opacity: 0; translate: 0 4px; }
.lang-swap-in.is-running {
  opacity: 1; translate: 0 0;
  transition: opacity 180ms ease, translate 180ms ease;
}

/* ═══════════════════════════════════ пара кадров: где нажать промокод */

.promo-shots { display: grid; gap: 12px; margin: 18px 0 0; }
.promo-shot { margin: 0; }
/* Ширина в пикселях, а не в процентах: от неё считается `--u`, и панель
   внутри должна знать свой масштаб. Пропорция та же, что у рамки в шапке. */
.promo-shot .phone { --phone-w: 208px; width: var(--phone-w); max-width: 100%; margin: 0; }
.promo-shot .phone-screen { height: auto; aspect-ratio: 1179 / 1716; }
.promo-shot .phone-screen::after { content: none; }
.promo-shot figcaption { margin-top: 8px; color: var(--dim); font-size: 13px; }

@media (min-width: 620px) {
  .promo-shots { grid-template-columns: 1fr 1fr; gap: 16px; }
}

@media (min-width: 1024px) {
  /* Промокод — по центру и крупнее. Порядок в DOM тот же, меняется только
     раскладка: номер шага над заголовком, рейл слева гаснет, ячейки 88–96 px,
     два кадра рядом до 460 px каждый.

     Блок стоит здесь, а не в общем десктопном выше, намеренно: базовые правила
     промо и правило для 620 px объявлены позже общего блока, и при равной
     специфичности перекрывали его. Именно так пара кадров получала
     `1fr 1fr` с зазором 16 px, а телефон — `max-width: 320px; margin: 0`:
     кадр прижимался к левому краю своей половины, подпись центрировалась
     по половине, и ось секции расходилась на сотню пикселей. */
  #kode .wrap { max-width: 1120px; }
  .sequence { max-width: none; }
  .seq { display: grid; justify-items: center; text-align: center; gap: 0; padding: 0 0 56px; }
  .seq:not(:last-child)::after { content: none; }
  .seq-num { width: 36px; height: 36px; font-size: 15px; margin-bottom: 14px; }
  .seq-body { width: 100%; display: grid; justify-items: center; }
  .seq-body h3 { font-size: 24px; }
  .cells { max-width: 520px; gap: 14px; margin: 18px auto 0; }
  .cell { max-width: 96px; font-size: 26px; }
  .cells::before { inset: -44px -56px; }
  .code-hint { margin-top: 14px; }
  /* Пара кадров — одна единица по оси: две ячейки до 460 px, зазор 40,
     всё вместе по центру. Кадр и подпись — в одной ячейке, у обоих одна
     ось, верхние кромки на одной высоте. */
  .promo-shots {
    grid-template-columns: repeat(2, minmax(0, 300px));
    justify-content: center; align-items: start;
    gap: 40px; width: 100%; margin-top: 28px;
  }
  .promo-shot { text-align: center; justify-self: center; width: 100%; }
  .promo-shot .phone { --phone-w: 240px; margin: 0 auto; }
  .promo-shot figcaption { margin-top: 12px; font-size: 14px; }
  .seq-body .fine { max-width: 640px; text-align: center; margin-top: 18px; }
  .seq-body .btn { min-width: 320px; margin-top: 8px; }
}

/* Подтверждение держится 1,2 с и гаснет — короткая вспышка, не состояние. */
.cells.is-just-copied .cell { border-color: var(--accent); }

