/* =====================================================================
   ВАРИАНТ 3 · «КРАСНАЯ ЛИНИЯ ВЕДЁТ ПО ВСЕМУ САЙТУ»

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

   Отсюда три следствия, ради которых всё и затевалось:

   1. Между секциями линия НЕ прерывается. Она не принадлежит блоку —
      она лежит отдельным слоем поверх всей страницы, в тех же
      координатах 1440 и с тем же масштабом --k. Граница блоков для
      неё не существует, там просто продолжается путь.

   2. Порядок появления задаёт не вёрстка, а география листа. Кадры
      справа оживают, когда линия свернула вправо; список слева — когда
      она возвращается влево. Поэтому категории и загораются справа
      налево: маркер идёт оттуда.

   3. Никаких таймеров-каскадов. Все задержки из section-events.css
      (delay 420, 700, 980, 1140…) здесь погашены: они описывали
      «блок пришёл в кадр и печатается по расписанию». Расписание
      теперь одно — рука человека на колесе.

   Что взято у incredibles.dev: инерция (голова линии догоняет
   прокрутку с запаздыванием, а не приклеена к пикселю) и раскрытие
   через clip-path вместо простого проявления прозрачностью. Что не
   взято: липкие секции — у нас сцены фиксированной макетной высоты в
   координатах 1440, sticky их ломает.

   Файл подключается ПОСЛЕ section-events.css и переопределяет его
   тем же весом селектора — просто потому, что идёт следом.
   ===================================================================== */

/* ---------------------------------------------------------------------
   СЛОЙ ЛИНИИ

   Почему не внутри секции: у .scene стоит overflow: clip, и линия
   обрывалась бы на каждой границе блока — ровно то, чего нельзя.
   Слой лежит в потоке страницы абсолютом от body, его высота равна
   сумме макетных высот всех секций (4401), и он масштабируется тем же
   --k. Значит, координата 1189 на линии и координата 1189 в вёрстке —
   одно и то же место листа.
   --------------------------------------------------------------------- */
body { position: relative; }

.thread-layer {
  position: absolute;
  left: 0;

  /* Линия считает первый экран высотой 841 макетных пикселя. С 05.09 он
     укорачивается на --squeeze (низ поджат, лишнее отрезано), и всё, что
     ниже, поднялось на столько же в экранных пикселях. Слой поднимается
     вместе с ними — иначе линия отстаёт от блоков, ради которых
     нарисована. На самом первом экране её отрезок — прямая у левого
     поля, и сдвиг там не читается. */
  top: calc(-1 * var(--squeeze, 0px) * var(--k, 1));
  z-index: 6;                 /* выше сцен, ниже маркера-курсора (55/60) */
  width: 1440px;
  height: 7328px;             /* = viewBox линии: ВЕСЬ лист, 7238 макетных
                                 пикселей всех восьми блоков плюс 90 поджима
                                 первого экрана. Числа сняты с живой страницы
                                 06.09; архив и заявка держат высоту по
                                 содержимому, поэтому при их изменении сверять
                                 заново.
                                 Высота слоя,
                                 viewBox и height у .thread обязаны совпадать,
                                 иначе линия сжимается по вертикали и её
                                 боковые ходы уезжают из кадра */
  transform: scale(var(--k, 1));
  transform-origin: 0 0;
  overflow: hidden;           /* линия уходит за верхний и нижний обрез листа */
  pointer-events: none;
}

/* ПОЛОСА — ОКНО В СЛОЕ. Их три: до архива, между архивом и заявкой,
   между заявкой и футером. В архиве, заявке и футере линию рисует не
   верхний слой, а копии .thread-under внутри самих блоков — только так
   она ложится ПОД кадры и книжку.

   Здесь на этом месте стоял вырез clipPath, и он ронял Safari с 60 кадров
   до 9,6 (замер 06.09, БАГИ.md, Б-3): маска пересчитывалась заново каждый
   кадр прокрутки по всей высоте листа. Окно с overflow: hidden браузеру
   ничего не стоит — за краем просто не рисуется.

   Верх и высоту ставит thread.js по настоящим границам блоков. */
.thread-band {
  position: absolute;
  left: 0;
  width: 1440px;
  overflow: hidden;
}

/* Высота у .thread больше не общая: каждая полоса показывает свой кусок
   листа через собственный viewBox, и высоту ей тоже ставит thread.js.
   Число здесь — на случай, если скрипт не завёлся. */
.thread { display: block; width: 1440px; height: 7328px; overflow: visible; }

/* Толщина та же, что была у маршрута внутри блока «события»: 2,4.
   Линия остаётся линией и не превращается в ленту. */
