/* ── Сторінка одного кейсу у стилі вітрини ──────────────────────────────
   Третій шар, поверх `keys.css` (змінні, шапка, картки) і
   `keysy-scroll.css` (фон-фото, полоска прогресу, приховування сцени).
   Порядок підключення обов'язковий:
     keys.css → keysy-scroll.css → keysy-case.css

   Власник 06.09.2026: «на всіх сторінках, де опис продукту, зробити в
   такому ж стилі, як головні сторінки кейсів: стиль + фон + колір кнопок
   і їх налаштування + підкладки + анімація появи тексту й фото».
   І одразу після першого показу: «плашки там, де текст у рамці, зробити
   як ми зробили у вкладці про мене, і всюди, де текст, кинути підкладки —
   бо тут упор на текст, а не на картинки».

   ☠ ЗВІДСИ ГОЛОВНЕ ПРАВИЛО ЦЬОГО ФАЙЛУ: сторінка кейсу — ТЕКСТОВА.
   Фото на фоні працює як атмосфера, а не як тло для читання. Тому кожен
   блок тексту лежить на своїй підкладці, а не просто поверх знімка.

   Що звідки взято, щоб не розійшлось:
     фон і його змінні     → `keysy-scroll.css` (той самий шар `.ks-bg`)
     кадр фону по розділу  → `<style>` у `<head>`, ставить `gen_cases.py`
     вуаль під текстом     → `/pro-mene/`, `.head-veil` (числа один в один)
     клейморфні плашки     → `/pro-mene/`, `.flow-facts span` (теж дослівно)
     колір і тінь абзаців  → `--txt-*` з `keys.css` (крутить `?txttest=1`)
     свічення кнопки шапки → `--cta-glow-*` з `keys.css` (`?btntest=1`)
   🛑 Числа плашок і вуалі не «підправляти на око»: обидва рецепти власник
      приймав окремо, на /pro-mene/ це коштувало чотирьох заходів
      (розписано там же, у блоці `.flow-facts`).
   ────────────────────────────────────────────────────────────────────── */

/* ☠ Шапка тут `position:fixed` (правило приходить із `keysy-scroll.css`),
   бо всередині ScrollSmoother `sticky` рахується від трансформованого
   контейнера. Fixed випадає з потоку — значить, верх сторінки треба
   відсунути руками, інакше крихти лізуть під шапку.
   Заміряно на 1467×678: шапка 51px, плюс повітря — 96px. */
.case-head{padding:96px 0 40px}
@media(max-width:700px){.case-head{padding:84px 0 30px}}

/* ── ЗМІННІ ПІДКЛАДОК ─────────────────────────────────────────────────
   Власник 06.09.2026: «створюй сторінку для редагування, сам виставлю
   ступінь прозорості рамок». Тому все, що стосується щільності підкладок,
   винесено сюди — а панель `?platetest=1` крутить рівно ці змінні на
   БОЙОВІЙ сторінці. Копії сторінки немає навмисно: копія розходиться з
   бойовою за годину, і потім півсеансу шукаєш, чому в тесті так, а на
   сайті інакше. Той самий підхід, що в `?txttest=1` і `?bgtest=1`.

   🛑 Стартові значення нижче — це те, що зараз бачить відвідувач. Власник
   крутить, тисне «показати значення» й надсилає рядок; я переношу числа
   сюди один в один, як було з `--txt-*`.

   🛑 ЧИСЛА НИЖЧЕ ВИСТАВИВ ВЛАСНИК панеллю `?platetest=1` 06.09.2026 і
      надіслав скріншотом. Перенесені один в один. Було: плашка 0.88,
      рамка 0.07, вуаль 0.95/0.45, поля 30/34.
      Рамку він вивів у нуль, праву половину вуалі теж — тобто підкладка
      тепер тримається однією заливкою, без обведення й без затемнення
      правого краю шапки. Не «підправляти на око». */
:root{
  --case-plate:0.74;        /* заливка плашки секції: 0 = зовсім прозора */
  --case-plate-line:0;      /* рамка плашки */
  --case-plate-r:22px;      /* скруглення плашки */
  --case-plate-y:25px;      /* поле плашки над і під текстом */
  --case-plate-x:44px;      /* поле плашки з боків */
  --case-plate-blur:0px;    /* розмиття фону ПІД плашкою */
  --case-veil-l:0.74;       /* вуаль шапки: щільність там, де текст */
  --case-veil-r:0;          /* вуаль шапки: щільність біля правого краю */
  --case-card:0.86;         /* картки: сусідні кейси і рамка знімка */
}

