/* STUDIO NOIR — шар матеріалів і вітринних блоків поверх site.css.

   Окремим файлом, а не дописом у site.css, з однієї причини: усе тут
   ДОДАЄ (нові класи, нові області змінних), а не перебиває. Коли шар
   правлять окремо, видно, що саме належить вітрині, а що — кістяку;
   коли він вмішаний у 1600 рядків, будь-яка правка кольору стає
   археологією.

   Порядок підключення важливий: цей файл іде ПІСЛЯ site.css, тому в
   спірних місцях виграє він без жодного !important.
   ────────────────────────────────────────────────────────────────────── */

/* ═══ 1. МАТЕРІАЛИ СМУГ ═══════════════════════════════════════════════════
   Сторінка чергує два матеріали: темний і кремовий, і один раз —
   суцільний бурштин під фінальним закликом. Це не «світла тема»
   всередині темної: це друкований розворот, де смуги різні на дотик.

   Механіка — перевизначення ЗМІННИХ у межах секції, а не переписування
   правил. Уся таблиця стилів побудована на var(--card), var(--line),
   var(--fg); підмінивши їх на вході в секцію, ми одягаємо разом із нею
   всі картки, рамки й підписи всередині, скільки б їх не було. Жодного
   `.sec-cream .card{...}` — саме такі каскади й перетворюють скіни на
   болото. */
.sec-cream{
  --bg:var(--cream); --bg-2:var(--cream-2);
  --fg:var(--cream-fg); --dim:var(--cream-dim); --faint:var(--cream-faint);
  --line:var(--cream-line); --line-2:oklch(0.82 0.006 80);
  --card:var(--cream-2); --card-2:oklch(0.96 0.005 85);
  /* Яскравий бурштин на кремі не читається як ТЕКСТ — контраст падає
     нижче будь-якого порога. Тому в кремовій смузі акцент глибший:
     він лишається тим самим кольором за родиною, але стає придатним
     і для напису, і для заливки з білим написом. */
  --accent:oklch(0.52 0.14 55); --accent-fg:oklch(0.99 0 0);
  --accent-soft:oklch(0.92 0.035 75);
  --shadow:0 30px 80px -46px oklch(0.2 0.02 60/0.35);
  background:var(--bg); color:var(--fg);
}
:root[data-theme="light"] .sec-cream{
  --line-2:oklch(0.4 0.01 70);
  --card-2:oklch(0.28 0.01 60);
  /* Той самий бурштин, що всюди (#f0a500 із core/01_base.css). Тут він
     ТЕМНОЇ теми: у світлій темі кремові секції перевертаються в темні,
     тож і акцент їм потрібен темнотемний, а не затемнений для білого. */
  --accent:#f0a500; --accent-fg:oklch(0.18 0.02 60);
  --accent-soft:oklch(0.32 0.05 65);
  --shadow:0 30px 80px -40px oklch(0.1 0.01 60/0.9);
}
/* Межа між матеріалами не потребує лінії: різниця тла і є межею.
   Лінія поверх стику читається як шов на місці, де його не зашивали. */
.sec-cream + section, section + .sec-cream{ border-top-color:transparent }

/* ── бурштинова смуга фіналу ─────────────────────────────────────────────
   Єдина суцільна заливка акцентом на всю сторінку. Саме тому вона
   спрацьовує: якби таких смуг було дві, жодна не була б подією. */
.sec-amber{
  /* Саме --amber, а не --accent: --accent перевизначається двома
     рядками нижче, і var(--accent) тут прочитав би вже його. */
  --bg:var(--amber); --bg-2:var(--amber);
  --fg:oklch(0.18 0.02 60); --dim:oklch(0.28 0.03 60); --faint:oklch(0.36 0.03 60);
  --line:oklch(0.18 0.02 60/0.22); --line-2:oklch(0.18 0.02 60/0.34);
  --card:oklch(0.18 0.02 60/0.08); --card-2:oklch(0.18 0.02 60/0.14);
  --accent:oklch(0.18 0.01 60); --accent-fg:oklch(0.93 0.008 85);
  --accent-soft:oklch(0.18 0.02 60/0.12);
  background:var(--amber); color:var(--fg);
  border-top-color:transparent;
}
.sec-amber + section{ border-top-color:transparent }

/* ═══ 2. ДОКАЗ ЯК ТАБЛО ═══════════════════════════════════════════════════
   Було: чотири комірки в рамці з розділювачами-заливкою. Стало: числа
   стоять просто на матеріалі, розділені волосяними вертикалями. Рамка
   навколо чисел робила з них таблицю; вертикаль між ними лишає числа
   числами. Правило з docs/DESIGN.md §1 — форму тримає заливка, лінія
   лишається тільки там, де щось РОЗДІЛЯЄ. Тут вона саме розділяє. */
.proof-grid{
  background:transparent; border:0; border-radius:0; overflow:visible;
  gap:0;
  border-top:1px solid var(--line); border-bottom:1px solid var(--line);
}
.proof-cell{ background:transparent; padding:34px 30px;
  border-left:1px solid var(--line) }
.proof-cell:first-child{ border-left:0; padding-left:0 }
.proof-cell b{ color:var(--accent) }
/* Розділювач мусить знати, ЩО він розділяє. Коли сітка складається у два
   стовпці й один, вертикаль між сусідами перетворюється на риску, що
   висить зліва від числа й не розділяє нічого. Тому на кожному щаблі
   вона стає горизонталлю між рядами. Межі — ті самі, що в site.css
   (1040 і 600); розійдись вони, розділювачі жили б своїм життям. */
@media (max-width:1040px){
  .proof-cell:nth-child(odd){ border-left:0; padding-left:0 }
  .proof-cell:nth-child(n+3){ border-top:1px solid var(--line) }
}
@media (max-width:600px){
  .proof-cell{ border-left:0; padding-left:0; padding-right:0 }
  .proof-cell:nth-child(n+2){ border-top:1px solid var(--line) }
}

/* ═══ 3. КІНОПЛІВКА: ХИТАННЯ ══════════════════════════════════════════════
   Стрічка їде рівно — і саме тому читається як банер. Кадр, що ледь
   гойдається у власній рамці, читається як фізичний предмет: плівка
   не буває натягнута ідеально.

   Хитання живе на ОКРЕМОМУ елементі від їзди. Дві анімації transform на
   одному вузлі перебивають одна одну — виграє остання оголошена, і рух
   мовчки зникає. Тому їде доріжка, а гойдається кадр усередині неї. */
@keyframes noirWobbleA{ 0%,100%{transform:rotate(-1.6deg)} 50%{transform:rotate(-.5deg)} }
@keyframes noirWobbleB{ 0%,100%{transform:rotate(1.2deg)}  50%{transform:rotate(2.4deg)} }
@keyframes noirWobbleC{ 0%,100%{transform:rotate(-.8deg)}  50%{transform:rotate(.4deg)} }
@keyframes noirWobbleD{ 0%,100%{transform:rotate(2deg)}    50%{transform:rotate(.8deg)} }
.marquee .reel{ animation:noirWobbleA 5.5s ease-in-out infinite; will-change:transform }
.marquee .reel:nth-child(4n+2){ animation-name:noirWobbleB; animation-duration:6.2s }
.marquee .reel:nth-child(4n+3){ animation-name:noirWobbleC; animation-duration:5s }
.marquee .reel:nth-child(4n+4){ animation-name:noirWobbleD; animation-duration:6.8s }
@media (prefers-reduced-motion: reduce){ .marquee .reel{ animation:none } }

/* ═══ 4. СТРІЧКА: ТРИ ЕКРАНИ, А НЕ ОДНА ІСТОРІЯ ═══════════════════════════
   Попередній варіант забракували справедливо: смуги прогресу вгорі й
   одна вертикальна картка — це Stories, а не стрічка. Різниця не
   косметична. У Stories кадр належить ОДНОМУ авторові й тримає час; у
   стрічці кадр належить стрічці, і його змінює не таймер угорі, а те,
   що ти гортаєш далі. Тому смуг тут немає взагалі.

   Три екрани замість одного — щоб було видно, що це стрічка, а не
   ролик. Один екран показує відео; три екрани показують ПОТІК. Середній
   більший і різкіший, бічні зменшені й приглушені: погляд отримує
   ціль, а не три рівноправні кандидати. */
.ttf{ padding:96px 0 104px; overflow:hidden }
.ttf-head{ text-align:center }
.ttf-head h2{ max-width:22ch; margin-left:auto; margin-right:auto }
.ttf-head .sub{ margin-left:auto; margin-right:auto; text-align:center }
.ttf-wall{
  display:flex; align-items:center; justify-content:center; gap:26px;
  padding:8px 24px 0;
}
.ttf-phone{
  position:relative; flex:0 0 auto;
  width:min(296px,29vw); aspect-ratio:9/16;
  border-radius:26px; overflow:hidden;
  background:#000;
  border:1px solid var(--line-2);
  box-shadow:0 40px 90px -34px oklch(0.05 0.01 60/.9);
}
/* Бічні екрани — не «менша копія», а ІНША глибина: менші, темніші й
   трохи відсунуті назад. Масштаб без затемнення читався б як помилка
   верстки, затемнення без масштабу — як зіпсоване відео. */
.ttf-phone.side{ width:min(214px,22vw); opacity:.62; transform:translateY(14px) }
.ttf-phone.side::after{
  content:""; position:absolute; inset:0; pointer-events:none; z-index:3;
  background:oklch(0.18 0.01 60/.34);
}
/* ── ГОРТАННЯ ───────────────────────────────────────────────────────────
   Тут стояло «жодного transition: кадр не розчиняється в наступний, він
   його ЗАМІНЮЄ». Правило було про заміну кадру — і як правило про заміну
   воно правильне. Але блок показує не заміну, а ГОРТАННЯ, а різкий стик
   гортання не показує: він читається як перемикання каналів. Людина, що
   гортає стрічку, тягне кадр угору, і наступний приходить знизу.

   Тому стик лишається різким за змістом (жодного розчинення, жодної
   прозорості), але набуває напрямку: старий кадр іде вгору, новий
   піднімається йому на зміну.

   Картки, що не беруть участі в переході, стоять унизу БЕЗ переходу.
   Інакше та, що щойно поїхала вгору (-100%), поверталася б униз (+100%)
   через увесь екран — тобто крізь кадр, який саме зараз дивляться. */
.ttf-card{
  position:absolute; inset:0;
  transform:translateY(100%);
  transition:none;
}
.ttf-card.on,.ttf-card.prev{ transition:transform .55s var(--ease) }
.ttf-card.on{ transform:translateY(0); z-index:2 }
.ttf-card.prev{ transform:translateY(-100%); z-index:1 }
@media (prefers-reduced-motion: reduce){
  .ttf-card,.ttf-card.on,.ttf-card.prev{ transition:none }
}
.ttf-card video{ width:100%; height:100%; object-fit:cover; display:block }
.ttf-shade{
  position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(to top,
    oklch(0.05 0.01 60/.82) 0%, oklch(0.05 0.01 60/.34) 26%,
    transparent 52%, transparent 78%, oklch(0.05 0.01 60/.36) 100%);
}
/* Правий стовпчик — впізнаваний силует будь-якої вертикальної стрічки.
   Числа під іконками обов'язкові: без них це декоративні значки, з ними
   — доказ, що ролик хтось дивився. */
.ttf-rail{
  position:absolute; right:9px; bottom:74px; z-index:2;
  display:flex; flex-direction:column; align-items:center; gap:15px;
  color:#fff;
}
.ttf-ic{ display:flex; flex-direction:column; align-items:center; gap:3px;
  filter:drop-shadow(0 2px 5px rgba(0,0,0,.6)) }
.ttf-ic i{ font-style:normal; font-family:var(--mono); font-size:10.5px;
  font-weight:600; letter-spacing:.02em }
.ttf-ava{
  width:32px; height:32px; border-radius:50%; border:1.6px solid #fff;
  background:var(--accent); position:relative; margin-bottom:4px;
  box-shadow:0 2px 6px rgba(0,0,0,.5);
}
.ttf-ava::after{
  content:"+"; position:absolute; left:50%; bottom:-7px; translate:-50% 0;
  width:15px; height:15px; border-radius:50%;
  background:#fe2c55; color:#fff; font-size:11px; line-height:15px;
  text-align:center; font-weight:700;
}
.ttf-cap{
  position:absolute; left:12px; right:52px; bottom:12px; z-index:2;
  color:#fff; text-align:left;
}
.ttf-cap b{ display:block; font-size:13px; font-weight:700; margin-bottom:3px;
  text-shadow:0 1px 4px rgba(0,0,0,.7) }
.ttf-cap span{ display:block; font-size:12px; line-height:1.35; opacity:.94;
  text-shadow:0 1px 4px rgba(0,0,0,.7) }
