/* Заставка «путь коробки»: рулон → чертёж → печать в два прогона →
   вырубка → склейка → сборка в 3D с поворотом в изометрию → крышка. Пока идёт загрузка, круг
   повторяется; дошла до конца — пачка остаётся в середине и затихает.

   Роман 16.09.2026: «крутую анимацию заставки для PWA… анимацию печати пачки
   картонной от чертежа до печати на листе, вырубки и склейки… минималистичный
   производственный цикл». Отлаживалась отдельной страницей
   (`design/splash/preview.html`); здесь — то же, с приставкой `fs-` у классов и
   id, чтобы не задеть ни одного правила остального Флоу. Вторая редакция —
   17.09.2026, разбор и список правок в шапке `js/splashMotion.js`.

   Палитра прежняя и не расширялась: индиго (`--fs-ink/side/top`), бумага
   (`--fs-paper`), искра (`--fs-spark`) и чертёжный `--accent-text`. Клей и
   прижим сделаны той же искрой — своих цветов у них нет нарочно, чтобы сцена
   осталась в одной гамме.

   Этапы до склейки — CSS (классы на `.fs-stage`), сборка, крышка и повтор
   круга — 3D-модель в `js/splashMotion.js`. */

:root {
  --fs-paper: rgba(26, 27, 38, .06); --fs-paper-line: rgba(26, 27, 38, .2);
  /* Тот же лист, но непрозрачный: полупрозрачный пропускал тень, и она
     ложилась поверх листа, а не под него (Роман, 18.09.2026). Это --fs-paper
     поверх фона заставки, смешанный заранее. */
  --fs-paper-solid: #E1DFE9;
  --fs-ink-a: #5B5BD6; --fs-ink-b: #7B69EC;
  --fs-side-a: #3F3B9E; --fs-side-b: #4C42AE;
  --fs-top-a: #8A86EE; --fs-top-b: #A597F4;
  --fs-mark: rgba(255, 255, 255, .94);
  --fs-spark: #5B5BD6;
  --fs-shadow: rgba(63, 59, 158, .34);
}
[data-theme="dark"] {
  /* Плотнее, чем было (.075): на почти чёрном фоне лист до печати не читался
     вовсе — виден был только чертёж. */
  --fs-paper: rgba(236, 236, 244, .14); --fs-paper-line: rgba(236, 236, 244, .3);
  --fs-paper-solid: #2B2B33;
  --fs-ink-a: #6E6ADE; --fs-ink-b: #8F7CF2;
  --fs-side-a: #4B47B0; --fs-side-b: #5A4FC2;
  --fs-top-a: #9B97F2; --fs-top-b: #B3A6F7;
  --fs-spark: #FFFFFF;
  --fs-shadow: rgba(110, 106, 222, .62);
}

/* Только на мобильных (метка `splash-motion` из <head>): на компьютере — знак,
   «Флоу.» и фраза, как было. */
:root:not(.splash-motion) .fs-stage { display: none; }
:root.splash-motion .splash__lockup,
:root.splash-motion .splash__phrase { display: none; }

/* Крупно: Роман 16.09.2026 про первую выкатку — «мелковато получилось, можно
   крупнее». На телефоне сцена почти во всю ширину, на мониторе — умеренно. */
.fs-stage { position: relative; width: min(400px, 92vw); aspect-ratio: 300 / 220; }
:root.splash-quick .fs-stage { width: min(320px, 86vw); }

/* Короткая заставка начинает со склейки: лист уже напечатан и вырублен.
   Этапы до неё проигрываются мгновенно — класс остаётся навсегда, иначе
   снятие обнулило бы длительность и анимации пошли бы заново. */
.fs-instant *, .fs-instant { animation-duration: 0s !important; animation-delay: 0s !important; transition-duration: 0s !important; transition-delay: 0s !important; }
.fs-stage svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.fs-stage .fs-css { transform-box: fill-box; }

.fs-ink-a { stop-color: var(--fs-ink-a); } .fs-ink-b { stop-color: var(--fs-ink-b); }
.fs-side-a { stop-color: var(--fs-side-a); } .fs-side-b { stop-color: var(--fs-side-b); }
.fs-top-a { stop-color: var(--fs-top-a); } .fs-top-b { stop-color: var(--fs-top-b); }

/* --- 0. рулон и лист ---
   Рулон — цилиндр с сердечником; полоски внутри едут поперёк и читаются
   проворотом, пока лист сходит. */