/* ── ПІДКЛАДКИ ПІД ТЕКСТОМ ────────────────────────────────────────────
   Рецепт із `/pro-mene/`: у шапці вуаль глуха ліворуч, де текст, і
   прозоріша праворуч, де видно кадр. Проміжні точки градієнта рахуються
   від крайніх, щоб один повзунок вів усю вуаль, а не ламав її навпіл.
   ⚠ `isolation:isolate` — щоб `.case-head::before` з `keys.css` (він на
   `z-index:-1`) не провалився за підкладку в чужий контекст. */
.case-head{isolation:isolate}
.case-head::before{content:'';position:absolute;inset:0;z-index:0;display:block;
  background:
    linear-gradient(90deg,
      rgba(0,22,33,var(--case-veil-l)) 0%,
      rgba(0,22,33,calc(var(--case-veil-l) - 0.05)) 38%,
      rgba(0,22,33,calc(var(--case-veil-r) + 0.17)) 72%,
      rgba(0,22,33,var(--case-veil-r)) 100%),
    radial-gradient(900px 380px at 12% -20%,rgba(255,65,3,0.16),transparent 62%)}
.case-head .wrap{position:relative;z-index:1}
/* На вузькому екрані текст іде на всю ширину — вуаль стає рівномірною. */
@media(max-width:700px){
  .case-head::before{background:
    linear-gradient(180deg,
      rgba(0,22,33,calc(var(--case-veil-l) - 0.05)),
      rgba(0,22,33,calc(var(--case-veil-l) - 0.07))),
    radial-gradient(600px 300px at 12% -20%,rgba(255,65,3,0.16),transparent 62%)}
}

/* Секції: кожен текстовий блок — на своїй плашці, а не просто поверх фото.
   ⚠ Плашка ширша за текст (`inset:-30px -34px`) і скруглена — так вона
   читається як окремий аркуш, а не як випадковий прямокутник. Той самий
   висновок, що записаний у `.ks-col::before` на вітрині.
   ⚠ `z-index:0` на плашці й `1` на вмісті, а не від'ємний z-index: на
   від'ємному вона провалюється під фон секції. Ту саму граблю вже
   ловили з шаром `.ks-bg` (див. keysy-scroll.css).
   ☠ Без `backdrop-filter` навмисно: плашка й так майже глуха (0.88), а
   розмиття на кожній секції — це окремий шар композитора на кожен блок.
   Заміряно на вітрині: саме через це там розмиття вмикається класом. */
.ks-stage main section > .wrap,
.ks-stage main section > .wrap-wide{position:relative}
.ks-stage main section > .wrap > *,
.ks-stage main section > .wrap-wide > *{position:relative;z-index:1}
.ks-stage main section > .wrap::before,
.ks-stage main section > .wrap-wide::before{content:'';position:absolute;z-index:0;
  pointer-events:none;
  inset:calc(var(--case-plate-y) * -1) calc(var(--case-plate-x) * -1);
  border-radius:var(--case-plate-r);
  background:linear-gradient(180deg,
    rgba(0,22,33,calc(var(--case-plate) + 0.02)),
    rgba(0,22,33,calc(var(--case-plate) - 0.02)));
  border:1px solid rgba(255,255,255,var(--case-plate-line))}
/* Розмиття коштує окремого шару композитора на КОЖНУ секцію, тому
   вмикається класом і тільки коли повзунок не в нулі — та сама схема,
   що в `.txt-blur` на вітрині. */
.case-blur .ks-stage main section > .wrap::before,
.case-blur .ks-stage main section > .wrap-wide::before{
  backdrop-filter:blur(var(--case-plate-blur))}
/* ⚠ На телефоні плашка НЕ вилазить за краї: `.wrap` там на всю ширину
   вікна, і від'ємний горизонтальний inset виносив би її за екран. Смуги
   прокрутки не буде (секція під `overflow-x:clip`), але край плашки
   зрізало б рівно по вікну, і скруглення зникало б. Тому 4px усередину. */
@media(max-width:700px){
  .ks-stage main section > .wrap::before,
  .ks-stage main section > .wrap-wide::before{
    inset:calc(var(--case-plate-y) * -0.7) 4px;border-radius:16px}
}

/* Секція з CTA власної плашки не отримує: `.cta-box` — уже рамка з
   градієнтом, і плашка під нею дає рамку в рамці. */
.ks-stage main section > .wrap:has(> .cta-box)::before{display:none}

/* Роздільники між секціями зайві: плашки самі відділяють блоки один від
   одного, а лінія поверх плашки читалась як шов. */
.ks-stage main section{border-top:0;padding:34px 0}

