/*
 * Non-critical CSS — everything below the first viewport (chapters 3/4 of
 * the hero scene, the light "day" sheet, and every section after it).
 * build.py hashes this file's content into dist/assets/css/site.<hash>.css
 * so a content change always busts the cache (docs/REVIEW-PACKAGE.md
 * задача A). Ported verbatim from design/mock-home-v2.html — only asset
 * paths were made absolute (/assets/...), nothing else changed.
 */

/* — chapter 3: колода з трьох карток підтвердження — */
.ch-card{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:5rem 0}
.tier-a .ch-card{padding:0}

/* tier B / no-JS: три картки статичним стеком */
.card-deck{display:flex;flex-direction:column;align-items:center;gap:2.75rem;width:100%}
.deck-item{margin:0;width:min(92vw,24.5rem)}
.deck-stage{width:100%;display:flex;flex-direction:column;align-items:center}
.deck-dots{display:none}
.deck-controls{display:none}

/* tier A: колода стала каруселлю (04.09.2026).
   Було — три картки в одній клітинці сітки, і прокрутка перегортала їх
   за читача. На телефоні це означало: хочеш затриматись на другій — не
   можеш, палець уже проніс сцену далі. Тепер картки лежать у ряд зі
   snap-точками: прокрутка веде їх сама, поки читач не торкнувся, а після
   дотику каруселлю керує тільки він. */
.tier-a .card-deck{
  display:flex;flex-direction:row;align-items:center;gap:0;
  width:100%;
  overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;
  overscroll-behavior-x:contain;
  scrollbar-width:none;-ms-overflow-style:none;
  -webkit-overflow-scrolling:touch;
}
.tier-a .card-deck::-webkit-scrollbar{width:0;height:0;display:none}
.tier-a .card-deck:focus-visible{outline:2px solid var(--primary-d);outline-offset:6px;border-radius:var(--r-card)}
.tier-a .deck-item{
  flex:0 0 100%;width:auto;
  display:flex;flex-direction:column;align-items:center;
  scroll-snap-align:center;
  padding-inline:.25rem;
  will-change:transform,opacity;
}
/* Ширину задаємо самій картці, а не всім дітям: мітка під нею має
   width:fit-content — інакше плашка розтягується на всю колонку. */
.tier-a .deck-item > .confirm-card{width:min(92vw,24.5rem)}
/* Ховається вся сцена одразу, а не кожна картка окремо: у ряду
   напівпрозора картка лишила б по собі порожню колонку. */
.tier-a .deck-stage{will-change:transform,opacity}
/* `.tier-a .ch` вимикає pointer-events усім главам, щоб сцена не заважала
   прокрутці. Карусель — єдине місце, де читач має щось натиснути, тому
   події вмикаємо назад точково. Поки сцена схована (visibility:hidden),
   натиснути все одно нічого не можна. touch-action лишаємо типовим:
   браузер сам вибирає вісь — горизонтальний змах гортає картки,
   вертикальний іде сторінці. */
.tier-a .deck-stage{pointer-events:auto}

.tier-a .deck-controls{
  display:flex;align-items:center;gap:.25rem;margin-top:1.4rem;
}
.tier-a .deck-dots{display:flex;gap:.35rem}
.deck-arrow{
  width:2.75rem;height:2.75rem;padding:0;
  display:flex;align-items:center;justify-content:center;
  background:rgba(18,28,25,.55);
  border:1px solid #2E413A;border-radius:50%;
  color:#B9CCC5;font-size:1.35rem;line-height:1;
  cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:border-color 180ms ease,color 180ms ease;
}
.deck-arrow:hover{border-color:var(--primary-d);color:var(--primary-d)}
.deck-arrow:focus-visible{outline:2px solid var(--primary-d);outline-offset:2px}
/* Поки тягнемо мишею — знімаємо snap, інакше він смикає трек назад на
   кожному русі; після відпускання клас іде, і браузер сам доводить. */
.tier-a .card-deck.is-dragging{scroll-snap-type:none;cursor:grabbing}
@media (hover:hover) and (pointer:fine){
  .tier-a .card-deck{cursor:grab}
}
.deck-dot{
  width:2.25rem;height:2.25rem;padding:0;border:0;background:none;
  cursor:pointer;position:relative;
  -webkit-tap-highlight-color:transparent;
}
.deck-dot::after{
  content:"";position:absolute;inset:50% auto auto 50%;
  width:7px;height:7px;margin:-3.5px 0 0 -3.5px;border-radius:50%;
  background:#4A5C55;transition:background 200ms ease,transform 200ms ease;
}
.deck-dot.is-on::after{background:var(--primary-d);transform:scale(1.35)}
.deck-dot:focus-visible{outline:2px solid var(--primary-d);outline-offset:2px;border-radius:50%}

.confirm-card{
  background:var(--card-d);
  border:1px solid var(--line-d);
  border-radius:var(--r-card);
  padding:1.15rem 1.05rem 1.25rem;
  box-shadow:0 1px 2px rgba(0,0,0,.35),0 12px 40px rgba(0,0,0,.4),0 0 60px rgba(79,200,180,.06);
}
.confirm-card.is-alert{box-shadow:0 1px 2px rgba(0,0,0,.35),0 12px 40px rgba(0,0,0,.4),0 0 60px rgba(232,163,61,.07)}
.cc-head{
  display:flex;align-items:center;gap:.55em;
  font-family:var(--ff-mono);font-size:.6875rem;letter-spacing:.06em;
  color:#7E8F88;margin-bottom:.9rem;
}
.cc-head .cc-dot{width:7px;height:7px;border-radius:50%;background:var(--primary-d);flex:none}
.is-alert .cc-head .cc-dot{width:10px;height:2px;border-radius:1px;background:var(--signal-d)}

/* підпис-мітка під карткою: чий це бізнес */
.deck-tag{
  /* Мітка лежить ПОВЕРХ світної рамки з частинок, тому самого лише кольору
     мало: на чистому тлі контраст 8.2:1, а над скупченням пилу локально
     падає майже до нуля — власник 04.09 не побачив її взагалі.
     Тінь під текстом цього не рятує, тому під міткою тепер щільна плашка:
     вона читається над будь-яким тлом сцени. */
  display:flex;align-items:center;justify-content:center;gap:.5em;
  width:fit-content;margin:1.1rem auto 0;
  padding:.34rem .7rem;border-radius:999px;
  background:rgba(9,15,14,.82);
  font-family:var(--ff-mono);font-size:.8125rem;font-weight:500;letter-spacing:.05em;
  color:#C3D3CC;                      /* 12.0:1 на тлі сцени */
}
.deck-tag::before{
  content:"";flex:none;width:6px;height:6px;border-radius:50%;
  background:var(--primary-d);
}
.deck-tag.is-alert{color:var(--signal-d)}
.deck-tag.is-alert::before{width:11px;height:2px;border-radius:1px;background:var(--signal-d)}
.chat{display:flex;flex-direction:column;gap:.8rem}
.msg{display:flex;flex-direction:column;max-width:92%;will-change:transform,opacity}
.msg.in{align-self:flex-start}
.msg.out{align-self:flex-end;align-items:flex-end}
/* Друга репліка добігає із затримкою після того, як картка стала
   активною: спершу читач бачить питання, і аж потім — відповідь. */
.tier-a .cc-beat{opacity:0;transform:translate3d(0,12px,0);
  transition:opacity 420ms ease, transform 520ms cubic-bezier(.22,1,.36,1)}
