/* RIVENO — сцены главной страницы.
 *
 * Отдельный файл поверх riveno.css: там живёт система (токены, полосы,
 * типографика, окна со снимками), здесь — только сцены, которые ведут
 * человека по истории. Токены не дублируются, все значения берутся оттуда.
 *
 * Правило движения то же, что и во всём проекте: двигаются transform,
 * opacity и clip-path; кривая одна; при prefers-reduced-motion всё
 * останавливается, но смысл сцены остаётся видимым.
 */

/* ═══════════════════════ Общее для сцен ═══════════════════════ */

/* Прогресс прокрутки сцены скрипт кладёт в --p (0…1). Всё остальное
   считается от него прямо в CSS — так нет ни одной анимации, которая
   живёт своей жизнью в отрыве от того, где человек находится. */
[data-scene] { --p: 0; }

.scene-rail {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: grid;
  align-content: center;
  overflow: clip;
}

.scene-title {
  font-size: clamp(30px, 5.4vw, 68px);
  line-height: 1.04;
  letter-spacing: -.02em;
  font-weight: 700;
  text-wrap: balance;
}

.scene-lead {
  margin-top: 20px;
  font-size: clamp(18px, 1.8vw, 23px);
  line-height: 1.4;
  color: var(--ink-mid);
  max-width: 52ch;
}

/* Крупная типографическая полоса — пауза между сценами */
.statement {
  padding-block: clamp(90px, 13vw, 170px);
  text-align: center;
}
.statement__text {
  font-size: clamp(34px, 7vw, 104px);
  line-height: 1.02;
  letter-spacing: -.028em;
  font-weight: 700;
  margin-inline: auto;
  max-width: 16ch;
}
.statement__text span { display: block; }
.statement__text .dim { color: var(--hairline); }

/* Мелкая надпись-указатель над заголовком сцены */
.scene-eyebrow {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* ═══════════════════════ 1. Первый экран ═══════════════════════ */

.stage {
  padding-top: clamp(48px, 7vw, 92px);
  padding-bottom: clamp(56px, 8vw, 110px);
  text-align: center;
  overflow: clip;
  position: relative;
  isolation: isolate;
}

/* Очень мягкий свет за окном продукта. Не свечение — приподнятость. */
.stage::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 34%;
  width: min(1500px, 130vw);
  aspect-ratio: 2 / 1;
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(0, 30, 80, .07), rgba(0, 30, 80, 0) 72%);
  pointer-events: none;
  z-index: 0;
}

.stage__content,
.stage__product {
  position: relative;
  z-index: 2;
}
.stage__h1 {
  font-size: clamp(46px, 9vw, 116px);
  line-height: .98;
  letter-spacing: -.028em;
  font-weight: 700;
  margin-inline: auto;
}
.stage__promise {
  margin: clamp(20px, 2.4vw, 30px) auto 0;
  font-size: clamp(21px, 2.6vw, 34px);
  line-height: 1.22;
  letter-spacing: -.014em;
  font-weight: 600;
  max-width: 20ch;
}
.stage__desc {
  margin: 18px auto 0;
  font-size: clamp(16px, 1.5vw, 19px);
  line-height: 1.5;
  color: var(--ink-mid);
  max-width: 56ch;
}
.stage__actions { margin-top: 30px; justify-content: center; }
.stage__reassure {
  margin-top: 16px;
  font-size: 14px;
  color: var(--ink-soft);
  letter-spacing: -.01em;
}

/* Сцена продукта: лёгкая перспектива и отклик на курсор.
   Углы намеренно крошечные — интерфейс должен читаться, а не «летать». */
.stage__product {
  margin-top: clamp(24px, 3.4vw, 48px);
}
/* Холодный отсвет под окном системы. Не свечение и не градиентная
   подложка — только намёк на то, что окно приподнято над листом.
   Лежит под кадром и не перехватывает указатель. */
.stage__product::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 8%;
  width: min(1080px, 92%);
  height: 78%;
  transform: translateX(-50%);
  background: radial-gradient(60% 60% at 50% 40%,
    rgba(0, 92, 210, .10), rgba(0, 92, 210, .04) 55%, rgba(0, 92, 210, 0) 78%);
  filter: blur(26px);
  pointer-events: none;
  z-index: 0;
}
.stage__product > * { position: relative; z-index: 1; }


/* Две ступени сжатия по высоте окна браузера. Ниже 940px (типичный
   ноутбук 1440×900) — умеренная, ниже 820px — плотная. Смысл один:
   верхний край работающей системы обязан попасть в первый экран. */
@media (max-height: 940px) and (min-width: 760px) {
  .stage { padding-top: clamp(28px, 3.4vw, 56px); }
  .stage__h1 { font-size: min(9vw, 12vh); }
  .stage__promise { margin-top: clamp(16px, 2vh, 26px); }
  .stage__product { margin-top: clamp(20px, 3vh, 40px); }
}

/* На невысоких экранах первый экран собирается плотнее: на 1280×720
   окно системы вообще не попадало в кадр, а оно здесь главное. Тексты
   те же, меняются только кегль и промежутки. */
@media (max-height: 820px) and (min-width: 760px) {
  .stage { padding-top: clamp(20px, 2.6vw, 34px); padding-bottom: clamp(28px, 4vw, 56px); }
  .stage__h1 { font-size: min(9vw, 10.4vh); }
  .stage__promise { font-size: min(2.6vw, 3.4vh); margin-top: clamp(12px, 1.6vh, 20px); }
  .stage__desc { font-size: clamp(15px, 1.9vh, 17px); margin-top: 12px; }
  .stage__actions { margin-top: 20px; }
  .stage__reassure { margin-top: 10px; }
  .stage__product { margin-top: clamp(18px, 2.4vh, 30px); }
}
/* Окно первого экрана стоит ровно и неподвижно. Наклон за курсором был
   уместен, пока внутри был снимок; в работающую систему целятся мышью,
   и уезжающая под курсором поверхность мешает. Заодно исчезает
   преобразование у предка — оно ломало position: fixed внутри. */
.stage__tilt { transform: none; }
.stage__product .viewer__window {
  /* Единственная тень такой силы на странице: окно системы
     действительно висит над листом, остальное — нет. */
  box-shadow: var(--lift-media);
}

/* ═══════════════════════ 2. Хаос ═══════════════════════ */

.chaos { position: relative; background: var(--canvas); }
.chaos__rail { position: sticky; top: 0; min-height: 100svh; display: grid; align-content: center; overflow: clip; }
.chaos__head { text-align: center; position: relative; z-index: 3; }
.chaos__head .scene-title { margin-inline: auto; max-width: 24ch; }
.chaos__head .scene-lead { margin-inline: auto; text-align: center; }

/* Поле роя и ядро в его центре. Высота и верхний отступ подобраны так,
   чтобы слово оказалось примерно на середине экрана: раньше оно
   собиралось на семидесяти процентах высоты, у нижнего края, и взгляд
   до него просто не доходил. */
.chaos__field {
  position: relative;
  /* Поле ровно той же формы, что и ролик, — тогда кадр заполняет его
     целиком и при этом ничего не срезается.

     Так вышло не сразу. Сначала высота была жёсткой (420 пикселей), и
     ролик 16:9 вписывался обрезкой — от него оставалась средняя
     полоса, а рамка внутри кадра в неё не попадала. Потом я включил
     contain: обрезка ушла, но по бокам появились пустые поля — кадр
     перестал заполнять блок.

     Верное решение — считать ШИРИНУ от высоты экрана. Поле держит
     пропорцию 16:9 и не вылезает за экран по вертикали, потому что
     118vh при этой пропорции дают высоту около двух третей экрана.
     Обрезать нечего, полей по бокам нет. */
  aspect-ratio: 16 / 9;
  /* Четвёртый предел: окно минус заголовок с подводкой сверху и
     подпись снизу (~300–380px). Без него панель выходила выше
     окна, и подпись под роликом срезалась на любом экране. */
  width: min(1360px, 94vw, 118vh, calc((100svh - var(--chaos-chrome, 380px)) * 16 / 9));

  margin-top: clamp(16px, 2vw, 28px);
  margin-inline: auto;
}

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

/* Ролик занимает поле сцены целиком, слово с подписью стоит поверх
   него. Кадр светлый, поэтому тёмный текст читается и без подложки;
   лёгкий белый вуаль всё же добавлен — в середине ролика объекты
   собираются как раз под строкой. */