.ttf-snd{
  display:flex; align-items:center; gap:5px; margin-top:7px;
  font-family:var(--mono); font-size:10.5px; opacity:.9;
  text-shadow:0 1px 4px rgba(0,0,0,.7);
}
.ttf-note{ text-align:center; margin:30px auto 0; color:var(--dim);
  font-size:13.5px; max-width:52ch }

@media (max-width:860px){
  /* Бічні екрани на телефоні не інформація, а тіснота: середній лишається
     сам і виростає до розміру, на якому видно, що саме там знято. */
  .ttf-phone.side{ display:none }
  .ttf-phone{ width:min(300px,74vw) }
  .ttf-wall{ padding:8px 16px 0 }
}

/* ═══ 5. ГЕРОЙ: ДВІ КОЛОНКИ Й ПРЕДМЕТ ═════════════════════════════════════
   Плівка лишається — але позаду, як глибина. Попереду стоїть екран.
   Обсяг доводить плівка, продукт доводить екран; на першому екрані
   потрібне друге. */
.hero-in{
  display:grid; grid-template-columns:1.12fr .88fr; gap:52px;
  align-items:center;
}
.hero-txt{ min-width:0 }
.hero-phone{ justify-self:end; position:relative }
/* Плівка за текстом була розрахована на всю ширину героя. Коли праворуч
   став екран, вона почала пробиватися крізь нього по краях і сперечатись
   за увагу з тим самим вмістом, що всередині кадру. Гасимо її сильніше:
   вона тепер тло під текстом, а не друга вітрина. */
.hero .filmstrip{ opacity:.42 }
@media (max-width:980px){
  /* Не ховаємо екран на телефоні — він і є доказ. Ставимо його ПІД текст:
     у вузькій колонці поруч він стиснувся б до розміру, на якому не видно,
     що саме там знято. */
  .hero-in{ grid-template-columns:1fr; gap:40px }
  .hero-phone{ justify-self:center }
  .hero .filmstrip{ opacity:.3 }
}

/* ── друкована плашка замість екструзії ──────────────────────────────────
   Тут стояв стос із чотирнадцяти текстових тіней. Він робив рядок опуклим,
   але на серіфі читався як наліпка з іншого проєкту — інша порода літери
   плюс інша епоха ефекту.

   Пробував і градієнтну заливку через `background-clip:text`: заливка
   робить гліф прозорим, тінь крізь нього не тримається, і рядок зрівнюється
   з рештою заголовка. Або суцільний колір із тінню, або градієнт без тіні;
   разом не буває.

   Працює третє: сторінка — друкований розворот, тож рядок не видавлюють,
   його ДРУКУЮТЬ. Бурштинова плашка, літери вибиті з неї чорнилом, поворот
   на -0.8° і одна тверда тінь під САМОЮ ПЛАШКОЮ, а не під літерами. */
.h1-b{
  display:inline-block;
  color:var(--amber-ink); background:var(--amber);
  padding:.02em .13em .12em; border-radius:.05em;
  transform:rotate(-.8deg);
  text-shadow:none;
  box-shadow:
    .04em .055em 0 oklch(0.56 0.12 54),
    .075em .11em .19em oklch(0.05 0.02 60/.5);
}
/* Поворот з'їдає праву кромку, коли рядок доходить до краю колонки. */
.h1-a{ margin-bottom:.06em }

/* ═══ 6. ХРОМ СТРІЧКИ: ЩО РОБИТЬ ЙОГО ВПІЗНАВАНИМ ═════════════════════════
   Рейка з числами в нас була, а впізнавання — ні. Дають його не іконки
   збоку, а два елементи, яких бракувало: рядок вкладок угорі й навігація
   внизу. Без них екран читається як абстрактний плеєр. */
.ph-top{
  position:absolute; top:11px; left:0; right:0; z-index:3;
  display:flex; align-items:center; justify-content:center; gap:16px;
  color:#fff; font-size:12px; letter-spacing:.01em;
  text-shadow:0 1px 4px rgba(0,0,0,.7);
}
.ph-top s{ text-decoration:none; opacity:.62 }
.ph-top b{ font-weight:700; position:relative }
.ph-top b::after{
  content:""; position:absolute; left:50%; translate:-50% 0; bottom:-5px;
  width:18px; height:2px; border-radius:2px; background:#fff;
}
/* Платівка. Єдине, що обертається рівномірно — і тому читається як звук. */
.ph-disc{
  width:26px; height:26px; border-radius:50%; margin-top:3px;
  background:
    radial-gradient(circle at 50% 50%, oklch(0.72 0.13 66) 0 26%, transparent 27%),
    conic-gradient(from 0deg, oklch(0.22 0.01 58), oklch(0.34 0.02 60),
                   oklch(0.18 0.01 58), oklch(0.3 0.02 60), oklch(0.22 0.01 58));
  box-shadow:0 2px 8px rgba(0,0,0,.6), inset 0 0 0 1px rgba(255,255,255,.13);
  animation:phDisc 5.5s linear infinite;
}
@keyframes phDisc{ to{ transform:rotate(360deg) } }
.ph-tags{ opacity:.82; font-weight:600 }
.ph-search{ position:absolute; right:11px; top:1px; width:15px; height:15px;
  opacity:.9 }
/* Рядок звуку біжить — це другий після смуги перемотки знак, що ролик
   ГРАЄ, а не стоїть. Біжить сам напис, а не контейнер: контейнер тримає
   ширину, інакше рядок розсунув би підпис. */
.ttf-snd{ overflow:hidden; white-space:nowrap; max-width:100% }
.ttf-snd span{ display:inline-block; animation:phSnd 11s linear infinite;
  padding-right:26px }
@keyframes phSnd{ from{ transform:translateX(0) } to{ transform:translateX(-50%) } }
@media (prefers-reduced-motion: reduce){ .ttf-snd span{ animation:none } }
/* Смуга ПЕРЕМОТКИ, не прогресу. Прогрес угорі йде сам і означає Stories;
   перемотку внизу тягне глядач і означає стрічку. */
/* Смуга перемотки МУСИТЬ їхати. Нерухома смуга на 38% читається не як
   «відео йде», а як «відео стоїть на паузі» — тобто прямо суперечить тому,
   що ми показуємо. Заповнення росте за той самий час, що живе картка:
   тривалість приходить із `--seek`, її ставить той самий код, що крутить
   колоду, тож смуга не може розійтися з монтажем. */
.ph-seek{
  position:absolute; left:0; right:0; bottom:34px; height:2.5px; z-index:3;
  background:rgba(255,255,255,.22); overflow:hidden;
}
.ph-seek i{
  position:absolute; inset:0; transform-origin:left; display:block;
  background:rgba(255,255,255,.95);
  animation:phSeek var(--seek,3s) linear infinite;
}
@keyframes phSeek{ from{ transform:scaleX(0) } to{ transform:scaleX(1) } }
@media (prefers-reduced-motion: reduce){
  .ph-seek i{ animation:none; transform:scaleX(.38) }
}
/* Стилі нижньої навігації прибрано разом із самою навігацією — див.
   пояснення в `_phone_ui.html`. Мертвий CSS переживає розмітку надовго й
   потім змушує гадати, чи він комусь потрібен. */
/* ── ПОЗИЦІЇ, ЗНЯТІ З РЕФЕРЕНСУ ──────────────────────────────────────────
   Виміряно з реального знімка (кадр 576×1280), у частках висоти екрана:
   аватар 53,5% · серце 60,5% · коментарі 67% · закладка 74,8% ·
   поділитись 81,5% · платівка 87,9%.

   Головне, що з цього випливає: рейка займає НИЖНІ 40% кадру, а платівка
   стоїть майже біля самого низу, окремо від решти значків. Спершу я поставив
   рейку на 98px і вона висіла у верхній половині; потім на 60px — уже краще,
   але платівка все одно тулилась до підпису.

   Чому саме низ: до цих значків тягнеться великий палець, не рухаючи телефон
   у долоні. Це ергономіка, і саме вона впізнається, а не форма іконок. */
.ttf-cap{ bottom:14px }
.ttf-rail{ bottom:44px }
.ph-seek{ bottom:0 }
@media (prefers-reduced-motion: reduce){ .ph-disc{ animation:none } }

/* ── масштаб рейки ───────────────────────────────────────────────────────
   Іконки тримаємо стриманими — у TikTok вони займають близько 4,5% ширини
   екрана, і роздуті значки одразу читаються як імітація. А от ЧИСЛА під
   ними навпаки збільшуємо: вони тут не підпис до значка, а доказ, що ролик
   хтось дивився. Дрібні цифри перетворювали рейку на декорацію. */
/* Крок між значками — 7% висоти кадру за референсом, тобто ~36px на нашому
   519px. Блок «значок + число» займає ~28, отже проміжок ~8.
   Числа лишаються більшими за пропорцію оригіналу (там вони ~2,6% ширини,
   у нас це дало б 7,6px): на макеті 292px такий кегль не читається, а число
   тут — доказ, а не підпис до значка. Свідоме відхилення. */
/* Компроміс, який варто назвати вголос. У референсі числа займають ~2,6%
   ширини екрана — на нашому кадрі це 7,6px, тобто нечитабельно. Лишаємо їх
   удвічі більшими, і через це блок «значок + число» вищий за оригінальний,
   а вся рейка — довша. Вирівнюємо не кеглем, а рештою: дрібніший крок,
   менші значки й трохи ширший кадр. Повного збігу з оригіналом тут бути не
   може: там колонка на екрані в руках, у нас — макет 320px на сторінці. */
.ttf-rail{ gap:5px }
.ttf-ic svg{ width:21px; height:21px }
/* Кегль трохи піднято (10,5 -> 11,5). Разом із переходом на десятки
   тисяч рядок став коротшим за символами («92,4K» проти «5 106»), тож
   більший кегль тепер уміщається, не розсуваючи рейку вшир. */
.ttf-ic i{ font-size:11.5px; font-weight:700; letter-spacing:0;
  text-shadow:0 1px 4px rgba(0,0,0,.8) }
.ttf-ava{ width:27px; height:27px; margin-bottom:2px }
/* Платівка стоїть окремо від колонки значків — у референсі між нею і
   «поділитись» помітно більший проміжок, ніж між рештою. */
.ph-disc{ width:25px; height:25px; margin-top:7px }

/* ── рейка на бічних екранах ─────────────────────────────────────────────
   Розміри рейки задані в пікселях, тож на вужчому екрані вона з'їдає більшу
   частку висоти: на героєві 320px це 40%, на бічному 214px — уже 67%, і
   колонка значків лізе під верхні вкладки.

   Тут числа знімаємо, і це не суперечить правилу «числа обов'язкові». Те
   правило про екран, який ДИВЛЯТЬСЯ: там число — доказ, що ролик хтось
   переглянув. Бічні екрани притемнені й зменшені навмисно, читати з них
   ніхто не буде, а от силует лишається — і саме він там працює. */
.ttf-phone.side .ttf-ic i{ display:none }
.ttf-phone.side .ttf-ic svg{ width:17px; height:17px }
.ttf-phone.side .ttf-ava{ width:21px; height:21px }
.ttf-phone.side .ttf-ava svg{ width:11px; height:11px }
.ttf-phone.side .ttf-ava::after{ width:11px; height:11px; font-size:8px;
  line-height:10px; bottom:-4px }
.ttf-phone.side .ph-disc{ width:19px; height:19px; margin-top:5px }
.ttf-phone.side .ttf-rail{ gap:11px }
.ttf-ava{
  width:30px; height:30px;
  background:linear-gradient(152deg, oklch(0.86 0.13 82), oklch(0.62 0.14 52));
  display:flex; align-items:center; justify-content:center;
  color:oklch(0.2 0.03 55);
}
/* `overflow:hidden` тут БУВ і його прибрано. Він лишився з тих часів, коли
   в колі стояв обрізаний кадр із ролика й його треба було вписати в круг.
   Тепер усередині вбудований знак, обрізати нічого — зате обрізало плюсик:
   значок висить на `bottom:-6px`, тобто виступає за межі кола, і батько
   мовчки зрізав його по краю. Ззовні це виглядало не як зникнення, а як
   злиття: від кружка лишалась тонка червона смужка на нижній дузі. */
.ttf-ava svg{ width:16px; height:16px; display:block }
/* Плюсик — ОКРЕМИЙ предмет, що лежить НА аватарці, а не її частина.
   Відокремлює його не колір (червоне на бурштиновому вже контрастне), а
   біле кільце: воно вирізає значок із того, що під ним, і саме тому в
   оригіналі кнопка читається навіть на строкатому фото. Плюс тінь — щоб
   кільце не губилось на світлому кадрі. */
.ttf-ava::after{ width:15px; height:15px; font-size:10px; line-height:12px;
  bottom:-7px; border:1.5px solid #fff; box-sizing:border-box;
  box-shadow:0 1px 3px rgba(0,0,0,.45) }
.ttf-phone.side .ttf-ava::after{ border-width:1.2px }