.fs-sheet { fill: var(--fs-paper-solid); stroke: var(--fs-paper-line); stroke-width: 1; transform-origin: 0 50%; transform: scaleX(0); }
.fs-roll { opacity: 0; }
.fs-roll-body { fill: var(--fs-paper-solid); stroke: var(--fs-paper-line); stroke-width: 1; }
.fs-roll-cap { fill: color-mix(in srgb, var(--accent-text) 18%, transparent); stroke: var(--fs-paper-line); stroke-width: .8; }
.fs-roll-core { fill: var(--accent-text); opacity: .55; }
.fs-roll-spin rect { fill: var(--fs-paper-line); opacity: .5; }
.fs-unroll .fs-sheet { animation: fs-unroll 340ms cubic-bezier(.45, 0, .2, 1) both; }
.fs-unroll .fs-roll { animation: fs-roll-go 340ms cubic-bezier(.45, 0, .2, 1) both; }
.fs-unroll .fs-roll-spin { animation: fs-roll-spin 260ms linear infinite; }
@keyframes fs-unroll { to { transform: scaleX(1); } }
@keyframes fs-roll-go {
  0% { opacity: 0; transform: translateX(0); } 12% { opacity: 1; } 86% { opacity: 1; }
  100% { opacity: 0; transform: translateX(286px); }
}
@keyframes fs-roll-spin { from { transform: translateX(-5px); } to { transform: translateX(0); } }

/* --- 1. чертёж ---
   Контур — одна линия вокруг всей развёртки, без разрывов; линии сгиба
   проступают следом и остаются до сборки (биговки отдельным валиком больше
   нет). Размер «70» показывается и гаснет внутри этапа, один раз: гас он на
   печати, и каждый прогон перезапускал угасание — «70» мигало снова. */
.fs-die { fill: none; stroke: color-mix(in srgb, var(--accent-text) 80%, transparent); stroke-width: 1.4;
  stroke-linejoin: round; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; }
.fs-fold { fill: none; stroke: color-mix(in srgb, var(--accent-text) 45%, transparent); stroke-width: 1;
  stroke-dasharray: 3 3; opacity: 0; }
/* До чертежа контура нет вовсе: пустой штрих со скруглённым концом всё равно
   рисуется точкой, и она висела на пустой сцене ещё до листа (Роман,
   18.09.2026, нулевой кадр). */
.fs-die { visibility: hidden; }
.fs-draw .fs-die { visibility: visible; animation: fs-draw 420ms cubic-bezier(.45, 0, .25, 1) both; }
.fs-draw .fs-fold { animation: fs-fade 220ms var(--ease) 300ms both; }
@keyframes fs-draw { to { stroke-dashoffset: 0; } }
@keyframes fs-fade { to { opacity: 1; } }
@keyframes fs-fade-out { from { opacity: 1; } to { opacity: 0; } }
.fs-tick { fill: none; stroke: color-mix(in srgb, var(--accent-text) 45%, transparent); stroke-width: 1; opacity: 0; }
.fs-tick-label { fill: var(--text-faint); font: 600 7px var(--font-head, var(--font)); letter-spacing: .08em; opacity: 0; }
.fs-draw .fs-tick, .fs-draw .fs-tick-label { animation: fs-tick 560ms linear both; }
@keyframes fs-tick { 0%, 40% { opacity: 0; } 55%, 80% { opacity: 1; } 100% { opacity: 0; } }

/* --- 3. печать ---
   Два прогона: первый накатывает цвет, второй — знак Флоу. На втором краска
   уже лежит (`fs-ink-base`) и не перекатывается (`fs-ink-hold`), а знак
   проявляется ровно за валиком — своей обрезкой `fs-markclip` с тем же ходом.
   Раньше столбики росли сами по себе, и прогон «ничего не делал».
   Краска — ровная, середина между --fs-ink-a и --fs-ink-b: тем же цветом
   скрипт красит лицо 3D-модели, и подмена листа моделью не видна. */
.fs-ink { fill: color-mix(in srgb, var(--fs-ink-a), var(--fs-ink-b)); opacity: var(--fs-ink-op, 1); }
/* Уже отпечатанные слои: лежат под текущим прогоном и не перекатываются. */
.fs-ink-base { fill: color-mix(in srgb, var(--fs-ink-a), var(--fs-ink-b)); opacity: var(--fs-ink-base, 0); }
.fs-inkclip { transform: scaleX(0); transform-origin: 0 50%; }
.fs-print .fs-inkclip { animation: fs-ink 480ms cubic-bezier(.55, .05, .25, 1) both; }
/* Прогон знака: краска уже на листе и не перекатывается заново. */
.fs-ink-hold .fs-inkclip { animation: none; transform: scaleX(1); }
@keyframes fs-ink { to { transform: scaleX(1); } }
/* После печати краска не обрезается: обрезка пересчитывалась бы на каждом
   кадре складывания. */
.fs-cut .fs-ink { clip-path: none; }
.fs-roller { fill: var(--accent-text); opacity: 0; }
.fs-print .fs-roller { animation: fs-roll 480ms cubic-bezier(.55, .05, .25, 1) both; }
@keyframes fs-roll {
  0% { opacity: 0; transform: translateX(0); } 8% { opacity: 1; } 92% { opacity: 1; }
  100% { opacity: 0; transform: translateX(262px); }
}
.fs-printed rect { fill: var(--fs-mark); }
.fs-markclip { transform: scaleX(0); transform-origin: 0 50%; }
.fs-ink-mark .fs-markclip { animation: fs-ink 480ms cubic-bezier(.55, .05, .25, 1) both; }

/* --- 4. вырубка ---
   Нож обходит контур, от него летит пыль, просечка-решётка быстро уезжает и
   тает. */