.chaos__video {
  position: absolute;
  inset: 0;
  border-radius: var(--r-card);
  overflow: hidden;
  background: var(--canvas);
}
.chaos__video video {
  display: block;
  width: 100%;
  height: 100%;
  /* cover при точном совпадении пропорций ничего не режет, но страхует
     от полос при дробных пикселях. */
  object-fit: cover;
}
.chaos__video::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(58% 46% at 50% 52%,
    rgba(255, 255, 255, .78), rgba(255, 255, 255, .38) 55%, rgba(255, 255, 255, 0) 78%);
  pointer-events: none;
}
/* Ровная вуаль поверх ролика. Без неё в кадре спорят три вещи сразу:
   летящие бумаги, слово и лучи, — и не читается ни одна. Ролик уходит
   в фактуру, разговор ведут слово и лучи. */
.chaos__video::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(255, 255, 255, .46);
  pointer-events: none;
}

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

/* Ядро сцены — слово и строка под ним. Непрозрачность больше не
   зависит от прокрутки: раньше весь блок проявлялся по --p, и на
   середине сцены текст оставался блёклым — читать его было нечем, хотя
   буквы уже стояли на месте. Теперь ядро всегда чёткое, а прогресс
   управляет только роем вокруг. */
.chaos__core {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  z-index: 2;
  /* В кадре осталось только слово. Подпись жила здесь же и ложилась на
     светлую рамку внутри ролика, мешаясь с летящими бумагами; теперь
     она стоит под кадром, обычным текстом страницы. */
  width: min(74%, 560px);
}
/* Кегль считается теми же величинами, что и сам кадр: его ширина —
   min(1360px, 94vw, 118vh), поэтому текст тоже смотрит и на ширину
   окна, и на высоту. С одной только vw на низком широком экране кадр
   сжимался, а надпись оставалась прежней и вылезала за рамку. */
.chaos__core span {
  display: block;
  color: var(--ink-mid);
  font-size: clamp(11px, min(1.9vw, 2.4vh), 17px);
  line-height: 1.45;
}
.chaos__core b {
  display: block;
  font-size: clamp(20px, min(6.2vw, 7.8vh), 62px);
  font-weight: 700;
  letter-spacing: .01em;
  margin-bottom: .35em;
}

/* Подпись под кадром. Ширина по мере чтения, а не по ширине ролика:
   строка в тысячу двести пикселей глазом не берётся. */
.chaos__note {
  margin: clamp(14px, 1.8vw, 24px) auto 0;
  max-width: 52ch;
  text-align: center;
  color: var(--ink-mid);
  font-size: clamp(15px, 1.6vw, 19px);
  line-height: 1.45;
}

/* Слово собирается по букве — но по появлению в кадре, а не по
   прогрессу прокрутки.

   Пока сборка была привязана к --p, она растягивалась на всю сцену и
   заканчивалась у самого нижнего края экрана: при обычном листании
   человек видел либо пустое место, либо уже готовую надпись. Теперь
   это один короткий, законченный жест: буквы приезжают снизу из
   размытия с шагом в 90 мс и встают на место меньше чем за полторы
   секунды — момент видно всегда. */
.chaos__word { display: flex; justify-content: center; }
.chaos__word i {
  font-style: normal;
  opacity: 0;
  transform: translateY(26px) scale(.86);
  filter: blur(8px);
  will-change: opacity, transform, filter;
}
.chaos__word.is-set i {
  animation: word-in 640ms var(--ease) calc(var(--n) * 90ms) both;
}
@keyframes word-in {
  from { opacity: 0; transform: translateY(26px) scale(.86); filter: blur(8px); }
  60%  { opacity: 1; filter: blur(0); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

@media (prefers-reduced-motion: reduce) {
  .chaos__word i,
  .chaos__word.is-set i { opacity: 1; transform: none; filter: none; animation: none; }
}
/* Кегль подписи задан выше, вместе со словом: там он считается теми же
   величинами, что и кадр. Здесь остались только отступ и цвет — прежнее
   объявление размера стояло ниже по файлу и молча перебивало новое. */
.chaos__core span {
  display: block;
  margin-top: 10px;
  color: var(--ink-mid);
  /* Ширину держит родитель, у которого она считается от кадра. Свой
     потолок в 30ch делал строку уже слова и сдвигал её влево: строка
     переставала быть подписью под RIVENO и висела сама по себе. */
  margin-inline: auto;
}

/* ═══════════════════════ 3. Путешествие заказа ═══════════════════════ */

.journey { position: relative; }
.journey__rail {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: grid;
  grid-template-rows: auto 1fr;
  align-content: center;
  gap: clamp(20px, 3vw, 40px);
  padding-block: clamp(40px, 6vw, 80px);
  overflow: clip;
}

.journey__steps {
  display: flex;
  gap: 6px;
  justify-content: center;
  flex-wrap: wrap;
}
.journey__step {
  font-size: 13px;
  letter-spacing: -.01em;
  color: var(--ink-soft);
  padding: 7px 14px;
  border-radius: var(--r-pill);
  transition: background var(--t-state) var(--ease), color var(--t-state) var(--ease);
}
.journey__step.is-on { background: var(--ink); color: #fff; }

.journey__grid {
  display: grid;
  gap: clamp(20px, 3vw, 44px);
  /* По верхнему краю, а не по центру. Текст слева и карточка справа
     разной высоты, и центрирование ставило их «врозь»: заголовок шага
     висел где-то посередине карточки, глазу не за что зацепиться.
     Теперь обе колонки начинаются с одной линии. */
  align-items: start;
}
@media (min-width: 940px) {
  .journey__grid { grid-template-columns: minmax(0, 4fr) minmax(0, 6fr); }
}

.journey__copy { min-height: 230px; position: relative; padding-top: 6px; }
/* Неактивный шаг убран полностью, а не «почти прозрачен».

   Раньше он оставался в потоке с opacity 0 и при остановке прокрутки
   рядом с активным текстом читались призраки соседних абзацев: строки
   накладывались друг на друга. Теперь к прозрачности добавлена
   visibility — она выключается сразу, а включается без задержки, так
   что двух текстов на экране одновременно не бывает. */
.journey__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(14px);
  transition:
    opacity 300ms var(--ease),
    transform 300ms var(--ease),
    visibility 0s linear 300ms;
  pointer-events: none;
}
.journey__slide.is-on {
  opacity: 1;
  visibility: visible;
  transform: none;
  pointer-events: auto;
  transition:
    opacity 300ms var(--ease),
    transform 300ms var(--ease),
    visibility 0s;
}
.journey__slide b {
  display: block;
  font-size: clamp(24px, 3vw, 38px);
  line-height: 1.12;
  letter-spacing: -.015em;
  font-weight: 600;
}
.journey__slide p { margin-top: 14px; color: var(--ink-mid); max-width: 40ch; }
.journey__where {
  display: inline-block;
  margin-bottom: 12px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--blue-link);
}

/* Карточка заказа — она одна на всю сцену и не пересоздаётся */
.order {
  background: var(--paper);
  border-radius: var(--r-card);
  box-shadow: 0 1px 0 rgba(0, 0, 0, .04), 0 26px 60px -30px rgba(16, 24, 40, .35);
  overflow: hidden;
}
.order__panel {
  position: absolute;
  inset: 0;
  padding: clamp(18px, 2.2vw, 26px) clamp(20px, 2.4vw, 30px);
  opacity: 0;
  visibility: hidden;
  transform: scale(.994);
  transition:
    opacity 300ms var(--ease),
    transform 300ms var(--ease),
    visibility 0s linear 300ms;
  pointer-events: none;
}
.order__panel.is-on {
  opacity: 1;
  visibility: visible;
  transform: none;
  pointer-events: auto;
  transition:
    opacity 300ms var(--ease),
    transform 300ms var(--ease),
    visibility 0s;
}

.order__rows { display: grid; gap: 10px; }
.order__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: baseline;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--hairline-soft);
  font-size: 15px;
}
.order__row:last-child { border-bottom: 0; }
.order__row span:first-child { color: var(--ink-soft); }
.order__row b { font-weight: 600; font-variant-numeric: tabular-nums; }

