/* ============================================================================
   site/film.css — скролл-фильм «Грузовик».

   Два состояния одной разметки:

   • БЕЗ класса .film-on (нет JS, либо prefers-reduced-motion) — обычная
     секция: постер сверху, реплики столбиком под ним. Законченный экран,
     а не обломок.
   • С классом .film-on — липкая сцена во весь экран, кадры на <canvas>,
     реплики выплывают по прогрессу (альфу и подъём считает film.js).

   Класс вешает крошечный синхронный скрипт в <head>, а не сам модуль:
   модуль отложенный, и переключение раскладки после разбора HTML дало бы
   видимый перескок.
   ========================================================================== */

/* Прогресс фильма и выведенная из него растушёвка — НЕНАСЛЕДУЕМЫЕ числа.
   film.js пишет --p каждый кадр прокрутки прямо тем, кто его читает
   (сцене, полоске прогресса, подсказке). Будь переменная наследуемой, её
   смена пересчитывала бы стиль всем потомкам сцены — репликам, кадрам,
   рельсу; а --film-exit без регистрации ещё и менялся бы на каждом кадре
   как строка «clamp(0, (0.4523 − .9)…)», хотя число в нём — ноль.
   Замер 24.09.2026: пересчёт стилей в фильме втрое меньше. */
@property --p{ syntax:'<number>'; inherits:false; initial-value:0 }
@property --q{ syntax:'<number>'; inherits:false; initial-value:0 }
@property --film-exit{ syntax:'<number>'; inherits:false; initial-value:0 }

.film{ position:relative; isolation:isolate }

.film-stage{ position:relative; overflow:hidden;
  /* Статичный вид — обычная секция страницы: те же поля, что у .wrap,
     и запас сверху под шапку. В режиме фильма всё это снимается. */
  width:100%; max-width:var(--maxw); margin:0 auto;
  padding:clamp(122px,15vh,196px) var(--pad) clamp(40px,7vh,88px);
}

/* Постер = первый кадр. Держит LCP и лежит под холстом, пока не доехали
   кадры: холст до этого прозрачный, поэтому пустого экрана нет ни секунды.
   Обёртка <picture> (AVIF/WebP/JPEG) в раскладке не участвует вовсе. */
.film-stage picture{ display:contents }
.film-poster{
  display:block; width:100%; height:auto;
  border-radius:var(--r);
}

.film-canvas{ display:none }

.film-rail{ display:none }

/* ── реплики: статичный столбик ─────────────────────────────────────── */

.film-beats{ display:grid; gap:56px; padding:56px 0 8px }

.beat{ display:grid; gap:18px; align-content:start }

.beat-eyebrow{
  font-size:12.5px; font-weight:700; letter-spacing:.12em; text-transform:uppercase;
  color:var(--acc);
}
.beat-eyebrow.is-quiet{ color:var(--muted) }

.beat h1,.beat h2{ max-width:16ch }
.beat p{ max-width:46ch; color:var(--muted); font-size:clamp(15px,1.5vw,18px); line-height:1.5 }

/* ── карточка «что видит FLUX» ──────────────────────────────────────── */

.beat-panel{
  width:min(360px,100%); padding:18px 18px 14px; border-radius:20px;
  background:var(--glass); border:var(--hair); box-shadow:var(--bevel),var(--shadow);
}
/* В фильме карточка стоит не на странице, а на кадре — и самый яркий кусок
   ленты («просвеченный» кузов с грузом) приходится ровно под неё. Обычного
   стекла там не хватает: строки заказа тонут в свечении. Поэтому под стеклом
   плотная подложка — плотнее общего --glass-base, тот рассчитан на спокойный
   фон страницы. */
.film-on .beat-panel{
  background-color:rgba(7,17,14,.86);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
}

.beat-panel-h{
  display:flex; align-items:center; gap:9px; padding-bottom:12px; margin-bottom:10px;
  border-bottom:var(--hair); font-size:13px; font-weight:700; letter-spacing:-.01em;
}
.beat-panel-h svg{ width:17px; height:17px; flex:none; stroke:var(--acc) }

.beat-rows{ display:grid; gap:9px }
.beat-row{ display:grid; grid-template-columns:20px 1fr auto; align-items:center; gap:10px;
  font-size:13.5px }
.beat-row svg{ width:18px; height:18px; stroke:var(--muted) }
.beat-row b{ font-weight:500; color:var(--ink) }
.beat-row span{ color:var(--muted); font-size:12.5px; white-space:nowrap }

.beat-foot{ padding-top:11px; margin-top:11px; border-top:var(--hair);
  font-size:11.5px; color:var(--muted); letter-spacing:.01em }