.fs-knife, .fs-knife-glow { fill: none; stroke-linecap: round; stroke-dasharray: .04 .96; stroke-dashoffset: 1; opacity: 0; }
.fs-knife { stroke: var(--fs-spark); stroke-width: 1.8; }
.fs-knife-glow { stroke: var(--accent-text); stroke-width: 6; }
.fs-cut .fs-knife { animation: fs-knife 360ms cubic-bezier(.5, 0, .5, 1) both; }
.fs-cut .fs-knife-glow { animation: fs-knife-glow 360ms cubic-bezier(.5, 0, .5, 1) both; }
@keyframes fs-knife { 0% { opacity: 0; stroke-dashoffset: 1; } 8% { opacity: 1; } 92% { opacity: 1; } 100% { opacity: 0; stroke-dashoffset: 0; } }
@keyframes fs-knife-glow { 0% { opacity: 0; stroke-dashoffset: 1; } 8% { opacity: .35; } 92% { opacity: .35; } 100% { opacity: 0; stroke-dashoffset: 0; } }
.fs-dust circle { fill: var(--fs-paper-line); opacity: 0; }
.fs-cut .fs-dust circle { animation: fs-dust 520ms ease-out both; }
.fs-cut .fs-dust circle:nth-child(2) { animation-delay: 110ms; }
.fs-cut .fs-dust circle:nth-child(3) { animation-delay: 190ms; }
.fs-cut .fs-dust circle:nth-child(4) { animation-delay: 280ms; }
@keyframes fs-dust {
  0% { opacity: 0; transform: translate(0, 0); } 25% { opacity: .5; }
  100% { opacity: 0; transform: translate(-6px, -12px); }
}
.fs-waste { fill: var(--fs-paper-solid); stroke: var(--fs-paper-line); stroke-width: 1; }
.fs-waste-wrap { opacity: 0; }
/* Лист на вырубке сразу подменяется отходом: отход (лист минус заготовка) и
   заготовка вместе и есть лист. Раньше лист гас с задержкой в 300 мс, и всё это
   время бумага лежала в два слоя — в светлой теме тёмной рамкой, в тёмной
   светлой плашкой вокруг заготовки. */
.fs-cut .fs-sheet { opacity: 0; }
/* Отход уходит коротко: большая бумажная плашка, ползущая почти полсекунды,
   в тёмной теме читалась призраком листа. */
.fs-cut .fs-waste-wrap { animation: fs-waste-out 300ms cubic-bezier(.45, 0, .7, .6) 300ms both; }
@keyframes fs-waste-out {
  0% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translate(26px, 20px) scale(.94); }
}
.fs-glue-on .fs-waste-wrap { visibility: hidden; }
/* В коротком виде вырубки не было — ни рулона, ни отхода на сцене нет. */
:root.splash-quick .fs-waste-wrap, :root.splash-quick .fs-roll { display: none; }
.fs-cut .fs-die { stroke-dashoffset: 0; animation: fs-die-cut 220ms var(--ease) 240ms both; }
@keyframes fs-die-cut { to { stroke: color-mix(in srgb, var(--accent-text) 28%, transparent); } }

/* --- 5. склейка ---
   Полоса клея на клеевом клапане, прижимной валик по ней и короткая искра.
   Своего цвета у клея нет: та же искра, что у ножа. */
.fs-glue-strip { fill: var(--fs-spark); opacity: 0; }
.fs-press { fill: var(--accent-text); opacity: 0; }
.fs-glue-on .fs-glue-strip { animation: fs-glue 360ms var(--ease) both; }
.fs-glue-on .fs-press { animation: fs-press 360ms cubic-bezier(.4, 0, .3, 1) both; }
@keyframes fs-glue {
  0% { opacity: 0; } 30% { opacity: .55; } 75% { opacity: .8; } 100% { opacity: .28; }
}
@keyframes fs-press {
  0% { opacity: 0; transform: translateX(0); } 15% { opacity: .85; }
  60% { opacity: .85; transform: translateX(14px); }
  100% { opacity: 0; transform: translateX(20px); }
}

/* --- 6–7: сборка и крышка — 3D-модель в скрипте ---
   Цвет граней скрипт считает сам из --fs-ink/side/top по направлению грани,
   обводку — из него же с чертёжным --accent-text: она и закрывает щели между
   гранями, и читается линиями сгиба с первого кадра сборки. */
.fs-3d { opacity: 0; }
.fs-3d-face { stroke-width: .7; stroke-linejoin: round; }
.fs-3d-mark { fill: var(--fs-mark); }

/* Тень — размытое пятно формы дна пачки. Форма (`clip-path`) меняется только
   на повороте, в качании — лишь `transform` и `opacity`: пятно двигает
   видеокарта, не пересчитывая размытие. Форма внутри, размытие снаружи. */
.fs-shadow {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  filter: blur(var(--fs-blur, 5px)); will-change: transform, opacity;
}
.fs-shadow > i { position: absolute; inset: 0; background: var(--fs-shadow); clip-path: polygon(0 0, 0 0, 0 0); }