.order__chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.order__chip {
  font-size: 13px;
  padding: 5px 11px;
  border-radius: var(--r-pill);
  background: var(--canvas);
  color: var(--ink-mid);
}
.order__chip--on { background: var(--ink); color: #fff; }

/* Финальные деньги */
.order__money { display: grid; gap: 12px; margin-top: 4px; }
.order__money div { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; }
.order__money span { color: var(--ink-soft); font-size: 15px; }
.order__money b { font-size: 21px; font-weight: 600; font-variant-numeric: tabular-nums; }
.order__money .result b { font-size: clamp(26px, 3vw, 36px); }

/* Доказательство под финальной фразой: настоящая полоса пути из системы */
.proof {
  margin-top: clamp(34px, 4vw, 54px);
  display: grid;
  gap: 14px;
  justify-items: center;
}

/* ═══════════════════════ 4. Не CRM ═══════════════════════ */

.pipeline { background: var(--ink); color: var(--ink-band-text); overflow: clip; }

/* Тёмная глава: утверждение и пять направлений под ним.

   Заголовок здесь набран крупно намеренно, но прежний кегль съедал весь
   экран, и ряд направлений оказывался у самого нижнего края — выглядело
   как случайная обрезка. Теперь текст ощутимо меньше высоты экрана, а
   между ним и рядом есть явная пауза: сначала читается мысль, потом
   видно, из чего она складывается. */
.pipeline .statement__text {
  font-size: clamp(30px, 5.4vw, 74px);
  max-width: 26ch;
  margin-inline: auto;
}
.pipeline .pipeline__track { margin-top: clamp(36px, 5vw, 72px); }

/* Активное направление — единственное синее пятно в главе. Остальные
   карточки нейтральные: ряд читается как список, а не как гирлянда. */
.pipeline__node.is-on .pipeline__thumb {
  background: rgba(0, 113, 227, .16);
  box-shadow: inset 0 0 0 1px rgba(0, 113, 227, .55);
  color: #fff;
}
.pipeline__node.is-on .pipeline__thumb svg { stroke: var(--ink-band-link); }
.pipeline__node.is-on b { color: #fff; }
.pipeline .statement__text .dim { color: rgba(255, 255, 255, .28); }
.pipeline__track {
  margin-top: clamp(40px, 6vw, 80px);
  display: grid;
  gap: 14px;
}
.pipeline__line {
  position: relative;
  height: 2px;
  background: rgba(255, 255, 255, .14);
}
.pipeline__line::after {
  content: "";
  position: absolute;
  inset: 0;
  background: #fff;
  transform: scaleX(var(--p));
  transform-origin: left center;
}
.pipeline__nodes {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
}
.pipeline__node {
  display: grid;
  gap: 10px;
  justify-items: center;
  text-align: center;
  opacity: .35;
  transition: opacity var(--t-state) var(--ease), transform var(--t-state) var(--ease);
  transform: translateY(6px);
}
.pipeline__node.is-on { opacity: 1; transform: none; }
.pipeline__node b { font-size: clamp(14px, 1.4vw, 17px); font-weight: 600; }
.pipeline__thumb {
  width: 100%;
  aspect-ratio: 8 / 5;
  border-radius: var(--r-control);
  overflow: hidden;
  background: var(--ink-band);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .1);
}
.pipeline__thumb img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }

@media (max-width: 760px) {
  .pipeline__nodes { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
  .pipeline__line { display: none; }
}

/* ═══════════════════════ 5. Витрина продукта ═══════════════════════ */

.showcase__grid { display: grid; gap: clamp(24px, 3vw, 48px); align-items: start; }
/* Живой блок внутри правой колонки шире экрана и прокручивается сам.
   Без min-width:0 он растягивал всю сетку, а вместе с ней и страницу. */
.showcase__grid > * { min-width: 0; }
@media (min-width: 1000px) {
  .showcase__grid { grid-template-columns: minmax(0, 340px) minmax(0, 1fr); }
  .showcase__screen { position: sticky; top: 92px; }
}

.showcase__list { display: grid; gap: 2px; }
.showcase__item {
  display: grid;
  gap: 6px;
  text-align: left;
  border: 0;
  background: none;
  cursor: pointer;
  padding: 18px 20px;
  border-radius: var(--r-tile);
  transition: background var(--t-state) var(--ease);
}
.showcase__item:hover { background: var(--paper); }
.band--gray .showcase__item:hover { background: var(--paper); }
.showcase__item[aria-selected="true"] { background: var(--paper); box-shadow: 0 1px 0 rgba(0,0,0,.04), 0 14px 30px -22px rgba(16,24,40,.4); }
.showcase__item b { font-size: 19px; font-weight: 600; letter-spacing: -.012em; }
.showcase__item span { font-size: 14px; line-height: 1.4; color: var(--ink-soft); }
.showcase__item[aria-selected="true"] span { color: var(--ink-mid); }

.showcase__outcome {
  font-size: clamp(21px, 2.4vw, 30px);
  line-height: 1.18;
  letter-spacing: -.014em;
  font-weight: 600;
  margin-bottom: 12px;
}
.showcase__how { color: var(--ink-mid); max-width: 62ch; }

.theme-switch {
  display: inline-flex;
  gap: 3px;
  padding: 3px;
  border-radius: var(--r-pill);
  background: var(--wash);
  margin-left: auto;
  flex: 0 0 auto;
}
.theme-switch button {
  border: 0;
  background: none;
  cursor: pointer;
  min-height: 30px;
  padding: 5px 13px;
  border-radius: var(--r-pill);
  font-size: 13px;
  color: var(--ink-mid);
  transition: background var(--t-hover) var(--ease), color var(--t-hover) var(--ease);
}
.theme-switch button[aria-pressed="true"] { background: var(--paper); color: var(--ink); }


/* ─────────────── Живой блок интерфейса ──────────────────────────
   Рядом со снимком экрана стоит настоящий кусок системы: разметка,
   выгруженная из ERP. Он не обрезан рамкой, тянется под ширину и
   остаётся текстом — в отличие от картинки. */

.live { margin-top: clamp(22px, 2.6vw, 32px); }
.erp-kanban.is-on { max-width: 340px; }

/* ═══════════════════════ 6. Экосистема ═══════════════════════ */

.eco { display: grid; gap: clamp(18px, 2.4vw, 26px); }
.eco__grid {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
}
.eco__cluster {
  position: relative;
  display: grid;
  gap: 12px;
  align-content: start;
  padding: clamp(22px, 2.4vw, 30px);
  /* Карточка — средний уровень скругления. Тени нет: её отделяет фон и
     тонкая граница, а тень приберегаем для окон системы и видео. */
  border-radius: var(--r-tile);
  background: var(--paper);
  box-shadow: inset 0 0 0 1px var(--hairline-soft);
  cursor: default;
  transition: transform var(--t-state) var(--ease), box-shadow var(--t-state) var(--ease);
}
.band--gray .eco__cluster { background: var(--paper); }
.eco__key {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .12em;
  color: var(--ink-soft);
}
.eco__cluster h3 { font-size: 21px; font-weight: 600; letter-spacing: -.012em; }
.eco__cluster p { font-size: 14px; line-height: 1.42; color: var(--ink-soft); }
.eco__list { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.eco__list span {
  font-size: 13px;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  background: var(--canvas);
  color: var(--ink-mid);
}

@media (hover: hover) and (pointer: fine) {
  .eco__cluster:hover { transform: translateY(-4px); box-shadow: inset 0 0 0 1px var(--hairline), 0 18px 40px -30px rgba(16, 24, 40, .40); }
}
@media (hover: none) {
}

/* ═══════════════════════ 7. Telegram ═══════════════════════ */

.tg { display: grid; gap: clamp(24px, 3vw, 46px); align-items: center; }
@media (min-width: 940px) { .tg { grid-template-columns: 300px minmax(0, 1fr); } }

.tg__wire {
  position: relative;
  min-height: 210px;
  display: grid;
  align-content: center;
  gap: 16px;
}
.tg__msg {
  justify-self: start;
  max-width: 90%;
  padding: 11px 15px;
  border-radius: var(--r-control);
  font-size: 15px;
  line-height: 1.35;
  background: var(--paper);
  box-shadow: 0 1px 0 rgba(0,0,0,.04), 0 12px 28px -20px rgba(16,24,40,.5);
  opacity: 0;
  transform: translateX(-24px);
  transition: opacity 520ms var(--ease), transform 520ms var(--ease);
}
/* Приезжает справа — но не из-за края экрана. На телефоне эти 24px
   вылезали за ширину страницы, и она уезжала вбок на четыре пикселя:
   мелочь, которая видна пальцем. Держим сдвиг внутри переполнения
   родителя. */
.tg__msg--in { justify-self: end; background: #d7ecff; transform: translateX(24px); }
.tg__wire { overflow: clip; }
.tg__msg.is-on { opacity: 1; transform: none; }
.tg__msg small { display: block; margin-top: 4px; font-size: 12px; color: var(--ink-soft); }

.tg__note { font-size: 14px; color: var(--ink-soft); }

/* ═══════════════════════ 8. Взгляд собственника ═══════════════════════ */

.owner__metrics {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
  margin-top: clamp(26px, 3vw, 40px);
}
.owner__metric {
  padding: 20px;
  border-radius: var(--r-tile);
  background: var(--paper);
  display: grid;
  gap: 4px;
}
.band--gray .owner__metric { background: var(--paper); }
.owner__metric b { font-size: 17px; font-weight: 600; }
.owner__metric span { font-size: 13px; line-height: 1.35; color: var(--ink-soft); }

/* ═══════════════════════ 9. До / После ═══════════════════════ */

.ba { position: relative; }
.ba__rail { position: sticky; top: 0; min-height: 100svh; display: grid; align-content: center; overflow: clip; }
/* Правая половина наезжает на левую — так и задумано: RIVENO не встаёт
   рядом со старым порядком, а закрывает его собой. Обе колонки лежат в
   одной ячейке сетки; левая занимает всю ширину, правая наползает по
   прокрутке. Текст левой при этом не режется: он прижат к своему краю и
   уходит под тёмную панель целыми строками. */
.ba__stack {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  border-radius: var(--r-card);
  overflow: hidden;
  min-height: clamp(340px, 52vh, 520px);
  isolation: isolate;
}
.ba__stack > .ba__side { grid-area: 1 / 1; }

.ba__side {
  padding: clamp(24px, 3.2vw, 46px);
  display: grid;
  align-content: center;
  gap: 14px;
}
.ba__before {
  background: var(--canvas);
  padding-right: 52%;
}
/* Старый порядок уходит целиком, а не разрезается краем панели:
   к середине сцены его текст уже погас, и перекрывать нечего. */
.ba__before > * {
  opacity: calc(1 - var(--p) * 1.5);
  transform: translateX(calc(var(--p) * -24px));
}
.ba__after {
  background: var(--ink);
  color: var(--ink-band-text);
  z-index: 1;
  /* Наезжает справа налево: сначала видна только кромка, к концу сцены
     панель закрывает почти всё поле. Не до конца — старое должно
     остаться видимым краем, иначе пропадает сравнение. */
  clip-path: inset(0 0 0 calc(100% - 4% - var(--p) * 96%));
  box-shadow: -30px 0 60px -30px rgba(0, 0, 0, .55);
}
/* Содержимое прижато к правому краю и проявляется вслед за кромкой.
   Если оставить его на месте, при первой четверти наезда виден только
   чёрный прямоугольник: текст ещё за срезом. */
/* justify-self, а не margin-left: auto — у списка ниже стоит margin: 0
   с большей специфичностью, и прижать его отступом не выходит. */
/* Содержимое правой панели едет к центру по мере перекрытия: в конце
   тёмная панель занимает всё поле, и текст, прижатый к краю, выглядел
   бы забытым в углу. */
.ba__side.ba__after > * {
  --cw: min(74%, 780px);
  width: var(--cw);
  justify-self: start;
  margin-left: calc((100% - var(--cw)) * (1 - var(--p) * 0.5));
  opacity: calc((var(--p) - .16) * 2.6);
  transform: translateX(calc((1 - var(--p)) * 26px));
  transition: none;
}

@media (max-width: 720px) {
  .ba__before { padding-right: clamp(24px, 3.2vw, 46px); padding-bottom: 46%; }
  .ba__side.ba__after > * { width: auto; margin-left: 0; justify-self: stretch; transform: translateY(calc((1 - var(--p)) * 18px)); }
  .ba__after {
    clip-path: inset(calc(100% - 8% - var(--p) * 92%) 0 0 0);
    padding-top: calc(14% + (1 - var(--p)) * 4%);
    box-shadow: 0 -30px 60px -30px rgba(0, 0, 0, .55);
  }
}
.ba__side h3 { font-size: clamp(20px, 2.2vw, 27px); font-weight: 600; letter-spacing: -.012em; }
.ba__side ul { display: grid; gap: 9px; padding: 0; margin: 0; }
.ba__side li { list-style: none; font-size: clamp(15px, 1.5vw, 18px); }
.ba__before li { color: var(--ink-soft); }
.ba__before li::before { content: "×"; margin-right: 10px; color: var(--ember); }

/* Тёмная панель — не второй список, а ведомость замен: в каждой строке
   старое слева, новое справа, между ними линия с синей точкой. Пока
   панель наезжает, строки заполняются одна за другой: старое
   зачёркивается, линия дотягивается до нового, новое проявляется.
   Прежде тут стоял одинокий список в углу пустой чёрной плоскости —
   хозяин показал снимок и спросил, нельзя ли лучше. Порядок строк
   слева и справа одинаковый: пары подобраны по смыслу, а не по
   очереди. */
.ba__after .brand-word { color: var(--ink-band-text); }
.ba__side .ba__ledger { gap: 0; }
.ba__ledger li {
  /* Своя доля прокрутки у каждой строки: --t — где начинается, --k —
     насколько готова (0…1). Первая идёт с 0.44, дальше через 0.07,
     последняя заканчивается около 0.95 — когда панель уже закрыла поле. */
  --t: calc(.44 + var(--i) * .072);
  --k: clamp(0, calc((var(--p) - var(--t)) / .16), 1);
  display: grid;
  grid-template-columns: minmax(0, 1fr) 34px minmax(0, 1.12fr);
  align-items: baseline;
  column-gap: 12px;
  padding: 10px 0;
  border-top: 1px solid rgba(255, 255, 255, .09);
  font-size: clamp(15px, 1.4vw, 17px);
}
.ba__ledger li:first-child { border-top: 0; padding-top: 0; }
.ba__ledger li:last-child { padding-bottom: 0; }
.ba__ledger s {
  position: relative;
  text-decoration: none;
  color: rgba(255, 255, 255, .46);
  font-size: .93em;
  opacity: calc(1 - var(--k) * .35);
}
/* Зачёркивание рисуется слева направо, а не появляется готовым. */
.ba__ledger s::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 56%;
  height: 1px;
  background: rgba(255, 255, 255, .6);
  transform: scaleX(var(--k));
  transform-origin: 0 50%;
}
/* Связка: линия тянется к новому, на конце — синяя точка. Точка не
   масштабируется вместе с линией, иначе на старте она сплюснута. */
.ba__ledger i {
  position: relative;
  display: block;
  align-self: center;
  height: 6px;
}
.ba__ledger i::before {
  content: "";
  position: absolute;
  left: 0; right: 4px; top: 50%;
  height: 1px;
  background: rgba(255, 255, 255, .26);
  transform: scaleX(var(--k));
  transform-origin: 0 50%;
}
.ba__ledger i::after {
  content: "";
  position: absolute;
  right: 0; top: 0;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--blue);
  opacity: var(--k);
}
.ba__ledger span {
  color: var(--ink-band-text);
  font-weight: 500;
  opacity: var(--k);
  transform: translateX(calc((1 - var(--k)) * 12px));
}
/* Итог под ведомостью и одна ссылка в живую систему. Проявляется
   последним — когда все строки уже заполнены. */
/* Селектор с родителем: правило «.ba__side.ba__after > *» выше ставит
   всем детям общую прозрачность по --p и перебивало бы своё. */
.ba__side.ba__after > .ba__foot {
  --kf: clamp(0, calc((var(--p) - .84) / .14), 1);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px 18px;
  margin: 6px 0 0;
  padding-top: 14px;
  border-top: 1px solid rgba(255, 255, 255, .09);
  font-size: 14px;
  line-height: 1.45;
  color: rgba(255, 255, 255, .58);
  opacity: var(--kf);
  transform: translateY(calc((1 - var(--kf)) * 8px));
}
.ba__foot .arrow-link {
  appearance: none;
  background-color: transparent;
  border: 0;
  padding: 0 0 1px;
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink-band-text);
  cursor: pointer;
  white-space: nowrap;
}
@media (max-width: 720px) {
  .ba__ledger li { grid-template-columns: 1fr; row-gap: 1px; padding: 9px 0; font-size: 16px; }
  .ba__ledger i { display: none; }
  .ba__ledger s { font-size: 13px; }
  .ba__ledger span { transform: translateY(calc((1 - var(--k)) * 6px)); }
  .ba__foot { flex-direction: column; align-items: flex-start; gap: 8px; }
}