/* ── ТЕКСТ ПОВЕРХ ФОТО ────────────────────────────────────────────────
   Ті самі колір і тінь, що на вітринах — власник підбирав їх панеллю
   `?txttest=1` і просив «для всього тексту на сторінках кейсів».
   ⚠ Заголовки НЕ чіпаємо: вони вже світліші за абзаци, і `--txt-color`
   зробив би їх темнішими, а не навпаки. */
.ks-stage p,
.ks-stage ul.plain li{color:var(--txt-color);
  text-shadow:0 2px 14px rgba(0,0,0,var(--txt-shadow))}
.ks-stage p.muted,
.ks-stage .metrics-note{color:var(--text-muted)}

/* ── ТРИ РІВНІ ТЕКСТУ, А НЕ ОДИН ──────────────────────────────────────
   Власник 06.09.2026 по блоку «Пошук чатів і парсер — перед розсилкою,
   а не після»: «все одним кольором, так не піде, не видно ж нічого».

   Він має рацію: `h3` був 19px майже того ж кольору, що абзац, а сам
   абзац ще й починався з жирного `<b>` — тобто підзаголовок і початок
   тексту зливались в один рядок. Тепер рівні розведені:
     h2  — великий, білий          (заголовок секції)
     h3  — бурштиновий, з повітрям (підзаголовок)
     <b> — білий у сірому абзаці   (акцент усередині тексту)

   ☠ БІРЮЗА ТУТ БУЛА І НЕ ВИТРИМАЛА. Власник 06.09.2026, той самий блок:
   «заголовки колір підбери, щоб кращий контраст був, текст зливається».
   Річ не в яскравості самої бірюзи — вона на плашці дає близько 9:1 до
   фону. Річ у сусідстві: одразу під `h3` абзац починається з жирного
   БІЛОГО `<b>`, і два світлих рядки холодного тону читались як один.
   Бурштин розводить їх не яскравістю, а тоном — тепле проти холодного
   видно навіть краєм ока, на фотофоні теж.
   ⚠ Бурштин той самий `--amber`, що вже стоїть у `.todo b`, а не новий
   колір. Помаранчевий зайнятий надзаголовком `.eyebrow`, бірюза лишається
   посиланням і цифрам у «Технічно» — тобто кожен колір і далі означає
   рівно одне.
   ⚠ `margin-top` більший за `margin-bottom` — підзаголовок мусить липнути
   до СВОГО абзацу, а не стояти посередині між двома. */
.ks-stage main h3{color:var(--amber);font-size:21px;font-weight:700;
  letter-spacing:.3px;margin:38px 0 8px}
.ks-stage main h3:first-child{margin-top:0}
.ks-stage main p b,
.ks-stage main li b{color:var(--text-primary);font-weight:700}

/* ── ПЛАШКИ ФАКТІВ — КЛЕЙМОРФНІ, ЯК НА /pro-mene/ ─────────────────────
   Власник: «плашки там, де текст у рамці, зробити як у вкладці про мене».
   Це паспорт проєкту в шапці й цифри в «Технічно» — короткий факт у рамці,
   рівно та роль, що в `.flow-facts span`.

   ☠ Рецепт перенесений ДОСЛІВНО і світла зовнішня тінь тут заборонена:
   обидві половини клейморфної тіні світліші за фон, і на темному вони
   читаються німбом. Опуклість дає ЗАЛИВКА (градієнт 145°), два `inset`
   її підкреслюють, темна тінь відриває від фону. Уся історія з чотирьох
   заходів розписана в `/pro-mene/` біля `.flow-facts`.
   🛑 Правиш числа тут — правь і там, це навмисно одна пара рецептів.
   ⚠ Текст на пластині ТЕМНИЙ, кольори живуть у `--plate-*` (keys.css).
   Бірюза `--cyan` на світлій пластині не читається. */
.ks-stage .passport{background:none;border:0;border-radius:0;overflow:visible;
  gap:10px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr))}
.ks-stage .metrics{gap:10px}