/* ══════════════════════════════════════════════════════════════════════
   Режим фильма
   ══════════════════════════════════════════════════════════════════════ */

/* 660 экранов-сотых — сам фильм, ещё 150 — хвост со сценой автографа
   (.film-coda, film-sign.js): кадры идут прежним темпом, film.js вычитает
   хвост из пути. */
.film-on .film{
  height:810vh;
  height:810svh;
  /* Путь меряется замороженным экраном: --vh ставит шапка главной при загрузке
     и меняет только вместе с шириной. Встроенный браузер Telegram на iPhone,
     сворачивая свои панели, меняет высоту веб-вью — и вместе с ней все vh, svh
     и dvh. Фильм, «живые экраны» и стейк — двенадцать экранов пути, и каждое
     движение панели сдвигало всё ниже них на экран с лишним: человек смотрит
     «Зал», а перед глазами вдруг каталог. Липкая сцена внутри остаётся в svh —
     она обязана закрывать экран целиком, а длину страницы она не меняет. */
  height:calc(var(--vh, 1svh) * 810);
}

/* Хвост фильма: пустая распорка в полтора экрана. film.js берёт её высоту
   как длину хвоста и отдаёт долю q; в хвосте — сцена автографа. */
.film-coda{ display:none }
.film-on .film-coda{ display:block; height:calc(var(--vh, 1svh) * 150); visibility:hidden; pointer-events:none }

/* Затемнение кадра в хвосте: карточка уходит в глубину и глохнет, чтобы
   лаймовые строки и подпись были главными. Прозрачность ставит film-sign.js. */
.film-tone{ display:none }
.film-on .film-tone{ display:block; position:absolute; inset:0; z-index:1; background:var(--bg); opacity:0; pointer-events:none }

/* Сцена хвоста на широком экране — как у Ландо: карточка кадра ужимается
   к центру (fx/parallax.css по --q), за ней две бегущие строки крупного
   шрифта — лаймовая антиква и светлый гротеск, — сверху метка. Слой строк
   липкий и ПОД сценой: z-index:-1 внутри изолированной секции (.film —
   isolation:isolate), поэтому карточка закрывает середину строк.
   Прозрачность слоя и сдвиг строк ведёт film-sign.js по q. */
.film-rows{ display:none }
@media (min-width:992px){
  .film-on .film-rows{
    display:block; position:sticky; top:0; z-index:-1; overflow:hidden;
    height:100vh; height:100svh; margin-top:-100vh; margin-top:-100svh;
    pointer-events:none; opacity:0;
  }
}
.film-from{
  position:absolute; left:50%; top:clamp(96px,14vh,140px); translate:-50% 0; margin:0;
  font-size:12px; font-weight:800; letter-spacing:.22em; text-transform:uppercase; color:var(--ink);
}
.film-row{
  position:absolute; left:50%; top:50%; margin:0;
  white-space:nowrap; text-transform:uppercase;
}
.film-row.r1{
  translate:-50% -100%;
  font-family:Oranienbaum, Georgia, "Times New Roman", serif; font-weight:400;
  font-size:clamp(72px,8.4vw,168px); line-height:.86; letter-spacing:-.005em;
  /* Приглушённый лайм: чистый акцент — только у подписи поверх строки,
     иначе перо тонет в буквах того же цвета. */
  color:#A9BF4A;
  color:color-mix(in oklab, var(--cta) 74%, var(--bg));
}
.film-row.r2{
  translate:-50% 4%;
  font-family:var(--disp); font-weight:800;
  font-size:clamp(46px,5.2vw,104px); line-height:.95; letter-spacing:-.02em;
  color:var(--paper);
}
.film-row.r1 span + span{ margin-left:.32em }
/* Разделитель — тусклый, не лаймовый: лаймовая точка вставала у «x» подписи
   и читалась как «Flux.» */