.ba__seam {
  /* Кромка наезжающей панели. Раньше это была статичная линия по центру;
     теперь она едет вместе с краем и светится тем ярче, чем быстрее
     идёт перекрытие — движение видно даже боковым зрением. */
  position: absolute;
  top: 0; bottom: 0;
  left: calc(96% - var(--p) * 96%);
  width: 2px;
  z-index: 2;
  background: linear-gradient(180deg,
    rgba(255, 255, 255, 0),
    rgba(255, 255, 255, .85) 22%,
    rgba(255, 255, 255, .85) 78%,
    rgba(255, 255, 255, 0));
  box-shadow: 0 0 18px rgba(255, 255, 255, .55);
  opacity: calc(.25 + var(--p) * (1 - var(--p)) * 3);
}
@media (max-width: 720px) {
  .ba__seam {
    left: 0; right: 0; width: auto;
    top: calc(92% - var(--p) * 96%);
    bottom: auto; height: 2px;
    background: linear-gradient(90deg,
      rgba(255, 255, 255, 0), rgba(255, 255, 255, .85) 22%,
      rgba(255, 255, 255, .85) 78%, rgba(255, 255, 255, 0));
  }
}
@media (max-width: 720px) { .ba__seam { display: none; } }

/* ═══════════════════════ 12. Внедрение ═══════════════════════ */

.steps-line { position: relative; display: grid; gap: 0; margin-top: clamp(30px, 4vw, 50px); }
.steps-line::before {
  content: "";
  position: absolute;
  left: 15px; top: 8px; bottom: 8px;
  width: 2px;
  background: var(--hairline-soft);
}
.steps-line::after {
  content: "";
  position: absolute;
  left: 15px; top: 8px;
  width: 2px;
  height: calc((100% - 16px) * var(--p));
  background: var(--ink);
}
.steps-line li {
  list-style: none;
  position: relative;
  padding: 0 0 clamp(22px, 2.6vw, 32px) 52px;
}
.steps-line li:last-child { padding-bottom: 0; }
.steps-line li::before {
  content: "";
  position: absolute;
  left: 9px; top: 6px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--canvas);
  box-shadow: inset 0 0 0 2px var(--hairline);
}
.steps-line li.is-on::before { background: var(--ink); box-shadow: inset 0 0 0 2px var(--ink); }
.steps-line em {
  font-style: normal;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .08em;
  color: var(--ink-soft);
}
.steps-line b { display: block; margin-top: 4px; font-size: clamp(18px, 1.9vw, 23px); font-weight: 600; }
.steps-line p { margin-top: 6px; color: var(--ink-mid); font-size: 15px; max-width: 52ch; }

/* ═══════════════════════ 13. Безопасность ═══════════════════════ */

.trust {
  display: grid;
  gap: 1px;
  background: var(--hairline-soft);
  border-radius: var(--r-card);
  overflow: hidden;
  margin-top: clamp(26px, 3vw, 40px);
}
@media (min-width: 780px) { .trust { grid-template-columns: repeat(3, 1fr); } }
.trust div { background: var(--paper); padding: clamp(20px, 2.2vw, 28px); display: grid; gap: 6px; align-content: start; }
.band--gray .trust div { background: var(--paper); }
.trust b { font-size: 16px; font-weight: 600; }
.trust span { font-size: 14px; line-height: 1.4; color: var(--ink-soft); }

/* ═══════════════════════ 14. Цена хаоса ═══════════════════════ */

.roi { display: grid; gap: clamp(24px, 3vw, 44px); align-items: start; }
@media (min-width: 940px) { .roi { grid-template-columns: minmax(0, 1fr) 380px; } }

.roi__fields { display: grid; gap: 18px; }
.roi__field { display: grid; gap: 8px; }
.roi__field label { font-size: 14px; color: var(--ink-mid); }
.roi__row { display: flex; align-items: center; gap: 16px; }
/* Высота — это площадь нажатия, а не толщина дорожки: 44px нужны
   пальцу. Сам вид ползунка задан один раз в riveno.css. */
.roi__row input[type="range"] { flex: 1; min-width: 140px; accent-color: var(--blue); height: 44px; }
.roi__row output { font-size: 19px; font-variant-numeric: tabular-nums; min-width: 6ch; text-align: right; }