/* ── ПАСПОРТ НА ТЕЛЕФОНІ: ДВІ КОЛОНКИ ─────────────────────────────────
   Власник 07.09.2026 з телефона: «5 білих блоків на початку кейсу
   великі, і ти зробив кожен окремим рядком — там спокійно можна по
   два блоки в ряд, а не по одному».

   ☠ Це не сітка була винна, а ОДНЕ ЧИСЛО в ній. `auto-fit` з
   `minmax(170px,1fr)` вимагає на дві колонки 170+170+10 = 350px,
   а паспорт на 390px екрані має всього 335px. Не вистачало 15px —
   і сітка мовчки згорталась в одну колонку. Заміряно: 5 плашок по
   70px = 388px висоти замість ~240.
   ⚠ Тому тут `repeat(2,1fr)` числом, а не менший `minmax`: підбирати
   поріг наосліп — це той самий баг через півроку на іншому екрані.
   ⚠ Плашок непарна кількість (5), і остання лишалась би сама в ряду
   з діркою праворуч. `:last-child:nth-child(odd)` розтягує її на
   обидві колонки — це завжди «Адреса», найдовший рядок у паспорті.
   ☠ `minmax(0,1fr)`, а НЕ просто `1fr`: голий `1fr` — це насправді
   `minmax(auto,1fr)`, і довгий рядок («B2B, постачання борошна»)
   роздуває свою колонку за рахунок сусідньої. Перший захід дав
   182 і 143px замість рівних — заміряно, не на око. */
@media(max-width:700px){
  .ks-stage .passport{grid-template-columns:repeat(2,minmax(0,1fr))}
  .ks-stage .passport div:last-child:nth-child(odd){grid-column:1/-1}
}
.ks-stage .passport div,
.ks-stage .metric{color:var(--plate-ink);
  background:linear-gradient(145deg,var(--plate-hi),var(--plate-lo));
  border:0;border-radius:14px;padding:12px 16px;
  box-shadow:4px 4px 10px rgba(0,0,0,0.45),
    inset 2px 2px 5px var(--plate-gloss),
    inset -2px -2px 5px var(--plate-shade);
  transition:transform .25s ease,box-shadow .25s ease}
.ks-stage .passport div:hover,
.ks-stage .metric:hover{transform:translateY(-4px);
  box-shadow:7px 7px 16px rgba(0,0,0,0.5),
    inset 2px 2px 5px var(--plate-gloss),
    inset -2px -2px 5px var(--plate-shade)}
.ks-stage .passport dt,
.ks-stage .metric span{color:var(--plate-ink-dim)}
.ks-stage .passport dd{color:var(--plate-ink)}
.ks-stage .passport dd a,
.ks-stage .metric b{color:var(--plate-link)}

/* ── РЕШТА КАРТОК ─────────────────────────────────────────────────────
   Сусідні кейси й знімок лишаються темними: це не факти в рамці, а
   посилання й фото. Але на фоні-фото їм потрібен свій щільний фон,
   інакше вони читаються як дірки в сторінці. */
.ks-stage .next-cases a,
.ks-stage .shot{background:rgba(0,22,33,var(--case-card));
  border-color:rgba(255,255,255,0.12);
  transition:border-color .25s ease,transform .25s ease}
.ks-stage .next-cases a:hover{transform:translateY(-3px)}

/* ── МАСКИ ПІД АНІМАЦІЮ ───────────────────────────────────────────────
   Рядки h1 виїжджають знизу на 400px, і обрізає їх НЕ плагін, а CSS —
   так само, як на вітрині (`overflow:hidden` на самому h1 і на рядку).
   ⚠ `padding-bottom` + рівний від'ємний `margin` — щоб маска не з'їдала
   хвости літер «р», «у», «ц».
   ☠ Клас рядка задає SplitText (`linesClass`), у розмітці його немає. */
.case-head h1{overflow:hidden;padding-bottom:.12em;margin-bottom:6px}
.case-line{display:block;overflow:hidden;padding-bottom:.12em;margin-bottom:-.12em}

/* Знімок виїжджає справа наліво — головний рух вітрини (`.ks-media`).
   ☠ Тримається на `overflow-x:clip` у секції: без нього стартова позиція
   (118% власної ширини вправо) дає горизонтальну смугу прокрутки на всю
   сторінку. Та сама грабля, що записана в `.ks-slide`.
   ⚠ `clip`, а не `hidden`: `hidden` зробив би секцію контейнером
   прокрутки і зламав `position:sticky` усередині. */
.ks-stage main section{overflow-x:clip}


/* ── КІБЕРПАНК-КНОПКИ CTA — БЛОК ПЕРЕЇХАВ У `keys.css` ────────────────
   07.09.2026. Власник: «на /keysy/, /keysy/boty/, агенти і апп теж унизу
   немає ретро кнопок» — і окремо попросив ті самі кнопки на /pro-mene/.
   Ці сторінки `keysy-case.css` НЕ вантажать: у вітрин розмітка інша
   (`.ks-cta-row`), а карта-маршрут має свої `.fbtn` у клейморфних
   панелях. Тримати блок тут означало б три копії одного стилю.
   🛑 Шукати правило — `keys.css`, блок «РЕТРО-КНОПКИ CTA». Скрипт смуг —
   `/assets/js/retro-btn.js` (раніше жив у кінці `keysy-case.js`). */