.thread__path {
  fill: none;
  stroke: var(--red);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: var(--len, 6000);
  stroke-dashoffset: var(--dash, var(--len, 6000));
}

/* Кончик маркера — короткий штрих на конце линии, положение и поворот
   считает s3.js по касательной. Пока линия дорисовывается, видно, чем
   именно её ведут. */
.thread__nib {
  stroke: var(--red);
  stroke-width: 2.4;         /* та же толщина, что у самой линии — это её же перо */
  stroke-linecap: round;
  opacity: 0;
}

.thread__nib[data-on] { opacity: 0.9; }

/* =====================================================================
   ГАШЕНИЕ СТАРОГО СЦЕНАРИЯ

   В index.html блок «события» печатается по расписанию, как только
   попал в кадр (.scene--events[data-in] + задержки). Здесь за порядок
   отвечает линия, поэтому расписание выключено целиком — иначе два
   сценария играли бы поверх друг друга.
   ===================================================================== */
.scene--events[data-in] .stamp--big .stamp__layer > span,
.scene--events[data-in] .pic,
.scene--events[data-in] .reel--hero,
.scene--events[data-in] .folio,
.scene--events[data-in] .cap,
.scene--events[data-in] .cat,
.scene--events[data-in] .note,
.scene--events[data-in] .lead path,
.stamp--since[data-lit] span { animation: none; }

.scene--events[data-in] .bar--events,
.scene--events[data-in] .bar--events2 { transition: none; transform: scaleX(0); }

/* =====================================================================
   ЧТО ЗНАЧИТ «ЛИНИЯ ДОШЛА»

   Один атрибут на всё — data-lit. Его ставит s3.js в тот момент, когда
   голова линии проходит мимо предмета. Дальше предмет сам решает, что
   у него значит «ожить»: текст проступает, кадр раскрывается, число
   впечатывается, полоса разъезжается.
   ===================================================================== */