.film-row.r2 span::after{ content:"·"; margin:0 .42em; color:#55665D; color:color-mix(in oklab, var(--paper) 36%, var(--bg)) }

/* Слой автографа — липкий ПОВЕРХ сцены, а не внутри неё: у сцены
   overflow:hidden и масштаб карточки, подпись обрезалась бы по её краю.
   Отрицательный отступ кладёт слой в поток ровно на место сцены, поэтому
   он прилипает и отлипает вместе с ней. Холст внутри — по рамке подписи
   (film-sign.js ставит ему место и размер). Тень — только пока есть чернила. */
.film-sign{ display:none }
.film-on .film-sign{
  display:block; position:sticky; top:0; z-index:4;
  height:100vh; height:100svh; margin-top:-100vh; margin-top:-100svh;
  pointer-events:none;
}
.film-sign canvas{ position:absolute; display:block }
.film-on .film-sign canvas.is-on{ filter:drop-shadow(0 3px 10px rgba(0,0,0,.45)) }

.film-on .film-stage{
  position:sticky; top:0;
  height:100vh; height:100svh;
  max-width:none; padding:0;
  background:var(--bg);
}

/* Уход фильма в полотно. В конце хвоста (--q .82…1, ставит film.js — сперва
   дописывается автограф) низ кадра растворяется: дальше сцена отлипает и
   уезжает вверх, и без этого по экрану поехал бы нижний край фотографии —
   ровная линия во всю ширину, первый же стык страницы. Подпись лежит на
   своём слое и не гаснет — уезжает вместе с секцией.
   Маской в прозрачность, а не заливкой в --bg: по полотну идут
   топографические линии (fx/contours.js), и ровная краска у низа сцены
   обрывала их по линейке — стык возвращался, только другой. Маска гасит
   кадр целиком (с репликой) — на последней десятой реплика уже сказана.
   На широком экране вместо растушёвки герой сжимается в карточку
   (fx/parallax.css гасит маску). */
.film-on .film-stage{
  --film-exit:clamp(0, (var(--q, 0) - .82) / .18, 1);
  -webkit-mask-image:linear-gradient(to top,
    rgb(0 0 0 / calc(1 - var(--film-exit))) 0%, rgb(0 0 0 / calc(1 - var(--film-exit))) 14%, #000 52%);
          mask-image:linear-gradient(to top,
    rgb(0 0 0 / calc(1 - var(--film-exit))) 0%, rgb(0 0 0 / calc(1 - var(--film-exit))) 14%, #000 52%);
}

.film-on .film-poster,
.film-on .film-canvas{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; border-radius:0;
}

.film-on .film-canvas{
  display:block; opacity:0;
  transition:opacity .45s var(--e-micro);
}
.film-on .film.is-live .film-canvas{ opacity:1 }

/* Затемнение слева под текст: кадры светлые (закат, лампы ангара), белая
   типографика на них без подложки не читается. Второй слой — низ кадра,
   чтобы рельс прогресса и подпись не висели в пустоте. */
.film-scrim{ display:none }
.film-on .film-scrim{
  display:block; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    linear-gradient(100deg, rgba(6,16,12,.90) 0%, rgba(6,16,12,.72) 26%,
                            rgba(6,16,12,.30) 52%, rgba(6,16,12,0) 74%),
    linear-gradient(0deg, rgba(6,16,12,.72) 0%, rgba(6,16,12,0) 26%);
}
/* Все реплики лежат стопкой в центре сцены. Абсолютом, а не потоком: иначе
   каждая двигала бы соседние, а нужно чтобы одна уходила ровно туда, откуда
   приходит следующая. */
.film-on .film-beats{ position:absolute; inset:0; z-index:2; display:block; padding:0 }

.film-on .beat{
  position:absolute; left:50%; top:50%;
  translate:-50% -50%;                    /* центрирование по своей высоте */
  transform:translate3d(0,18px,0);        /* этот канал ведёт film.js */
  width:min(1180px,100% - 48px);
  opacity:0;
  will-change:transform,opacity;
  display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  align-items:center; gap:48px;
}
.film-on .beat > .beat-copy{ grid-column:1; max-width:640px }

.film-on .beat-1{ opacity:1 }
/* Первая реплика — афиша: стоит не в середине кадра, а у нижнего левого
   угла, на тёмном полу ангара. Светлый кузов в середине кадра остаётся
   чистой картинкой, а крупные буквы — на тёмном, где им не нужна подложка.
   Левый край — по знаку в шапке, как у Ландо: имя и первый экран на одной
   вертикали. */
@media (min-width:901px){
  .film-on .beat-1{ top:auto; bottom:clamp(56px,11vh,120px); translate:0 0;
    left:calc(var(--pad) + 16px); width:calc(100% - 2 * var(--pad) - 32px) }
  .film-on .beat-1 > .beat-copy{ max-width:none; gap:22px }
  .film-on .beat-1 .beat-eyebrow{ max-width:none; white-space:nowrap }
}

.film-on .beat-copy{ display:grid; gap:18px; align-content:center }

/* ЗАГОЛОВОК ГЕРОЯ — ПЛАКАТОМ. У Ландо первый экран держит шрифт: имя
   набрано так крупно, что оно и есть картинка. Наш h1 стоял на 58 px —
   заголовок раздела, а не афиша. Теперь до 84 px, строки ровняет
   balance («Весь ресторан / в одном / приложении», а не висячее «в» в конце
   первой строки), интерлиньяж сжат до плакатного. Правее 13ch заголовок не
   идёт: там светлый кузов, и по нему белые буквы не читаются. */
.film-on .beat h1{ font-size:clamp(34px,5.4vw,84px); max-width:13ch;
  line-height:.98; letter-spacing:-.02em; text-wrap:balance }
.film-on .beat h2{ font-size:clamp(24px,3.5vw,44px); max-width:15ch;
  font-weight:700; letter-spacing:-.01em; line-height:1.12 }
.film-on .beat p{ color:#C6D8D1; max-width:44ch; text-shadow:0 1px 18px rgba(0,0,0,.5) }
.film-on .beat h1,
.film-on .beat h2{ text-shadow:0 2px 30px rgba(0,0,0,.55) }
/* Надпись над репликой — лаймом и мелко, как подписи у Ландо. Раньше
   правило для абзацев реплики (.beat p) перебивало ей и цвет, и кегль: она
   выходила серой строкой в 18 px и на первом экране ломалась надвое. */
.film-on .beat .beat-eyebrow{ font-size:13px; letter-spacing:.16em; color:var(--cta);
  text-shadow:0 1px 14px rgba(0,0,0,.6) }
.film-on .beat .beat-eyebrow.is-quiet{ color:#C6D8D1 }

.film-on .beat-panel{ grid-column:2; justify-self:end }

/* ── рельс прогресса: где я в фильме ────────────────────────────────────
   Он же заменяет «крутите вниз»: полоса, которая наливается, объясняет
   происходящее лучше подпрыгивающей стрелки — и ничего не мигает. */

.film-on .film-rail{
  display:block; position:absolute; z-index:3;
  right:26px; top:50%; translate:0 -50%;
  width:2px; height:min(240px,32vh);
  border-radius:2px; background:rgba(255,255,255,.14);
  overflow:hidden;
}
.film-on .film-rail i{
  display:block; width:100%; height:100%;
  background:var(--cta);
  transform:scaleY(var(--p,0)); transform-origin:top;
}
.film-on .film-rail b{
  position:absolute; left:-3px; width:8px; height:1px; background:rgba(255,255,255,.28);
}

.film-on .film-cap{
  position:absolute; z-index:3; left:50%; translate:-50% 0; bottom:22px;
  font-size:11.5px; letter-spacing:.14em; text-transform:uppercase;
  color:rgba(230,243,238,.42);
  opacity:calc(1 - var(--p,0) * 7);
}

/* ── телефон ────────────────────────────────────────────────────────── */

@media (max-width:900px){
  /* Путь фильма на телефоне короче: шесть реплик на 5,6 экрана — это
     минута прокрутки большим пальцем ради ролика, который сам по себе
     длится десять секунд. Реплики те же и в том же порядке, просто кадр
     перематывается живее — так фильм читается за один жест, а не за
     десять. */
  .film-on .film{ height:520vh; height:520svh; height:calc(var(--vh, 1svh) * 520) }
  .film-on .film-coda{ height:calc(var(--vh, 1svh) * 80) }

  /* Кадр вертикальный, и середину занимает сама машина. Реплику сажаем
     на низ: там она не спорит с сюжетом и стоит на плотной подложке.
     Прижимаем по нижнему краю, а не по центру — иначе реплики разной
     высоты прыгали бы друг относительно друга. */
  .film-on .beat{ grid-template-columns:minmax(0,1fr); gap:22px;
    top:auto; bottom:clamp(46px,8vh,92px); translate:-50% 0;
    align-content:end; justify-items:start }
  .film-on .beat-panel{ grid-column:1; justify-self:start; width:min(320px,100%) }
  .film-on .film-rail{ right:13px; top:38%; height:min(150px,22vh) }
  .film-on .film-cap{ display:none }   /* низ занят репликой */

  .film-on .film-scrim{
    background:
      linear-gradient(180deg, rgba(6,16,12,.62) 0%, rgba(6,16,12,.16) 22%,
                              rgba(6,16,12,.60) 54%, rgba(6,16,12,.93) 100%);
  }
}

@media (max-width:520px){
  .film-on .beat h1{ font-size:clamp(28px,8.6vw,42px) }
  .film-on .beat h2{ font-size:clamp(22px,5.8vw,30px) }
  .film-on .beat-panel{ display:none }   /* на 360 px карточка съедает реплику */
}