/* ── ПОСИЛАННЯ В ТЕКСТІ — НЕ БРАУЗЕРНА СИНЯ ───────────────────────────
   Власник 07.09.2026 по списку «ПЛЕТІНКА / STWBH / Майстер з укладання
   підлоги» на /rozrobka-saitiv/: «тут відштовхуючий синій колір! поміняй
   на цей світлий колір як заголовки на всіх 4 вкладках, прибери цей
   синій колір».

   ☠ Синій ніхто не ставив — це ДЕФОЛТ БРАУЗЕРА. У списку `ul.plain`
   назви кейсів обгорнуті в голий `<a>` без класу, а в жодному з трьох
   файлів стилів правила для посилання в тексті не було: `.crumbs a`,
   `.footer-links a` і `.passport dd a` є, а звичайного — нема. Тому
   #0000EE на темному фоні, і саме він відштовхує.
   ⚠ Правило поставлено на весь `.ks-stage main`, а не тільки на
   `ul.plain` тієї однієї сторінки: інакше наступне посилання в абзаці
   вилізе тим самим синім. Зараз такі посилання є лише на
   /rozrobka-saitiv/ (три штуки), решта трьох вкладок і кейси їх просто
   не містять — правило там нічого не міняє, але й не дасть з'явитися.
   ⚠ Колір — той самий, що в заголовків `h2` (`--text-primary`), як і
   просив власник. Підкреслення лишається: без нього і без кольору
   посилання перестало б відрізнятись від тексту зовсім.
   ⚠ Бурштин на наведенні — щоб було видно, що це клікається. Той самий
   `--amber`, що в підзаголовків, нового кольору не заводимо. */
.ks-stage main a:not([class]){color:var(--text-primary);
  text-decoration-color:rgba(228,231,239,0.45);
  text-underline-offset:3px;transition:color .2s}
.ks-stage main a:not([class]):hover,
.ks-stage main a:not([class]):focus-visible{color:var(--amber);
  text-decoration-color:currentColor}

/* ── ВИНЯТОК: ПОСИЛАННЯ В ПАСПОРТІ ────────────────────────────────────
   Власник 07.09.2026 по /keysy/sait-maistra-pidlohy/: «слово Відкрити
   сайт білим кольором і зливається з фоном, на решті трьох вкладках
   та сама проблема».

   ☠ Правило вище (`main a:not([class])`) З'ЇДАЄ фіолетовий колір
   паспорта. Специфічність в обох однакова — (0,2,2): `.ks-stage`+
   `:not([class])` проти `.ks-stage`+`.passport`, плюс по два теги.
   При рівній специфічності виграє те, що НИЖЧЕ у файлі, а `main a`
   стоїть нижче за `.passport dd a` (рядок 213). Тому на світлій
   неоморфній плашці опинявся майже білий `--text-primary` #e4e7ef.
   ⚠ Баг був не тільки на чотирьох сайтових вкладках, а на ВСІХ десяти
   кейсах, де в паспорті є посилання: @Belkamarketbot, @theblade2bot,
   @DomotekaDPBot, @SpotTradingzBot, @avtorozsylka_bot і чотири адреси
   сайтів. Тому лікується тут, у стилях, а не в розмітці сторінок.
   ⚠ Наведення теж перевизначене: `--amber` — колір під темний фон,
   на світлій плашці він жовтяво-блідий. Беремо темніший фіолетовий.

   ⚠ Колір НЕ рівно `#6f42c1` з /pro-mene/, а глибший — і ось чому.
   Пластина не однотонна, це градієнт 145°, а рядок `dd` стоїть на
   0.64 її висоти, тобто ближче до ТЕМНОГО кінця. Шрифт тут 16px/700 —
   за WCAG це ще не «великий текст», поріг 4.5.
   🛑 Правиш цей колір — міряй по НИЖНЬОМУ кінцю градієнта: по
   верхньому перевірка брехливо проходить.
   ⚠ 07.09 увечері пластину приглушили (див. `--plate-*` у keys.css),
   і колір поїхав слідом: #5f37a6 давав на новому фоні 3.55:1.
   Тепер це `--plate-link` #43277a — 5.06:1 по нижньому кінцю. */
.ks-stage .passport dd a:not([class]){color:var(--plate-link)}
.ks-stage .passport dd a:not([class]):hover,
.ks-stage .passport dd a:not([class]):focus-visible{color:#2f1b57;
  text-decoration:underline;text-decoration-color:currentColor}