/* --- ТЕКСТ: проступает и доезжает на 6px --- */
.folio, .cap, .stub-title, .cat {
  transform: translateY(6px);
  transition: opacity 520ms ease, transform 560ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

.folio[data-lit],
.cap[data-lit],
.stub-title[data-lit],
.cat[data-lit] { opacity: 1; transform: translateY(0); }

/* Рукопись только проступает: наклон у неё содержательный, трогать его
   нельзя. */
.note { transition: opacity 620ms ease; }
.note[data-lit] { opacity: 1; }

/* --- КАДРЫ: раскрытие clip-path ---------------------------------------
   Единственное, что взято у референса напрямую. Кадр не «включается»
   прозрачностью, а раскрывается полосой слева направо — так, как
   ложится краска, и в ту же сторону, в какую идёт маркер.
   Прозрачность при этом переключается почти мгновенно: тянуть надо
   раскрытие, а не проявление, иначе кадр читается как всплывающий. */
.stage--events .pic,
.stage--events .reel--hero {
  /* Раскрыт по умолчанию: линия задаёт КОГДА красиво шевельнуться,
     а не «показывать ли вообще». Пока стояло inset(0 100% 0 0), кадры
     оставались невидимыми всякий раз, когда линия не двигалась. */
  clip-path: inset(0 0 0 0);
  transition:
    opacity 120ms linear,
    clip-path 700ms cubic-bezier(0.22, 0.75, 0.25, 1),
    transform 0.45s cubic-bezier(0.2, 0.7, 0.3, 1),
    filter 0.55s ease;
}

.stage--events .pic[data-lit],
.stage--events .reel--hero[data-lit] { opacity: 1; clip-path: inset(0 0 0 0); }

/* --- ЧИСЛА: впечатываются ---------------------------------------------
   Знаки те же и анимация та же (stamp-in из section-events.css),
   меняется только повод: не «секция пришла», а «маркер дошёл». */
.stamp[data-lit] .stamp__layer > span,
.stamp--mid[data-lit] > span {
  opacity: 1;
  animation: stamp-in 440ms cubic-bezier(0.2, 0.85, 0.3, 1) forwards;
  animation-delay: calc(var(--i, 0) * 64ms);
}

/* --- ВЫНОСКИ У ГРУППОВЫХ ПОДПИСЕЙ --- */
.lead[data-lit] path {
  animation: lead-draw var(--lead-ms, 620ms) cubic-bezier(0.25, 0.8, 0.35, 1) forwards;
}

/* --- ПОЛОСЫ --- */
.bar--events, .bar--events2, .bar--stub { transform: scaleX(0); transform-origin: 0 50%; }

.bar--events[data-lit],
.bar--events2[data-lit],
.bar--stub[data-lit] {
  transform: scaleX(1);
  transition: transform 620ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* =====================================================================
   СЕКЦИИ-ЗАГЛУШКИ

   Пустая бумага с колонтитулом и крупным моно. Нужны, чтобы был виден
   ход линии на нескольких блоках подряд, и построены под него: слово
   стоит там, где линия идёт горизонтально, и подчёркивается ею —
   отдельной черты для этого не рисуется, черта и есть сама линия.
   ===================================================================== */
/* Кегли чисел и правое поле объявлены в section-events.css на
   .stage--events. Заглушки — другая сцена, поэтому те же значения
   нужны и здесь: без них .stamp--mid остаётся без размера и число
   печатается служебной мелочью. */
.stage--stub {
  --num-mid: 104px;
  --num-ls: -0.055em;
  --edge-r: 73px;
}

.stage--stub .paper { left: 18px; top: 18px; width: calc(100% - 36px); height: calc(100% - 36px); }
.stage--stub .grain { left: 18px; top: 18px; width: calc(100% - 36px); height: calc(100% - 36px); }

/* Колонтитул в заглушках отодвинут от левого поля: там, где в блоке
   «события» пусто, здесь идёт сама линия, и на 73px она перечёркивала
   бы косую черту метки. */
.stage--stub .folio { left: 118px; }

.stub-title {
  left: 118px;
  font-size: 72px;
  line-height: 78px;
  color: var(--ink);
  opacity: 0;
  z-index: 4;
}

.cap--stub { left: 118px; }

/* 03 — линия приходит слева и идёт вправо на y 2449 (макетных),
   то есть на 328 внутри секции. Слово стоит в 20px над ней. */
.stage--stub3 .stub-title { top: 230px; }
.stage--stub3 .cap--stub  { top: 354px; }

/* 04 — линия горизонтальна на 391 внутри секции. */
.stage--stub4 .stub-title { top: 293px; }
.stage--stub4 .cap--stub  { top: 417px; }

/* Число справа: линия к этому моменту спускается по правому полю и
   проходит на его высоте. */
.stamp--stub { right: var(--edge-r, 73px); top: 560px; text-align: right; }
.cap--stub-num { right: var(--edge-r, 73px); top: 646px; text-align: right; }

/* 05 — линия горизонтальна на 439 внутри секции. */
.stage--stub5 .stub-title { top: 341px; }
.stage--stub5 .cap--stub  { top: 465px; }

.bar--stub { left: 0; top: 700px; width: 420px; height: var(--stripe-h); background: var(--red); }

/* Красные плашки в заглушках берут цвет из компонента .bar, но у 05-й
   он свой — на всякий случай задан явно выше. */

/* =====================================================================
   СЛУЖЕБНЫЙ РЕЖИМ ?scroll=…

   В headless-браузере время CSS не идёт: переходы не проигрываются,
   rAF не вызывается. Поэтому для съёмки состояние выставляется разом,
   а вся анимация выключается — снимок показывает ровно то, к чему
   пришли бы переходы.
   ===================================================================== */
.is-static *,
.is-static *::before,
.is-static *::after {
  transition: none !important;
  animation: none !important;
}

.is-static .lead[data-lit] path { stroke-dashoffset: 0; }
.is-static .stamp[data-lit] .stamp__layer > span,
.is-static .stamp--mid[data-lit] > span { opacity: 1; transform: none; }

/* =====================================================================
   СПОКОЙНЫЙ РЕЖИМ

   Линия нарисована целиком и сразу, всё, что она вела, показано.
   Тянуть нечего: сайт открывается дочитанным.
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  .thread__path { stroke-dashoffset: 0; }
  .thread__nib { display: none; }

  .folio, .cap, .stub-title, .cat, .note { opacity: 1; transform: none; }
  .note--year { transform: rotate(-3deg); }
  .note--work { transform: rotate(-9deg); }

  .stage--events .pic,
  .stage--events .reel--hero { opacity: 1; clip-path: none; transition: none; }

  .stamp .stamp__layer > span,
  .stamp--mid > span { opacity: 1; animation: none !important; }

  .lead path { stroke-dashoffset: 0; animation: none !important; }
  .bar--events, .bar--events2, .bar--stub { transform: none; }
}


/* =====================================================================
   БАЗОВОЕ СОСТОЯНИЕ — ВИДНО

   Правило всего сайта: линия ведёт и подсвечивает, но содержимое
   существует независимо от неё. Всё, что раньше пряталось до прихода
   головы линии, теперь по умолчанию на месте.
   ===================================================================== */
.stage--events .pic,
.stage--events .reel--hero,
.stamp .stamp__layer > span,     /* так же специфично, как правило,
.stamp--mid > span,                 которое их гасит, — иначе не победить */
.stamp span,
.stub-title { opacity: 1; }