/* ── лайк ────────────────────────────────────────────────────────────────
   Серце наливається кольором і трохи підскакує, а вгору спливають два
   дрібних. Розмір стрибка малий навмисно: сильний відскок читається як
   святкування, а нам треба, щоб це виглядало як звичайний рух пальця. */
.ttf-ic{ position:relative }
/* Серце не просто фарбується, а СМИКАЄТЬСЯ: пружний відскок за власною
   кривою. Плавний перехід кольору без руху читався як зміна стану
   інтерфейсу, а не як чийсь дотик. */
.ttf-ic.is-like svg{ transition:color .2s var(--ease) }
.ttf-ic.is-like.liked svg{ color:#fe2c55; animation:phPop .5s var(--ease) }
.ttf-ic.is-like.liked i{ color:#fe2c55 }
/* Удар підсилено свідомо. Стриманий відскок (×1,45) губився поруч із
   гортанням: кадр їде на всю висоту, і на такому тлі дрібний стрибок
   значка не помічають. Тут ×1,8 і зайвий провал на 70% — серце спершу
   вибиває, потім осідає нижче за вихідний розмір і аж тоді стає на місце.
   Саме друга фаза дає відчуття натиснутої кнопки, а не блимання. */
@keyframes phPop{
  0%  { transform:scale(1) }
  22% { transform:scale(1.8) }
  45% { transform:scale(.86) }
  70% { transform:scale(1.14) }
  100%{ transform:scale(1) }
}
/* Кільце-сплеск: одне коло, що розходиться й гасне. Дає удару вагу, якої
   самим лише масштабом серця не отримати. */
.ttf-ic.is-like.liked::before{
  content:""; position:absolute; left:50%; top:11px; width:26px; height:26px;
  translate:-50% -50%; border-radius:50%; pointer-events:none;
  border:2px solid #fe2c55; animation:phRing .7s var(--ease) forwards;
}
@keyframes phRing{
  from{ opacity:.9; transform:scale(.3) }
  to  { opacity:0;  transform:scale(2.8) }
}
.ph-float{
  position:absolute; left:50%; top:2px; width:15px; height:15px;
  pointer-events:none; translate:-50% 0;
  background:#fe2c55;
  /* Серце малюємо маскою, а не ще одним svg-вузлом на кожен спалах. */
  -webkit-mask:center/contain no-repeat url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 21s-7.2-4.6-10-9C.3 8.6 1.8 5 5.4 5c2 0 3.5 1 4.9 2.8C11.7 6 13.2 5 15.2 5c3.6 0 5.1 3.6 3.4 7-2.8 4.4-6.6 9-6.6 9z'/></svg>");
  mask:center/contain no-repeat url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 21s-7.2-4.6-10-9C.3 8.6 1.8 5 5.4 5c2 0 3.5 1 4.9 2.8C11.7 6 13.2 5 15.2 5c3.6 0 5.1 3.6 3.4 7-2.8 4.4-6.6 9-6.6 9z'/></svg>");
  animation:phFloat 1.1s var(--ease) forwards;
}
@keyframes phFloat{
  0%   { opacity:0; transform:translate(0,0) scale(.4) }
  15%  { opacity:1; transform:translate(calc(var(--dx)*.25),-12px) scale(1.15) }
  100% { opacity:0; transform:translate(var(--dx),-62px) scale(.7) }
}
@media (prefers-reduced-motion: reduce){
  .ph-float{ display:none }
  .ttf-ic.is-like svg{ transition:none }
}

/* ── екран у героєві ─────────────────────────────────────────────────────
   Трохи більший за центральний у стрічці: там він один із трьох і його
   тримає сусідство, тут він сам за себе. */
/* Ширший за центральний у стрічці: там екран один із трьох і його тримає
   сусідство, тут він сам за себе. Плюс на 320px рейка вкладається в
   пропорцію референсу без того, щоб робити числа нечитабельними. */
.hero-ph{ width:min(320px,34vw) }
@media (max-width:980px){ .hero-ph{ width:min(320px,78vw) } }

/* ═══ 7. ПРОДУКТ У ДІЇ: ІНТЕРФЕЙС ЯК ПРЕДМЕТ ══════════════════════════════
   Знімок доводить, що продукт існує. Предмет — із тінню, нахилом і сусідніми
   вікнами навколо — доводить, що ним КОРИСТУЮТЬСЯ.

   Тут навмисно немає жодного скріншота, і причина конкретна. Знімки з
   handoff-бандла показували десктопний застосунок v0.1.12 у старій
   фіолетовій палітрі, а в аналітиці на них стояли самі нулі: чужий бренд,
   не той продукт і порожні дані замість доказу. Розмітка натомість бере
   кольори з тих самих змінних, що й решта сторінки, тож не може відстати
   від бренду — і не може показати нуль там, де ми обіцяємо результат. */
.stage{
  position:relative; margin-top:8px; padding:22px 0 30px;
  display:flex; justify-content:center;
}
.mock{
  position:relative; z-index:2; width:min(660px,100%);
  display:flex; overflow:hidden;
  border-radius:var(--r-md); border:1px solid var(--line);
  background:var(--bg-2);
  box-shadow:var(--shadow);
  transition:transform .4s var(--ease);
}
/* Підіймається СЦЕНА цілком, а не кожна панель окремо: три незалежні
   підйоми читаються як три різні предмети, один — як один стіл. */
.stage:hover .mock{ transform:translateY(-5px) }
.mock-rail{
  width:152px; flex:0 0 auto; padding:16px 11px;
  background:var(--bg); border-right:1px solid var(--line);
  display:flex; flex-direction:column; gap:2px;
}
.mock-logo{ font-family:var(--serif); font-size:15.5px; color:var(--fg);
  margin-bottom:11px; padding:0 8px }
.mock-nav{ font-size:12px; padding:7px 10px; border-radius:6px; color:var(--faint) }
.mock-nav.on{ background:color-mix(in srgb,var(--accent) 15%,transparent);
  color:var(--accent); font-weight:600 }
.mock-body{ flex:1; min-width:0; padding:16px; display:flex;
  flex-direction:column; gap:12px }
.mock-t{ font-size:12.5px; color:var(--dim) }
.mock-work{ display:grid; grid-template-columns:auto 1fr; gap:14px }
/* Кадр усередині мокапа — 9:16. Продукт, що робить вертикаль, не має права
   показувати себе горизонталлю у власному інтерфейсі. */
.mock-frame{
  width:76px; aspect-ratio:9/16; border-radius:7px; overflow:hidden;
  border:1px solid var(--line); background:var(--card); position:relative;
}
.mock-frame video,.mock-frame img{ width:100%; height:100%; object-fit:cover }
.mock-frame span{
  position:absolute; left:5px; top:5px; z-index:2;
  font-family:var(--mono); font-size:8px; letter-spacing:.04em;
  color:#fff; background:oklch(0.1 0.01 58/.6); padding:2px 5px; border-radius:4px;
}
.mock-side{ display:flex; flex-direction:column; gap:9px; min-width:0 }
.mock-chips{ display:flex; gap:6px; flex-wrap:wrap }
.mock-chip{ font-family:var(--mono); font-size:10px; padding:4px 9px;
  border-radius:99px; background:var(--card); color:var(--dim) }
.mock-chip.on{ background:color-mix(in srgb,var(--accent) 18%,transparent);
  color:var(--accent) }
.mock-q{ display:flex; flex-direction:column; gap:0; margin-top:2px }
.mock-q b{ font-family:var(--mono); font-size:9.5px; letter-spacing:.12em;
  text-transform:uppercase; color:var(--faint); font-weight:600; margin-bottom:5px }
.mock-q i{ font-style:normal; font-size:11px; color:var(--dim);
  padding:6px 0; border-top:1px solid var(--line) }
.mock-go{ margin-top:auto; align-self:flex-start;
  background:var(--accent); color:var(--accent-fg);
  font-size:12px; font-weight:600; padding:8px 16px; border-radius:99px }

/* Супутники — інші кімнати того самого застосунку. Нахил різного знаку:
   однаковий кут у сусідів читається як збите вирівнювання, а не як задум. */
.sat{
  position:absolute; z-index:1; width:190px; overflow:hidden;
  border-radius:var(--r-sm); border:1px solid var(--line);
  background:var(--card);
  box-shadow:0 30px 60px -26px oklch(0.06 0.01 60/.9);
  transition:transform .45s var(--ease);
}
.sat-h{ padding:9px 12px; border-bottom:1px solid var(--line);
  font-size:11.5px; color:var(--dim) }
.sat-b{ padding:12px; display:flex; flex-direction:column; gap:9px }
.sat-l{ left:0; top:8%; transform:rotate(-3.2deg) }
.sat-r{ right:0; bottom:6%; transform:rotate(2.6deg) }
.stage:hover .sat-l{ transform:rotate(-3.2deg) translateY(-7px) }
.stage:hover .sat-r{ transform:rotate(2.6deg) translateY(-7px) }
.bars{ display:flex; align-items:flex-end; gap:5px; height:52px }
.bars i{ flex:1; border-radius:3px; background:var(--line-2) }
.bars i.on{ background:var(--accent) }
.inbox-row{ display:flex; gap:8px; align-items:center }
.inbox-av{ width:21px; height:21px; border-radius:50%; flex:0 0 auto;
  background:linear-gradient(150deg,var(--accent),oklch(0.5 0.09 45)) }
.inbox-l{ height:8px; flex:1; border-radius:4px; background:var(--line-2) }
.inbox-l.s{ flex:.55 }

@media (max-width:1040px){
  /* Супутники на вужчому екрані — не інформація, а тіснота. Те саме
     правило, що для бічних екранів стрічки. */
  .sat{ display:none }
}
@media (max-width:620px){
  .mock-rail{ display:none }   /* рейка з'їдає половину вузького екрана */
}

/* ═══ 8. ФІНАЛЬНИЙ ЗАКЛИК НА БУРШТИНІ ═════════════════════════════════════ */
.sec-amber .btn-primary{ background:var(--accent); color:var(--accent-fg) }
.sec-amber .btn-ghost{ border-color:oklch(0.18 0.02 60/.34); color:var(--fg) }
.sec-amber .btn-ghost:hover{ border-color:oklch(0.18 0.02 60/.6) }

/* ── велике серце по центру кадру ────────────────────────────────────────
   Жест подвійного дотику. Значок у рейці показує стан кнопки; помітною
   реакцію робить оце — воно перекриває кадр і його неможливо не побачити.

   Розмір у ВІДСОТКАХ ширини картки, не в пікселях: телефони на сторінці
   різні (герой 320, центральний 296, бічні 214), а жест має читатись
   однаково на всіх. У пікселях він на бічних виглядав би величезним.

   Колір — фірмовий рожевий TikTok плюс біле світіння. Без світіння серце
   провалюється в темні кадри: на нашій колоді половина роликів знята на
   темному тлі, і чистий #fe2c55 там ледь видно. */
.ph-bigheart{
  position:absolute; left:50%; top:46%; z-index:4; pointer-events:none;
  width:42%; aspect-ratio:1; translate:-50% -50%;
  background:#fe2c55;
  filter:drop-shadow(0 0 14px rgba(254,44,85,.55))
         drop-shadow(0 0 3px rgba(255,255,255,.5));
  -webkit-mask:center/contain no-repeat url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 21.3c-.35 0-.7-.12-.98-.36C6.2 16.75 2.4 13.5 2.4 9.2 2.4 5.9 4.9 3.4 8.1 3.4c1.6 0 3.06.7 4.06 1.86A5.33 5.33 0 0 1 16.2 3.4c3.2 0 5.7 2.5 5.7 5.8 0 4.3-3.8 7.55-8.62 11.74-.28.24-.63.36-.98.36z'/></svg>");
  mask:center/contain no-repeat url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 21.3c-.35 0-.7-.12-.98-.36C6.2 16.75 2.4 13.5 2.4 9.2 2.4 5.9 4.9 3.4 8.1 3.4c1.6 0 3.06.7 4.06 1.86A5.33 5.33 0 0 1 16.2 3.4c3.2 0 5.7 2.5 5.7 5.8 0 4.3-3.8 7.55-8.62 11.74-.28.24-.63.36-.98.36z'/></svg>");
  animation:phBig .95s var(--ease) forwards;
}
/* Поява з перельотом, коротка пауза «на місці» й зникнення вгору. Пауза
   обов'язкова: без неї серце встигає лише блимнути, і жест не встигає
   прочитатися — саме через це попередня версія лайка була непомітною. */
@keyframes phBig{
  0%  { opacity:0; transform:rotate(var(--tilt,0deg)) scale(.2) }
  18% { opacity:1; transform:rotate(var(--tilt,0deg)) scale(1.22) }
  32% { opacity:1; transform:rotate(var(--tilt,0deg)) scale(.96) }
  62% { opacity:1; transform:rotate(var(--tilt,0deg)) scale(1) }
  100%{ opacity:0; transform:rotate(var(--tilt,0deg)) translateY(-14%) scale(1.1) }
}
@media (prefers-reduced-motion: reduce){ .ph-bigheart{ display:none } }

/* ═══ СЦЕНИ ЗАМІСТЬ ЗНІМКІВ ЗАСТОСУНКУ ═══════════════════════════════════
   Три об'єкти на місці трьох `webp`. Кожен показує ДІЮ, а не орган: що
   станеться, якщо це ввімкнути, а не як виглядає панель, де це вмикають.

   Перша версія цих сцен була гарною й мовчазною: рух був, змісту не було.
   Порожні кадри, безіменні смуги, порожні бульбашки — глядач бачив, що
   щось відбувається, але не міг сказати що саме. Тому головна правка тут
   не в анімації, а в ПІДПИСАХ: кожен крок, кожен пост і кожна репліка
   тепер названі словами. Рух лише веде око по них у правильному порядку.

   Спільні правила на всі три:
   · жодного зображення — тільки розмітка й змінні секції, тому сцена
     сама вдягається в крем або темряву, у якій опинилась;
   · рух іде лише коли секцію ВИДНО (`.is-in`). Без цієї прив'язки три
     нескінченні цикли крутились би весь час, зокрема поки людина читає
     зовсім інший екран, і сторінка гріла б процесор ні за що;
   · `prefers-reduced-motion` зупиняє все й лишає останній кадр —
     композиція має читатись і нерухомою, інакше це не ілюстрація, а
     атракціон. Саме тому підписи статичні: вони не з'являються по ходу
     анімації, вони стоять від початку. */
.scn{
  margin:26px 0 4px; border-radius:var(--r-lg);
  border:1px solid var(--line); background:var(--card);
  padding:22px 22px 16px; position:relative; overflow:hidden;
}
/* Підписи по краях — не заголовки, а полюси: «звідси» і «сюди». Тому
   вони дрібні, розведені в кути й моноширинні: так читається шкала, а
   не два самостійні написи. */
.scn-ends{
  display:flex; justify-content:space-between; gap:12px;
  font-family:var(--mono); font-size:11px; letter-spacing:.04em;
  text-transform:uppercase; color:var(--faint); margin-bottom:16px;
}
.scn-note{
  margin:14px 0 0; font-size:12.5px; color:var(--faint);
  font-family:var(--mono); letter-spacing:.01em; line-height:1.5;
}

/* ── 1. СТУДІЯ: ЦИКЛ ІЗ ШЕСТИ СТАДІЙ ─────────────────────────────────────
   Спільний такт — 9 секунд на повне коло, по 1,25 с на стадію. Один такт
   на всі шість, а порядок задає затримка `--n`: так стадії не можуть
   розійтися між собою, скільки б хвилин сторінка не була відкрита.

   Чому 1,25, а не 1,5: шість стадій по 1,5 займали рівно всі 9 секунд, і
   на зворотний хід кружечка по дузі не лишалось жодної миті. Дрібніший
   крок звільняє останню секунду циклу — саме в ній кружечок і їде назад
   до ідеї, коли аналітика вже догоріла.
   Якби кожна крутилась за власним таймером, вони поступово зсунулись би
   й почали спалахувати навперебій — а це вже не цикл, а гірлянда. */
.scn-cycle{
  display:grid; grid-template-columns:repeat(6,1fr); gap:10px;
  align-items:end;
}
.scn-stage{
  display:flex; flex-direction:column; align-items:center; gap:9px;
  text-align:center;
  animation:scnStage 9s var(--ease) infinite;
  animation-delay:calc(var(--n) * 1.25s);
  animation-play-state:paused;
}
.is-in .scn-stage{ animation-play-state:running }
/* Стадія підіймається й трохи більшає, коли надходить її черга. Підйом
   малий (−6px) навмисно: сильний стрибок читається як святкування, а нам
   треба показати роботу, що йде своєю чергою. */
@keyframes scnStage{
  0%,2%   { transform:translateY(0) scale(1) }
  8%      { transform:translateY(-6px) scale(1.06) }
  16%     { transform:translateY(-6px) scale(1.06) }
  24%,100%{ transform:translateY(0) scale(1) }
}
/* 🛑 Саме `> b`, а не `b`. Підпис стадії — прямий нащадок, а всередині
   мініатюр є свої `<b>` (пігулки хештегів у стадії «Пост»). Нащадковий
   селектор чіпляв і їх: `.scn-stage b` специфічніший за `.mi-tag`, тож
   пігулки мовчки отримували анімацію ПІДПИСУ замість власної й лишались
   невидимими. Помилка дзеркальна до сусідньої, де навпаки бракувало
   нащадкового селектора, — і обидві однаково тихі: жодного попередження,
   просто елемент, який ніколи не грає. */
.scn-stage > b{
  font-size:12.5px; font-weight:700; color:var(--dim); line-height:1.25;
  animation:scnStageLab 9s var(--ease) infinite;
  animation-delay:calc(var(--n) * 1.25s); animation-play-state:paused;
}
.is-in .scn-stage > b{ animation-play-state:running }
@keyframes scnStageLab{
  0%,2%   { color:var(--dim) }
  8%,16%  { color:var(--accent) }
  24%,100%{ color:var(--dim) }
}
/* Мініатюра — рамка, у якій живе рух. Пропорція близька до квадрата, а не
   9:16: тут не кадр відео, а стадія роботи, і прикидатись кадром їй нема
   потреби. Виняток — сама стадія «Відео», у якої всередині стоїть
   справжній вертикальний екранчик. */
.scn-mini{
  position:relative; width:100%; aspect-ratio:5/4;
  border-radius:10px; overflow:hidden;
  border:1px solid var(--line-2);
  background:linear-gradient(168deg, var(--card-2), var(--bg-2));
  animation:scnMini 9s var(--ease) infinite;
  animation-delay:calc(var(--n) * 1.25s); animation-play-state:paused;
}
.is-in .scn-mini{ animation-play-state:running }
@keyframes scnMini{
  0%,2%   { border-color:var(--line-2); box-shadow:none }
  8%,16%  { border-color:var(--accent);
            box-shadow:0 0 0 3px color-mix(in oklab, var(--accent) 16%, transparent) }
  24%,100%{ border-color:var(--line-2); box-shadow:none }
}
/* Усі мініатюри крутяться СВОЇМ циклом на 9s із тією ж затримкою, що й
   стадія: рух усередині має припадати на мить, коли на картку дивляться.

   🛑 Селектор мусить бути `*`, а не `> *`. Тут була справжня, довго
   невидима поломка: складники стадії «Пост» лежать усередині `.mi-card`,
   тобто ОНУКАМИ мініатюри, а не дітьми. Дочірній комбінатор їх не
   зачіпав — вони отримували `animation-name`, але не отримували
   тривалості. Тривалість за замовчуванням нульова, анімація не
   запускається жодного разу, і діє статичний `opacity:0`.

   На екрані це виглядало не як помилка, а як слабка ідея: рамка картки
   моргала кольором, усередині порожньо. Жодного попередження в консолі —
   CSS не вважає нульову тривалість помилкою. Саме тому стадію «Пост» і
   назвали ніякою: вона не була ніякою, вона просто ніколи не грала. */
.scn-mini *{
  animation-duration:9s; animation-iteration-count:infinite;
  animation-timing-function:var(--ease);
  animation-play-state:paused;
}
.is-in .scn-mini *{ animation-play-state:running }

/* ── СТАН СПОКОЮ ────────────────────────────────────────────────────────
   Перша версія цих мініатюр показувала вміст ТІЛЬКИ в мить активності, а
   решту циклу картка стояла порожня. На екрані це означало п'ять пустих
   рамок і одну живу — сцена виглядала недовантаженою, а не працюючою.

   Тепер у кожної стадії є стан спокою: вміст видно завжди, але тьмяно,
   і активація не «вмикає» його з нуля, а ПЕРЕРОБЛЯЄ на очах — рядок
   набирається наново, стовпчики виростають наново. Так видно і склад
   роботи (шість різних дій), і те, яка з них іде саме зараз. */

/* ідея — лампочка, що загорається */
.mi-bulb{
  position:absolute; left:50%; top:50%; translate:-50% -50%;
  height:74%; display:block; color:var(--line-2);
  animation-name:miBulb; animation-delay:calc(var(--n) * 1.25s);
}
.mi-bulb svg{ height:100%; width:auto; display:block }
.mb-fil{ stroke-width:1.4 }
@keyframes miBulb{
  0%,4%   { color:var(--line-2); filter:none }
  10%     { color:var(--accent);
            filter:drop-shadow(0 0 7px color-mix(in oklab, var(--accent) 70%, transparent)) }
  18%     { color:var(--accent);
            filter:drop-shadow(0 0 4px color-mix(in oklab, var(--accent) 45%, transparent)) }
  26%,100%{ color:var(--line-2); filter:none }
}
/* Скло наливається кольором ЗСЕРЕДИНИ окремою анімацією. Якби ми просто
   перефарбували лінії, лампочка не «загорілась» би, а стала бурштиновим
   малюнком лампочки — різні речі. Окремою, бо `fill` не успадковується
   від `color`, як це робить `stroke:currentColor`: одним правилом обидва
   разом не змінити. */
.mb-glass{
  fill:transparent;
  animation:miGlass 9s var(--ease) infinite;
  animation-delay:calc(var(--n) * 1.25s); animation-play-state:paused;
}
.is-in .mb-glass{ animation-play-state:running }
@keyframes miGlass{
  0%,4%   { fill:transparent }
  10%,18% { fill:color-mix(in oklab, var(--accent) 24%, transparent) }
  26%,100%{ fill:transparent }
}
/* Промені тільки ВГОРУ: так світить лампа. Промені на всі боки
   перетворювали цей знак на сонце — саме через це стадію й довелось
   перемальовувати. Обертання йде навколо центру самого променя, а
   `translateY` після нього рухає промінь уздовж уже поверненої осі,
   тобто назовні від лампи. */
.mi-ray{
  position:absolute; left:50%; top:34%;
  width:2px; height:8px; margin:-4px 0 0 -1px;
  border-radius:2px; background:var(--accent); opacity:0;
  transform-origin:50% 50%;
  animation-name:miRay; animation-delay:calc(var(--n) * 1.25s);
}
@keyframes miRay{
  0%,4%   { opacity:0;   transform:rotate(var(--a)) translateY(-10px) scaleY(.4) }
  10%     { opacity:.9;  transform:rotate(var(--a)) translateY(-16px) scaleY(1) }
  18%     { opacity:.45; transform:rotate(var(--a)) translateY(-18px) scaleY(1) }
  26%,100%{ opacity:0;   transform:rotate(var(--a)) translateY(-10px) scaleY(.4) }
}

/* сценарій — рядки, що набираються */
.mi-ln{
  position:absolute; left:14%; height:5px; border-radius:3px;
  background:var(--line-2); transform-origin:left; transform:scaleX(0);
  top:calc(20% + var(--i) * 17%); width:72%;
  animation-name:miLine;
  /* Рядки набираються ПО ЧЕРЗІ всередині своєї стадії: до затримки самої
     стадії додається ще й крок рядка. Без цього чотири рядки з'являлися б
     одночасно — тобто не набір тексту, а поява таблиці. */
  animation-delay:calc(var(--n) * 1.25s + var(--i) * .16s);
}
.mi-ln.short{ width:44% }
@keyframes miLine{
  0%      { transform:scaleX(1); opacity:.4 }
  4%      { transform:scaleX(0); opacity:.4 }
  11%,18% { transform:scaleX(1); opacity:1 }
  26%,100%{ transform:scaleX(1); opacity:.4 }
}

/* відео — вертикальний екранчик, що грає */
.mi-scr{
  position:absolute; left:50%; top:50%; translate:-50% -50%;
  height:76%; aspect-ratio:9/16; border-radius:5px;
  border:1px solid var(--line-2); background:var(--bg-2);
  animation-name:miScr; animation-delay:calc(var(--n) * 1.25s);
}
@keyframes miScr{
  0%,4%   { border-color:var(--line-2) }
  10%,18% { border-color:var(--accent) }
  26%,100%{ border-color:var(--line-2) }
}
.mi-play{
  position:absolute; left:50%; top:44%; translate:-50% -50%;
  width:0; height:0; border-style:solid; border-width:6px 0 6px 10px;
  border-color:transparent transparent transparent var(--line-2);
  animation-name:miPlay; animation-delay:calc(var(--n) * 1.25s);
}
@keyframes miPlay{
  0%,4%   { border-left-color:var(--line-2); opacity:.5; transform:scale(.85) }
  10%     { border-left-color:var(--accent); opacity:1; transform:scale(1.2) }
  18%     { border-left-color:var(--accent); opacity:1; transform:scale(1) }
  26%,100%{ border-left-color:var(--line-2); opacity:.5; transform:scale(.85) }
}
/* Смуга перемотки доходить до половини, а не до кінця — те саме правило,
   що й у великій стрічці нагорі: ролик у стрічці дивляться не до кінця. */
.mi-seek{
  position:absolute; left:10%; right:10%; bottom:9%; height:3px;
  border-radius:2px; background:var(--line-2); transform-origin:left;
  transform:scaleX(0);
  animation-name:miSeek; animation-delay:calc(var(--n) * 1.25s);
}
@keyframes miSeek{
  0%      { transform:scaleX(.5); background:var(--line-2); opacity:.55 }
  4%      { transform:scaleX(0);  background:var(--line-2); opacity:.55 }
  18%     { transform:scaleX(.5); background:var(--accent); opacity:1 }
  26%,100%{ transform:scaleX(.5); background:var(--line-2); opacity:.55 }
}

/* пост — картка з хештегами й реакціями */
.mi-card{
  position:absolute; inset:11% 16%; border-radius:6px;
  border:1px solid var(--line-2); background:var(--bg-2);
  animation-name:miCard; animation-delay:calc(var(--n) * 1.25s);
}
@keyframes miCard{
  0%,4%   { border-color:var(--line-2) }
  10%,18% { border-color:var(--accent) }
  26%,100%{ border-color:var(--line-2) }
}
.mi-img{
  position:absolute; left:8%; right:8%; top:7%; height:40%;
  border-radius:4px; opacity:0;
  background:linear-gradient(152deg,
    color-mix(in oklab, var(--accent) 55%, transparent),
    color-mix(in oklab, var(--accent) 22%, transparent));
  animation-name:miPop; animation-delay:calc(var(--n) * 1.25s);
}
.mi-cap{
  position:absolute; left:8%; width:62%; top:53%; height:4px;
  border-radius:3px; background:var(--line-2); opacity:0;
  animation-name:miPop; animation-delay:calc(var(--n) * 1.25s + .12s);
}
/* Хештеги — ПІГУЛКИ, а не рядки. Форма тут несе весь зміст: рядок
   виглядав би як ще один шматок тексту, тобто як стадія «Сценарій» двома
   картками лівіше. Дві сусідні стадії, схожі на вигляд, не розповідають
   нічого — око бачить повтор, а не крок. Пігулка не схожа ні на що інше
   в цьому ряду. */
.mi-tag{
  position:absolute; top:64%; height:7px; border-radius:4px;
  background:var(--accent); opacity:0;
  animation-name:miTag;
  /* Вискакують по одному, інакше три пігулки читаються як одна смуга. */
  animation-delay:calc(var(--n) * 1.25s + var(--t) * .11s + .2s);
}
.mi-tag:nth-of-type(1){ left:8%;  width:20% }
.mi-tag:nth-of-type(2){ left:31%; width:26% }
.mi-tag:nth-of-type(3){ left:60%; width:17% }
/* Стан спокою — пігулки ВИДНО, лише тьмяно. Спершу я лишив їх на нулі, і
   картка «Пост» більшу частину циклу стояла порожньою: у ряду з шести
   одна виглядала недоробленою. Те саме правило, що й для решти стадій —
   вміст видно завжди, активація його ПЕРЕРОБЛЯЄ, а не вмикає з нуля. */
@keyframes miTag{
  0%      { opacity:.45; transform:scale(1) }
  6%      { opacity:0;   transform:scale(.4) }
  13%     { opacity:1;   transform:scale(1.18) }
  17%,20% { opacity:1;   transform:scale(1) }
  28%,100%{ opacity:.45; transform:scale(1) }
}
/* Рядок реакцій знизу: картка має виглядати опублікованою ще до
   публікації — саме цим пост і відрізняється від тексту про пост. */
.mi-react{
  position:absolute; left:8%; bottom:8%; width:46%; height:5px;
  border-radius:3px; opacity:0; text-decoration:none;
  background:repeating-linear-gradient(to right,
    var(--line-2) 0 5px, transparent 5px 9px);
  animation-name:miPop; animation-delay:calc(var(--n) * 1.25s + .3s);
}
@keyframes miPop{
  0%      { opacity:.6; transform:translateY(0) }
  4%      { opacity:0;  transform:translateY(5px) }
  11%,18% { opacity:1;  transform:translateY(0) }
  26%,100%{ opacity:.6; transform:translateY(0) }
}

/* публікація — пост відлітає в три мережі */
.mi-up{
  position:absolute; left:50%; bottom:16%; width:16px; height:16px;
  translate:-50% 0; border-radius:4px; background:var(--accent); opacity:0;
  animation-name:miUp; animation-delay:calc(var(--n) * 1.25s);
}
@keyframes miUp{
  0%,4%   { opacity:.35; transform:translateY(0) scale(.85) }
  10%     { opacity:1;   transform:translateY(0) scale(1) }
  20%     { opacity:1;   transform:translateY(-26px) scale(.6) }
  24%     { opacity:0;   transform:translateY(-30px) scale(.5) }
  /* Повертається на місце НЕВИДИМИМ і аж потім проявляється: інакше
     квадратик їхав би згори вниз, тобто пост вертався б із мережі. */
  25%     { opacity:0;   transform:translateY(0) scale(.85) }
  32%,100%{ opacity:.35; transform:translateY(0) scale(.85) }
}
/* Три мережі спалахують ПІСЛЯ того, як пост до них долетів. Якби вони
   загорались одразу, вийшло б, що вони світяться самі по собі, а посилка
   до них не має стосунку. */
.mi-net{
  position:absolute; top:20%; width:9px; height:9px; border-radius:50%;
  background:var(--line-2);
  left:calc(28% + var(--i) * 22%);
  animation-name:miNet;
  animation-delay:calc(var(--n) * 1.25s + var(--i) * .1s + .3s);
}
@keyframes miNet{
  0%,10%  { background:var(--line-2); transform:scale(1) }
  15%     { background:var(--accent); transform:scale(1.5) }
  20%     { background:var(--accent); transform:scale(1) }
  26%,100%{ background:var(--line-2); transform:scale(1) }
}

/* аналітика — стовпчики ростуть */
.mi-bar{
  position:absolute; bottom:16%; width:11%; border-radius:3px 3px 1px 1px;
  background:var(--accent); transform-origin:bottom;
  height:var(--h); transform:scaleY(0);
  left:calc(20% + var(--i) * 17%);
  animation-name:miBar;
  animation-delay:calc(var(--n) * 1.25s + var(--i) * .09s);
}
@keyframes miBar{
  0%      { transform:scaleY(1); opacity:.35 }
  4%      { transform:scaleY(0); opacity:.35 }
  12%,18% { transform:scaleY(1); opacity:1 }
  26%,100%{ transform:scaleY(1); opacity:.35 }
}

/* ── дуга повернення ──────────────────────────────────────────────────
   Півколо під рядом, від останньої картки до першої. Це не оздоба: без
   неї шість стадій читаються як конвеєр із кінцем, а весь сенс у тому,
   що кінця немає — аналітика останнього кроку живить ідею першого. */
.scn-return{
  position:relative; height:34px; margin-top:10px;
  border:0 solid var(--line-2); border-bottom-width:1px;
  border-left-width:1px; border-right-width:1px;
  border-radius:0 0 14px 14px;
  margin-left:6%; margin-right:6%;
}
/* Вістря на дузі не малюємо. Пробував — на скругленому кінці воно сідало
   криво й читалось як дефект рамки, а не як стрілка. Напрям натомість
   називає сам напис у розриві дуги: «цикл замикається» не потребує
   вказівника, щоб бути зрозумілим. */
/* Кружечок їде нижнім краєм дуги справа наліво — від аналітики назад до
   ідеї. Час підібрано так, щоб він рушив, КОЛИ АНАЛІТИКА ВЖЕ ДОГОРІЛА
   (остання стадія світиться до 88% циклу), і дійшов до лівого краю рівно
   на стику циклів, тобто в мить, коли спалахує ідея. Ця збіжність і є вся
   суть: коло не намальоване, воно замикається на очах. */
.scn-back{
  position:absolute; bottom:-4px; left:8%; z-index:1;
  width:9px; height:9px; margin-left:-4.5px; border-radius:50%;
  background:var(--accent); opacity:0;
  box-shadow:0 0 12px 3px color-mix(in oklab, var(--accent) 55%, transparent);
  animation:scnBack 9s linear infinite; animation-play-state:paused;
}
.is-in .scn-back{ animation-play-state:running }
@keyframes scnBack{
  0%,87%  { left:92%; opacity:0 }
  89%     { left:92%; opacity:1 }
  98%     { left:8%;  opacity:1 }
  100%    { left:8%;  opacity:0 }
}
/* Напис лежить ПОВЕРХ кружечка, і кружечок на мить пірнає за нього. Це не
   дефект: розрив у русі читається як розрив у дузі, який напис і робить. */
.scn-return span{
  position:absolute; left:50%; bottom:-9px; translate:-50% 0; z-index:2;
  padding:0 10px; background:var(--card);
  font-family:var(--mono); font-size:10.5px; letter-spacing:.04em;
  text-transform:uppercase; color:var(--faint);
}

/* ── 2. АВТОПІЛОТ: смуга часу йде по вже розставленому тижню ─────────── */
.scn-plan{ padding-bottom:16px }
/* Дні тижня згори. Без них сцена показувала якісь смуги в невідомому
   проміжку: рух є, а що це — доба, тиждень чи квартал — сказати не можна.
   Рядок днів робить проміжок названим за одну секунду. */
.scn-days{ display:flex; align-items:center; gap:12px; margin-bottom:8px }
.scn-dayrow{
  position:relative;
  flex:1; display:grid; grid-template-columns:repeat(7,1fr);
  font-family:var(--mono); font-size:10.5px; color:var(--faint);
  letter-spacing:.04em; text-align:center;
}
.scn-dayrow span{ position:relative; z-index:1 }
/* 🛑 Підсвітка дня мусить бути й ТУТ, а не лише на доріжках. На доріжці
   колонку видно тільки в порожній комірці: там, де стоїть пост, він її
   собою й закриває. Виходило, що «поточний день» показувався випадковою
   світлою клітинкою в тій доріжці, якій цього дня нема чого публікувати.

   Назва дня не закривається ніколи. Разом із колонкою нижче вони
   називають той самий день двічі — згори підписом, знизу тлом. */
.scn-dayrow::before{
  content:""; position:absolute; z-index:0; top:-3px; bottom:-3px; left:0;
  width:calc(100% / 7); border-radius:5px;
  background:color-mix(in srgb, var(--accent) 16%, transparent);
  animation:scnDayNow 7.4s linear infinite; animation-play-state:paused;
  opacity:0;
}
.is-in .scn-dayrow::before{ animation-play-state:running }
.scn-lane{ display:flex; align-items:center; gap:12px; margin-bottom:10px }
.scn-tag{
  flex:0 0 78px; font-family:var(--mono); font-size:11px;
  color:var(--faint); text-align:right; letter-spacing:.02em;
}
/* 34, а не 30: блок мусить читатись як картка, а не як смужка. Вище не
   треба — у блоці лише підпис, і зайва висота зробила б із нього порожню
   коробку з текстом унизу.

   Пробував класти сюди кадр ролика: на цій висоті він виходить 16-26 px
   завширшки, тобто пляма, яку не впізнати. Забрано — дрібне зображення
   гірше за його відсутність, воно лише засмічує блок. */
.scn-track{
  position:relative; flex:1; height:34px; border-radius:8px;
  background:var(--bg-2); border:1px solid var(--line);
  /* Волосяні вертикалі по днях: пости мають стояти В КОМІРКАХ, а не
     плавати десь посередині. Без сітки прив'язка до днів на слово. */
  background-image:repeating-linear-gradient(to right,
    transparent 0 calc(100%/7 - 1px), var(--line) calc(100%/7 - 1px) calc(100%/7));
}
/* `--x` і `--w` приходять з розмітки БЕЗ одиниць, і це не недогляд.
   Затримку треба вирахувати з позиції — тобто помножити частку на
   секунди, — а calc() не вміє поділити відсоток так, щоб на виході було
   безрозмірне число. Тому число їде голим, а одиниця дописується на
   місці вжитку: `* 1%` для геометрії, `* 0.0666s` для часу
   (7,4s циклу × 0,9 корисної частини ÷ 100). */
/* ── ДЕНЬ, ЯКИЙ ЗАРАЗ ВИХОДИТЬ ────────────────────────────────────────
   Смуга-олівець, що їхала через усю сцену, колись була і її прибрали:
   вона перетягувала увагу з постів на себе. Але без жодного покажчика
   заповнення виглядало як «щось саме собою фарбується».

   Компроміс — не лінія, а КОЛІРНА КОЛОНКА завширшки в день. Вона стоїть
   ПІД постами (`::before` плюс `z-index` на шарах), не має різких країв
   і рухається тими самими стрибками, що й межа заповнення. Три доріжки
   мають однакову ширину, тож три колонки складаються в одну вертикальну
   смугу через усю сцену — без жодного елемента, який довелось би
   вирівнювати руками. */
.scn-track::before{
  content:""; position:absolute; top:0; bottom:0; left:0; z-index:0;
  /* Радіус 3, а не 6: із заокругленими кутами смуга читалась як ВИДІЛЕНА
     КЛІТИНКА однієї доріжки, а не як колонка через усю сцену. */
  width:calc(100% / 7); border-radius:3px; pointer-events:none;
  background:color-mix(in srgb, var(--accent) 9%, transparent);
  animation:scnDayNow 7.4s linear infinite; animation-play-state:paused;
  opacity:0;
}
.is-in .scn-track::before{ animation-play-state:running }
@keyframes scnDayNow{
  0%,   5.99%{ animation-timing-function:step-end; transform:translateX(0);    opacity:0 }
  6%,  17.99%{ animation-timing-function:step-end; transform:translateX(0);    opacity:1 }
  18%, 29.99%{ animation-timing-function:step-end; transform:translateX(100%); opacity:1 }
  30%, 41.99%{ animation-timing-function:step-end; transform:translateX(200%); opacity:1 }
  42%, 53.99%{ animation-timing-function:step-end; transform:translateX(300%); opacity:1 }
  54%, 65.99%{ animation-timing-function:step-end; transform:translateX(400%); opacity:1 }
  66%, 77.99%{ animation-timing-function:step-end; transform:translateX(500%); opacity:1 }
  78%, 90%   { animation-timing-function:step-end; transform:translateX(600%); opacity:1 }
  95%, 100%  { animation-timing-function:step-end; transform:translateX(600%); opacity:0 }
}
/* Пости — над колонкою. Без цього `::before` як останній псевдоелемент
   малювався б ПОВЕРХ них і підфарбовував самі блоки. */
.scn-set{ position:absolute; inset:0; z-index:1 }
.scn-set i{
  position:absolute; top:4px; bottom:4px;
  left:calc(var(--x) * 1%); width:calc(var(--w) * 1%);
  border-radius:5px; display:flex; align-items:center; justify-content:center;
  overflow:hidden;
}
.scn-set i b{
  font-size:10px; font-weight:600; line-height:1;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  padding:0 5px; letter-spacing:-.01em;
}

/* Нижній шар — заплановане: обрис без заливки. Саме обрис, а не блідий
   бурштин: напівпрозорий колір читався б як «уже трохи вийшло», а пост
   або вийшов, або ні. */
.scn-set:not(.lit) i{ background:var(--card-2); border:1px solid var(--line-2) }
.scn-set:not(.lit) i b{ color:var(--dim) }
.scn-set.lit i{ background:var(--accent) }
.scn-set.lit i b{ color:var(--accent-fg) }

/* 🛑 МЕЖА ЙДЕ ДНЯМИ, А НЕ ПОВЗЕ. Це головна правка в цій сцені.

   Було: межа відкриття рухалась рівномірно через усю доріжку. Наслідок
   видно на будь-якому знімку — блок, через який вона саме проходить,
   стоїть зафарбований наполовину, з вертикальною бурштиновою смугою
   посередині. Виглядало це не як «публікується», а як брак верстки, і
   таким був щомиті бодай один блок із десяти: межа перетинає блок за
   0,76 с із 7,4 с циклу.

   Стало: сім стрибків, по одному на день тижня. Пост НІКОЛИ не буває
   розрізаний, бо кожен пост цілком лежить усередині своєї денної комірки
   (комірка 14,29% завширшки, пост 11,4% з відступом 1,4%). Заразом це
   чесніше по суті: тиждень і йде днями, а не міліметрами.

   Пари ключових кадрів (12.85/12.86 і далі) — це і є стрибок: значення
   тримається до першого числа пари, а між ним і другим немає часу на
   плавний перехід. */
.scn-set.lit{
  clip-path:inset(0 100% 0 0);
  animation:scnWipe 7.4s linear infinite; animation-play-state:paused;
}
.is-in .scn-set.lit{ animation-play-state:running }
/* 🛑 `step-end` на КОЖНОМУ кадрі. Пари відсотків (6/17.99 і далі) самі по
   собі майже прибирають плавний перехід — «майже» тут і було проблемою:
   на скиданні лишалось вікно 0,74 мс, і в замірі я впіймав у ньому
   напівзаповнену доріжку. Один кадр із десяти тисяч — але це рівно той
   дефект, заради якого все й переробляли.

   Зі `step-end` значення тримається до наступного кадру й міняється
   стрибком. Інтерполяції немає ЗА ПОБУДОВОЮ, а не за розрахунком. */
@keyframes scnWipe{
  0%,      5.99%{ animation-timing-function:step-end; clip-path:inset(0 100% 0 0) }     /* тиждень попереду */
  6%,     17.99%{ animation-timing-function:step-end; clip-path:inset(0 85.71% 0 0) }   /* пн */
  18%,    29.99%{ animation-timing-function:step-end; clip-path:inset(0 71.43% 0 0) }   /* вт */
  30%,    41.99%{ animation-timing-function:step-end; clip-path:inset(0 57.14% 0 0) }   /* ср */
  42%,    53.99%{ animation-timing-function:step-end; clip-path:inset(0 42.86% 0 0) }   /* чт */
  54%,    65.99%{ animation-timing-function:step-end; clip-path:inset(0 28.57% 0 0) }   /* пт */
  66%,    77.99%{ animation-timing-function:step-end; clip-path:inset(0 14.29% 0 0) }   /* сб */
  78%,    95%   { animation-timing-function:step-end; clip-path:inset(0 0 0 0) }        /* нд, і тиждень стоїть */
  95.01%, 100%  { animation-timing-function:step-end; clip-path:inset(0 100% 0 0) }     /* скидання, без руху */
}

/* Кожен пост, до якого дійшла черга, СПЛИВАЄ: більшає з тінню й одразу
   сідає назад. Провал нижче вихідного розміру (0,94) обов'язковий — без
   нього рух читається як роздування, а з ним як поштовх, після якого
   предмет стає на місце. Тінь у піку відриває пост від доріжки, інакше
   він більшає, лишаючись плаский.

   Стрибок живе на ОБОХ шарах, не лише на кольоровому. Інакше тьмяний
   блок стояв би нерухомо, поки кольоровий над ним підскакує, і на межі
   відкриття було б видно два різні прямокутники замість одного. */
.scn-set i{
  animation:scnPop 7.4s var(--ease) infinite; animation-play-state:paused;
  /* Затримка ВИРАХУВАНА з позиції: стрибок мусить припадати на мить, коли
     межа відкриття проходить блок. Виставлена на око, вона розповідала б,
     що дні тижня ні до чого.

     Доданок 0,62s — це час, за який межа перетинає сам блок (ширина 11,4%
     × 0,0666s на відсоток). Без нього стрибок починався б, коли межа
     торкнулась лівого краю, і блок підскакував би розфарбованим наполовину:
     видно було б вертикальну лінію посеред нього. Тепер він спершу
     наливається кольором цілком, а тоді спливає. */
  /* Затримка вирахувана з ДНЯ, у якому стоїть пост, а не з відстані.
     День посту: k = (x - 1.4) / 14.286. Його черга настає на 6% + 12%·k
     циклу, тобто 0,444s + 0,888s·k. Підставивши k, дістаємо множник
     0,0622 на одиницю x і сталу 0,357.

     Перевірка на краях: x=1.4 (понеділок) → 0,444s = 6% циклу; x=87.2
     (неділя) → 5,78s ≈ 78% циклу. Обидва збігаються з ключовими кадрами
     `scnWipe` вище — і мусять збігатися далі, якщо їх колись правити. */
  animation-delay:calc(var(--x) * 0.0622s + 0.357s);
}
.is-in .scn-set i{ animation-play-state:running }
/* 🛑 Було `scale(1.5)`. На блоці 109x32 це не акцент, а стрибок у півтора
   разу: предмет вилітав за межі своєї денної комірки, налізав на сусідні
   й читався як дешева мальована анімація, а не як подія в розкладі.

   Стало: підйом на 2 px, збільшення на 5%, бурштиновий обідок і теплий
   відсвіт — і за чверть секунди все сідає назад. Провал нижче вихідного
   (0,985) лишився: без нього рух читається як роздування, з ним — як
   поштовх, після якого предмет стає на місце. Але провал теж стриманий,
   бо разом із меншим підйомом велика просадка виглядала б як збій.

   `box-shadow` на нульовому кадрі — не `none`, а прозорий обідок того ж
   виду: між `none` і значенням браузер не інтерполює, і замість появи
   світла вийшов би стрибок. */
@keyframes scnPop{
  0%      { transform:none;
            box-shadow:0 0 0 0 transparent, 0 0 0 0 transparent }
  2.5%    { transform:translateY(-2px) scale(1.05);
            box-shadow:0 6px 16px -6px color-mix(in oklab, var(--accent) 70%, transparent),
                       0 0 0 2px color-mix(in oklab, var(--accent) 30%, transparent) }
  6%      { transform:translateY(0) scale(.985);
            box-shadow:0 0 0 0 transparent, 0 0 0 0 transparent }
  9%,100% { transform:none;
            box-shadow:0 0 0 0 transparent, 0 0 0 0 transparent }
}

/* ── ПІДСУМОК ТИЖНЯ ──────────────────────────────────────────────────
   Сцена показувала процес без результату. Лічильник дає їй кінець.

   Одометр, а не підстановка тексту: усі вісім значень лежать у розмітці
   стовпчиком, видно рівно одне, і смужка перескакує на наступне разом із
   днем. Скрипта тут немає взагалі — отже, нема чого чекати, нема що
   ламати й нічого не блимне до його завантаження.

   🛑 Висота рядка (22px) СТАЛА і повторена в трьох місцях: у коробці, у
   рядку й у ключових кадрах. Розійдуться — число з'їде наполовину, і
   виглядатиме це як зламаний шрифт, а не як зламана анімація. */
.scn-foot{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:20px; flex-wrap:wrap; margin-top:12px;
}
.scn-foot .scn-note{ margin:0 }
.scn-out{ display:flex; align-items:baseline; gap:7px; flex:0 0 auto }
.sc-odo{
  display:block; height:22px; overflow:hidden; text-align:left;
  font-size:19px; font-weight:700; line-height:22px; color:var(--accent);
  font-variant-numeric:tabular-nums; min-width:24px;
}
.sc-odo > span{
  display:block;
  animation:scnOdo 7.4s linear infinite; animation-play-state:paused;
}
.is-in .sc-odo > span{ animation-play-state:running }
.sc-odo i{ display:block; height:22px; line-height:22px; font-style:normal }
.scn-out em{ font-style:normal; font-size:11.5px; color:var(--faint) }
@keyframes scnOdo{
  0%,   5.99%{ animation-timing-function:step-end; transform:translateY(0) }
  6%,  17.99%{ animation-timing-function:step-end; transform:translateY(-22px) }
  18%, 29.99%{ animation-timing-function:step-end; transform:translateY(-44px) }
  30%, 41.99%{ animation-timing-function:step-end; transform:translateY(-66px) }
  42%, 53.99%{ animation-timing-function:step-end; transform:translateY(-88px) }
  54%, 65.99%{ animation-timing-function:step-end; transform:translateY(-110px) }
  66%, 77.99%{ animation-timing-function:step-end; transform:translateY(-132px) }
  78%, 95%   { animation-timing-function:step-end; transform:translateY(-154px) }
  95.01%,100%{ animation-timing-function:step-end; transform:translateY(0) }
}

/* Стилі смуги «зараз» прибрано разом із самою смугою: вона пояснювала
   порядок ціною зайвої рухомої деталі, яка перетягувала увагу з постів.
   Мертвий CSS переживає розмітку надовго й потім змушує гадати, чи він
   комусь потрібен. */

/* ── 3. МЕНЕДЖЕР: ТРИ ЕКРАНИ ПЕРЕПИСКИ ───────────────────────────────────
   Замість схеми «вхід → ядро → вихід» тут предмет: телефон із відкритою
   перепискою. Схема пояснювала механіку, але механіку тут ніхто й не
   питає — питають, як це виглядає. А виглядає воно як діалог.

   Три екрани, бо робіт теж три і плутати їх не можна: відповісти на
   питання, зібрати замовлення, розібрати коментарі. Останній навмисно
   закінчується передачею людині. */
.scn-phones{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:18px; justify-items:center; align-items:start;
}
.scn-ph{
  position:relative; width:100%; max-width:214px;
  border-radius:16px; overflow:hidden;
  border:1px solid var(--line-2); background:var(--bg-2);
  box-shadow:0 14px 34px -22px oklch(0.2 0.02 60/.45);
  display:flex; flex-direction:column;
  /* Мінімальна висота, а не жорстка пропорція: репліки різної довжини
     переносяться по-різному в кожній мові, і 9:16 тут або обрізало б
     текст, або лишало б порожнечу. Екран телефона впізнають за
     скругленням і шапкою, а не за точним співвідношенням сторін. */
  min-height:250px;
  /* Екрани з'являються по черзі, зліва направо — так само, як людина
     розбирала б чергу. Одночасна поява трьох читається як завантаження
     сторінки, а не як робота. */
  opacity:0; transform:translateY(10px);
  animation:scnPh .6s var(--ease) forwards;
  animation-delay:calc(var(--p) * .18s);
  animation-play-state:paused;
}
.is-in .scn-ph{ animation-play-state:running }
@keyframes scnPh{ to{ opacity:1; transform:translateY(0) } }

/* шапка */
.ph-hd{
  display:flex; align-items:center; gap:8px; padding:9px 10px;
  border-bottom:1px solid var(--line); background:var(--card-2);
}
.ph-av{
  flex:0 0 auto; width:24px; height:24px; border-radius:50%;
  overflow:hidden; background:oklch(0.3 0.02 60);
}
.ph-av img{ width:100%; height:100%; object-fit:cover; display:block }
.ph-who{ display:flex; flex-direction:column; min-width:0 }
.ph-who b{
  font-size:11.5px; font-weight:700; color:var(--fg); line-height:1.2;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.ph-who i{
  font-style:normal; font-size:9.5px; color:var(--faint); line-height:1.3;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

/* тіло переписки */
.ph-body{
  flex:1; display:flex; flex-direction:column; gap:6px;
  padding:10px; align-items:flex-start;
}
/* Репліки з'являються ПО ЧЕРЗІ, з кроком у пів секунди після появи
   самого екрана. Це не оздоба: одночасна поява всіх реплік перетворює
   діалог на список, а порядок реплік — єдине, що робить його діалогом. */
.ph-body > *{
  opacity:0; transform:translateY(6px);
  animation:scnPh .45s var(--ease) forwards;
  animation-delay:calc(var(--p) * .18s + var(--m) * .5s + .35s);
  animation-play-state:paused;
}
.is-in .ph-body > *{ animation-play-state:running }
.ph-msg{
  max-width:88%; padding:6px 9px; border-radius:11px;
  border-bottom-left-radius:4px;
  border:1px solid var(--line-2); background:var(--card-2);
  font-size:11px; line-height:1.35; color:var(--fg);
}
/* Відповідь системи тулиться до правого краю й залита акцентом — та сама
   граматика, що в будь-якому месенджері: своє праворуч, чуже ліворуч. */
.ph-msg.out{
  align-self:flex-end; border-bottom-left-radius:11px;
  border-bottom-right-radius:4px;
  border-color:var(--accent); background:var(--accent-soft);
}

/* картка замовлення */
.ph-ord{
  align-self:stretch; display:flex; flex-direction:column; gap:2px;
  padding:8px 9px; border-radius:10px;
  border:1px solid var(--accent); background:var(--accent-soft);
}
.ph-ord b{ font-size:11px; font-weight:700; color:var(--fg); line-height:1.25 }
.ph-ord i{ font-style:normal; font-size:10px; color:var(--dim) }
.ph-ord em{
  align-self:flex-start; margin-top:4px; font-style:normal;
  font-family:var(--mono); font-size:9px; font-weight:700;
  padding:2px 7px; border-radius:6px;
  background:var(--accent); color:var(--accent-fg);
}

/* «друкує…» — три крапки, що біжать */
.ph-typing{
  display:flex; gap:3px; align-self:flex-end;
  padding:7px 10px; border-radius:11px; border-bottom-right-radius:4px;
  border:1px solid var(--accent); background:var(--accent-soft);
}
.ph-typing i{
  width:4px; height:4px; border-radius:50%; background:var(--accent);
  animation:phType 1.1s var(--ease) infinite;
}
.ph-typing i:nth-child(2){ animation-delay:.15s }
.ph-typing i:nth-child(3){ animation-delay:.3s }
@keyframes phType{
  0%,60%,100%{ opacity:.3; transform:translateY(0) }
  30%        { opacity:1;  transform:translateY(-3px) }
}

/* передано людині */
.ph-held{
  align-self:stretch; padding:6px 9px; border-radius:10px;
  border:1px dashed var(--line-2); background:transparent;
  font-size:10px; font-style:italic; line-height:1.35; color:var(--dim);
}

/* Підпис унизу екрана — не частина інтерфейсу, а НАШ коментар до нього:
   що саме на цьому екрані щойно сталося. Тому моноширинний і приглушений,
   як решта службових підписів на сцені. */
.ph-badge{
  display:block; padding:7px 10px; border-top:1px solid var(--line);
  background:var(--card-2);
  font-family:var(--mono); font-size:9px; letter-spacing:.02em;
  color:var(--faint); text-align:center;
}
/* Назва екрана — смуга на всю ширину над шапкою. Плашка в куті лягала
   просто на ім'я співрозмовника, і з двох написів в одній точці видно
   було лише верхній. */
.ph-cap{
  display:block; padding:4px 10px;
  font-family:var(--mono); font-size:9px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--accent-fg);
  background:var(--accent); text-align:center;
}

@media (max-width:820px){
  .scn{ padding:16px 14px 12px }
  .scn-tag{ flex-basis:56px; font-size:10px }
  .scn-days,.scn-lane{ gap:8px }
  /* Шість стадій в один ряд на вузькому екрані не вміщаються — стають
     у два ряди по три. Порядок читання лишається той самий, а дуга
     повернення просто веде з кінця другого ряду в початок першого. */
  .scn-cycle{ grid-template-columns:repeat(3,1fr); gap:12px 10px }
  .scn-stage > b{ font-size:11px }
  .scn-set i b{ font-size:8.5px }
}
@media (max-width:560px){
  /* Назви тем на постах уже не вміщаються — лишається сама розкладка по
     днях. Обрізаний до двох літер підпис гірший за жоден. */
  .scn-set i b{ display:none }
  /* Три екрани в ряд на телефоні не вміщаються. Ставимо один під одним,
     а не стискаємо: екран переписки вужчий за 150px перестає бути
     схожим на переписку. */
  .scn-phones{ grid-template-columns:minmax(0,1fr); gap:14px }
  .scn-ph{ max-width:280px }
}
@media (prefers-reduced-motion: reduce){
  .scn-stage,.scn-stage b,.scn-mini,.scn-mini > *,
  .scn-set i,.scn-set.lit,.scn-ph,.ph-body > *,.ph-typing i,.scn-back,.mb-glass,
  .scn-track::before,.scn-dayrow::before,.sc-odo > span{
    animation:none !important;
  }
  /* Колонки поточного дня в нерухомому кадрі бути не може: тиждень уже
     виконаний, «зараз» немає. */
  .scn-track::before,.scn-dayrow::before{ opacity:0 }
  /* Одометр стоїть на підсумку, а не на нулі: показуємо результат тижня. */
  .sc-odo > span{ transform:translateY(-154px) }
  /* Нерухомий кадр має лишитись осмисленим: усі шість стадій проявлені,
     тиждень виконаний, репліки видимі. Мініатюри всередині стадій живуть
     на transform-ах із нульового кадру, тож їх треба повернути в
     «зроблений» стан руками, інакше зупинена анімація лишить порожні
     рамки. */
  .mi-ln,.mi-bar,.mi-seek{ transform:scaleX(1) scaleY(1) }
  .mi-img,.mi-cap,.mi-up,.mi-ray{ opacity:1 }
  /* Нерухомий кадр показує тиждень ВИКОНАНИМ: заповнення на місці. */
  .scn-set.lit{ clip-path:none }
  .scn-ph,.ph-body > *{ opacity:1; transform:none }
}

/* ═══ ПРЕДМЕТИ СТОРІНКИ «ЯК ПРАЦЮЄ» ══════════════════════════════════════
   Три об'єкти на місці трьох знімків інтерфейсу. Та сама причина, що й на
   головній: знімок показує панель, а крок розповідає про дію.

   Тут вони простіші за сцени головної й це навмисно. На головній об'єкт
   мусить сам зупинити на собі погляд — його ніхто не просив дивитись. На
   цій сторінці людина вже читає покроково, предмет лише підтверджує
   щойно прочитаний абзац. Гучний рух тут заважав би читати. */
.hw{
  border:1px solid var(--line); border-radius:var(--r-lg);
  background:var(--card); padding:16px; position:relative;
}
.hw-cap{
  display:block; font-family:var(--mono); font-size:10px;
  letter-spacing:.07em; text-transform:uppercase; color:var(--faint);
  margin-bottom:12px;
}
.hw-note{
  display:block; margin-top:12px; font-family:var(--mono);
  font-size:11px; color:var(--faint);
}

/* ── крок 3: пропозиція розкадровки ────────────────────────────────── */
.hw-frames{ display:flex; gap:8px; margin-bottom:13px }
.hw-frames i{
  flex:1; aspect-ratio:9/16; border-radius:7px; overflow:hidden;
  border:1px solid var(--line-2);
  background:linear-gradient(168deg, var(--card-2), var(--bg-2));
  /* Кадри проявляються по черзі — це і є «показує розкадровку». Один
     прохід на завантаженні, без нескінченного циклу: сторінку читають, а
     не дивляться, і повторюваний рух збоку заважав би тексту. */
  opacity:0; transform:translateY(6px);
  animation:hwIn .5s var(--ease) forwards;
  animation-delay:calc(var(--n) * .12s);
}
.hw-frames i img{ width:100%; height:100%; object-fit:cover; display:block }
@keyframes hwIn{ to{ opacity:1; transform:translateY(0) } }
.hw-t{ display:block; font-size:14px; font-weight:700; color:var(--fg) }
.hw-s{ display:block; margin-top:3px; font-size:12px; color:var(--faint) }
/* «0 кредитів списано» — головний рядок цього предмета, і тому єдиний
   тут, що має заливку. Уся суть кроку в тому, що подивитись пропозицію
   нічого не коштує; якби цей рядок виглядав як решта підписів, крок
   втратив би те, заради чого існує. */
.hw-free{
  display:inline-block; margin-top:10px;
  font-family:var(--mono); font-size:11px; font-weight:700;
  padding:3px 9px; border-radius:7px;
  background:var(--accent); color:var(--accent-fg);
}
.hw-btns{ display:flex; gap:8px; margin-top:13px }
.hw-btn{
  flex:1; text-align:center; padding:7px 10px; border-radius:9px;
  border:1px solid var(--line-2); font-size:12px; color:var(--dim);
}
.hw-btn.on{
  border-color:var(--accent); background:var(--accent-soft);
  color:var(--fg); font-weight:600;
}

/* ── крок 4: черга на затвердження ─────────────────────────────────── */
.hw-row{
  display:flex; align-items:center; gap:10px;
  padding:9px 0; border-bottom:1px solid var(--line);
  opacity:0; transform:translateY(6px);
  animation:hwIn .5s var(--ease) forwards;
  animation-delay:calc(var(--n) * .14s);
}
.hw-row:last-of-type{ border-bottom:0 }
.hw-th{
  flex:0 0 auto; width:28px; height:38px; border-radius:5px;
  border:1px solid var(--line-2); overflow:hidden;
  background:linear-gradient(168deg, var(--card-2), var(--bg-2));
}
.hw-th img{ width:100%; height:100%; object-fit:cover; display:block }
.hw-rt{ flex:1; display:flex; flex-direction:column; min-width:0 }
.hw-rt b{ font-size:13px; font-weight:600; color:var(--fg); line-height:1.3 }
.hw-rt i{ font-style:normal; font-size:11px; color:var(--faint) }
/* Галочка малюється двома лініями через `border`, а не символом: символ
   ✓ у різних шрифтах різного розміру й сидить на різній висоті, і
   вирівняти його в колі однаково на всіх системах неможливо. */
.hw-ok{
  flex:0 0 auto; position:relative; width:20px; height:20px;
  border-radius:50%; background:var(--accent);
  animation:hwPop .45s var(--ease) backwards;
  animation-delay:calc(var(--n) * .14s + .35s);
}
.hw-ok::after{
  content:""; position:absolute; left:6px; top:5px;
  width:5px; height:9px; border:solid var(--accent-fg);
  border-width:0 2px 2px 0; transform:rotate(42deg);
}
@keyframes hwPop{
  0%  { transform:scale(0); opacity:0 }
  60% { transform:scale(1.25); opacity:1 }
  100%{ transform:scale(1); opacity:1 }
}
/* Останній рядок лишається БЕЗ галочки, і це не забутий стан. Черга не
   порожніє сама собою: у ній завжди є те, що чекає рішення людини, і
   предмет мусить це показувати, а не обіцяти рівний ряд галочок. */
.hw-wait{
  flex:0 0 auto; width:20px; height:20px; border-radius:50%;
  border:1.5px dashed var(--line-2);
}

/* ── крок 5: тиждень без вас ───────────────────────────────────────── */
.hw-week-grid{
  display:grid; grid-template-columns:repeat(7,1fr); gap:5px;
  margin-bottom:14px;
}
.hw-day{ display:flex; flex-direction:column; align-items:center; gap:5px }
.hw-day b{
  font-family:var(--mono); font-size:10px; font-weight:400;
  color:var(--faint);
}
.hw-day i{
  display:block; width:100%; height:30px; border-radius:5px;
  background:var(--accent); transform-origin:bottom;
  transform:scaleY(0);
  animation:hwFill .5s var(--ease) forwards;
  animation-delay:calc(var(--n) * .1s + .2s);
}
/* Субота й неділя нижчі й тьмяніші: у вихідні виходить менше, і тиждень,
   у якому всі сім днів однакові, читається як згенерований, а не як
   спланований. */
.hw-day:nth-child(6) i,.hw-day:nth-child(7) i{
  height:16px; background:color-mix(in srgb, var(--accent) 45%, transparent);
}
@keyframes hwFill{ to{ transform:scaleY(1) } }
.hw-stats{ display:flex; gap:14px; flex-wrap:wrap }
.hw-stat{ display:flex; flex-direction:column; min-width:0 }
.hw-stat b{
  font-family:var(--display,var(--mono)); font-size:24px; font-weight:700;
  line-height:1.05; color:var(--fg);
}
.hw-stat i{ font-style:normal; font-size:11px; color:var(--faint) }
/* Нуль — головне число цього предмета, тож воно єдине тут бурштинове.
   «0 хвилин вашого часу» і є вся обіцянка кроку; поруч із двома іншими
   числами однакового кольору воно загубилось би як найменше. */
.hw-stat:last-child b{ color:var(--accent) }

@media (prefers-reduced-motion: reduce){
  .hw-frames i,.hw-row,.hw-ok,.hw-day i{ animation:none }
  .hw-frames i,.hw-row{ opacity:1; transform:none }
  .hw-day i{ transform:scaleY(1) }
}

/* ── крок 1: картка товару з посилання ──────────────────────────────── */
.hw-url{
  display:block; padding:8px 11px; border-radius:8px;
  border:1px solid var(--line-2); background:var(--bg-2);
  font-family:var(--mono); font-size:11.5px; color:var(--dim);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
/* Стрілка вниз між посиланням і карткою: без неї це два блоки поруч, з
   нею — «з цього виходить оце». Малюємо псевдоелементом, бо це зв'язок
   між сусідами, а не самостійний предмет. */
.hw-prod{
  position:relative; display:flex; align-items:center; gap:11px;
  margin-top:26px; padding:11px; border-radius:10px;
  border:1px solid var(--accent); background:var(--accent-soft);
  opacity:0; animation:hwIn .5s var(--ease) .45s forwards;
}
.hw-prod::before{
  content:""; position:absolute; left:22px; top:-19px;
  width:0; height:0; border-style:solid; border-width:7px 5px 0 5px;
  border-color:var(--line-2) transparent transparent transparent;
}
.hw-pimg{
  flex:0 0 auto; width:38px; height:48px; border-radius:6px;
  overflow:hidden; background:var(--bg-2);
}
.hw-pimg img{ width:100%; height:100%; object-fit:cover; display:block }
.hw-ptxt{ display:flex; flex-direction:column; min-width:0 }
.hw-ptxt b{ font-size:13.5px; font-weight:700; color:var(--fg) }
.hw-ptxt i{ font-style:normal; font-size:11.5px; color:var(--dim) }

/* ── крок 2: підключення мереж ──────────────────────────────────────── */
.hw-dot{
  flex:0 0 auto; width:10px; height:10px; border-radius:50%;
  background:var(--line-2);
  animation:hwDot .4s var(--ease) backwards;
  animation-delay:calc(var(--n) * .14s + .3s);
  animation-fill-mode:both;
}
@keyframes hwDot{
  from{ background:var(--line-2); transform:scale(1) }
  60% { background:var(--accent); transform:scale(1.6) }
  to  { background:var(--accent); transform:scale(1) }
}

/* ═══ ОДНА ГОДИНА РОБОТИ ══════════════════════════════════════════════════
   Три колонки: хронологія — ролик — числа. Порядок читання зліва направо
   і є причинно-наслідковим: спершу що робилось, потім що вийшло, потім
   скільки це коштувало вашого часу (нуль).

   Ролик посередині, а не збоку, бо він тут доказ, а не ілюстрація до
   тексту. Обидві колонки поруч із ним — про нього. */
/* 🛑 `stretch`, а не `center`. Поки в правій колонці стояли три дрібні
   числа, обидві бічні колонки були приблизно однакові й центрування
   тримало їх на одній лінії. Числа-герої плюс блок «за місяць» витягнули
   праву до 499 px проти 224 px у хронології — і хронологія повисла
   посеред порожнечі, як забутий уривок.

   Тепер колонки на всю висоту, а рядки хронології розходяться по ній.
   Це заразом чесніше по суті: ліворуч ГОДИНА, і рядки, розтягнуті на всю
   висоту кадру, читаються як час, що минає, а не як список. */
.hour{
  display:grid; grid-template-columns:1fr auto 1fr;
  gap:26px; align-items:stretch; margin-top:28px;
}
/* Кадру розтягуватись не можна — у нього своє співвідношення сторін. */
.hour-clip{ align-self:center }
.hour-tl{ justify-content:space-between }
.hour-tl,.hour-sum{ display:flex; flex-direction:column }
.hour-row{
  display:flex; gap:12px; align-items:baseline;
  padding:9px 0; border-bottom:1px solid var(--line);
  opacity:0; transform:translateX(-8px);
  animation:hourIn .5s var(--ease) forwards;
  animation-delay:calc(var(--n) * .12s);
  animation-play-state:paused;
}
/* Рух прив'язаний до `.is-in`, як і на решті сцен: анімація, що
   відпрацювала до того, як секцію побачили, — це просто зникла анімація. */
.is-in .hour-row,.is-in .hour-n{ animation-play-state:running }
@keyframes hourIn{ to{ opacity:1; transform:translateX(0) } }
.hour-row:last-child{ border-bottom:0 }
/* Час моноширинний і фіксованої ширини — цифри мусять стояти в колонку.
   Пропорційний шрифт зсуває «09:12» відносно «09:26», і рівний стовпчик
   часу перетворюється на драбинку. */
.hour-t{
  flex:0 0 auto; width:44px; font-family:var(--mono); font-size:12px;
  font-weight:700; color:var(--accent);
}
.hour-w{ font-size:13.5px; line-height:1.4; color:var(--fg) }

.hour-clip{
  margin:0; position:relative; width:min(232px,26vw);
  border-radius:14px; overflow:hidden;
  border:1px solid var(--line-2); background:var(--bg-2);
  box-shadow:0 22px 50px -30px oklch(0.2 0.02 60/.5);
}
.hour-clip video{
  display:block; width:100%; aspect-ratio:9/16; object-fit:cover;
}
.hour-clip figcaption{
  display:flex; flex-direction:column; gap:2px; padding:10px 12px;
  border-top:1px solid var(--line); background:var(--card-2);
}
.hour-clip figcaption b{ font-size:12.5px; font-weight:700; color:var(--fg) }
.hour-clip figcaption i{ font-style:normal; font-size:11px; color:var(--faint) }

.hour-n{
  display:flex; flex-direction:column; padding:9px 0;
  opacity:0; transform:translateX(8px);
  animation:hourIn .5s var(--ease) forwards;
  animation-delay:calc(var(--n) * .12s + .3s);
  animation-play-state:paused;
}
/* 🛑 Число — ГЕРОЙ секції, а не підпис до неї. Було 30px: рівно стільки,
   скільки має заголовок поруч, тобто числа не читались як головне, вони
   читались як ще один рядок тексту. Правило з дизайн-коду просте — герой
   це число.

   `clamp`, а не одне значення: 62px на телефоні, де колонка стає рядком з
   трьох, зіштовхнули б числа одне з одним. Нижня межа 40px — та, нижче
   якої число знову зрівнюється з підписом. */
.hour-n b{
  font-size:clamp(40px, 5.2vw, 62px); font-weight:700; line-height:1;
  letter-spacing:-.02em; color:var(--fg);
  font-variant-numeric:tabular-nums;
}
.hour-n i{ font-style:normal; font-size:12.5px; color:var(--faint) }
/* Нуль — головне число секції, тож воно єдине бурштинове. «0 ваших дій»
   і є вся обіцянка; поруч із двома іншими однакового кольору воно
   загубилось би як найменше. */
/* 🛑 `:last-of-type`, а не `:last-child`. Поки в колонці стояли лише три
   числа, останнє з них було й останнім дитям. Щойно під ними з'явився
   блок «за місяць», `:last-child` перестав збігатися взагалі — і нуль
   мовчки втратив і колір, і смужку. Жодної помилки, просто сірий нуль
   замість головного числа секції.

   `:last-of-type` рахує серед `span`, а блок проєкції — `div`. Підпис
   `.hw-cap` угорі теж `span`, але він ПЕРШИЙ, тож останнім лишається
   саме третє число. */
.hour-n:last-of-type b{ color:var(--accent) }
/* Нуль лишається головним і після збільшення решти. Поки всі числа були
   дрібні, вистачало кольору; на 62px «0» стало найкоротшим із трьох, і
   сама його форма робить його легшим за «6». Тонка бурштинова лінія збоку
   повертає йому вагу, не додаючи ще одного кольору на екран. */
.hour-n:last-of-type{
  border-left:2px solid var(--accent); padding-left:14px; margin-left:-16px;
}

/* ── ГОДИНА × МІСЯЦЬ ─────────────────────────────────────────────────── */
.hour-proj{
  margin-top:16px; padding-top:16px; border-top:1px solid var(--line);
  display:flex; flex-direction:column;
}
/* Стовпчиком, а не в рядок. У рядок три числа з підписами не влазять у
   колонку 296 px: виміряно 395 px потрібної ширини, тобто два переносились
   під третє, і виходило 2+1 — розкладка, яку читаєш як «щось поїхало».
   Стовпчик заразом римується з хронологією ліворуч: там теж рядки, у яких
   зліва коротке, справа довге. */
.hp-row{ display:flex; flex-direction:column; gap:2px; margin-top:6px }
.hp{
  display:grid; grid-template-columns:auto minmax(0,1fr);
  gap:0 12px; align-items:baseline; padding:6px 0; min-width:0;
  opacity:0; transform:translateY(6px);
  animation:hourIn .5s var(--ease) forwards;
  animation-delay:calc(var(--n) * .12s + .75s);
  animation-play-state:paused;
}
.is-in .hp{ animation-play-state:running }
/* Помітно менші за числа години: другий такт, а не другий герой.
   Однаковий кегль перетворив би шість чисел на таблицю. */
/* Ширина числа стала: «30» і «4 320» різної довжини, а підписи праворуч
   мусять стояти в колонку. Без цього рядки виглядають як драбинка — той
   самий дефект, що вже полагоджений у часі хронології. */
.hp b{
  grid-row:1 / span 2; align-self:center; min-width:62px;
  font-size:26px; font-weight:700; line-height:1.05; color:var(--fg);
  font-variant-numeric:tabular-nums;
}
.hp:last-child b{ color:var(--accent) }
.hp + .hp{ border-top:1px solid var(--line) }
.hp i{ font-style:normal; font-size:12px; color:var(--dim) }
.hp em{ font-style:normal; font-size:10.5px; color:var(--faint); line-height:1.35 }

@media (max-width:900px){
  /* Ролик угору, колонки під нього: три колонки на телефоні дали б
     кадр завширшки з палець. */
  .hour{ grid-template-columns:minmax(0,1fr); gap:20px; justify-items:center }
  .hour-tl{ justify-content:flex-start }
  .hour-clip{ width:min(232px,62vw); order:-1 }
  .hour-tl,.hour-sum{ width:100%; max-width:420px }
  /* Сітка з трьох колонок, а не гнучкий рядок із переносом. Рядок
     переносив третє число на власний рядок: колонка обмежена 420 px, а
     три підписи («finished video», «customer replies», «actions from
     you») просять 424 px разом із проміжками. Виходило 2+1 і пів екрана
     порожнечі під нулем. Сітка ділить ширину порівну й дозволяє підпису
     перенестись усередині своєї колонки. */
  .hour-sum{
    display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
    gap:0 16px; align-items:start;
  }
  .hour-sum .hw-cap,.hour-proj{ grid-column:1 / -1 }
  /* Смужка біля нуля вертикальна, і в рядку вона з підкреслення значення
     перетворилась би на межу між сусідами. */
  .hour-n:last-of-type{ border-left:0; padding-left:0; margin-left:0 }
  .hour-proj{ width:100%; max-width:420px }
}
@media (prefers-reduced-motion: reduce){
  .hour-row,.hour-n,.hp{ animation:none; opacity:1; transform:none }
}