.tier-a .deck-stage.is-done .cc-beat{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .tier-a .cc-beat{transition:none}
}
.msg-meta{
  font-family:var(--ff-mono);font-size:.6875rem;color:#7E8F88;
  margin-bottom:.25rem;display:flex;gap:.5em;
}
.bubble{
  background:#0F1916;
  border:1px solid var(--line-d);
  border-radius:var(--r-bubble);
  padding:.75rem .9rem;
  font-size:.9375rem;line-height:1.5;
}
.msg.in .bubble{border-bottom-left-radius:4px}
.msg.out .bubble{
  background:#1B2C27;
  border-color:#2E413B;
  border-bottom-right-radius:4px;
}
.bubble p+p{margin-top:.4rem}
.bubble .q{font-weight:500;color:#F0F4EE}
.choices{display:flex;gap:.45rem;margin-top:.7rem}
.chip{
  flex:1 1 0;min-width:0;
  display:block;text-align:center;
  padding:.5rem .55rem;
  border-radius:8px;
  border:1px solid #3A4A44;
  background:transparent;color:var(--text-d);
  font-family:var(--ff-display);font-weight:600;font-size:.9375rem;
  /* transform не в списку: масштаб натискання веде GSAP, CSS-перехід його б розмазував */
  transition:background-color 160ms ease,opacity 200ms ease,color 160ms ease,border-color 160ms ease;
}
.choices-3 .chip{font-size:.8125rem;letter-spacing:-0.01em}
/* вузький екран: «Так» на весь рядок, дві альтернативи — під ним */
@media (max-width:30rem){
  .choices-3{flex-wrap:wrap}
  .choices-3 .chip-yes{flex:1 0 100%}
  .choices-3 .chip-no{flex:1 1 40%}
}
.chip-yes.pressed{background:var(--signal-d);border-color:var(--signal-d);color:var(--ink-stage)}
.chip-no.dimmed{opacity:.35}
.check{color:var(--proof-d)}
/* картка-виняток: замість пари кнопок — чесна помітка */
.cc-note{
  margin-top:.75rem;padding-top:.6rem;
  border-top:1px solid #2A3A34;
  font-family:var(--ff-mono);font-size:.6875rem;letter-spacing:.03em;
  color:var(--signal-d);
}
.cc-caption{
  margin:0 0 2.4rem;max-width:34em;padding-inline:1.25rem;
  font-family:var(--ff-mono);font-size:.75rem;color:#8FA29B;
  text-align:center;letter-spacing:.02em;line-height:1.6;
}
.tier-a .ch-card .cc-caption{display:none}

/* — chapter 4: тиша — */
.ch-quiet{display:flex;align-items:center;justify-content:center;text-align:center;padding:6rem 0 max(8rem,18vh)}
.tier-a .ch-quiet{padding:0}
.quiet-inner{will-change:transform,opacity;padding-inline:1.25rem}
/* За замовчуванням прихована в tier-a (та сама логіка, що .tier-a
   .deck-item{opacity:0} вище): initMotionHeavy() тепер відкладений на
   requestIdleCallback (QA CRITICAL LCP, 03.09.2026), тож між першим
   малюванням і стартом сценарію ще нема inline-style від applyBeats() —
   без цього правила глава 4 («тиша») майнула б поверх усього (усі .ch —
   position:absolute;inset:0, ch-quiet останній у DOM і намальований би
   зверху). JS перекриває inline-стилем, щойно порахує прогрес. */


/* — chapter 2: потік — */
/* Без цього блоку .ch-flow не має жодної розкладки (лише position:relative
   у спільному .ch, або position:absolute;inset:0;display:flex у
   .tier-a .ch — flex за замовчуванням вирівнює вміст у лівий верхній кут):
   рядок лягав поверх логотипа шапки замість центру екрана (тестерський
   аудит 03.09.2026, п.8).
   03.09.2026, другий захід: композиція. Було — заголовок і чотири короткі
   рядки вузькою смугою по центру кадру, нижня половина порожня. Стало —
   один лівий стовпець у сітці кадру (той самий лівий край, що в h1 глави
   1: .wrap усередині), а потік частинок лишається праворуч. Вертикаль
   тримає крок журналу (--flow-step у vh), а не padding. */
.ch-flow{display:flex;align-items:center;justify-content:center;padding:6rem 0 max(8rem,18vh)}
.tier-a .ch-flow{padding:0}
.flow-inner{width:100%;will-change:transform,opacity}
/* Та сама причина, що і в .tier-a .quiet-inner вище: до старту
   відкладеного сценарію inline-стилю ще нема, і глава майнула б поверх. */

/* Стовпець кадру: заголовок і журнал одним лівим стовпцем. Висоту
   тримає не min-height, а крок журналу нижче — на 1400×900 блок займає
   ~600px із 900 замість смуги в ~180px, як було до 03.09.2026. */
.flow-col{
  max-width:min(100%,35rem);
  /* Крок хроніки прив'язаний до висоти кадру, а не до кегля: на 900px це
     ~65px, на низькому екрані журнал стискається сам, без окремої
     медіа-умови. Висоту глави тримає саме він — жодних min-height і
     розтягувань, тому в tier-b (звичайний потік) ритм такий самий. */
  --flow-step:clamp(1.25rem,6.5vh,4.25rem);
  display:flex;flex-direction:column;
  /* Заголовок відпущений від журналу сильніше, ніж рядки один від одного,
     інакше «Робота йде без вас.» читається першим пунктом списку. */
  gap:calc(var(--flow-step) * 1.55);
}
/* Легкий зсув униз: над заголовком у кадрі працює потік частинок, під
   журналом — нічого, тож блок стоїть трохи нижче геометричного центру. */
.tier-a .flow-col{padding-block-start:clamp(0px,7vh,4rem)}
.flow-line{
  font-family:var(--ff-display);font-weight:600;
  /* Було clamp(1.35rem,3vw,2.2rem) — для повноекранної глави дрібно.
     52px проти 73.6px у h1: глава 2 чутно тихіша за перший екран, але
     тримає екран сама. max-width у ch ламає рядок на два — у лівому
     стовпці двоповерховий заголовок має вагу, однорядковий розтікається. */
  font-size:clamp(1.75rem,1.05rem + 2.6vw,3.25rem);
  letter-spacing:-0.022em;line-height:1.08;
  color:#DCE5DF;margin:0;max-width:11ch;
  text-wrap:balance;
}

/* Журнал глави 2: доказ під лозунгом.
   Рядок «Робота йде без вас» сам по собі — заява; журнал показує саму
   роботу: хроніка однієї доби від 07:01 до 03:00, справи відмічаються
   зробленими по такту прокрутки, попередні лишаються на місці й трохи
   притухають, тож видно накопичений результат. */
.flow-log{
  list-style:none;margin:0;padding:0;
  display:grid;gap:var(--flow-step);
}
.flow-item{
  /* Три колонки: час — вердикт — що зроблено. minmax(0,1fr) у третій
     означає, що на вузькому екрані переноситься лише текст, а колонка
     часу ніколи не ламається і не тягне рядок за межу екрана. */
  display:grid;
  grid-template-columns:auto auto minmax(0,1fr);
  gap:0 .8em;
  align-items:baseline;
  font-family:var(--ff-mono);font-weight:400;
  /* #C3D3CC на --ink-stage = 12.0:1; притухлий стан (opacity .70) = 6.4:1 */
  color:#C3D3CC;
  /* Було clamp(.75rem,1.05vw,.875rem) — 14px на весь екран. 17px читається
     з відстані, з якої дивляться повноекранну сцену. */
  font-size:clamp(.75rem,.55rem + .62vw,1.0625rem);
  letter-spacing:.01em;line-height:1.45;
  /* Той самий прийом, що в .deck-tag: журнал лежить поруч із хмарою
     частинок, і без цієї тіні мono-рядок у неї провалюється.
     Порахований контраст рахується до самого фону сцени — тінь лише
     повертає його там, де поверх фону світять частинки. */
  text-shadow:0 1px 10px rgba(12,20,18,.95),0 0 22px rgba(12,20,18,.8);
  will-change:transform,opacity;
}
/* 07:01 і 07:11 — одна дія у два кроки (знайшов → передав). Пауза між
   рядками означає пройдений час, тому однакова година = щільніше.
   Клас ставить шаблон, порівнюючи години сусідніх записів. */
.flow-item.is-cont{margin-top:calc(var(--flow-step) * -0.6)}
.flow-time{
  /* Тихіше за сам запис, але це не «сірий текст»: #A6B7B0 на --ink-stage
     = 8.9:1, притухлий (opacity .70) = 4.9:1. tabular-nums — щоб колонка
     стояла по цифрах, а не по знаках. */
  color:#A6B7B0;
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;
  letter-spacing:.02em;
}
.flow-mark{
  display:inline-block;
  /* Галочка — це вердикт, і вона тухне менше за текст (×0.85 проти ×0.70
     у main.js): рядок відступає в фон, а сам факт «зроблено» лишається.
     --proof-d на --ink-stage = 8.7:1; притухлий (opacity .85) = 6.6:1 */
  color:var(--proof-d);
  font-weight:500;font-size:1.05em;
  will-change:transform,opacity;
}
/* tier A: рядки веде диригент сцени (applyBeats у main.js) — та сама
   логіка, що .tier-a .cc-beat вище: до старту відкладеного сценарію
   inline-стилю ще нема, і весь журнал майнув би готовим списком.
   tier-b / без JS бачить повний список одразу — контент ніколи не
   залежить від анімації. */

/* Страховка, незалежна від тир-детекту: reduce вже дає tier-b (head.j2),
   але правило нижче гарантує повний список навіть якщо тир колись
   зміниться. !important — бо перекриваємо inline-стиль диригента. */
@media (prefers-reduced-motion:reduce){
  .flow-item,.flow-mark{opacity:1 !important;transform:none !important}
}

.quiet-line{
  font-family:var(--ff-display);font-weight:600;
  font-size:clamp(1.55rem,3.6vw,2.7rem);
  letter-spacing:-0.015em;line-height:1.15;
  color:#F4F6F1;max-width:18em;margin-inline:auto;
  text-wrap:balance;
}
.quiet-cap{
  margin-top:1.5rem;
  font-family:var(--ff-mono);font-size:.75rem;color:#7E8F88;letter-spacing:.03em;
}
/* Раніше display:none за замовчуванням + display:block лише в .tier-a —
   підпис «Час справжній» (власник підтвердив 22:04/03:00 як реальні,
   04.09.2026) ховався саме там, де немає WebGL-сцени, що показує ці часи:
   tier-b, save-data, reduced-motion. Текст той самий скрізь — просто не
   ховаємо. animate on tier-a лишається на .quiet-inner (opacity), яка й
   так ховає дитину до старту сценарію. */

/* poster capture mode */
.posterize .ch,.posterize .nav,.posterize .rail,.posterize .hint,.posterize .grain{visibility:hidden}
.posterize .cursor{display:none !important}

/* ============ light sheet: день ============ */
.sheet{
  position:relative;z-index:7;
  background:var(--paper);
  border-radius:var(--r-sheet) var(--r-sheet) 0 0;
  margin-top:-4rem;
  box-shadow:0 -18px 50px rgba(0,0,0,.35);
}
.tier-a .sheet{margin-top:-16vh}

/* ============ глава 2: білий кадр «кому це допомагає» ============ */
/* Єдиний світлий екран усередині темної сцени. Стоїть другим кадром —
   на «а це про мене?» читач отримує відповідь раніше, ніж на будь-що інше
   (рішення власника 04.09.2026). Кадр мусить поміститись в один екран
   телефона, тому рядки короткі: назва + «біль → рішення» одним рядком. */
.ch-niches{display:flex;align-items:center;justify-content:center;padding:4rem 0}
.tier-a .ch-niches{padding:0}
.niches-frame{
  width:100%;
  background:#FFFFFF;color:var(--text-l);
  /* Зверху — місце під шапку сцени: логотип і адреса лежать поверх глав,
     і без цього відступу заголовок кадру заїжджав просто на них. */
  padding-block:max(4.75rem,9vh) clamp(1.5rem,5vh,3rem);
}
.tier-a .niches-frame{
  position:absolute;inset:0;
  display:flex;align-items:center;
}
/* 04.09.2026: тут стояли opacity:0;visibility:hidden — їх вимикав
   диригент, коли рахував сцену часткою прокрутки. Після переходу на
   дискретні кадри той код зник, а правило лишилось, і білий кадр став
   невидимим назавжди. Прозорістю тепер керує сам кадр (.ch/.ch.is-in),
   і жоден шар усередині нього не має права гасити себе сам. */
.nichesx-h2{
  font-size:clamp(1.35rem,5vw,2.3rem);font-weight:600;
  letter-spacing:-0.015em;line-height:1.12;max-width:16em;
}
.nichesx-intro{
  margin-top:.6rem;max-width:40em;
  color:var(--muted-l);font-size:clamp(.875rem,3.4vw,1.0625rem);line-height:1.45;
}
.nichesx-list{
  list-style:none;margin:clamp(1rem,3vh,2.2rem) 0 0;padding:0;
  display:grid;gap:clamp(.5rem,1.4vh,.9rem);
  grid-template-columns:repeat(3,1fr);
}
/* Плитки, а не рядки: власник 04.09.2026 — «страницу оставить такую же
   как была! квадратиками!». На телефоні шість штук в один екран влазять
   лише двома колонками, тому сітка фіксована, а не auto-fit: auto-fit на
   390px дав би одну колонку і кадр перестав би бути кадром. */
.nichesx-item{
  position:relative;overflow:hidden;
  background:var(--paper);
  border:1px solid #E2E4DB;
  border-radius:var(--r-card);
  padding:clamp(.7rem,1.6vh,1.1rem) clamp(.75rem,1.6vw,1.15rem);
  /* межа кольору плитки їде разом з екраном, інакше на темному макеті
     лишається світла рамка-обідок */
  transition:border-color 200ms ease-out,box-shadow 240ms var(--ease-out);
}
.nichesx-face{display:flex;flex-direction:column;gap:.2rem}
.tier-a .nichesx-item{will-change:transform,opacity}

/* ---- плитка як екран ------------------------------------------------
   Власник 04.09.2026: «хочется еще какой-то визуал прикольный, пусть это
   будут мокапы». Мокап тут не картинка і не окремий пристрій збоку —
   пристрою в кадр не влізе: на iPhone SE під увесь вміст лишається 362 px
   і 77 px запасу. Тому екран живе всередині самої плитки: absolute поверх
   обличчя, тих самих габаритів. Висота кадру не змінюється ні на піксель,
   CLS нуль.

   Що на екрані: сповіщення від бота в темній темі месенджера — крапка,
   ім'я, час 07:11 і той самий рядок, що написаний на обличчі плитки.
   Навколо — порожнє темне поле: другий наскрізний мотив сайту, тиша як
   результат (docs/DESIGN-DIRECTION.md). Це навмисно НЕ картка
   підтвердження з глави 4: там діалог з [Так][Ні] на весь екран, тут —
   один сигнал розміром з плитку. Дві різні речі, два різні силуети.

   Вмикається: прокруткою (прожектор іде плиткою за плиткою, main.js
   NICHE_LIT), мишею — наведенням, пальцем — дотиком. Гасне все разом при
   prefers-reduced-motion: переходи знімаються, текст лишається на місці. */
.nichesx-screen{
  position:absolute;inset:0;z-index:1;
  display:flex;flex-direction:column;
  /* ті самі відступи, що в плитки: назва ніші на екрані стоїть РІВНО там,
     де вона стояла на обличчі, і при вмиканні не зсувається ні на піксель.
     Око тримається за неї — міняється світ навколо, а не текст.
     Знизу відступ менший: на широкій короткій плитці (1280 px — 338×93)
     повний нижній відступ з'їдав 10 px, і сповіщення зрізалось. Міряно,
     не вгадано. Знизу нічого вирівнювати не треба — там смужка «додому». */
  padding:clamp(.7rem,1.6vh,1.1rem) clamp(.75rem,1.6vw,1.15rem)
          clamp(.4rem,.9vh,.6rem);
  background:#080E0C;
  opacity:0;visibility:hidden;
  transition:opacity 200ms ease-out,visibility 0s linear 200ms;
}
/* рядок стану: хто це і котра година. Час один на всі плитки і він
   схвалений — 07:11, той самий ранок, що в журналі доби нижче. */
.nsx-bar{
  display:flex;align-items:baseline;gap:.6em;
  font-family:var(--ff-mono);font-size:clamp(.5625rem,1.5vw,.6875rem);
  letter-spacing:.05em;text-transform:uppercase;line-height:1.3;
  color:#93A9A1;                       /* 8.9:1 на #080E0C */
}
/* Назва переноситься так само, як на обличчі плитки: на 360 px
   «Салон краси, майстер» в один рядок не влазить, і крапки замість
   половини назви ламали б і сенс, і збіг позицій між станами. Час
   тримається за перший рядок (align-items:baseline) і не переноситься. */
.nsx-who{min-width:0}
.nsx-time{
  margin-left:auto;white-space:nowrap;
  font-variant-numeric:tabular-nums;color:#7B918A;
}
/* саме сповіщення */
.nsx-note{
  display:flex;align-items:flex-start;gap:.5em;
  margin-top:.45rem;
  border-radius:10px;
  background:#16231F;
  /* світло, що чіпляється за верхню грань матеріалу: цим екран і
     відрізняється від «плитки, яка просто змінила колір» */
  border-top:1px solid rgba(233,237,231,.10);
  padding:clamp(.4rem,1.1vh,.55rem) clamp(.5rem,1.5vw,.65rem);
  box-shadow:0 6px 18px rgba(0,0,0,.45);
  transform:translateY(7px);opacity:0;
  transition:transform 260ms var(--ease-out) 60ms,opacity 200ms ease-out 60ms;
}
.nsx-dot{
  position:relative;flex:none;margin-top:.42em;
  width:6px;height:6px;border-radius:50%;
  background:var(--primary-d);
}
.nsx-dot::after{
  content:"";position:absolute;inset:-1px;border-radius:50%;
  border:1px solid var(--primary-d);opacity:0;
}
.nsx-body{
  display:block;color:var(--text-d);
  /* Стеля 13 px, а не 15: на широкій плитці (1280 px) рядок «система
     пише, коли час продовжити» при 15 px переходив на другий рядок і
     сповіщення вилазило за плитку на 2 px, з'їдаючи смужку «додому».
     Дрібний кегль тут не помилка, а масштаб: це екран телефона, а не
     основний текст — те саме речення поруч на обличчі плитки стоїть
     повним розміром. */
  font-size:clamp(.6875rem,1.4vw,.8125rem);line-height:1.34;
  text-wrap:pretty;
}
.nsx-check{color:var(--proof-d);font-style:normal;margin-left:.35em}
/* смужка «додому» знизу — три пікселі, після яких темний прямокутник
   читається телефоном, а порожнеча над нею перестає бути порожнечею і
   стає тим, чим вона є: тихим екраном, де за ранок одне повідомлення. */
.nsx-home{
  flex:none;                 /* інакше при тісному вмісті flex стискає її в нуль */
  margin:auto auto 0;width:34%;max-width:56px;height:3px;border-radius:2px;
  background:#2B3B35;
}

/* Увімкнена плитка трохи піднімається над аркушем — не рухом (transform
   на плитці веде такт появи, main.js beat()), а тінню. Другий шар тіні
   ледь тиловий: увімкнений екран підсвічує папір навколо себе. */
.nichesx-item.is-lit{
  border-color:#080E0C;
  box-shadow:0 10px 28px -8px rgba(8,14,12,.45),0 2px 10px rgba(14,107,92,.10);
}
.nichesx-item.is-lit .nichesx-screen{
  opacity:1;visibility:visible;transition:opacity 200ms ease-out;
}
.nichesx-item.is-lit .nsx-note{transform:none;opacity:1}
/* сигнал прийшов: одне коло від крапки, один раз, 700 мс */
.nichesx-item.is-lit .nsx-dot::after{animation:nsxPing 700ms var(--ease-out) 120ms 1 both}
@keyframes nsxPing{
  from{opacity:.7;transform:scale(1)}
  to{opacity:0;transform:scale(3.4)}
}

/* Миша — бонус, не основа: на телефоні наведення не існує, там працює
   прожектор по такту прокрутки і дотик. */
@media (hover:hover) and (pointer:fine){
  .nichesx-item:hover{
    border-color:#080E0C;
    box-shadow:0 10px 28px -8px rgba(8,14,12,.45),0 2px 10px rgba(14,107,92,.10);
  }
  .nichesx-other:hover{border-color:#B9BEB2;box-shadow:none}
  .nichesx-item:hover .nichesx-screen{
    opacity:1;visibility:visible;transition:opacity 160ms ease-out;
  }
  .nichesx-item:hover .nsx-note{transform:none;opacity:1;transition-delay:0ms}
  .nichesx-item:hover .nsx-dot::after{animation:nsxPing 700ms var(--ease-out) 1 both}
}
/* Дотик: плитка мусить відповідати на палець, а не тільки на прокрутку.
   pointer-events всередині сцени вимкнено главам цілком (.tier-a .ch),
   тому список вмикаємо назад точково — заразом оживає й посилання
   «Розповісти про свій випадок», яке в tier-a було недосяжним. */
.tier-a .nichesx-list{pointer-events:auto}

@media (prefers-reduced-motion:reduce){
  .nichesx-item,.nichesx-screen,.nsx-note{transition:none !important}
  .nsx-note{transform:none}
  .nsx-dot::after{animation:none !important}
}
.nichesx-name{
  font-family:var(--ff-mono);font-size:clamp(.5625rem,1.5vw,.6875rem);
  letter-spacing:.05em;text-transform:uppercase;color:var(--muted-l);
  line-height:1.3;
}
.nichesx-pain{
  color:var(--muted-l);
  font-size:clamp(.75rem,1.5vw,.9375rem);line-height:1.3;
}
.nichesx-fix{
  font-size:clamp(.8125rem,1.6vw,1.0625rem);line-height:1.3;
  color:var(--text-l);
}
.nichesx-other{border-style:dashed;background:transparent}
.nichesx-cta{
  margin-top:.3rem;align-self:flex-start;
  font-family:var(--ff-mono);font-size:clamp(.625rem,1.4vw,.8125rem);
  color:var(--primary-l);text-decoration:none;
  border-bottom:1px solid currentColor;
}

/* Низькі екрани (iPhone SE, 568px): кадр мусить лишитись одним екраном,
   інакше він або заповзає під логотип, або зрізається знизу. Міряно
   висотою вмісту, не на око. */
@media (max-width:720px){
  .nichesx-list{grid-template-columns:repeat(2,1fr)}
}
/* Низькі екрани (iPhone SE, 568px): кадр мусить лишитись одним екраном.
   Міряно висотою вмісту, не на око. */
@media (max-height:620px){
  .tier-a .niches-frame{padding-block:4rem .75rem}
  .nichesx-screen{padding:.5rem .55rem}
  .nsx-bar{font-size:.5rem}
  .nsx-note{margin-top:.3rem;padding:.3rem .38rem;border-radius:8px}
  .nsx-body{font-size:.625rem;line-height:1.25}
  .nsx-home{height:2px;width:30%}
  .nichesx-h2{font-size:1.05rem;line-height:1.15}
  .nichesx-intro{font-size:.75rem;line-height:1.3;margin-top:.35rem}
  .nichesx-list{margin-top:.6rem;gap:.35rem}
  /* gap живе на .nichesx-face: сама плитка більше не flex-контейнер
     (усередині неї два шари — обличчя і екран), і gap на ній тихо
     нічого не робив би. Міряно: на iPhone SE це давало кадру зайві
     7.7 px, тобто рівно те, чого кадр не має права собі дозволити. */
  .nichesx-item{padding:.5rem .55rem}
  .nichesx-face{gap:.12rem}
  .nichesx-pain{font-size:.6875rem;line-height:1.25}
  .nichesx-fix{font-size:.75rem;line-height:1.25}
  .nichesx-name{font-size:.5rem}
}

/* Поки білий кадр піднятий, хром сцени мусить стати темним: логотип,
   адреса і рейка світлі, на білому їх просто немає. */
.story.on-light .logo,
.story.on-light .nav-tag{color:var(--text-l)}
.story.on-light .rail span{color:#8A9691}
.story.on-light .rail span.on{color:var(--text-l)}
.story.on-light .rail span::before{background:#B6BEB8}
.story.on-light .cursor i{background:var(--text-l)}
.story.on-light .hint i{background:var(--text-l)}

/* ============ cases ============ */
.cases{padding-block:var(--sp-6) var(--sp-5);border-radius:inherit}
/* Заголовок секції з'явився 04.09.2026: без нього підводка висіла окремим
   абзацом і не читалась як вступ до карток («як будто текст отдельно»).
   Тому ж підпорядкований і розмір: веде h2, підводка стала звичайним
   текстом, а не другим заголовком поруч.

   Другий захід того самого дня: заголовка виявилось мало. Текст усе одно
   читався окремим поверхом, бо стояв НАД списком і був відділений від
   нього порожнечею в цілий екран. Тепер на широкому екрані це дві колонки
   одного блока: підводка ліворуч, приклади праворуч, і підводка їде
   разом зі списком (sticky) — прочитати їх окремо вже неможливо.
   На вузькому — той самий стек, але відстань між текстом і першою
   карткою вдвічі менша. */
.cases-h2{margin-bottom:.9rem;max-width:16em}
.cases-intro{
  font-size:1.0625rem;
  max-width:34em;line-height:1.55;
  color:var(--muted-l);
  margin-bottom:2rem;
}
@media (min-width:1000px){
  .cases .wrap{
    display:grid;
    grid-template-columns:19rem minmax(0,1fr);
    column-gap:3.5rem;
    align-items:start;
  }
  .cases-head{position:sticky;top:6rem}
  .cases-intro{margin-bottom:0}
}
.case-list{display:flex;flex-direction:column;gap:1.1rem}
.case{
  position:relative;
  display:grid;
  grid-template-columns:3.2rem 1fr auto;
  gap:0 1.6rem;
  align-items:start;
  background:var(--card-l);
  border:1px solid var(--line-l);
  border-radius:var(--r-card);
  padding:1.6rem 1.8rem 1.5rem;
  overflow:hidden;
  transition:border-color 200ms ease,box-shadow 250ms ease;
}
.case::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(100deg,rgba(232,163,61,.10),rgba(232,163,61,0) 45%);
  transform:scaleX(0);transform-origin:left center;
  transition:transform 260ms var(--ease-out);
}
.case::after{
  content:attr(data-idx);
  position:absolute;right:.4rem;top:-1.2rem;pointer-events:none;
  font-family:var(--ff-mono);font-weight:500;font-size:7.5rem;line-height:1;
  color:var(--text-l);opacity:.045;
  transition:transform 300ms var(--ease-out),opacity 300ms ease;
}
@media (hover:hover) and (pointer:fine){
  .case:hover{
    border-color:#BFC6BB;
    box-shadow:0 1px 2px rgba(22,33,30,.05),0 10px 30px rgba(22,33,30,.07);
  }
  .case:hover::before{transform:scaleX(1)}
  .case:hover::after{transform:translateX(-6px);opacity:.09}
  .case:hover .case-arrow{transform:translateX(4px);color:var(--primary-l)}
}
.case-idx{
  grid-row:1 / span 3;
  font-family:var(--ff-mono);font-size:.8125rem;color:var(--muted-l);
  padding-top:.35rem;
}
.case-label{display:block;margin-bottom:.45rem}
.case-name{font-size:clamp(1.35rem,2.2vw,1.7rem);font-weight:600;letter-spacing:-0.01em}
.case-name a{color:inherit;text-decoration:none}
.case-name a::after{content:"";position:absolute;inset:0;border-radius:var(--r-card)}
.case-line{margin-top:.55rem;color:var(--muted-l);max-width:44em}

/* Знімок продукту в картці (04.09.2026).
   Порожня права половина картки робила з вітрини список абзаців: чотири
   приклади — і жодного екрана, хоча справжні скріншоти лежать у репозиторії
   і вже стоять на сторінках кейсів.
   Абсолютне позиціювання навмисне: сітка картки (3.2rem 1fr auto) лишається
   недоторканою разом із наведенням, стрілкою і водяним номером. Картка має
   overflow:hidden, тож високий знімок телефона природно обрізається — маска
   гасить нижній край, щоб це читалось як «екран продовжується», а не «фото
   обрубали». */
.case-shot{
  display:none;
  position:absolute;right:1.8rem;top:1.6rem;bottom:0;
  width:9.5rem;
  overflow:hidden;
  border-radius:.75rem .75rem 0 0;
  border:1px solid var(--line-l);border-bottom:0;
  box-shadow:0 2px 6px rgba(22,33,30,.06),0 16px 40px rgba(22,33,30,.10);
  /* Обрізає рамка, а не сам <img>: object-fit:cover на абсолютному
     зображенні з заданими top і bottom масштабував знімок у кілька разів —
     видно було два слова з екрана замість екрана. Рамка тримає ширину,
     картинка лишається у своїх пропорціях, а зайве ховає overflow.
     Маска рахується від видимої смуги, тому нижній край згасає, а не
     обрубується. */
  -webkit-mask-image:linear-gradient(to bottom,#000 58%,transparent);
  mask-image:linear-gradient(to bottom,#000 58%,transparent);
  transition:transform 300ms var(--ease-out);
}
.case-shot img{display:block;width:100%;height:auto}
@media (min-width:900px){
  .case-shot{display:block}
  /* місце під знімок + стрілку, інакше рядок опису заповзе під картинку */
  .case{padding-right:13.5rem;min-height:14.5rem}
  .case-arrow{position:relative;z-index:1}
  /* Водяний номер і знімок билися за той самий кут. У картки має бути один
     зоровий якір; номер лишається зліва в колонці .case-idx, а великий —
     тільки там, де знімка немає (телефон). */
  .case::after{display:none}
}
/* Стоїть саме тут, а не поруч із сіткою двох колонок вище: специфічність
   однакова, тож виграє те правило, що нижче у файлі. У першій редакції
   ці два рядки лежали ДО базових .case/.case-shot і не робили нічого —
   спіймав тест, який шукав рамку і знайшов цей огризок. */
@media (min-width:1000px){
  /* у двох колонках картка вужча — знімку і стрілці треба менше місця */
  .case{padding-right:12rem}
  .case-shot{width:8.5rem}
}
@media (hover:hover) and (pointer:fine){
  .case:hover .case-shot{transform:translateY(-4px)}
}
@media (prefers-reduced-motion:reduce){
  .case-shot{transition:none}
  .case:hover .case-shot{transform:none}
}
.case-foot{
  grid-column:2;
  display:flex;flex-wrap:wrap;align-items:center;gap:1.4rem;
  margin-top:1rem;
}
.case-price{font-family:var(--ff-mono);font-size:.875rem;color:var(--text-l)}
.case-status{
  display:inline-flex;align-items:center;gap:.45em;
  font-family:var(--ff-mono);font-size:.75rem;letter-spacing:.02em;
  color:var(--proof-l);
}
.case-status .dot{position:relative;width:7px;height:7px;border-radius:50%;background:var(--proof-l)}
/* живая точка (В4): пульсирующее кольцо, только transform/opacity —
   reduced-motion выключает анимацию, точка остаётся статичной */
.case-status .dot::after{
  content:"";position:absolute;inset:0;border-radius:50%;
  border:1px solid var(--proof-l);
  animation:statusPulse 2s var(--ease-out) infinite;
}
@keyframes statusPulse{
  0%{transform:scale(1);opacity:.7}
  100%{transform:scale(1.8);opacity:0}
}
@media (prefers-reduced-motion:reduce){.case-status .dot::after{animation:none;display:none}}
.case-arrow{
  grid-row:1;grid-column:3;
  font-family:var(--ff-display);font-size:1.3rem;color:var(--muted-l);
  transition:transform 200ms var(--ease-out),color 200ms ease;
  padding-top:.2rem;position:relative;
  /* Тестерський аудит 03.09.2026, BUG-005: декоративна стрілка (aria-hidden
     у services.j2) лежить у тому самому стековому контексті, що й
     .case-name a::after (розтягнуте посилання картки), і — будучи
     position:relative, пізніше в DOM — перехоплювала клік замість нього.
     pointer-events:none пропускає клік наскрізь до посилання; ::before
     transform на :hover (нижче) далі працює, бо hover рахується від .case,
     не від самої стрілки. */
  pointer-events:none;
}

/* ============ manifest ============ */
.manifest{padding-block:var(--sp-6)}
.manifest h2,
.cases-h2,
.school h2,
.who h2,
.price h2{
  font-size:clamp(1.7rem,3.2vw,2.5rem);
  font-weight:600;letter-spacing:-0.015em;
}
.manifest h2{margin-bottom:var(--sp-5)}
.manifest-items{display:flex;flex-direction:column;gap:2.6rem;max-width:46rem}
.manifest-item{
  font-family:var(--ff-display);
  font-size:clamp(1.2rem,2vw,1.6rem);
  font-weight:500;line-height:1.42;
  color:var(--text-l);
  text-wrap:pretty;
}
.manifest-item strong{font-weight:600;color:var(--primary-l)}
.manifest-item .w{opacity:.14;display:inline-block;will-change:opacity}
html:not(.has-motion) .manifest-item .w{opacity:1}

/* ============ numbers: тёмная плита ============ */
.numbers{padding-block:var(--sp-5) var(--sp-6)}
.plate{
  position:relative;overflow:hidden;
  background:
    radial-gradient(60rem 30rem at 90% -30%,rgba(79,200,180,0.09),transparent 60%),
    var(--ink-stage);
  color:var(--text-d);
  border-radius:var(--r-sheet);
  padding:clamp(2rem,4.5vw,3.8rem);
}
.numbers-intro{color:var(--muted-d);max-width:40em;margin-bottom:var(--sp-4);position:relative;z-index:2}
.num-row{
  position:relative;z-index:2;
  display:grid;grid-template-columns:repeat(4,1fr);
  gap:2rem;
}
.num-item{border-left:1px solid var(--line-d);padding-left:1.4rem}
.num-item:first-child{border-left:0;padding-left:0}
.num-val{
  font-family:var(--ff-mono);font-weight:500;
  font-size:clamp(2.1rem,4.5vw,3.4rem);
  letter-spacing:-0.02em;line-height:1.1;
  font-variant-numeric:tabular-nums;
  color:#F4F6F1;
}
/* Перегортання цифр (07.09.2026). Кожен символ — вікно висотою в рядок,
   усередині стовпчик із двох гліфів; зсув на 50% і є переворот. Стовпчик
   зсувається, а не сам символ: так старий гліф іде вгору за край вікна, а
   новий приходить знизу — рух читається як механічний лічильник, а не як
   підміна тексту.

   Затримка на кожен символ ставиться з JS (--flap-delay): без неї всі
   розряди перевертаються разом і виходить блимання, а не перегортання.

   Ширина не фіксована: моноширинний шрифт плити і так тримає розряди, а
   жорстка ширина зламала б «07:11» і «1 500+», де символи різні. */
.num-flap{display:inline-block;overflow:hidden;height:1.1em;vertical-align:bottom}
.num-flap-col{
  display:block;
  transform:translateY(0);
  transition:transform 420ms cubic-bezier(.2,.7,.2,1);
  transition-delay:var(--flap-delay,0ms);
}
.num-flap.is-turning .num-flap-col{transform:translateY(-50%)}
.num-flap-col > span{display:block;height:1.1em;line-height:1.1}

/* Підпис міняється разом із цифрою, але не перевертається: слова так
   читати незручно. Простий перехід прозорістю, трохи повільніше за цифру —
   око встигає спершу побачити нове число, потім прочитати, що воно. */
.num-label{transition:opacity 260ms ease}
.num-item.is-turning .num-label{opacity:0}

@media (prefers-reduced-motion:reduce){
  .num-flap-col{transition:none}
  .num-label{transition:none}
}

.num-label{margin-top:.5rem;color:var(--muted-d);font-size:.9375rem;line-height:1.45;max-width:16em}
.numbers-caption{
  position:relative;z-index:2;
  margin-top:var(--sp-4);
  font-family:var(--ff-mono);font-size:.75rem;color:var(--muted-d);letter-spacing:.02em;
}

/* ============ school loop teaser ============ */
.school{background:var(--paper-tint);padding-block:var(--sp-6)}
.school h2{max-width:20em;margin-bottom:1.4rem}
.school-text{max-width:44em;color:var(--text-l);font-size:1.1rem;margin-bottom:2rem}
.school-cta{
  display:inline-flex;align-items:center;gap:.5em;
  font-family:var(--ff-display);font-weight:600;
  color:var(--primary-l);text-decoration:none;
  border-bottom:2px solid currentColor;padding-bottom:2px;
}
@media (hover:hover) and (pointer:fine){
  .school-cta:hover{color:#0A5548}
}

/* ============ who ============ */
.who{padding-block:var(--sp-6)}
.who-grid{
  display:grid;grid-template-columns:1fr minmax(14rem,19rem);
  gap:clamp(2rem,5vw,4.5rem);align-items:start;
}
/* Фото — друга колонка, текст — перша: погляд на знімку йде вліво, отже
   веде в текст. У DOM фото лишається першим (на мобільному воно зверху). */
.who-photo{grid-column:2;grid-row:1}
.who-grid > div:not(.who-photo){grid-column:1;grid-row:1}
.who-photo{
  aspect-ratio:4/5;
  border-radius:var(--r-card);
  overflow:hidden;
  background:linear-gradient(160deg,#DCDFD8,#C9CEC5);
}
.who-photo img{width:100%;height:100%;object-fit:cover;display:block}
.who h2{margin-bottom:1.4rem}
.who-text{max-width:40em;font-size:1.1rem}
.who-line{
  margin-top:1.6rem;
  font-family:var(--ff-display);font-weight:600;font-size:1.1rem;
  color:var(--primary-l);
}

/* ============ price + faq ============ */
.price{padding-block:var(--sp-6) calc(var(--sp-6) + 2rem);border-top:1px solid var(--line-l)}
.price h2{margin-bottom:1.2rem}
.price-intro{max-width:42em;color:var(--muted-l);margin-bottom:var(--sp-4)}
.price-factors{
  display:grid;grid-template-columns:repeat(3,1fr);gap:2.5rem;
  padding:0;margin:0 0 var(--sp-4);list-style:none;
}
.price-factors li{border-top:2px solid var(--text-l);padding-top:1.1rem}
.price-factors strong{
  display:block;font-family:var(--ff-display);font-weight:600;font-size:1.15rem;
  margin-bottom:.5rem;
}
.price-factors p{color:var(--muted-l);font-size:1rem}
.price-outro{max-width:42em;font-size:1.05rem}

.faq{margin-top:var(--sp-5);max-width:46rem}
.faq details{border-top:1px solid var(--line-l)}
.faq details:last-child{border-bottom:1px solid var(--line-l)}
.faq summary{
  cursor:pointer;list-style:none;
  display:flex;align-items:baseline;justify-content:space-between;gap:1.5rem;
  padding:1.15rem 0;
  font-family:var(--ff-display);font-weight:600;font-size:1.05rem;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{
  content:"+";font-family:var(--ff-mono);font-weight:400;color:var(--muted-l);
  transition:transform 200ms var(--ease-out);flex-shrink:0;
}
.faq details[open] summary::after{transform:rotate(45deg)}
.faq .faq-a{padding:0 0 1.3rem;color:var(--muted-l);max-width:56em}

/* ============ form: снова вечер ============ */
.contact{
  position:relative;overflow:hidden;z-index:8;
  background:
    radial-gradient(70rem 40rem at 15% 115%,rgba(79,200,180,0.07),transparent 60%),
    var(--ink-stage);
  color:var(--text-d);
  padding-block:var(--sp-6);
  border-radius:var(--r-sheet) var(--r-sheet) 0 0;
  margin-top:-2rem;
}
.contact h2{
  font-size:clamp(1.8rem,3.4vw,2.6rem);font-weight:600;letter-spacing:-0.015em;
  color:#F4F6F1;margin-bottom:1rem;text-align:center;
}
.contact-intro{
  color:var(--muted-d);max-width:34em;margin:0 auto 3rem;text-align:center;
}
.card-form{
  position:relative;z-index:2;
  max-width:33rem;margin-inline:auto;
  background:var(--card-d);
  border:1px solid var(--line-d);
  border-radius:var(--r-card);
  padding:2rem clamp(1.25rem,4vw,2.2rem) 1.8rem;
  box-shadow:0 1px 2px rgba(0,0,0,.3),0 16px 48px rgba(0,0,0,.4);
}
.field{margin-bottom:1.3rem}
.field label{
  display:block;margin-bottom:.45rem;
  font-family:var(--ff-mono);font-size:.75rem;letter-spacing:.05em;
  color:var(--muted-d);
}
.field input,.field textarea{
  width:100%;
  background:#0F1916;
  border:1px solid #2A3833;
  border-radius:8px;
  color:var(--text-d);
  font-family:var(--ff-text);font-size:1rem;line-height:1.5;
  padding:.75rem .9rem;
  transition:border-color 160ms ease;
}
.field textarea{min-height:7.5rem;resize:vertical}
.field input:focus-visible,.field textarea:focus-visible{
  outline:2px solid var(--primary-d);outline-offset:0;border-color:var(--primary-d);
}
.form-actions{display:flex;flex-direction:column;gap:.9rem;margin-top:1.8rem}
.btn-submit{width:100%;justify-content:center;font-size:1.05rem}
.btn-submit[disabled]{opacity:.6;cursor:not-allowed}
.form-note{
  margin:1rem 0 0;text-align:center;font-size:.875rem;
  font-family:var(--ff-text);
}
.form-note[data-state="error"]{color:var(--stop-d)}
.form-note[data-state="ok"]{color:var(--proof-d)}
.alt-cta{
  text-align:center;
  color:var(--primary-d);text-decoration:none;
  font-family:var(--ff-display);font-weight:500;font-size:.95rem;
  padding:.6em;border-radius:var(--r-btn);
}
@media (hover:hover) and (pointer:fine){
  .alt-cta:hover{text-decoration:underline}
}
.privacy-line{
  margin-top:1.4rem;text-align:center;
  font-size:.8125rem;color:var(--muted-d);
}
.privacy-line a{color:var(--muted-d)}

/* ============ footer ============ */
.footer{
  background:var(--ink-stage);color:var(--muted-d);
  border-top:1px solid var(--line-d);
  padding-block:2.2rem;
}
/* Кейси + школа + /test/ (SEO-audit HIGH п.5, 03.09.2026) — над
   .footer-row, трохи світліший текст (--text-d, не --muted-d), бо це
   навігація, а не службова строка з доменом/копірайтом нижче. */
.footer-links{
  display:flex;flex-wrap:wrap;gap:.5em 1.4em;
  margin-bottom:1.3rem;padding-bottom:1.3rem;
  border-bottom:1px solid var(--line-d);
  font-family:var(--ff-mono);font-size:.8125rem;
}
.footer-links a{color:var(--text-d)}
@media (hover:hover) and (pointer:fine){
  .footer-links a:hover{color:var(--primary-d)}
}
.footer-row{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:.6em 1.6em;
  font-family:var(--ff-mono);font-size:.8125rem;
}
.footer a{color:var(--muted-d)}
.footer-contacts{margin-bottom:.9rem;color:var(--text-d)}
.footer-contacts a{color:var(--text-d)}
.footer-contacts-label{color:var(--muted-d)}
.footer-contacts-note{color:var(--muted-d)}

.footer-brand{font-family:var(--ff-display);font-weight:700;font-size:1rem;color:var(--text-d)}
.footer-line{margin-top:1rem;font-size:.8125rem;font-family:var(--ff-mono);color:#7E8F88}

/* ============ consent banner (задача C, вне мока) ============ */
/* Компактная плашка: короткий текст в одну-дві строки + кнопки в ряд.
   На мобильном герой-CTA лежит по центру вьюпорта (min-height:100vh,
   justify-content:center) — плашка обязана оставаться низкой (measured
   ~70-90px), иначе перекрывает CTA на коротких экранах (найдено скриншотом
   360/390, см. docs/REVIEW-PACKAGE §5.4 про измерение, не "на глаз"). */
@media (hover:hover) and (pointer:fine){
  .btn-consent-deny:hover{border-color:var(--muted-d);color:var(--text-d)}
}
@media (max-width:23rem){
  .consent-text{flex-basis:100%}
  .consent-actions{flex-basis:100%;justify-content:flex-end}
}

/* ============ responsive ============ */
@media (max-width:64rem){
  .num-row{grid-template-columns:repeat(2,1fr);gap:2.5rem 2rem}
  .num-item:nth-child(3){border-left:0;padding-left:0}
  .price-factors{grid-template-columns:1fr;gap:1.8rem}
  /* Одна колонка: фото на всю її ширину, а не вужче з дірою праворуч.
     Центрувати не можна — заголовок і текст ліворуч, і третє вирівнювання
     читалося б як недбалість. Один лівий край на весь блок.
     Скарга власника 04.09.2026 (телефон) + знахідка QA про 768px, де фото
     лишалося вузьким ліворуч, а праворуч зяяла порожнеча. */
  .who-grid{grid-template-columns:1fr;gap:1.75rem}
  .who-photo,.who-grid > div:not(.who-photo){grid-column:1;grid-row:auto}
  .who-photo{max-width:none}
}
@media (max-width:40rem){
  .hero-cta{flex-direction:column}
  .hero-cta .btn{width:100%;justify-content:center}
  .case{grid-template-columns:1fr;padding:1.3rem 1.25rem 1.25rem}
  .case-idx{grid-row:auto;padding-top:0;margin-bottom:.6rem}
  .case-foot{grid-column:1}
  .case-arrow{display:none}
  .case::after{font-size:5.5rem;top:-.9rem}
  .num-row{grid-template-columns:1fr 1fr;gap:2rem 1.2rem}
  .num-item{border-left:0;padding-left:0}
  .sheet{margin-top:-2.5rem}
  .tier-a .sheet{margin-top:-10vh}
}

/* ============ reduced motion ============ */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:.01ms !important;animation-duration:.01ms !important}
}


/* Прямой контакт из блока «хто за цим стоїть»: строка «відповідаю я, не
   менеджер» — самое доверительное место на странице, поэтому она же и есть
   вход в личный диалог. Подчёркивание растёт из-под текста, а не появляется. */
.who-link{
  color:inherit;text-decoration:none;
  background-image:linear-gradient(var(--signal-l),var(--signal-l));
  background-repeat:no-repeat;background-position:0 100%;background-size:0 1.5px;
  transition:background-size 220ms var(--ease-out),color 220ms var(--ease-out);
}
@media (hover:hover) and (pointer:fine){
  .who-link:hover{background-size:100% 1.5px;color:var(--signal-l)}
}
.who-link:focus-visible{outline:2px solid var(--signal-l);outline-offset:3px;border-radius:2px}
@media (prefers-reduced-motion:reduce){.who-link{transition:none}}

/* Быстрый выбор рутины: снимает трение «страшно писать сочинение», но не
   отменяет само поле — из пустой заявки схему не составить.
   .routine-chip, не .chip: QA-аудит 03.09.2026 знайшов колізію двох
   однакових за вагою селекторів `.chip` (тут і в картках сцени вище,
   .choices .chip) — форма успадковувала звідти `flex:1 1 0;min-width:0`,
   і пʼять чипів стискались в один ряд на 375px, текст налазив один на
   одного. Компоненти розведено окремими класами замість перевизначення. */
.chips{display:flex;flex-wrap:wrap;gap:.5rem;margin:0 0 .6rem}
.routine-chip{
  font:inherit;font-size:.86rem;line-height:1;
  padding:.55rem .85rem;border-radius:999px;cursor:pointer;
  color:var(--text-d-2);background:transparent;
  border:1px solid var(--line-d);
  transition:transform 140ms var(--ease-out),border-color 180ms var(--ease-out),color 180ms var(--ease-out);
}
@media (hover:hover) and (pointer:fine){
  .routine-chip:hover{border-color:var(--signal-d);color:var(--text-d)}
}
.routine-chip:active{transform:scale(.97)}
.routine-chip[aria-pressed="true"]{border-color:var(--signal-d);color:var(--signal-d)}
.routine-chip:focus-visible{outline:2px solid var(--signal-d);outline-offset:2px}
@media (prefers-reduced-motion:reduce){.routine-chip{transition:none}}

/* =======================================================================
   Сторінки кейсів (docs/REVIEW-PACKAGE.md §V4, день 4): статичний
   темний hero (без WebGL-сцени головної) + спліт-екран текст/мокап +
   ЦИФРИ (перевикористовує .numbers/.plate/.num-row з головної) + оффер.
   Видимість керується IntersectionObserver у case.js, не ScrollTrigger —
   тому "прихований до реveal" стан тут заданий інлайново через
   .cs-reveal, а не через .has-motion (main.js на цих сторінках не
   підключений, отже клас .has-motion ніколи не з'явиться).
   ======================================================================= */

.cs-header{position:relative;background:var(--ink-stage)}
.cs-header .nav{position:static;padding:1.4rem clamp(1.25rem,4vw,3rem);pointer-events:auto}

.cs-breadcrumb{
  position:relative;z-index:2;
  font-family:var(--ff-mono);font-size:.75rem;letter-spacing:.03em;
  color:#7E8F88;
  padding:0 clamp(1.25rem,4vw,3rem) 1.6rem;
  max-width:74rem;margin-inline:auto;
  display:flex;gap:.5em;align-items:center;
}
.cs-breadcrumb a{color:var(--muted-d);text-decoration:none}
@media (hover:hover) and (pointer:fine){.cs-breadcrumb a:hover{color:var(--text-d)}}
.cs-breadcrumb [aria-current]{color:var(--muted-d)}

.cs-hero{
  position:relative;overflow:hidden;
  background:
    radial-gradient(70rem 40rem at 85% -20%,rgba(79,200,180,0.08),transparent 60%),
    var(--ink-stage);
  color:var(--text-d);
  padding-bottom:clamp(3rem,7vw,5rem);
  border-radius:0 0 var(--r-sheet) var(--r-sheet);
}
.cs-hero .wrap{position:relative;z-index:2}
/* Перехід на сторінку продукту в шапці кейса (07.09.2026).
   Навмисно НЕ кнопка: головна дія кейса — прочитати його, а це бічний
   вихід для того, хто вже зрозумів, що йому потрібен сам продукт.
   Кнопка тут перетягнула б увагу з h1. Підкреслення робить посилання
   впізнаваним без ваги кнопки. */
.cs-hero-product{margin-top:1.2rem}
.cs-hero-product a{
  color:var(--signal-d);text-decoration:none;
  border-bottom:1px solid currentColor;
  font-size:1.0625rem;
}
.cs-hero-product a:focus-visible{outline:2px solid var(--signal-d);outline-offset:3px;border-radius:2px}

.cs-status{
  display:inline-flex;align-items:center;gap:.5em;
  margin-bottom:1.1rem;
  font-family:var(--ff-mono);font-size:.75rem;letter-spacing:.03em;
  color:var(--proof-d);
}
.cs-status .dot{position:relative;width:7px;height:7px;border-radius:50%;background:var(--proof-d)}
.cs-status .dot::after{
  content:"";position:absolute;inset:0;border-radius:50%;
  border:1px solid var(--proof-d);
  animation:statusPulse 2s var(--ease-out) infinite;
}
@media (prefers-reduced-motion:reduce){.cs-status .dot::after{animation:none;display:none}}
.cs-hero h1{
  font-family:var(--ff-display);font-weight:600;
  font-size:clamp(2.2rem,4.6vw,3.8rem);
  letter-spacing:-0.02em;line-height:1.08;
  color:#F4F6F1;max-width:17em;margin:0 0 1.3rem;
  text-wrap:balance;
}

/* =========== спліт-блоки: текст ліворуч, мокап праворуч =========== */
.cs-sections{background:var(--paper);position:relative;z-index:2;padding-block:var(--sp-5)}
.cs-block{
  padding-block:var(--sp-5);
  border-top:1px solid var(--line-l);
}
.cs-block:first-child{border-top:0;padding-top:0}
.cs-split{
  display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(2.5rem,6vw,5rem);align-items:center;
}
.cs-block-heading{
  font-family:var(--ff-display);font-weight:600;
  font-size:clamp(1.3rem,2.2vw,1.7rem);
  letter-spacing:-0.01em;margin-bottom:.7rem;
}
.cs-block-quote{
  font-family:var(--ff-display);font-style:italic;font-weight:500;
  color:var(--primary-l);margin-bottom:.7rem;max-width:34em;
}
.cs-block-body{max-width:38em;color:var(--muted-l);font-size:1.05rem;line-height:1.62}
.cs-text-block{max-width:52em}

/* Перевернутий спліт: телефон ліворуч. Без медіазапиту навмисно — на
   вузькому екрані нижче ВСІ знімки й так стоять зверху (order:-1), тож тут
   правило нічого не міняє, а на широкому ставить знімок у ліву колонку. */
.cs-split--flip .cs-split-media{order:-1}

@media (max-width:56rem){
  .cs-split{grid-template-columns:1fr;gap:2.2rem}
  .cs-split-media{order:-1}
}

/* =========== рамка пристрою — CSS, не запечена в картинку =========== */
.device-frame{width:min(100%,18.5rem);margin-inline:auto}
.device-iphone .device-shell{
  position:relative;
  background:#0B0B0D;
  border-radius:2.5rem;
  padding:.5rem;
  box-shadow:var(--shadow);
}
.device-iphone .device-shell::before{
  content:"";position:absolute;top:.55rem;left:50%;
  transform:translateX(-50%);
  width:34%;height:1.05rem;
  background:#0B0B0D;border-radius:0 0 .8rem .8rem;
  z-index:2;
}
.device-desktop .device-shell{
  background:#1B1F1E;
  border-radius:.9rem .9rem 0 0;
  padding:.5rem .5rem 0;
  box-shadow:var(--shadow);
}
.device-desktop .device-shell::before{
  content:"";display:block;height:1.4rem;
  background:
    radial-gradient(circle 4px at 12px 7px,#E48174 0 100%,transparent 101%),
    radial-gradient(circle 4px at 28px 7px,#E8A33D 0 100%,transparent 101%),
    radial-gradient(circle 4px at 44px 7px,#77C186 0 100%,transparent 101%);
}
.device-screen{
  position:relative;overflow:hidden;
  aspect-ratio:390/844;
  border-radius:2rem;
  background:
    radial-gradient(60% 60% at 50% 0%,rgba(79,200,180,.10),transparent 60%),
    var(--ink-stage);
}
.device-desktop .device-screen{aspect-ratio:16/11;border-radius:0 0 .5rem .5rem}
.device-screen img{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block;
}
.cs-mockup-caption{
  margin-top:.75rem;text-align:center;
  font-family:var(--ff-text);font-style:italic;
  font-size:.8125rem;color:var(--muted-l);
}

/* =========== списки/FAQ full-width під спліт-блоками =========== */
.cs-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.9rem;max-width:52em}
.cs-list li{position:relative;padding-left:1.4rem;color:var(--text-l);line-height:1.55}
/* Список на темній панелі: .cs-list li фарбується токеном світлої теми
   (--text-l), і на .on-dark пункти зливаються з фоном — на сторінці
   помічника «Два способи» їх було майже не видно (07.09.2026). Правило
   загальне, а не для однієї сторінки: будь-який список на темному тлі
   мусить читатись. */
.on-dark .cs-list li{color:var(--text-d)}
.on-dark .cs-list li b{color:var(--text-d)}
.cs-offer .cs-list{margin-bottom:1.2rem}
.cs-list li::before{
  content:"";position:absolute;left:0;top:.6em;
  width:7px;height:7px;border-radius:50%;background:var(--primary-l);
}
.cs-block .faq{margin-top:1.2rem;max-width:52rem}

/* =========== цифри — той самий компонент, що на головній =========== */
.cs-numbers-wrap{padding-block:var(--sp-4) var(--sp-6)}

/* =========== оффер: знову темна картка =========== */
.cs-offer{
  position:relative;overflow:hidden;
  background:
    radial-gradient(60rem 34rem at 12% 110%,rgba(79,200,180,0.08),transparent 60%),
    var(--ink-stage);
  color:var(--text-d);
  border-radius:var(--r-sheet);
  padding:clamp(2.2rem,5vw,3.6rem);
  margin-bottom:var(--sp-6);
}
.cs-offer-label{margin-bottom:.6rem}
.cs-offer-price{
  font-family:var(--ff-mono);font-weight:500;
  font-size:clamp(1.9rem,4vw,2.7rem);
  color:var(--signal-d);letter-spacing:-0.01em;
  margin-bottom:1rem;
}
/* Ціна способу в блоці «Два способи» (сторінка помічника). Моно й янтарний —
   як великі ціни в оффері, тільки в рядок: тут ціна не заголовок блоку, а
   уточнення до способу. nowrap, щоб «від €180 під ключ» не ламалось навпіл. */
.take-price{
  font-family:var(--ff-mono);font-weight:600;
  color:var(--signal-d);white-space:nowrap;
}

/* Дві ціни (підписка і під ключ) — кожна своїм рядком і НЕ рветься всередині.
   Перша редакція лишала розмір 1.9–2.7rem: на 390px «від €180 під ключ» не
   влазив, і «ключ» падав окремим третім рядком — знімок 13.09.2026. Розмір
   тепер іде від ширини екрана і впирається в той самий верх 2.7rem, тож на
   десктопі нічого не міняється. Правило чіпляється за span — вони є лише там,
   де цін дві, тому оффер з однією ціною лишається як був. */
.cs-offer-price span{display:block;white-space:nowrap;font-size:clamp(1.25rem,5.8vw,2.7rem)}
.cs-offer-text{max-width:44em;color:var(--muted-d);margin-bottom:1.9rem;font-size:1.05rem}
.cs-offer-actions{display:flex;flex-wrap:wrap;gap:1rem}

/* =========== reveal (IntersectionObserver, case.js) ===========
   Прогресивне посилення, як .has-motion [data-reveal] на головній: за
   замовчуванням .cs-reveal нічим не прихований (safe default — якщо
   case.js не виконався, весь текст все одно видно). Приховати й потім
   плавно показати можна лише під класом .js-reveal, який сам case.js
   додає синхронно на <html> одразу при старті. */
.js-reveal .cs-reveal{opacity:0;transform:translateY(24px);transition:opacity 700ms var(--ease-out),transform 700ms var(--ease-out)}
.js-reveal .cs-reveal.is-in{opacity:1;transform:translateY(0)}
@media (prefers-reduced-motion:reduce){
  .js-reveal .cs-reveal{opacity:1;transform:none;transition:none}
}

@media (max-width:40rem){
  .cs-hero{padding-bottom:2.4rem}
  .cs-offer-actions{flex-direction:column}
  .cs-offer-actions .btn,.cs-offer-actions .alt-cta{width:100%;justify-content:center;text-align:center}
}

/* =======================================================================
   /test/ + /bot/: демо-модуль (docs/REVIEW-PACKAGE.md задача дня 5).
   Кожен блок несе ДВІ версії розмітки: .demo-static (звичайний список,
   видимий за замовчуванням — і при вимкненому JS, і поки JS ще не
   доробив) і .demo-interactive (порожній контейнер, demo.js наповнює й
   показує лише ПІСЛЯ успішної збірки — клас .js-demo ставиться post-factum,
   не заздалегідь). Це навмисно суворіше за .js-reveal у case.js: там ціна
   помилки — недоречна анімація, тут — зниклий контент.
   ======================================================================= */
.js-demo .demo-static{display:none}
/* ID-селектори, не .demo-interactive: .demo-chat/.demo-ex-grid нижче в
   цьому файлі самі оголошують display:flex/grid з тією самою
   специфічністю (0,1,0), і чия заявка виграє залежало б від порядку
   оголошення — той самий клас багів, що вже ловили на typography (head.j2
   коментар). ID б'є будь-який клас незалежно від порядку. */
#demoChat,#demoExercises{display:none}
.js-demo #demoChat{display:flex}
.js-demo #demoExercises{display:grid}

.demo-block{padding-block:var(--sp-5);border-top:1px solid var(--line-l)}
.demo-block:first-of-type{border-top:0}
.demo-block-title{
  font-family:var(--ff-display);font-weight:600;
  font-size:clamp(1.4rem,2.4vw,1.9rem);
  letter-spacing:-0.01em;margin-bottom:1.4rem;
}

/* — статичний фолбек: діалог — */
.demo-chat-static{max-width:34rem}
.demo-msg-static-time{margin:1.1rem 0 .2rem;font-family:var(--ff-mono);font-size:.75rem;color:var(--muted-l)}
.demo-msg-static-time:first-child{margin-top:0}
.demo-msg-static-text{margin:0 0 .4rem;font-size:1.02rem;line-height:1.5}
.demo-choices-static{margin:0 0 .6rem;padding-left:1.2rem;color:var(--muted-l)}
.demo-choices-static li.is-correct{color:var(--primary-l);font-weight:600}

/* — статичний фолбек: вправи — */
.demo-ex-list-static{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:1.6rem}
.demo-ex-static-prompt{font-family:var(--ff-mono);font-size:.75rem;letter-spacing:.04em;color:var(--muted-l);margin-bottom:.3rem}
.demo-ex-static-main{font-family:var(--ff-display);font-weight:600;font-size:1.15rem;margin-bottom:.5rem}
.demo-done{margin-top:2rem;padding-top:1.4rem;border-top:1px solid var(--line-l)}
.demo-done-title{font-family:var(--ff-display);font-weight:600;font-size:1.15rem;margin-bottom:.4rem}
.demo-done-text{color:var(--muted-l);max-width:38em}
.demo-ex-grid .demo-done{grid-column:1/-1;margin-top:.5rem;border-top:1px solid var(--line-l)}

/* — телефон-панель діалогу (інтерактив) — */
.demo-phone{
  position:relative;max-width:26rem;margin-inline:auto;
  background:var(--ink-stage);color:var(--text-d);
  border-radius:var(--r-card);border:1px solid var(--line-d);
  box-shadow:var(--shadow);overflow:hidden;
}
.demo-phone-head{
  display:flex;align-items:center;gap:.7rem;
  padding:.9rem 1.1rem;border-bottom:1px solid var(--line-d);
  background:#0F1916;
}
.demo-phone-avatar{
  display:flex;align-items:center;justify-content:center;flex:none;
  width:2.2rem;height:2.2rem;border-radius:50%;
  background:var(--primary-d);color:var(--ink-stage);
  font-family:var(--ff-display);font-weight:700;
}
.demo-phone-meta{display:flex;flex-direction:column;line-height:1.25}
.demo-phone-name{font-family:var(--ff-display);font-weight:600;font-size:.95rem}
.demo-phone-tag{font-family:var(--ff-mono);font-size:.6875rem;color:var(--muted-d)}

.demo-chat{padding:1.1rem 1.1rem 1.3rem;display:flex;flex-direction:column;gap:.7rem;min-height:14rem}
.demo-msg{display:flex;flex-direction:column;align-items:flex-start;max-width:88%;animation:demoIn 260ms var(--ease-out)}
@keyframes demoIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
@media (prefers-reduced-motion:reduce){.demo-msg{animation:none}}
.demo-msg-time{font-family:var(--ff-mono);font-size:.6875rem;color:#7E8F88;margin:0 0 .25rem}
.demo-bubble{
  background:#0F1916;border:1px solid var(--line-d);border-radius:var(--r-bubble);
  border-bottom-left-radius:4px;padding:.7rem .9rem;font-size:.9375rem;line-height:1.5;
}
.demo-choice-row{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.55rem}
.demo-choice-btn{
  font:inherit;font-family:var(--ff-display);font-weight:600;font-size:.875rem;
  padding:.5rem .85rem;border-radius:8px;cursor:pointer;
  color:var(--text-d);background:transparent;border:1px solid #3A4A44;
  transition:background-color 160ms ease,border-color 160ms ease,opacity 160ms ease;
}
@media (hover:hover) and (pointer:fine){
  .demo-choice-btn:not([disabled]):hover{border-color:var(--primary-d)}
}
.demo-choice-btn:focus-visible{outline:2px solid var(--primary-d);outline-offset:2px}
.demo-choice-btn[disabled]{cursor:default}
.demo-choice-btn.is-chosen.is-correct{background:var(--primary-d);border-color:var(--primary-d);color:var(--ink-stage)}
.demo-choice-btn.is-chosen.is-wrong{border-color:var(--stop-d);color:var(--stop-d)}
.demo-choice-btn[disabled]:not(.is-chosen){opacity:.4}

.demo-typing{display:flex;gap:.28rem;padding:.55rem 0 .2rem .2rem}
.demo-typing span{width:6px;height:6px;border-radius:50%;background:var(--muted-d);animation:demoBounce 1.1s ease-in-out infinite}
.demo-typing span:nth-child(2){animation-delay:.15s}
.demo-typing span:nth-child(3){animation-delay:.3s}
@keyframes demoBounce{0%,60%,100%{transform:translateY(0);opacity:.4}30%{transform:translateY(-4px);opacity:1}}
@media (prefers-reduced-motion:reduce){.demo-typing span{animation:none;opacity:.7}}

/* — вправи (інтерактив) — */
.demo-ex-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:1.4rem}
@media (max-width:48rem){.demo-ex-grid{grid-template-columns:1fr}}
.demo-ex-card{
  background:var(--card-l);border:1px solid var(--line-l);border-radius:var(--r-card);
  padding:1.3rem 1.4rem 1.4rem;
}
.demo-ex-card.is-solved{border-color:var(--primary-l)}
.demo-ex-prompt{font-family:var(--ff-mono);font-size:.75rem;letter-spacing:.04em;color:var(--muted-l);margin-bottom:.5rem}
.demo-ex-main{font-family:var(--ff-display);font-weight:600;font-size:1.15rem;line-height:1.4;margin-bottom:.9rem}
.demo-ex-options{display:flex;flex-wrap:wrap;gap:.5rem;margin-bottom:.7rem}
.demo-ex-btn{
  font:inherit;font-family:var(--ff-text);font-size:.9375rem;
  padding:.5rem .85rem;border-radius:8px;cursor:pointer;
  color:var(--text-l);background:var(--paper);border:1px solid var(--line-l);
  transition:background-color 160ms ease,border-color 160ms ease,color 160ms ease;
}
@media (hover:hover) and (pointer:fine){
  .demo-ex-btn:not([disabled]):hover{border-color:var(--primary-l)}
}
.demo-ex-btn:focus-visible{outline:2px solid var(--primary-l);outline-offset:2px}
.demo-ex-btn.is-correct{background:var(--primary-l);border-color:var(--primary-l);color:#fff}
.demo-ex-btn.is-wrong{border-color:var(--stop-l);color:var(--stop-l)}
.demo-ex-feedback{font-family:var(--ff-mono);font-size:.8125rem;min-height:1.2em}
.demo-ex-feedback[data-state="ok"]{color:var(--proof-l)}
.demo-ex-feedback[data-state="wrong"]{color:var(--stop-l)}

/* — тур по кабінету — */
.demo-tour-intro{color:var(--muted-l);margin-bottom:1.6rem;max-width:34em}
.demo-tour-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.8rem}
@media (max-width:56rem){.demo-tour-grid{grid-template-columns:1fr;max-width:22rem;margin-inline:auto}}

/* — альтернатива — */
.demo-alt{background:var(--paper-tint);padding-block:var(--sp-5)}
.demo-alt-text{max-width:40em;font-size:1.05rem;color:var(--text-l);margin-bottom:1.2rem}
.demo-alt-actions{display:flex;flex-wrap:wrap;gap:1.6rem;align-items:center}
.demo-alt-tg{
  color:var(--muted-l);text-decoration:none;font-family:var(--ff-text);font-size:.95rem;
  border-bottom:1px solid var(--line-l);padding-bottom:2px;
}
@media (hover:hover) and (pointer:fine){.demo-alt-tg:hover{color:var(--text-l);border-color:var(--muted-l)}}

@media (max-width:40rem){
  .demo-phone{max-width:none}
}

/* =======================================================================
   /thanks/ (докс REVIEW-PACKAGE.md День 6, ТЗ п.A) — коротка сторінка
   підтвердження, той самий .cs-hero/.wrap/.grain, що на /test/. Свій
   .tk-* префікс лише для елементів, яких більше ніде на сайті немає
   (галочка, нумеровані кроки "що далі").
   ======================================================================= */
.tk-wrap{max-width:34rem}
.tk-check{
  display:inline-flex;align-items:center;justify-content:center;
  width:2.75rem;height:2.75rem;margin-bottom:1.6rem;border-radius:50%;
  background:rgba(79,200,180,.12);border:1.5px solid var(--primary-d);
  color:var(--primary-d);font-size:1.25rem;
}
.tk-sub{margin-bottom:1.8rem}
.tk-steps{
  list-style:none;margin:0 0 2.2rem;padding:0;counter-reset:tk;
  display:flex;flex-direction:column;gap:1.05rem;max-width:32em;
}
.tk-steps li{
  position:relative;padding-left:2.6rem;color:var(--text-d);line-height:1.55;
}
.tk-steps li::before{
  counter-increment:tk;content:counter(tk);
  position:absolute;left:0;top:-.1em;
  width:1.9rem;height:1.9rem;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-family:var(--ff-mono);font-size:.8125rem;color:var(--muted-d);
  border:1px solid var(--line-d);
}
.tk-line{color:var(--text-d);font-size:1.05rem;margin-bottom:1.9rem;max-width:32em}
.tk-actions{display:flex;flex-wrap:wrap;gap:1.1rem;align-items:center}
@media (max-width:40rem){
  .tk-actions{flex-direction:column;align-items:flex-start}
}

/* =======================================================================
   /pryvatnist/ (докс REVIEW-PACKAGE.md День 6, ТЗ п.B) — сторінка для
   читання: вузька колонка (~65-70 символів = .legal-col{max-width:36rem}),
   без 3D-сцени/лічильників/декору головної. Верх (.legal-hero-wrap)
   переюзує .cs-hero/.eyebrow/.hero-sub, тут лише дата оновлення.
   ======================================================================= */
.legal-hero-wrap{max-width:36rem}
.legal-updated{
  margin-top:1.3rem;
  font-family:var(--ff-mono);font-size:.8125rem;color:var(--muted-d);
  letter-spacing:.02em;
}
.legal-sections{background:var(--paper);padding-block:var(--sp-6)}
.legal-col{max-width:36rem}
.legal-block{padding-block:2.3rem;border-top:1px solid var(--line-l)}
.legal-block:first-child{border-top:0;padding-top:0}
.legal-heading{
  font-family:var(--ff-display);font-weight:600;
  font-size:clamp(1.2rem,2vw,1.4rem);
  letter-spacing:-0.01em;margin-bottom:.9rem;
}
.legal-list{margin:0 0 1rem;padding-left:1.2rem;color:var(--text-l)}
.legal-list li{margin-bottom:.55rem;line-height:1.62}
.legal-list li:last-child{margin-bottom:0}
.legal-body{color:var(--text-l);font-size:1.0625rem;line-height:1.65}
.legal-back{margin-top:2.6rem}
.legal-back a{
  color:var(--primary-l);text-decoration:none;
  font-family:var(--ff-display);font-weight:600;
}
@media (hover:hover) and (pointer:fine){.legal-back a:hover{text-decoration:underline}}

/* =======================================================================
   /cases/school-loop/ (докс REVIEW-PACKAGE.md День 6, ТЗ п.C) — розворот
   "одна школа — весь контур": НЕ кейс, власний .loop-* набір. Нумерація
   кроків не декоративна — вони йдуть у реальному порядку "привести →
   зустріти → утримати", тому конектор між кружками (.loop-step-num::after)
   несе сенс послідовності. Крок 2 (сайт школи) навмисно без .loop-step-link
   — окремої сторінки немає, тому й лінка на неї немає.
   ======================================================================= */
.loop-steps-section{background:var(--paper);padding-block:var(--sp-6)}
.loop-steps-label{margin-bottom:var(--sp-4)}
.loop-steps{list-style:none;margin:0;padding:0}
.loop-step{
  position:relative;display:flex;gap:1.6rem;
  padding-block:2.2rem;border-top:1px solid var(--line-l);
}
.loop-step:first-child{border-top:0;padding-top:0}
.loop-step:last-child{padding-bottom:0}
.loop-step-num{
  position:relative;flex:none;
  display:flex;align-items:center;justify-content:center;
  width:3.4rem;height:3.4rem;border-radius:50%;
  background:var(--card-l);border:1.5px solid var(--primary-l);
  color:var(--primary-l);
  font-family:var(--ff-mono);font-weight:500;font-size:1.15rem;
}
.loop-step:not(:last-child) .loop-step-num::after{
  content:"";position:absolute;left:50%;top:100%;
  width:1px;height:2.2rem;background:var(--line-l);
  transform:translateX(-50%);
}
.loop-step-body{flex:1 1 auto;min-width:0;padding-top:.4rem}
.loop-step-title{
  font-family:var(--ff-display);font-weight:600;
  font-size:clamp(1.3rem,2.2vw,1.6rem);
  letter-spacing:-0.01em;margin-bottom:.55rem;
}
.loop-step-text{max-width:38em;color:var(--muted-l);font-size:1.05rem;line-height:1.6;margin-bottom:.9rem}
.loop-step-link{
  display:inline-flex;align-items:center;gap:.4em;
  font-family:var(--ff-display);font-weight:600;font-size:.9375rem;
  color:var(--primary-l);text-decoration:none;
  border-bottom:1.5px solid transparent;
  transition:border-color 180ms ease;
}
@media (hover:hover) and (pointer:fine){
  .loop-step-link:hover{border-color:var(--primary-l)}
}
.loop-why{background:var(--paper-tint);padding-block:var(--sp-6)}
.loop-why-inner{max-width:44rem}
.loop-why-text{margin-bottom:1.8rem;max-width:44em}

@media (max-width:40rem){
  .loop-step{gap:1.1rem}
  .loop-step-num{width:2.6rem;height:2.6rem;font-size:1rem}
  .loop-step:not(:last-child) .loop-step-num::after{height:1.9rem}
}

/* ============ якірне меню (topbar) ============ */
/* Тонка шапка на всю ширину, а не плаваюча пігулка. Перша редакція була
   пігулкою по центру — власник 09.09.2026: «фігня якась на пів сторінки».
   Він має рацію: темний округлий блок посеред світлої сторінки читається як
   сторонній предмет, що впав на текст. Смуга на всю ширину читається як
   шапка сайту — вміст іде під неї, і питання «що це таке» не виникає.

   З'являється так само тільки після сцени: оповідь не переривається.

   z-index 80: під курсором-крапкою (90), над усім вмістом сторінки. */
.topbar{
  position:fixed;top:0;left:0;right:0;z-index:80;
  transform:translateY(-100%);
  opacity:0;visibility:hidden;
  transition:opacity 260ms var(--ease-out),transform 300ms var(--ease-out),
             visibility 0s linear 300ms;
}
.topbar.is-on{transform:none;opacity:1;visibility:visible;transition-delay:0s,0s,0s}
.topbar-in{
  display:flex;align-items:center;justify-content:space-between;
  gap:1rem;
  max-width:74rem;margin-inline:auto;
  padding:.55rem clamp(1.25rem,4vw,3rem);
}
/* Щільний фон, не напівпрозорий: розмиття не ховає темний текст на світлому
   папері — перший знімок на 390px читався наскрізь панелі. */
.topbar::before{
  content:"";position:absolute;inset:0;z-index:-1;
  background:#FAFAF6;
  border-bottom:1px solid var(--line-l);
  box-shadow:0 6px 20px rgba(12,20,18,.06);
}
.topbar-logo{
  font-family:var(--ff-display);font-weight:700;font-size:1rem;
  color:var(--text-l);text-decoration:none;letter-spacing:-0.01em;
}
.topbar ul{
  display:flex;align-items:center;gap:clamp(.1rem,1.4vw,.4rem);
  margin:0;padding:0;list-style:none;
}
.topbar a:not(.topbar-logo){
  display:block;padding:.4rem clamp(.4rem,1.8vw,.7rem);border-radius:8px;
  font-family:var(--ff-display);font-weight:600;
  font-size:clamp(.8125rem,.78rem + .16vw,.9375rem);
  line-height:1;white-space:nowrap;
  color:var(--muted-l);text-decoration:none;
  transition:color 180ms ease,background-color 180ms ease;
}
@media (hover:hover) and (pointer:fine){
  .topbar a:not(.topbar-logo):hover{color:var(--text-l);background:rgba(12,20,18,.05)}
}
.topbar a:focus-visible{outline:2px solid var(--signal-l);outline-offset:2px}
/* Поточний розділ. Підсвітку ставить main.js: меню без неї показує чотири
   однакові слова й не відповідає на питання «де я зараз». */
.topbar a[aria-current]{color:var(--signal-l)}

/* Ціль якоря не повинна ховатись під шапкою. Число одне на два місця: тут
   для рідної прокрутки браузера і в main.js для Lenis — той на десктопі
   перехоплює клік по якорю сам і про scroll-margin не знає (замір
   09.09.2026: заголовок ставав рівно під панеллю). Тому JS читає цю змінну,
   а не свою копію числа. */
:root{--topbar-gap:4.5rem}
#cases,#price,#faq,#contact{scroll-margin-top:var(--topbar-gap)}
/* Нерухома точка для якоря: нічого не займає й не рухається анімацією. */
.anchor-mark{display:block;height:0;overflow:hidden}

/* На вузькому екрані слово-логотип з'їдає місце в чотирьох пунктів. */
@media (max-width:26rem){
  .topbar-logo{display:none}
  .topbar ul{width:100%;justify-content:space-between}
}

@media (prefers-reduced-motion:reduce){
  .topbar{transition:opacity 1ms linear,visibility 0s linear 1ms;transform:none}
  .topbar a{transition:none}
}

/* Приглушена кнопка для світлого полотна. .btn-ghost-dark був лише для
   сцени; на папері його рамка #3A4A44 і світлий текст нечитабельні. */
.btn-ghost-light{background:transparent;color:var(--text-l);border-color:#C9C7BC}
@media (hover:hover) and (pointer:fine){
  .btn-ghost-light:hover{border-color:var(--text-l);background:rgba(12,20,18,.04)}
}
.btn-ghost-light:focus-visible{outline:2px solid var(--signal-l);outline-offset:3px}
.who-cta{margin-top:1.1rem}

/* ---- прайс-лист у розділі «Скільки це коштує» ---------------------------
   Рядок-крапки між назвою і ціною, як у меню: очей веде від послуги до
   числа сам, без таблиці й без рамок. Цифри тут — головне, тому вони
   моноширинні й важчі за назву. */
.price-list{
  list-style:none;margin:0 0 var(--sp-3);padding:0;
  border-top:1px solid var(--line-l);
}
.price-list li{
  display:flex;align-items:baseline;gap:.6rem;
  padding:.85rem 0;
  border-bottom:1px solid var(--line-l);
}
.price-list a{
  color:var(--text-l);text-decoration:none;
  font-family:var(--ff-display);font-weight:600;
  font-size:clamp(1rem,.95rem + .3vw,1.125rem);
}
@media (hover:hover) and (pointer:fine){
  .price-list a:hover{color:var(--signal-l)}
}
.price-list a:focus-visible{outline:2px solid var(--signal-l);outline-offset:3px;border-radius:3px}
.price-dots{
  flex:1 1 auto;min-width:1.5rem;height:1px;
  align-self:center;
  background-image:radial-gradient(circle,var(--line-l) 1px,transparent 1px);
  background-size:6px 1px;background-repeat:repeat-x;
}
.price-list b{
  font-family:var(--ff-mono);font-weight:600;
  font-size:clamp(.95rem,.9rem + .25vw,1.0625rem);
  color:var(--text-l);white-space:nowrap;
  font-variant-numeric:tabular-nums;
}
/* Розділювач між двома цінами одного рядка (підписка · під ключ). */
.price-or{color:var(--muted-l);font-family:var(--ff-mono)}
@media (max-width:30rem){
  /* на вузькому екрані крапки з'їдають назву — переносимо ціну під неї */
  .price-list li{flex-wrap:wrap;gap:.15rem .6rem}
  .price-list .price-dots{display:none}
  .price-list b{width:100%}
  /* дві ціни стають двома рядками — крапка між ними лишилась би сама */
  .price-list .price-or{display:none}
}