.roi__result {
  padding: clamp(24px, 2.8vw, 34px);
  border-radius: var(--r-card);
  background: var(--ink);
  color: var(--ink-band-text);
  display: grid;
  gap: 12px;
}
.roi__result b { font-size: clamp(28px, 3.4vw, 42px); font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -.015em; }
.roi__result span { font-size: 14px; line-height: 1.45; color: var(--ink-band-soft); }
.roi__disclaimer { font-size: 13px; line-height: 1.45; color: #7d8899; }

/* ═══════════════════════ 16. Финал ═══════════════════════ */

.final { position: relative; overflow: clip; }
.final__grid { display: grid; gap: clamp(28px, 4vw, 60px); align-items: start; }
@media (min-width: 940px) { .final__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); } }
.final__title {
  font-size: clamp(34px, 6vw, 78px);
  line-height: 1.02;
  letter-spacing: -.026em;
  font-weight: 700;
}
.final__sub { margin-top: 22px; font-size: clamp(17px, 1.7vw, 21px); line-height: 1.45; color: var(--ink-mid); max-width: 44ch; }
.final__facts { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
.final__facts span {
  font-size: 14px;
  padding: 7px 14px;
  border-radius: var(--r-pill);
  background: var(--canvas);
  color: var(--ink-mid);
}
.band--gray .final__facts span { background: var(--paper); }

/* Кейсы: секция существует, но не показывается, пока нет настоящих. */
[data-proof="empty"] { display: none; }

/* ═══════════════════════ Общее: спокойнее движение ═══════════════════════ */

@media (prefers-reduced-motion: reduce) {
  .chaos__core { opacity: 1 !important; transform: translate(-50%, -50%) !important; }
  .pipeline__line::after { transform: scaleX(1); }
  .pipeline__node { opacity: 1; transform: none; }
  .ba__after { clip-path: none; }
  .ba__ledger li { --k: 1; }
  .ba__side.ba__after > .ba__foot { --kf: 1; }
  .steps-line::after { height: calc(100% - 16px); }
  /* Спокойный режим: никаких переходов, но и никаких призраков —
     видно ровно один шаг, полностью читаемый. */
  .journey__slide, .order__panel, .tg__msg { transition: none; }
  .journey__slide:not(.is-on), .order__panel:not(.is-on) { display: none; }
  .journey__slide.is-on, .order__panel.is-on { opacity: 1; visibility: visible; transform: none; }
}

/* ═══════════════════ Зацикленное появление по блокам ═══════════════════

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

   Как сделано: каждому ребёнку контейнера [data-cycle] скрипт ставит
   свой номер --i, из него считается задержка. Цикл длинный (шесть
   секунд) и большую его часть блок просто стоит на месте: мельтешение
   раздражает сильнее, чем неподвижность. Крутится только пока блок на
   экране — за этим следит скрипт, снимая класс. */

[data-cycle] > * { --d: calc(var(--i, 0) * 130ms); }
[data-cycle].is-live > * {
  animation: cycle-in 6.4s var(--ease) var(--d) infinite both;
}
@keyframes cycle-in {
  0%          { opacity: 0; transform: translateY(12px); }
  7%, 78%     { opacity: 1; transform: none; }
  90%, 100%   { opacity: 0; transform: translateY(-8px); }
}

/* Заголовок-утверждение: строки выходят одна за одной и так же уходят. */
.statement__text[data-cycle] > span { will-change: opacity, transform; }

/* Показатели владельца: карточки ещё и приподнимаются — так видно, что
   это отдельные числа, а не сплошная полоса. */
.owner__metrics[data-cycle].is-live > * {
  animation: cycle-lift 6.4s var(--ease) var(--d) infinite both;
}
@keyframes cycle-lift {
  0%        { opacity: 0; transform: translateY(14px) scale(.985); }
  8%, 76%   { opacity: 1; transform: none; }
  90%, 100% { opacity: 0; transform: translateY(-10px) scale(.99); }
}

/* Блок про доступы: пунктов шесть, поэтому шаг мельче, иначе последний
   появляется, когда первый уже гаснет. */
.trust[data-cycle] > * { --d: calc(var(--i, 0) * 95ms); }

@media (prefers-reduced-motion: reduce) {
  [data-cycle].is-live > *,
  .owner__metrics[data-cycle].is-live > * { animation: none; opacity: 1; transform: none; }
}

/* ═══════════════════ Ролик впровадження ═══════════════════

   Шесть этапов внедрения показаны не текстом рядом со снимком, а
   короткими сценами: у каждой свой маленький сюжет. Видеофайла нет
   намеренно — это лишний вес и внешняя зависимость, а разметкой то же
   самое получается резче и подстраивается под ширину.

   Кадры сменяются сами по кругу; наведение и точки внизу отдают
   управление человеку. */

.reel {
  border-radius: var(--r-card);
  background: var(--paper);
  overflow: hidden;
  box-shadow: 0 1px 0 rgba(0, 0, 0, .04), 0 26px 60px -34px rgba(16, 24, 40, .4);
}
.reel__screenframe {
  position: relative;
  aspect-ratio: 8 / 5;
  background:
    radial-gradient(120% 90% at 50% 0%, #fff, var(--canvas) 70%);
}
.reel__frame {
  position: absolute;
  inset: 0;
  margin: 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  padding: clamp(18px, 2.4vw, 32px);
  gap: 16px;
  opacity: 0;
  transform: scale(1.015);
  transition: opacity var(--t-state) var(--ease), transform var(--t-state) var(--ease);
  pointer-events: none;
}
.reel__frame.is-on { opacity: 1; transform: none; pointer-events: auto; }
.reel__stage { position: relative; display: grid; place-items: center; min-height: 0; }
.reel__frame figcaption { display: grid; gap: 6px; }
.reel__frame figcaption b { font-size: clamp(17px, 1.8vw, 21px); font-weight: 600; letter-spacing: -.012em; }
.reel__frame figcaption span { font-size: 14px; color: var(--ink-mid); max-width: 62ch; }

/* Кадр 1: цепочка отделов, узлы зажигаются по очереди. */
.reel__flow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; justify-content: center; }
.reel__node {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 15px; border-radius: var(--r-control);
  background: var(--paper); color: var(--ink-2); font-size: 14px;
  box-shadow: 0 1px 0 rgba(0, 0, 0, .04), 0 10px 22px -16px rgba(16, 24, 40, .5);
  opacity: 0;
  animation: reel-pop 5.4s var(--ease) calc(var(--n) * .42s) infinite;
}
.reel__node svg { width: 16px; height: 16px; fill: none; stroke: var(--blue); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.reel__link {
  width: 26px; height: 2px; border-radius: 2px; background: var(--hairline);
  transform-origin: left center; transform: scaleX(0);
  animation: reel-line 5.4s var(--ease) calc(var(--n) * .42s + .22s) infinite;
}
@keyframes reel-pop {
  0%          { opacity: 0; transform: translateY(8px); }
  10%, 86%    { opacity: 1; transform: none; }
  96%, 100%   { opacity: 0; transform: translateY(-6px); }
}
@keyframes reel-line {
  0%        { transform: scaleX(0); }
  12%, 86%  { transform: scaleX(1); }
  96%, 100% { transform: scaleX(0); }
}

/* Кадр 2: настройки проставляются галочками. */
.reel__list { display: grid; gap: 10px; }
.reel__check {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 15px; color: var(--ink-2);
  opacity: 0;
  animation: reel-pop 5.4s var(--ease) calc(var(--n) * .5s) infinite;
}
.reel__check i {
  width: 18px; height: 18px; border-radius: 50%;
  border: 1.5px solid var(--hairline);
  position: relative; flex: none;
}
.reel__check i::after {
  content: ""; position: absolute; inset: 3px;
  border-radius: 50%; background: var(--blue);
  transform: scale(0);
  animation: reel-tick 5.4s var(--ease) calc(var(--n) * .5s + .3s) infinite;
}
@keyframes reel-tick {
  0%        { transform: scale(0); }
  14%, 86%  { transform: scale(1); }
  96%, 100% { transform: scale(0); }
}

/* Кадр 3: карточки перелетают из старых таблиц в систему. */
.reel__move { display: flex; align-items: center; gap: 14px; position: relative; }
.reel__box {
  padding: 14px 18px; border-radius: var(--r-control); font-size: 14px; white-space: nowrap;
}
.reel__box--old { background: var(--canvas); color: var(--ink-3); }
.reel__box--new { background: var(--ink); color: #fff; }
.reel__fly {
  position: absolute; left: 32%; top: 50%;
  width: 34px; height: 22px; margin-top: -11px;
  border-radius: 5px; background: var(--paper);
  box-shadow: 0 6px 16px -8px rgba(16, 24, 40, .7);
  animation: reel-fly 2.1s var(--ease) calc(var(--n) * .5s) infinite;
  opacity: 0;
}
@keyframes reel-fly {
  0%   { opacity: 0; transform: translateX(0) scale(.9); }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { opacity: 0; transform: translateX(150px) scale(1); }
}

/* Кадр 4: провідник ведёт по шагам.

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

   Теперь шаги приезжают снизу один за другим и отмечаются галочкой —
   ровно то, что делает провідник внутри системы. Приём взят у
   Animated List (magicui) и написан на CSS: там React и framer-motion,
   здесь четыре строки и две анимации.

   Цикл 5,4 с — столько же держится кадр в ролике (HOLD в scenes.js).
   Если менять там, менять и здесь. */
.reel__guide { width: min(100%, 420px); display: grid; gap: 9px; }
.reel__gstep {
  display: grid;
  grid-template-columns: 20px 1fr 18px;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  border-radius: var(--r-control);
  background: var(--paper);
  box-shadow: inset 0 0 0 1px var(--hairline);
  font-size: 14px;
  letter-spacing: -.01em;
  opacity: 0;
  animation: reel-gstep 5.4s var(--ease) calc(var(--n) * .46s) infinite;
}
.reel__gstep > svg {
  width: 17px; height: 17px; justify-self: center;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
  color: var(--ink-3);
}
.reel__gstep i {
  width: 18px; height: 18px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(0, 113, 227, .10);
}
.reel__gstep i svg { width: 11px; height: 11px; fill: none; stroke: var(--blue); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* Галочка не появляется, а прочерчивается — шаг именно выполняется,
   а не просто оказывается отмеченным. */
.reel__gstep i path {
  stroke-dasharray: 16;
  stroke-dashoffset: 16;
  animation: reel-gtick 5.4s var(--ease) calc(var(--n) * .46s + .5s) infinite;
}
@keyframes reel-gstep {
  0%        { opacity: 0; transform: translateY(14px); }
  9%, 90%   { opacity: 1; transform: none; }
  100%      { opacity: 0; transform: translateY(-6px); }
}
@keyframes reel-gtick {
  0%, 3%    { stroke-dashoffset: 16; }
  14%, 92%  { stroke-dashoffset: 0; }
  100%      { stroke-dashoffset: 16; }
}

/* Кадр 5: первая неделя — дни закрашиваются один за другим. */
.reel__week { display: flex; gap: 10px; }
.reel__day {
  width: 54px; height: 54px; border-radius: var(--r-control);
  display: grid; place-items: center;
  background: var(--canvas); color: var(--ink-3); font-size: 13px;
  animation: reel-day 5.4s var(--ease) calc(var(--n) * .42s) infinite;
}
@keyframes reel-day {
  0%        { background: var(--canvas); color: var(--ink-3); }
  14%, 86%  { background: var(--ink); color: #fff; }
  96%, 100% { background: var(--canvas); color: var(--ink-3); }
}

/* Кадр 6: сопровождение — спокойный пульс вокруг щита. */
.reel__pulse { position: relative; display: grid; place-items: center; width: 160px; height: 160px; }
.reel__pulse span {
  position: absolute; inset: 0; border-radius: 50%;
  box-shadow: 0 0 0 1.5px rgba(0, 113, 227, .35);
  transform: scale(.4); opacity: 0;
  animation: reel-ring 3.6s var(--ease) infinite;
}
.reel__pulse span:nth-child(2) { animation-delay: 1.2s; }
.reel__pulse span:nth-child(3) { animation-delay: 2.4s; }
.reel__pulse em {
  width: 56px; height: 56px; border-radius: 50%;
  display: grid; place-items: center; background: var(--ink);
}
.reel__pulse svg { width: 24px; height: 24px; fill: none; stroke: #fff; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
@keyframes reel-ring {
  0%   { transform: scale(.4); opacity: .9; }
  100% { transform: scale(1); opacity: 0; }
}

/* Низ ролика: полоса времени и точки. */
.reel__foot {
  display: flex; align-items: center; gap: 16px;
  padding: 14px clamp(18px, 2.4vw, 32px);
  border-top: 1px solid var(--hairline);
}
.reel__time { flex: 1; height: 3px; border-radius: 3px; background: var(--canvas); overflow: hidden; }
.reel__time i { display: block; height: 100%; width: 0; background: var(--ink); border-radius: 3px; }
.reel__dots { display: flex; gap: 7px; }
.reel__dot {
  width: 7px; height: 7px; border-radius: 50%; border: 0; padding: 0;
  background: var(--hairline); cursor: pointer;
  transition: transform var(--t-state) var(--ease), background var(--t-state) var(--ease);
}
.reel__dot.is-on { background: var(--ink); transform: scale(1.3); }

@media (prefers-reduced-motion: reduce) {
  .reel__node, .reel__link, .reel__check, .reel__check i::after,
  .reel__fly, .reel__day, .reel__pulse span { animation: none; opacity: 1; }
  /* Шаги и галочки просто стоят готовыми, лучи не бегут. */
  .reel__gstep { animation: none; opacity: 1; transform: none; }
  .reel__gstep i path { animation: none; stroke-dashoffset: 0; }
  .reel__time i { transition: none; }
}

/* Пункт списка, о котором сейчас идёт кадр ролика. */
.steps-line > li.is-reel { color: var(--ink); }
.steps-line > li.is-reel em { color: var(--blue); }
.steps-line > li.is-reel b { letter-spacing: -.014em; }
.steps-line > li { transition: color var(--t-state) var(--ease); }

/* Переписка с ботом: сообщения выходят по очереди и цикл повторяется.
   Текст — настоящий сценарий из системы, поэтому и порядок реплик тот
   же: приветствие, вопрос клиента, подсказка про /status, ответ. */
.phone__chat[data-tg-chat] > * {
  opacity: 0;
  animation: tg-say 13s var(--ease) calc(var(--n) * 1.5s) infinite;
}
@keyframes tg-say {
  0%        { opacity: 0; transform: translateY(8px) scale(.98); }
  4%, 88%   { opacity: 1; transform: none; }
  96%, 100% { opacity: 0; transform: translateY(-6px); }
}
.phone__chat code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .92em;
  padding: 1px 5px;
  border-radius: 5px;
  background: rgba(0, 0, 0, .06);
}
@media (prefers-reduced-motion: reduce) {
  .phone__chat[data-tg-chat] > * { animation: none; opacity: 1; }
}

/* На узком экране плашки роя мельче: иначе три слова в подписи шире
   самого поля. */

/* Живое окно в сцене пути: высота фиксирована, чтобы при смене раздела
   страница не прыгала. */
.journey__live { position: relative; }
.journey__live .viewer__foot { padding-top: 12px; }

/* Подпись под словом вернулась: она пряталась, пока вокруг летал рой
   из плашек и строка читалась вперемешку с ними. Теперь под ядром
   ролик, и текст стоит поверх спокойного кадра. */
@media (max-width: 560px) {
  /* На телефоне кадр узкий, и слово в 12vw уже не помещалось в рамку
     внутри ролика. Размер теперь общий, здесь только чуть шире поле
     под текст и меньше отступ. */
  .chaos__core { width: min(86%, 420px); }
  .chaos__core span { margin-top: 8px; }
}

/* Сцена «Хаос» на невысоких экранах: заголовок набирается мельче, поле
   роя ниже — иначе слово в центре собирается у самого нижнего края, и
   кульминацию сцены человек просто не видит. Тексты не меняются. */
@media (max-height: 900px) {
  .chaos .scene-title { font-size: min(5.4vw, 6.4vh); }
  .chaos .scene-lead { margin-top: 14px; font-size: clamp(16px, 2vh, 20px); }
  .chaos__field { width: min(1360px, 94vw, 106vh, calc((100svh - var(--chaos-chrome, 380px)) * 16 / 9)); margin-top: clamp(12px, 1.6vh, 22px); }
}
@media (max-height: 760px) {
  .chaos .scene-title { font-size: min(5vw, 6vh); }
  .chaos__field { width: min(1360px, 94vw, 98vh, calc((100svh - var(--chaos-chrome, 380px)) * 16 / 9)); }
}

/* ── Появление показателей владельца ─────────────────────────────────
   Пять метрик выходили разом и читались как одна строка. Теперь
   выступают по очереди — глаз успевает пройти по ним слева направо,
   а не отскакивает от сплошной полосы. */
.owner__metric {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--t-enter, 420ms) var(--ease), transform var(--t-enter, 420ms) var(--ease);
  transition-delay: calc(var(--n, 0) * 90ms);
}
.is-in .owner__metric,
.owner__metrics.is-in .owner__metric { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .owner__metric { opacity: 1; transform: none; transition: none; }
}

/* Черта под словом. Проходит один раз, сразу после того как встала
   последняя буква, и гаснет. Единственное цветное движение в сцене —
   поэтому короткое: постоянная подсветка превратила бы имя в баннер. */
.chaos__word { position: relative; }
.chaos__word::after {
  content: "";
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: -.12em;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, rgba(0, 113, 227, 0), var(--blue), rgba(0, 113, 227, 0));
  transform: scaleX(0);
  transform-origin: 50% 50%;
  opacity: 0;
}
.chaos__word.is-set::after {
  animation: word-line 1100ms var(--ease) 700ms 1;
}
@keyframes word-line {
  0%   { transform: scaleX(0); opacity: 0; }
  35%  { transform: scaleX(1); opacity: .9; }
  70%  { transform: scaleX(1); opacity: .9; }
  100% { transform: scaleX(1); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .chaos__word::after { animation: none; opacity: 0; }
}

/* Слово RIVENO внутри приглушённой строки — бренд, а не часть фразы.
   Хозяин увидел его серым в ряд с остальным текстом и спросил, почему
   бренд никак не выделен. Даём ему полный цвет заголовка и синюю
   метку-ромб — ту же, что у надзаголовка первого экрана. Само
   приглушение строки остаётся: «тільки починається» по-прежнему
   второй голос. */
.brand-word {
  color: var(--ink);
  font-weight: 700;
  letter-spacing: .01em;
  white-space: nowrap;
}
.brand-word::before {
  content: "";
  display: inline-block;
  width: min(.22em, 14px);
  height: min(.22em, 14px);
  margin-right: .3em;
  vertical-align: .18em;
  background: var(--blue);
  border-radius: 1px;
  transform: rotate(45deg);
}
/* Строка набирается по буквам: пока слова ещё нет, ромб не показываем —
   иначе он висит один посреди строки. */
.brand-word:empty::before { display: none; }
.pipeline .brand-word { color: var(--ink-band-text); }

/* ═══════════════════════ 6a. Факти з системи ═══════════════════════
   П'ять чисел, які можна перевірити у вікні на цій же сторінці. Не
   обіцянки, а склад системи: етапи, повідомлення, розділи, ролі, CSV.
   Числа докручуються при появі (riveno.js, initFacts). */
.facts { padding-top: clamp(28px, 4vw, 48px); padding-bottom: clamp(28px, 4vw, 48px); }
.facts__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  border-top: 1px solid var(--hairline);
}
.facts__list li {
  display: grid;
  align-content: start;
  gap: 6px;
  padding: 22px 22px 22px 0;
  border-right: 1px solid var(--hairline);
  margin-right: 22px;
}
.facts__list li:last-child { border-right: 0; margin-right: 0; }
.facts__list b {
  font-size: clamp(34px, 3.6vw, 52px);
  font-weight: 600;
  letter-spacing: -.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.facts__list span { font-size: 14px; line-height: 1.4; color: var(--ink-soft); max-width: 22ch; }
.facts__note { margin-top: 6px; }
@media (max-width: 900px) {
  .facts__list { grid-template-columns: repeat(2, minmax(0, 1fr)); border-top: 0; }
  .facts__list li { border-right: 0; margin-right: 0; border-top: 1px solid var(--hairline); padding: 18px 0; }
  .facts__list li:last-child { grid-column: 1 / -1; }
}

/* Що буде після заявки: три кроки замість трьох пігулок «30 хвилин ·
   без презентацій · у робочій системі» — ті самі обіцянки, але у
   вигляді порядку дій, який знімає страх «зараз почнуть продавати». */
.final__after {
  list-style: none;
  margin: 28px 0 0;
  padding: 0;
  display: grid;
  gap: 0;
  counter-reset: after;
}
.final__after li {
  counter-increment: after;
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr);
  gap: 4px 12px;
  padding: 12px 0;
  border-top: 1px solid var(--hairline);
  font-size: 15px;
  line-height: 1.45;
}
.final__after li::before {
  content: counter(after, decimal-leading-zero);
  grid-row: 1 / span 2;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--blue);
  padding-top: 3px;
  font-variant-numeric: tabular-nums;
}
.final__after b { font-weight: 600; color: var(--ink); }
.final__after span { color: var(--ink-soft); }

/* Стрічка впровадження їде разом зі списком: список із шести кроків
   вищий за екран, і без прилипання до кроків 05–06 стрічки вже не
   видно — хозяин дійшов донизу й спитав, навіщо тоді колонка збоку.
   Прилипає під шапкою; на телефоні колонка одна, прилипання не треба. */
@media (min-width: 900px) {
  .reel-stick { position: sticky; top: calc(var(--topbar-h, 64px) + 28px); align-self: start; }
}

/* ═══════════════ Впровадження: перетікання кроку в крок ═══════════════
   Хозяин: «перетекание из 1 в 2-й пункт должно быть красивее». Ліворуч —
   список дихає: майбутні кроки тихіші, поточний — із синім номером і
   синьою крапкою з ореолом. Праворуч — кадр не блимає, а перегортається:
   старий іде вгору й гасне, новий приходить знизу; підпис і сцена
   заходять із невеликим запізненням, у кутку кадру той самий синій номер,
   що й у списку. Смуга часу тягнеться, а не стрибає. */
.steps-line li { transition: opacity .45s var(--ease); }
.steps-line li:not(.is-on) { opacity: .42; }
.steps-line li::before {
  transition: background var(--t-state) var(--ease), box-shadow var(--t-state) var(--ease);
}
.steps-line li.is-reel::before {
  background: var(--blue);
  box-shadow: inset 0 0 0 2px var(--blue), 0 0 0 5px rgba(0, 113, 227, .16);
}
.steps-line em { transition: color var(--t-state) var(--ease); }
.steps-line li.is-reel b { color: var(--ink); }

.reel__screenframe { counter-reset: frame; }
.reel__frame {
  counter-increment: frame;
  transform: translateY(22px) scale(.985);
  transition: opacity .32s var(--ease), transform .32s var(--ease);
}
.reel__frame.is-on {
  transition: opacity .55s cubic-bezier(.2, .7, .2, 1) .08s, transform .55s cubic-bezier(.2, .7, .2, 1) .08s;
}
.reel__frame.is-leaving { opacity: 0; transform: translateY(-14px) scale(.985); }
.reel__frame::before {
  content: counter(frame, decimal-leading-zero);
  position: absolute;
  top: clamp(16px, 2vw, 24px); right: clamp(18px, 2.4vw, 32px);
  font-size: 12px; font-weight: 600; letter-spacing: .08em;
  color: var(--blue);
  font-variant-numeric: tabular-nums;
}
.reel__frame .reel__stage {
  transform: translateY(10px);
  transition: transform .55s cubic-bezier(.2, .7, .2, 1);
}
.reel__frame.is-on .reel__stage { transform: none; transition-delay: .14s; }
.reel__frame figcaption {
  opacity: 0;
  transform: translateX(-10px);
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}
.reel__frame.is-on figcaption { opacity: 1; transform: none; transition-delay: .24s; }
.reel__time i { transition: width .55s var(--ease); }
@media (prefers-reduced-motion: reduce) {
  .steps-line li, .steps-line li::before, .steps-line em,
  .reel__frame, .reel__frame .reel__stage, .reel__frame figcaption { transition: none; }
  .steps-line li:not(.is-on) { opacity: 1; }
  .reel__frame .reel__stage { transform: none; }
  .reel__frame figcaption { opacity: 1; transform: none; }
}

/* ── Плитки конвеєра «Не CRM»: відео за іконкою ──
   Хозяин: «картинки полная лажа, загрузи видео». П'ять коротких
   роликів (Kling 3.0, 5 с, без звуку, 720×450, 51–154 КБ): стіл
   продажу, іскри різки, склад, монтаж у сутінках, розрахунок. Грають
   самі, по колу; вантажаться ліниво (data-src, initVideo). Поверх —
   темний градієнт, іконка й підпис. */
.pipeline__thumb { position: relative; background: var(--ink-band); }
.pipeline__vid {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  border-radius: inherit;
  opacity: .85;
  transition: opacity var(--t-state) var(--ease), transform .6s cubic-bezier(.2, .7, .2, 1);
}
.pipeline__thumb::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  background: linear-gradient(180deg, rgba(11, 13, 18, .18) 0%, rgba(11, 13, 18, .7) 100%);
  z-index: 1;
  transition: opacity var(--t-state) var(--ease);
}
.pipeline__thumb > svg, .pipeline__thumb > span, .pipeline__thumb > .lv, .pipeline__thumb > .lv-gif { position: relative; z-index: 2; }
.pipeline__thumb { transition: transform .45s cubic-bezier(.2, .7, .2, 1), box-shadow .45s cubic-bezier(.2, .7, .2, 1); }
.pipeline__thumb:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 30px 46px -24px rgba(0, 0, 0, .7), inset 0 0 0 1px rgba(255, 255, 255, .2); }
.pipeline__thumb:hover .pipeline__vid { opacity: 1; transform: scale(1.04); }
.pipeline__thumb:hover::before { opacity: .82; }

/* ── Кадр «Переносимо дані»: блокноти й таблиці йдуть у машину RIVENO ──
   Хозяин: «не прямоугольники, а блокноты передаются; RIVENO — не кнопка,
   а комплекс, который их принимает и обрабатывает». Зліва три джерела
   (зошит, таблиця, 1С), по стрічці один за одним їдуть документи й
   заходять у приймальний отвір тёмного блока; всередині крутиться
   шестерня, блимають лампи, знизу з'являється чиста картка з галочкою. */
.reel__migr { width: min(100%, 360px); height: auto; display: block; color: var(--ink-3); }
.rm__src { animation: rm-src 4s ease-in-out infinite; transform-box: fill-box; transform-origin: 50% 50%; }
.rm__src--2 { animation-delay: .6s; } .rm__src--3 { animation-delay: 1.2s; }
.rm__belt { animation: rm-belt 1.2s linear infinite; }
.rm__doc { animation: rm-doc 2.7s cubic-bezier(.3, .1, .4, 1) infinite; transform-box: fill-box; transform-origin: 50% 50%; opacity: 0; }
.rm__doc--2 { animation-delay: .9s; } .rm__doc--3 { animation-delay: 1.8s; }
.rm__gear { animation: rm-spin 4s linear infinite; transform-box: fill-box; transform-origin: 50% 50%; }
.rm__lamp { animation: rm-lamp 1.35s ease-in-out infinite; }
.rm__lamp--2 { animation-delay: .45s; } .rm__lamp--3 { animation-delay: .9s; }
.rm__out { animation: rm-out 2.7s cubic-bezier(.2, .7, .2, 1) infinite; transform-box: fill-box; transform-origin: 50% 100%; }
.rm__mark { animation: li-pulse 2.4s var(--ease) infinite; transform-box: fill-box; transform-origin: 50% 50%; }
@keyframes rm-src { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-2px); } }
@keyframes rm-belt { to { stroke-dashoffset: -9; } }
@keyframes rm-doc {
  0% { transform: translateX(0) scale(.9); opacity: 0; }
  12% { opacity: 1; transform: translateX(6px) scale(1); }
  78% { opacity: 1; transform: translateX(126px) scale(1); }
  92%, 100% { opacity: 0; transform: translateX(142px) scale(.5); }
}
@keyframes rm-spin { to { transform: rotate(360deg); } }
@keyframes rm-lamp { 0%, 100% { opacity: .25; } 40% { opacity: 1; } }
@keyframes rm-out { 0%, 60% { transform: scaleY(0); opacity: 0; } 75%, 92% { transform: scaleY(1); opacity: 1; } 100% { transform: scaleY(1); opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .rm__src, .rm__belt, .rm__doc, .rm__gear, .rm__lamp, .rm__out, .rm__mark { animation: none; }
  .rm__doc { opacity: 1; } .rm__out { transform: none; opacity: 1; }
}

/* Підказка «гортайте» у «Шляху одного замовлення»: розділ закріплений і
   довгий, людина може не зрозуміти, що його треба листати. Хозяин
   попросив позначку. Видно лише на першому кроці, далі гасне сама. */
.journey__scroll {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--ink-soft);
  opacity: 0;
  transition: opacity .5s var(--ease);
}
.journey[data-scene-at="0"] .journey__scroll { opacity: 1; }
.journey__scroll svg {
  width: 15px; height: 15px;
  fill: none; stroke: var(--blue); stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
  animation: journey-hint 1.8s var(--ease) infinite;
}
@keyframes journey-hint {
  0%, 100% { transform: translateY(-2px); opacity: .5; }
  50% { transform: translateY(3px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .journey__scroll svg { animation: none; } }

/* Слово з матеріалів у заяві трохи нижче: воно вище за звичайні букви
   й наїжджало на рядок над ним (хозяин: «трохи опусти, щоб не налазило»). */
.pipeline .brand-word .rv .brand__made { margin-top: .1em; }
.statement__text .rv { vertical-align: -.06em; }
