/* НАВЕДЕННЯ ЖИВЕ ЛИШЕ ТАМ, ДЕ Є МИША.
 *
 * На тач-екрані `:hover` не знімається: браузер лишає його на останньому
 * натиснутому елементі до наступного тапу деінде. Кожна кнопка після
 * натискання лишалась світлою, наче палець досі на ній, — це читалось як
 * «вона виділена» або «вона зламалась».
 *
 * Наведення (`:hover`) скрізь загорнуте в `@media (hover: hover)`. Натиск
 * (`:active`) лишається для всіх — саме він відповідає за відгук на дотик.
 */
/* ═══════════════════════════════════════════════════════════════════════════
   МУЛЬТИВСЕСВІТ — увесь вигляд застосунку в одному файлі.

   Раніше стилів було ТРИ: fonts.css, style.css і glass.css, і кожен їхав
   окремим запитом. Через повільний тунель це коштувало двох зайвих
   рукостискань перед першим кадром — і саме тому на першому відкритті встигав
   промайнути напівзастосований вигляд: базові стилі вже приїхали, скляні ще ні.

   Друга, гірша біда була в розбіжностях. Файли перевизначали одне одного, і
   одне й те саме імʼя означало різне залежно від того, звідки читати: `--r-lg`
   був 22px у style.css і 20px у glass.css. За час роботи так накопичилось
   шість правил для `.sec` і пʼять для індикатора вкладки.

   ПОРЯДОК СКЛЕЮВАННЯ ЗНАЧУЩИЙ і саме такий:
     1) fonts.css — @font-face мусить бути оголошений до першого використання;
     2) style.css — основа: палітра, сітка, типографіка;
     3) glass.css — скляний шар, який навмисно перекриває основу.

   Правити тепер тільки цей файл. Старі три видалено, щоб не лишалось спокуси
   редагувати те, що вже нікуди не підключено.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ────────────────────────────────────────────────────────────────────────
   Далі — колишній fonts.css
   ──────────────────────────────────────────────────────────────────────── */

/* Гарнітури лежать поруч із застосунком, а не на CDN: зовнішній домен
   коштував би ще одного DNS+TLS рукостискання на першому екрані, а він і
   так їде через повільний тунель. */
/* АКЦИДЕНТ НЕ МІНЯЄТЬСЯ НА ЛЬОТУ.
   Було `swap`: перший кадр назва малюється запасним шрифтом, за мить приїжджає
   Unbounded — ширший — і шапка стрибає. Власник: «хедер спочатку якийсь
   менший шрифт, потім нормальний, усе дьоргається». `optional` лишає браузеру
   вибір один раз і назавжди для цього відкриття: файл уже в кеші (а на першому
   відкритті його тягне `preload` з `index.html`) — беремо його; не встиг —
   лишаємось на запасному, без підміни посеред читання. */
@font-face {
  font-family: 'Unbounded';
  font-style: normal;
  font-weight: 700;
  font-display: optional;
  src: url('/fonts/unbounded-normal-700-cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Unbounded';
  font-style: normal;
  font-weight: 700;
  font-display: optional;
  src: url('/fonts/unbounded-normal-700-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Unbounded';
  font-style: normal;
  font-weight: 700;
  font-display: optional;
  src: url('/fonts/unbounded-normal-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Unbounded';
  font-style: normal;
  font-weight: 900;
  font-display: optional;
  src: url('/fonts/unbounded-normal-900-cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Unbounded';
  font-style: normal;
  font-weight: 900;
  font-display: optional;
  src: url('/fonts/unbounded-normal-900-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Unbounded';
  font-style: normal;
  font-weight: 900;
  font-display: optional;
  src: url('/fonts/unbounded-normal-900-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/playfair-italic-700-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/playfair-italic-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: italic;
  font-weight: 900;
  font-display: swap;
  src: url('/fonts/playfair-italic-900-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Playfair Display';
  font-style: italic;
  font-weight: 900;
  font-display: swap;
  src: url('/fonts/playfair-italic-900-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('/fonts/jetbrains-800-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('/fonts/jetbrains-800-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


/* ────────────────────────────────────────────────────────────────────────
   Далі — колишній style.css
   ──────────────────────────────────────────────────────────────────────── */

/* Мультивсесвіт — Telegram Mini App.

   ПАЛІТРА взята з портального вихору: кислотна зелень (#b6f24a → #2d7a1c) на
   темно-зеленому ґрунті, з жовтими й білими бризками з тієї ж картинки. Неон
   маджента/ціан — з другої, «розколотої планети»: він працює як семантичний
   колір (небезпека / інформація), а не як другий акцент.

   ТИПОГРАФІКА: три ролі й один масштаб. Display — важкий, широкий, з від'ємним
   трекінгом (заголовки екранів). Body — системний ґротеск. Data — моноширинний,
   для чисел і кодів: він і читабельніший у колонках, і підтримує «портальний
   термінал» як настрій.

   НАВІГАЦІЯ: фіксована знизу, БЕЗ горизонтального скролу. У Telegram свайп від
   краю — системний жест «закрити», тож стрічка вкладок, що їздить убік, змушує
   гравця випадково виходити із застосунку.
*/

:root {
  /* ґрунт — нейтрально-синій, як у гамі «Небо» (30.10.2026, рішення власника);
     текст і акценти — ті, що на лендінгу. Раніше ґрунт був зелено-чорний. */
  --void:        #0a0b0d;
  --void-2:      #111215;
  --panel:       #1a1b1f;
  --panel-2:     #202227;
  --line:        #212c45;

  /* портал */
  --acid:        #b6f24a;
  --portal:      #8fd93f;
  --portal-mid:  #4fa32a;
  --portal-deep: #2d7a1c;
  --portal-dark: #123f16;
  /* Те саме трійками для rgba(): палітру оформлення міняє JS, а число,
     зашите в rgba(), за змінною не йде. */
  --portal-rgb:  143, 217, 63;
  --acid-rgb:    182, 242, 74;
  --mid-rgb:     79, 163, 42;

  /* бризки з тієї ж картинки */
  --splash:      #f5e35c;
  --foam:        #eef7e6;

  /* семантика (з «розколотої планети») — не акцент, а стан */
  --danger:      #ff4f8b;
  --info:        #35e0f5;

  --ink:         #f5f7f2;
  --ink-2:       #c1c8bf;
  --ink-3:       #959c94;

  /* Шкалу заокруглень визначено НИЖЧЕ, одним блоком. Тут вона колись була
     теж — і два набори тихо розходились: --r-lg існував і як 22px, і як 20px,
     а перемагав той, що нижче. Плитки одного рангу через це мали 10/12/16/20/22
     на одному екрані. */

  --scrim: .78;      /* виводиться з яскравості фото, не задається вручну */
  --bg-opacity: .30;
  --bg-image: none;
  --dim: .88;   /* щільність вуалі над фоном; світле фото потребує більшої */
  --glow:     0 0 16px rgba(var(--portal-rgb), .45);
  --glow-max: 0 0 30px rgba(var(--acid-rgb), .7);

  /* типографічна шкала — одна на весь застосунок */
  /* Заголовок — головний орієнтир на екрані, тож він має читатись
     з відстані витягнутої руки, а не «поміщатись». */
  --t-display: clamp(44px, 13vw, 68px);
  --t-h1:      clamp(27px, 7.4vw, 36px);
  --t-h2:      20px;
  --t-body:    15px;
  --t-small:   13px;
  --t-label:   13px;

  --font-display: "Trebuchet MS", "Segoe UI", system-ui, sans-serif;
  --font-body:    -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
                  "Segoe UI", Roboto, system-ui, sans-serif;
  --font-data:    "JetBrains Mono", "Cascadia Mono", "Consolas", ui-monospace, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  background: var(--void);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

/* ГОРИЗОНТАЛЬНЕ ОБРІЗАННЯ — ЛИШЕ НА `html`.
   Стояло на обох, і це мовчки ламало липку шапку: `overflow-x: hidden`
   робить `overflow-y` обчисленим як `auto`, тобто `body` ставав скрол-
   контейнером. Сторінку при цьому прокручує `html`, тож коробка, до якої
   чіплялась липкість, не рухалась ніколи — `position` був `sticky`, а шапка
   їхала геть, і жодної помилки ніде. */
html { overflow-x: hidden; }

/* Портальний вихор — той самий, що на картинці: кілька зелених шарів, що
   повільно обертаються назустріч один одному. */
/* Сам портал — фоновим зображенням, приглушений і трохи розмитий, щоб текст
   лишався читабельним. Поверх нього — темна вуаль із того ж зеленого сімейства. */
body::before {
  content: ""; position: fixed; inset: -12%; z-index: 0; pointer-events: none;
  /* Спершу шукаємо ТВОЄ фото в media/bg/portal.jpg; якщо його там немає —
     браузер тихо падає на згенерований portal.svg. Тож файл можна покласти
     будь-коли, перезбирати нічого не треба. */
  background-image: var(--bg-image);
  background-position: center; background-size: cover; background-repeat: no-repeat;
  opacity: var(--bg-opacity);
  /* Без розмиття: воно з'їдало саме зображення, заради якого фон і ставили.
     Читабельність тримають скло й тінь тексту, а не замилений фон. */
  filter: saturate(1.15) contrast(1.02);
  /* Фон статичний навмисно: рухоме тло перетягує увагу на себе
     і безперервно з'їдає кадри. Рух живе в об'єктах поверх нього. */
}

/* ВИСОТА ФОНУ НЕ ЗАЛЕЖИТЬ ВІД ТОГО, ЯК САМЕ ЗАРАЗ РОЗГОРНУТЕ ВІКНО.

   `inset: -12%` міряє вікно, а вікно в Telegram відкривається НЕ одразу на
   повний екран: спершу компактна картка, потім розгортання. `cover` на
   низькій коробці збільшує зображення, щоб закрити її по висоті, — і перший
   кадр показує фото зазумленим. Коли вікно доростає, `cover` перераховується,
   і фото «стає на місце». Власник 19.09.2026: «при відкритті мініапу з чату
   фонова фотка якась зазумлена, а потім стає на місце».

   `lvh` — НАЙБІЛЬША висота вікна, і вона не міняється ні від розгортання, ні
   від появи клавіатури. Тож коробка фону та сама з першого кадру, і
   перераховувати `cover` нема від чого.

   Ті самі числа — і для смуги під шапкою: вона малює копію цього фону й мусить
   збігтися з ним пікселями. */
@supports (height: 100lvh) {
  body::before,
  #hdrmask::before {
    inset: auto;
    left: -12vw; width: 124vw;
    top: -12lvh; height: 124lvh;
  }
}
/* Вуаль розрахована на СВІТЛЕ зображення: кислотно-зелений фон інакше з'їдає
   світлий текст. Щільність керується змінною --dim, яку задає адмін у панелі —
   темному фону вистачає 0.5, світлому потрібно 0.8+. */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(ellipse 95% 65% at 50% 38%,
      rgba(7, 8, 9, calc(var(--dim) * .78)) 0%,
      rgba(7, 8, 9, calc(var(--dim) * .96)) 58%,
      rgba(7, 8, 9, var(--dim)) 100%),
    linear-gradient(180deg,
      rgba(7, 8, 9, calc(var(--dim) * .85)) 0%,
      rgba(7, 8, 9, var(--dim)) 100%);
}
@keyframes swirl {
  from { transform: rotate(0deg)   scale(1.05); }
  50%  { transform: rotate(180deg) scale(1.16); }
  to   { transform: rotate(360deg) scale(1.05); }
}
@media (prefers-reduced-motion: reduce) {
  body::before, body::after, .krutylka-zapas { animation: none !important; }
}

/* Поля Telegram у повноекранному режимі.

   `env(safe-area-inset-*)` знає про виріз екрана й НІЧОГО не знає про
   плаваючі кнопки Telegram (закрити, меню), які в повному екрані малюються
   поверх застосунку. Тому величин дві, і вони складаються. Поза повним
   екраном `--tg-*` лишаються нулями, і верстка та сама, що була. */
:root {
  --tg-top: 0px;
  /* Висота шапки. Одне число на два місця: сама шапка й смуга під нею. */
  --topbar-h: 70px;
  --tg-bottom: 0px;
  /* Бічне поле сторінки. Іменем, а не числом: горизонтальні смужки
     виходять за нього рівно на цю величину, і два числа розʼїхались би. */
  --gutter: 14px;
}

.wrap {
  position: relative; z-index: 2;
  max-width: 760px; margin: 0 auto;
  /* Знизу з запасом. 84px ледве покривали саму панель навігації, і остання
     картка сторінки прилипала до неї впритул — читати останній абзац
     доводилось над самими кнопками. */
  padding: calc(10px + var(--tg-top)) var(--gutter)
           calc(116px + var(--tg-bottom) + env(safe-area-inset-bottom, 0px));
}

/* ── шапка ───────────────────────────────────────────────────────────────── */
.topbar {
  display: flex; align-items: center; gap: var(--s3);
  padding: 12px 16px; margin-bottom: 16px;
  /* ВИСОТА ШАПКИ — СТАЛА, і це не примха.
     Смуга `#hdrmask` мусить кінчатись рівно там, де кінчається шапка.
     Спершу її висоту рахував JS на кожен кадр прокрутки — і відставав:
     `--hdr-h` був 80px там, де шапка вже мала 70, тож смуга на десять
     пікселів заходила на вміст і зрізала його. Власник побачив саме це:
     «за хедером усе ще чорна полоса, вона контент обрізає при скролі».
     Стале число не може відстати. */
  height: var(--topbar-h);
  box-sizing: border-box;
  /* ШАПКА ПРОЗОРА. Власник 19.09.2026: «ти за хедером зробив чорну плашку,
     прибери її — просто коли за неї заходить контент, хай зникає».
     Плашка була суцільною (.98–.99) і затуляла фон, заради якого його й
     ставили. Тепер за шапкою лежить смуга `#hdrmask`, що малює ТОЙ САМИЙ
     фон, тож прибрати заливку можна без наслідків: вміст під шапкою й далі
     зникає — його ховає смуга, а не заливка, — а Морті видно НАСКРІЗЬ.
     Лишається розмиття: воно береться саме з тієї смуги, тож напис і
     числа читаються на будь-якому фоні. */
  background: transparent;
  backdrop-filter: blur(10px) saturate(1.1);
  border: 1px solid var(--line); border-radius: var(--r);
}
/* СВІТНОЇ СФЕРИ В ГРІ БІЛЬШЕ НЕМАЄ.
   Власник 19.09.2026: «оцю сферу з підложкою портала взагалі прибери з гри».
   Вона була і знаком чекання, і заглушкою аватара, і в обох ролях читалась
   як щось стороннє: на фоні світу — зелена куля нізвідки. Знак чекання тепер
   один на всю гру — піксельний портал із `game/pixels.js`; тут лишається
   тільки запасна крутилка на випадок, коли клітинки не доїхали. */
.krutylka-zapas {
  display: block; width: 26px; height: 26px; margin: 0 auto;
  border-radius: 50%;
  border: 2px solid rgba(var(--portal-rgb), .25);
  border-top-color: var(--acid);
  animation: pixkrut .8s linear infinite;
}
.avatar-porozhnii { background: rgba(255, 255, 255, .06); }

.brand {
  font-family: var(--font-display);
  font-size: var(--t-h1); font-weight: 800;
  letter-spacing: -.5px; line-height: 1.1;
}
.brand span { color: var(--acid); text-shadow: 0 0 14px rgba(var(--acid-rgb), .6); }
.who { margin-left: auto; text-align: right; font-size: var(--t-label); color: var(--ink-3); }
.who b {
  display: block; font-family: var(--font-data); font-size: var(--t-small);
  color: var(--splash); font-variant-numeric: tabular-nums;
}

/* ── заголовки ───────────────────────────────────────────────────────────── */
h1.screen {
  font-family: var(--font-display);
  font-size: var(--t-display); font-weight: 800;
  letter-spacing: -1.4px; line-height: 1.02;
  margin: 6px 0 16px; text-wrap: balance;
  text-shadow: 0 2px 18px rgba(7, 8, 9, .95), 0 0 34px rgba(var(--portal-rgb), .28);
}
/* Друга половина слова — моноширинним і кислотним. Одне слово, два накреслення:
   так заголовок читається як вивіска, а не як рядок тексту. */
h1.screen em {
  font-style: normal; font-family: var(--font-data); font-weight: 700;
  color: var(--acid); letter-spacing: -.5px;
  text-shadow: 0 0 22px rgba(var(--acid-rgb), .55);
}
h1.screen small {
  display: block; font-family: var(--font-body); font-size: var(--t-small);
  font-weight: 400; letter-spacing: 0; color: var(--ink-2); margin-top: 6px;
}
.sec {
  font-family: var(--font-data);
  font-size: var(--t-label); letter-spacing: 2.5px; text-transform: uppercase;
  color: var(--portal); font-weight: 700;
  margin: 26px 0 12px; display: flex; align-items: center; gap: var(--s3);
}
.sec::after { content: ""; flex: 1; height: 1px; background: linear-gradient(90deg, var(--line), transparent); }

/* ── картки ──────────────────────────────────────────────────────────────── */
.card {
  background: linear-gradient(165deg, rgba(20, 22, 25, .975) 0%, rgba(12, 13, 15, .985) 100%);
  backdrop-filter: blur(6px);
  border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden; margin-bottom: 14px;
  transition: border-color .2s, box-shadow .2s, transform .2s;
}

@media (hover: hover) {
  .card:hover { border-color: var(--portal-mid); box-shadow: var(--glow); }
}
.card .body { padding: 14px 16px; }
.card h3 {
  font-family: var(--font-display); font-size: var(--t-h2); font-weight: 700;
  margin: 0 0 6px; letter-spacing: -.2px;
}
.card p { margin: 0 0 8px; font-size: var(--t-small); color: var(--ink-2); }

/* Велике зображення — головний носій настрою світу */
.banner {
  position: relative; width: 100%; aspect-ratio: 16 / 9;
  background:
    linear-gradient(160deg, var(--portal-dark) 0%, var(--panel) 60%, var(--void-2) 100%);
  display: grid; place-items: center; cursor: pointer; overflow: hidden;
}
.banner img { width: 100%; height: 100%; object-fit: cover; display: block; }
.banner .ph { font-size: 46px; opacity: .5; filter: drop-shadow(var(--glow)); }
.banner::after {
  content: "＋ фото"; position: absolute; right: 10px; bottom: 8px;
  font-family: var(--font-data); font-size: var(--t-label); letter-spacing: 1px;
  color: var(--acid); background: rgba(10, 11, 13, .78);
  padding: 3px 9px; border-radius: 999px; border: 1px solid var(--line);
}
.banner.readonly { cursor: default; }
.banner.readonly::after { content: none; }
.banner .veil {
  position: absolute; inset: auto 0 0 0; height: 58%;
  background: linear-gradient(180deg, transparent, rgba(10, 11, 13, .92));
  pointer-events: none;
}
.banner .cap {
  position: absolute; left: 16px; right: 16px; bottom: 12px;
  font-family: var(--font-display); font-size: var(--t-h1); font-weight: 800;
  letter-spacing: -.4px; text-shadow: 0 2px 14px #000;
}
/* Назва світу переносилась під «＋ фото» в куті й зливалась із кнопкою
   (04.11.2026). Відступ, а не `right`: смуга під назвою лишається на всю ширину.
   Другий селектор — бо `#ownerBody .banner .cap` задає padding через ID. */
.banner:not(.readonly) .cap,
#ownerBody .banner:not(.readonly) .cap { padding-right: 92px; }
/* портрет NPC / локації — квадратне, але велике */
.portrait { aspect-ratio: 1 / 1; }
.grid2 { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: var(--s3); }
.grid3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s2); }

/* ── пігулки стану ───────────────────────────────────────────────────────── */
.stats { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: 10px; }
.pill {
  font-family: var(--font-data); font-size: var(--t-label); font-weight: 700;
  padding: 4px 10px; border-radius: 999px; font-variant-numeric: tabular-nums;
  background: rgba(var(--portal-rgb), .13); border: 1px solid rgba(var(--portal-rgb), .35);
  color: var(--acid);
}
.pill.warn { background: rgba(245, 227, 92, .12); border-color: rgba(245, 227, 92, .4); color: var(--splash); }
.pill.dim  { background: rgba(168, 201, 164, .08); border-color: rgba(168, 201, 164, .22); color: var(--ink-3); }
.pill.hot  { background: rgba(255, 79, 139, .13); border-color: rgba(255, 79, 139, .4); color: var(--danger); }
.pill.info { background: rgba(53, 224, 245, .1); border-color: rgba(53, 224, 245, .35); color: var(--info); }

/* ── кнопки ──────────────────────────────────────────────────────────────── */
button, .btn {
  font-family: var(--font-body); font-size: var(--t-small); font-weight: 700;
  cursor: pointer; padding: 11px 16px; border-radius: var(--r-sm);
  border: 1px solid var(--portal-deep); min-height: 42px;
  background: linear-gradient(135deg, var(--portal-deep), var(--portal));
  color: #05230a; transition: box-shadow .2s, transform .12s;
}

@media (hover: hover) {
  button:hover { box-shadow: var(--glow-max); transform: translateY(-1px); }
}
button:active { transform: none; }
button:focus-visible { outline: 2px solid var(--acid); outline-offset: 2px; }
button.ghost { background: transparent; color: var(--acid); border-color: var(--line); }
button.tiny { padding: 6px 12px; min-height: 32px; font-size: var(--t-label); }
button.danger { background: transparent; color: var(--danger); border-color: rgba(255, 79, 139, .45); }
.actions { display: flex; gap: var(--s2); flex-wrap: wrap; margin-top: 12px; }

/* КНОПКА ЗАЙМАЄ ВСЮ ШИРИНУ СВОГО КОНТЕЙНЕРА.
   Кнопки росли по тексту й тулились ліворуч: «Поповнити ходи» займала
   третину рядка, «Перейменувати» з «Видалити» збивались у куток. На
   телефоні це читається як недоробка, а не як задум.
   `1 1 140px` замість `1 1 0`: двоє стають в один рядок і ділять його
   порівну, а пʼятеро не перетворюються на пʼять нечитабельних стовпчиків —
   вони переносяться й заповнюють свої рядки. */
.actions > button,
.actions > .btn,
.actions > a.btn { flex: 1 1 140px; min-width: 0; }

/* Поодинока кнопка просто в картці — теж на всю ширину. */
.card > .body > button,
.card > .body > .btn { width: 100%; }

/* ── форми ───────────────────────────────────────────────────────────────── */
input[type="text"], textarea, select {
  width: 100%; background: var(--void-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 9px 12px; font-family: var(--font-body); font-size: var(--t-body);
}
textarea { min-height: 90px; resize: vertical; line-height: 1.5; }
input:focus, textarea:focus, select:focus { outline: none; border-color: var(--portal); box-shadow: var(--glow); }
label.field { display: block; margin-bottom: 12px; }
label.field > span {
  display: block; font-family: var(--font-data); font-size: var(--t-label);
  letter-spacing: 1.4px; text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px;
}

/* ── таблиці ─────────────────────────────────────────────────────────────── */
.tablewrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: var(--t-small); }
th, td { text-align: left; padding: 9px 8px; border-bottom: 1px solid var(--line); }
td { font-variant-numeric: tabular-nums; }
th {
  font-family: var(--font-data); color: var(--portal);
  font-size: var(--t-label); text-transform: uppercase; letter-spacing: 1.4px;
}

/* ── онбординг ───────────────────────────────────────────────────────────── */
.hero {
  position: relative; overflow: hidden; border-radius: var(--r-lg);
  border: 1px solid var(--portal-mid); box-shadow: var(--glow);
  background: linear-gradient(145deg, var(--portal-dark) 0%, var(--panel) 55%, var(--void-2) 100%);
  padding: 22px 18px; margin-bottom: 18px;
}
.hero::before {
  content: ""; position: absolute; right: -70px; top: -80px;
  width: 230px; height: 230px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(var(--acid-rgb), .4) 0%, rgba(45, 122, 28, .15) 48%, transparent 72%);
  animation: swirl 18s linear infinite;
}
.hero h1 {
  position: relative; font-family: var(--font-display); font-size: var(--t-display);
  font-weight: 800; letter-spacing: -1px; line-height: 1.06; margin: 0 0 8px; text-wrap: balance;
}
.hero p { position: relative; margin: 0 0 14px; font-size: var(--t-body); color: var(--ink-2); }
.hero .actions { position: relative; }

.bar { height: 8px; border-radius: 999px; background: rgba(10, 11, 13, .75); overflow: hidden; margin: 12px 0 6px; }
.bar > i {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--portal-deep), var(--acid));
  box-shadow: var(--glow); transition: width .6s cubic-bezier(.2, .8, .2, 1);
}
.bar-label { font-family: var(--font-data); font-size: var(--t-label); color: var(--ink-3); letter-spacing: .6px; }

.steps { display: flex; flex-direction: column; gap: var(--s2); }
.step {
  display: flex; gap: var(--s3); align-items: flex-start; padding: 13px 14px;
  background: var(--panel); border-radius: var(--r-sm); border-left: 3px solid var(--line);
}
.step.now { border-left-color: var(--acid); background: rgba(var(--portal-rgb), .09); }
.step.done { opacity: .5; }
.step .mark { font-size: 17px; flex: none; }
.step b { display: block; font-size: var(--t-body); margin-bottom: 3px; }
.step span { font-size: var(--t-small); color: var(--ink-2); }

.tip {
  font-size: var(--t-small); padding: 11px 14px; border-radius: var(--r-sm);
  background: rgba(53, 224, 245, .06); border-left: 3px solid var(--info);
}

/* ПЕРЕЛІК ПОРАД — ОДИН ОБʼЄКТ, А НЕ ШІСТЬ ОДНАКОВИХ ПЛАШОК.
   Шість карток поспіль, кожна з власною рамкою і тінню, читались як шість
   окремих сутностей, хоч це один перелік: власник 21.09.2026 назвав це
   «негарно і безглуздо». Рамка, фон і заокруглення кажуть «окремий обʼєкт»,
   і платити ними шість разів за один список — це втрата ієрархії.
   Тепер панель одна, а рядки в ній розділені волоснею.
   Матеріал увесь наявний: фон і лінія картки, відступи зі шкали. */
.tips {
  display: flex; flex-direction: column;
  background: rgba(255, 255, 255, .028);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}
.tips .tip {
  background: none; border-left: none; border-radius: 0;
  padding: 13px 15px 13px 34px; position: relative;
  color: var(--ink-2); line-height: 1.5;
}
.tips .tip + .tip { border-top: 1px solid var(--line); margin-top: 0; }
/* Маркер — крапка, а не номер: поради рівноправні, і нумерація збрехала б
   про порядок, якого немає. */
.tips .tip::before {
  content: ""; position: absolute; left: 15px; top: 1.05em;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--info); opacity: .75;
}

.badge {
  display: inline-block; font-family: var(--font-data); font-weight: 700;
  font-size: 13px; letter-spacing: 1.4px; padding: 2px 8px; border-radius: var(--r-sm);
  background: var(--splash); color: #2a2400; margin-left: 8px; vertical-align: middle;
}

/* ── мапа ────────────────────────────────────────────────────────────────── */
.mapgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(165px, 1fr)); gap: var(--s3); }
.node {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 12px; font-size: var(--t-small);
}
.node.spawn { border-color: var(--splash); box-shadow: 0 0 14px rgba(245, 227, 92, .3); }
.node b { display: block; margin-bottom: 6px; font-size: var(--t-body); font-family: var(--font-display); }
.node .exits { color: var(--ink-3); font-size: var(--t-label); margin-top: 8px; line-height: 1.5; }

/* ── стани ───────────────────────────────────────────────────────────────── */
.empty { text-align: center; padding: 48px 20px; color: var(--ink-2); }
.empty .big { font-size: 52px; display: block; margin-bottom: 14px; filter: drop-shadow(var(--glow)); }
.err {
  background: rgba(255, 79, 139, .1); border: 1px solid var(--danger);
  color: #ffd9e6; padding: 13px 15px; border-radius: var(--r-sm);
  margin-bottom: 14px; font-size: var(--t-small);
}
.ok {
  background: rgba(var(--portal-rgb), .1); border: 1px solid var(--portal-mid);
  color: var(--ink); padding: 13px 15px; border-radius: var(--r-sm);
  margin-bottom: 14px; font-size: var(--t-small);
}
.loader { text-align: center; padding: 56px; }
.loader .px { width: 48px; height: 48px; margin: 0 auto; display: block;
  fill: var(--acid); animation: pixkrut .9s steps(12) infinite; }

/* ── НИЖНЯ НАВІГАЦІЯ ─────────────────────────────────────────────────────
   Фіксована, п'ять цілей, без горизонтального скролу: у Telegram свайп від
   краю закриває застосунок, тож стрічку вкладок, що їздить убік, чіпати не можна. */
.bottomnav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  display: grid; grid-template-columns: repeat(5, 1fr);
  background: rgba(16, 17, 20, .97);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  backdrop-filter: blur(12px);
}
.navitem {
  display: flex; flex-direction: column; align-items: center; gap: var(--s1);
  padding: 9px 4px 8px; cursor: pointer; color: var(--ink-3);
  font-size: 13px; font-weight: 600; border-top: 2px solid transparent;
  transition: color .18s, border-color .18s;
}
.navitem .ic { font-size: 19px; line-height: 1; }
.navitem.active { color: var(--acid); border-top-color: var(--acid); }
.navitem.active .ic { filter: drop-shadow(0 0 8px rgba(var(--acid-rgb), .8)); }

/* «Ще» — сітка розділів замість стрічки */
.menugrid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
/* Те, що стоїть ПІСЛЯ сітки, відділяється так само, як плитки між собою.
   Картка «Гра в бета-версії» лежала впритул: між кнопками 12px, а між
   кнопками й панеллю — нуль, тож вона читалась як пʼята плитка, що злиплась
   із рядом. Власник: «отступ виправ між оцією панеллю інформаційною і
   кнопками». */
.menugrid + .card,
.menugrid + .tip { margin-top: var(--s3); }
.menucard {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r);
  padding: 18px 14px; text-align: center; cursor: pointer; transition: background .2s, border-color .2s, transform .2s;
}

@media (hover: hover) {
  .menucard:hover { border-color: var(--portal); box-shadow: var(--glow); transform: translateY(-2px); }
}
.menucard .ic { font-size: 30px; display: block; margin-bottom: 8px; }
.menucard b { display: block; font-size: var(--t-body); font-family: var(--font-display); }
.menucard span { font-size: var(--t-label); color: var(--ink-3); }


/* ── ігровий режим: аркуш «Я» ────────────────────────────────────────────── */
.sheet { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--s3); margin-top: 12px; }
.stat {
  background: rgba(10, 11, 13, .6); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 12px 8px; text-align: center;
}
.stat b {
  display: block; font-family: var(--font-data); font-size: 24px;
  color: var(--acid); font-variant-numeric: tabular-nums; line-height: 1.1;
}
.stat span {
  font-family: var(--font-data); font-size: 13px; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--ink-3);
}

.hpbar { height: 12px; border-radius: 999px; background: rgba(10, 11, 13, .8); overflow: hidden; margin: 10px 0 4px; }
.hpbar > i { display: block; height: 100%; border-radius: 999px; transition: width .5s; }
.hpbar > i.full { background: linear-gradient(90deg, var(--portal-deep), var(--acid)); }
.hpbar > i.mid  { background: linear-gradient(90deg, #b58b1c, var(--splash)); }
.hpbar > i.low  { background: linear-gradient(90deg, #a02348, var(--danger)); }

.scene { display: flex; flex-direction: column; gap: var(--s2); }
.who-row {
  display: flex; align-items: center; gap: var(--s3); padding: 10px 12px;
  background: rgba(10, 11, 13, .5); border-radius: var(--r-sm); border-left: 3px solid var(--line);
}
.who-row.player { border-left-color: var(--info); }
.who-row.npc { border-left-color: var(--portal-mid); }
.who-row .av {
  width: 42px; height: 42px; flex: none; border-radius: var(--r-sm); overflow: hidden;
  background: var(--panel-2); display: grid; place-items: center; font-size: 19px;
}
.who-row .av img { width: 100%; height: 100%; object-fit: cover; }
.who-row b { display: block; font-size: var(--t-body); }
.who-row span { font-size: var(--t-small); color: var(--ink-3); }

.exits-list { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: 10px; }
.exit {
  font-family: var(--font-data); font-size: var(--t-small);
  padding: 8px 13px; border-radius: 999px;
  background: rgba(var(--portal-rgb), .1); border: 1px solid var(--portal-mid); color: var(--acid);
}
.inv-list { display: flex; flex-direction: column; gap: var(--s2); margin-top: 8px; }
.inv-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 9px 12px; background: rgba(10, 11, 13, .45); border-radius: var(--r-sm); font-size: var(--t-small);
}
.inv-row .q { font-family: var(--font-data); color: var(--splash); font-variant-numeric: tabular-nums; }

/* перемикач режиму */
.modeswitch {
  display: flex; gap: var(--s2); padding: 4px; margin-bottom: 14px;
  background: rgba(10, 11, 13, .6); border: 1px solid var(--line); border-radius: 999px;
}
.modeswitch div {
  flex: 1; text-align: center; padding: 9px; border-radius: 999px; cursor: pointer;
  /* Той самий дисплейний шрифт, що й у тумблері вітрини: два тумблери в
     одному застосунку мусять виглядати одним елементом, а не двома схожими. */
  font-family: var(--font-display);
  font-size: 15px; font-weight: 700; color: var(--ink-3); transition: color .18s, background .18s, border-color .18s;
}
.modeswitch div.on { background: linear-gradient(135deg, var(--portal-deep), var(--portal)); color: #05230a; }


/* ── графіки: sparkline на CSS-сітці ─────────────────────────────────────── */
.chart {
  display: flex; align-items: flex-end; gap: var(--s1); height: 110px;
  padding: 12px 0 0; border-bottom: 1px solid var(--line);
}
.chart .col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; gap: var(--s1); }
.chart .col i {
  display: block; border-radius: 3px 3px 0 0; min-height: 2px;
  background: linear-gradient(180deg, var(--acid), var(--portal-deep));
  transition: height .4s;
}
.chart .col i.ai { background: linear-gradient(180deg, var(--info), #1a7f92); }
.chart-x {
  display: flex; gap: var(--s1); margin-top: 6px;
  font-family: var(--font-data); font-size: 13px; color: var(--ink-3);
}
.chart-x span { flex: 1; text-align: center; }
.legend { display: flex; gap: var(--s4); margin-top: 10px; font-size: var(--t-label); color: var(--ink-3); }
.legend b { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; }

/* аватар бота в шапці */
.avatar {
  width: 38px; height: 38px; border-radius: 50%; flex: none; overflow: hidden;
  border: 2px solid var(--portal-mid); box-shadow: var(--glow);
}
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* завантажувач зображень */
.uploader {
  display: grid; grid-template-columns: 88px 1fr; gap: var(--s3); align-items: center;
  padding: 12px; background: rgba(7, 8, 9, .5); border-radius: var(--r-sm); margin-bottom: 10px;
}
.uploader .prev {
  width: 88px; height: 88px; border-radius: var(--r-sm); overflow: hidden;
  background: var(--panel-2); display: grid; place-items: center; font-size: 26px;
  border: 1px solid var(--line);
}
.uploader .prev img { width: 100%; height: 100%; object-fit: cover; }

input[type="range"] { width: 100%; accent-color: var(--portal); }


/* ── скелетони: макет замість спінера ────────────────────────────────────── */
@keyframes shimmer { 0% { background-position: -420px 0; } 100% { background-position: 420px 0; } }
.skel-h, .skel-img, .skel-line {
  background: linear-gradient(90deg,
    rgba(30, 69, 38, .35) 0%, rgba(var(--mid-rgb), .28) 50%, rgba(30, 69, 38, .35) 100%);
  background-size: 420px 100%;
  animation: shimmer 1.25s linear infinite;
  border-radius: var(--r-sm);
}
.skel-h { height: 40px; width: 62%; margin: 6px 0 18px; border-radius: var(--r-sm); }
.skel-card {
  border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden; margin-bottom: 14px; background: rgba(12, 13, 15, .8);
}
.skel-img { height: 128px; border-radius: 0; }
.skel-body { padding: 14px 16px; display: flex; flex-direction: column; gap: var(--s2); }
.skel-line { height: 12px; }
.skel-line.w70 { width: 70%; } .skel-line.w40 { width: 40%; } .skel-line.w90 { width: 90%; }

/* Поява екрана і натиск живуть у glass.css — тут їх немає навмисно.
   Два набори анімацій в різних файлах гарантовано розійдуться. */

@media (prefers-reduced-motion: reduce) {
  #view.in > *, .skel-h, .skel-img, .skel-line { animation: none !important; }
}


/* ── Читабельність поверх довільного фото ─────────────────────────────────
   Вуаль між фото і вмістом. Її щільність приходить із заміру яскравості
   (див. applyBackdrop), тому світло-зелене фото не з'їдає текст. */
/* ВУАЛЬ ОДНА, І ЖИВЕ У ЗМІННІЙ.
   Її малює не лише `body::after`, а ще й смуга під шапкою (`#hdrmask`), яка
   мусить збігтися з фоном ПІКСЕЛЬ У ПІКСЕЛЬ. Я вже раз скопіював ці числа
   руками — і взяв попереднє визначення, яке нижче перебите цим: копія
   вийшла темнішою за фон із першого ж дня. */
:root {
  --vual: linear-gradient(
    180deg,
    rgba(10, 11, 13, calc(var(--scrim) * .96)) 0%,
    rgba(10, 11, 13, calc(var(--scrim) * .82)) 42%,
    rgba(10, 11, 13, calc(var(--scrim) * .99)) 100%
  );
}
body::after { background: var(--vual) !important; }

/* Свічення допомагає на темному фоні і шкодить на світлому. */
:root[data-bg="light"] h1.screen { text-shadow: 0 2px 10px rgba(7, 8, 9, .98); }
:root[data-bg="light"] h1.screen em { text-shadow: none; color: #d8ff7a; }

/* ── Заголовок як вивіска ─────────────────────────────────────────────────
   Великий кегль сам по собі ще не читабельний: без щільного трекінгу і
   підкладки він розсипається на строкатому фоні. */
h1.screen {
  font-size: var(--t-display);
  font-weight: 900;
  letter-spacing: -2px;
  line-height: .96;
  text-transform: uppercase;
}
h1.screen em {
  /* Ключове слово іншою гарнітурою — щоб око чіплялось за суть, а не за
     початок рядка. Це той самий прийом, що й акцент у логотипі. */
  display: inline-block;
  font-size: 1.06em;
  letter-spacing: -1px;
  transform: rotate(-1.2deg);
  padding: 0 .12em;
  background: linear-gradient(180deg, transparent 62%, rgba(var(--portal-rgb), .22) 62%);
}
h1.screen small {
  /* Підзаголовок — речення, а не вивіска: капс тут лише сповільнює читання. */
  text-transform: none;
  font-weight: 500;
  letter-spacing: .1px;
  font-size: clamp(13px, 3.6vw, 16px);
  letter-spacing: .2px;
  opacity: .92;
  margin-top: 10px;
}
.hero h1 { font-size: var(--t-display); line-height: .95; letter-spacing: -2px; }
.sec { font-size: 13px; letter-spacing: 3px; }


/* ────────────────────────────────────────────────────────────────────────
   Далі — колишній glass.css
   ──────────────────────────────────────────────────────────────────────── */

/* ═══════════════════════════════════════════════════════════════════════════
   СКЛЯНИЙ ШАР — матеріали в дусі Apple HIG (Vibrancy & Materials) для
   Telegram Mini App.

   Головний принцип, від якого залежить усе інше: **скло не фарбується**.
   Заливка нейтральна (rgba(30,30,30,.4)), а колір приходить крізь неї з фону
   завдяки saturate(180%). Якби ми підмішали зелений у саму заливку, світло-
   зелене фото під склом дало б каламуть замість соковитого кольору.

   Швидкість: `backdrop-filter` — найдорожча операція мобільного рендеру, тож
   він живе ЛИШЕ на контейнерах (картки, панелі, хедер, навігація). Вкладені
   всередину рядки й пігулки отримують просту напівпрозору заливку: усередині
   вже розмитої поверхні власне розмиття однаково не видно, а кадри воно їсть.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Матеріали ─────────────────────────────────────────────────────────
     Дві щільності: звичайна для вмісту і густіша для панелей, що
     перекривають прокрутку (крізь хедер не має просвічувати текст). */
  /* З 30.10.2026 матеріали щільні, як картка «Мої ходи» (власник: «усі
     напівпрозорі елементи — з налаштуваннями як у плашки мої ходи, крім
     хедера»). Скляною лишилась лише шапка: вона сама задає `transparent`. */
  --mat:          rgba(20, 22, 25, .84);
  --mat-thick:    rgba(16, 17, 20, .9);
  --mat-hover:    rgba(30, 32, 36, .88);
  /* ОДНЕ МАТОВЕ СКЛО ДЛЯ ВСІХ ПАНЕЛЕЙ (31.10.2026, власник: «напівпрозорі
     затоновані, має трошечки фон крізь них просвічуватися, але не сильно,
     вони матові»). Тон — щільність .84, розмиття — те, що робить його
     матовим. */
  --mat-skl:      rgba(18, 20, 24, .84);
  --blur-mat:     blur(16px) saturate(140%);
  --mat-light:    rgba(255, 255, 255, .15);   /* світлі елементи поверх скла */

  /* Три щільності матеріалу. Плитки заливались БІЛОЮ плівкою поверх фото:
     світле по світлому, тому текст на них і губився. Скло затемнює, а не
     освітлює — тоді білому тексту є на чому триматись. Різниця між рівнями
     означає глибину вкладеності, а не декор. */
  --mat-1: rgba(18, 19, 22, .84);   /* тиха плитка всередині панелі     */
  --mat-2: rgba(20, 22, 25, .84);   /* інтерактивна: кнопка, поле, рядок */
  --mat-3: rgba(33, 35, 39, .9);    /* наведення й фокус                */

  /* ── Відблиск на грані ─────────────────────────────────────────────────
     Верхня грань світліша за решту: так поводиться реальне скло, коли світло
     падає згори, і саме ця дрібниця відрізняє «скло» від «прозорого блоку». */
  --edge:         rgba(255, 255, 255, .20);
  --edge-top:     rgba(255, 255, 255, .30);
  --edge-soft:    rgba(255, 255, 255, .10);

  /* ── Тіні ──────────────────────────────────────────────────────────────
     Мʼякі й багатошарові: широка розмита зовнішня плюс внутрішній волосок,
     що дає товщину. Жорстких тіней немає ніде. */
  --sh:      0 8px 32px 0 rgba(0, 0, 0, .12), 0 0 1px 0 rgba(0, 0, 0, .05) inset;
  --sh-lift: 0 12px 40px 0 rgba(0, 0, 0, .18), 0 0 1px 0 rgba(255, 255, 255, .1) inset;

  --blur: blur(20px) saturate(180%);

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

       xl  велика панель, модалка
       lg  картка, панель
       md  плитка всередині картки
       sm  чіп, пігулка, дрібний елемент

     Сирих пікселів у решті файлу бути не повинно: саме вони й дали 10/12/16/
     20/22 на одному екрані. */
  /* ШКАЛА ВІДСТУПІВ. Крок 4px — на ньому вже стояла більшість значень, просто
     ніхто цього не записав: у файлі було 57 різних padding і 12 різних gap,
     включно з парами 10/11/12 і 13/14, які око читає як недбалість, а не як
     задум.

       s1  4px   між значком і підписом
       s2  8px   між елементами в ряду
       s3  12px  внутрішній відступ дрібного блоку
       s4  16px  внутрішній відступ картки
       s5  20px  між секціями
       s6  24px  великі поля панелі */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;

  --r-xl: 24px;
  --r-lg: 20px;
  --r-md: 16px;
  --r-sm: 12px;
  /* Старе імʼя для --r-lg. Лишається заради місць, які ще ним користуються;
     нові правила пишуть --r-lg. */
  --r:    var(--r-lg);

  --ease: cubic-bezier(.2, .8, .2, 1);

  /* Текст поверх скла: легка тінь тримає його читабельним, коли під склом
     проходить світла ділянка фото. */
  --tsh: 0 1px 2px rgba(0, 0, 0, .35);
}

/* ── Базовий матеріал ───────────────────────────────────────────────────── */
.glass,
.card,
.menucard,
.tablewrap,
.chart,
.uploader,
.empty,
.tip,
.node,
.step,
.hero {
  background: var(--mat);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--edge);
  border-top-color: var(--edge-top);
  border-radius: var(--r-lg);
  box-shadow: var(--sh);
  transition: background .25s var(--ease), border-color .25s var(--ease),
              box-shadow .25s var(--ease), transform .14s var(--ease);
}

.hero { border-radius: var(--r-xl); }
.tip, .step, .node { border-radius: var(--r-md); }

@media (hover: hover) {
  .card:hover,
  .menucard:hover {
    background: var(--mat-hover);
    border-color: rgba(255, 255, 255, .28);
    box-shadow: var(--sh-lift);
    transform: none;              /* підйом заважає на дотику */
  }
}

/* ── Панелі, що перекривають вміст ──────────────────────────────────────── */
/* Нижня навігація стоїть НАД прокруткою, тож матеріал тут густіший: крізь
   напівпрозору панель текст, що під нею проїжджає, читається як шум.

   ШАПКИ ТУТ БІЛЬШЕ НЕМАЄ, і причина саме в тій умові. Під нею вміст тепер
   не проїжджає взагалі: його ховає смуга `#hdrmask`, яка малює той самий
   фон сторінки. Тобто підстава для густого матеріалу зникла, а сам він
   лишався — і затуляв фото, заради якого фон і ставили. Власник це побачив
   першим: «ти за хедером зробив чорну плашку, прибери її». */
.bottomnav,
.modeswitch {
  background: var(--mat-thick);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--edge);
  border-top-color: var(--edge-top);
  box-shadow: var(--sh);
}
.topbar {
  border-radius: var(--r-lg);
  /* Скло без заливки: розмиття бере саме те, що за шапкою, — а за нею
     лежить фон сторінки, не вміст. Тож напис і числа читаються, а Морті
     видно наскрізь. */
  background: transparent;
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--edge);
  border-top-color: var(--edge-top);
  /* БЕЗ ТІНІ. На заливці вона читалась як обʼєм, на прозорому склі — як
     темна пляма по контуру: власник 19.09.2026 показав її збільшеною —
     «по краях хедера не було оцієї чорної штуки». Тінь малює ТЕМРЯВУ
     довкола, а довкола тепер фон, заради якого заливку й прибрали. */
  box-shadow: none;
}
.modeswitch { border-radius: 999px; overflow: hidden; }
.bottomnav {
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  border-bottom: 0; border-left: 0; border-right: 0;
}

/* ── Вміст усередині скла: заливка без власного розмиття ────────────────── */
.stat,
.who-row,
.exit,
.inv-row,
.bar,
.hpbar,
.legend {
  background: var(--mat-2);
  border: 1px solid var(--edge-soft);
  border-radius: var(--r-md);
  backdrop-filter: none;
}

/* Згруповані списки як у iOS: одна коробка, рядки розділені волосинкою. */
.exits-list,
.inv-list {
  background: var(--mat-2);
  border: 1px solid var(--edge-soft);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.exits-list .exit,
.inv-list .inv-row {
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--edge-soft);
  border-radius: 0;
}
.exits-list .exit:last-child,
.inv-list .inv-row:last-child { border-bottom: 0; }

.pill {
  background: var(--mat-2);
  border: 1px solid var(--edge);
  text-shadow: var(--tsh);
}
.pill.warn { background: rgba(245, 227, 92, .2);  border-color: rgba(245, 227, 92, .4); }
.pill.hot  { background: rgba(255, 79, 139, .2);  border-color: rgba(255, 79, 139, .4); }
.pill.info { background: rgba(53, 224, 245, .18); border-color: rgba(53, 224, 245, .4); }
.pill.dim  { background: var(--mat-2); border-color: var(--edge-soft); }

/* ── Типографіка поверх скла ────────────────────────────────────────────── */
/* Тінь ледь помітна, але саме вона рятує текст у момент, коли під склом
   проходить світла ділянка фото. */
.card h3, .card p, .menucard b, .menucard span,
.stat b, .stat span, .who-row b, .who-row span,
.node b, .step b, .tip, .brand, .who, .navitem {
  text-shadow: var(--tsh);
}

h1.screen {
  text-shadow: 0 2px 4px rgba(0, 0, 0, .45), 0 8px 30px rgba(0, 0, 0, .3);
}
h1.screen em {
  /* Ключове слово іншим накресленням і з підсвіченою підкладкою — око
     чіпляється за суть, а не за початок рядка. */
  background: linear-gradient(180deg, transparent 60%, rgba(var(--acid-rgb), .28) 60%);
  text-shadow: 0 2px 4px rgba(0, 0, 0, .5), 0 0 24px rgba(var(--acid-rgb), .35);
}

/* ── Кнопки ─────────────────────────────────────────────────────────────── */
/* 40px (власник 25.10.2026: «панельки й іконки на всіх сторінках чуть
   меншими, як на сторінці оплати»). Було 48 — з запасом на промах пальцем,
   але кнопки виходили вдвічі вищими за рядки оплати, і кожна картка сесії
   займала пів екрана. 40 — як `h-10` у shadcn: палець влучає, екран дихає.
   Головна кнопка світиться, щоб її було видно на склі; решта — скляні. */
button, .btn {
  min-height: 40px;
  padding: 9px 16px;
  border-radius: var(--r-md);
  font-weight: 600;
  border: 1px solid rgba(255, 255, 255, .25);
  border-top-color: rgba(255, 255, 255, .4);
  background: linear-gradient(180deg, rgba(168, 232, 74, .95) 0%, rgba(var(--mid-rgb), .95) 100%);
  color: #06240b;
  text-shadow: none;
  box-shadow: 0 4px 16px rgba(var(--portal-rgb), .3),
              0 0 1px 0 rgba(255, 255, 255, .35) inset;
  transition: background .25s var(--ease), box-shadow .25s var(--ease),
              transform .12s var(--ease);
}

@media (hover: hover) {
  button:hover {
    background: linear-gradient(180deg, rgba(184, 245, 92, 1) 0%, rgba(92, 184, 50, 1) 100%);
    box-shadow: 0 6px 22px rgba(var(--portal-rgb), .45),
                0 0 1px 0 rgba(255, 255, 255, .5) inset;
    transform: none;
  }
}

button.ghost, button.tiny {
  background: var(--mat-light);
  backdrop-filter: blur(12px) saturate(180%);
  -webkit-backdrop-filter: blur(12px) saturate(180%);
  border: 1px solid var(--edge);
  border-top-color: var(--edge-top);
  color: #fff;
  text-shadow: var(--tsh);
  box-shadow: var(--sh);
}

@media (hover: hover) {
  button.ghost:hover, button.tiny:hover {
    background: var(--mat-3);
    box-shadow: var(--sh-lift);
  }
}
button.tiny { min-height: 34px; padding: 7px 12px; border-radius: var(--r-sm); }

button.danger {
  background: rgba(255, 79, 139, .22);
  border: 1px solid rgba(255, 79, 139, .45);
  color: #ffe3ee;
  text-shadow: var(--tsh);
  box-shadow: var(--sh);
}

@media (hover: hover) {
  button.danger:hover { background: rgba(255, 79, 139, .34); box-shadow: var(--sh-lift); }
}

/* НАТИСК: СТИСК — АЛЕ ЛИШЕ НА ТОМУ, ЩО СПРАВДІ НАТИСКАЄТЬСЯ.

   Палець закриває кнопку, тож зсув на пікселі під ним не видно, а зміна
   розміру відчувається навіть наосліп. Саме тому стиск не можна давати
   всьому підряд: він ОБІЦЯЄ дію. Власник 19.09.2026: «картки натякають, що з
   ними можна взаємодіяти, як кнопка зменшується — але це ж не так, то просто
   інфа».

   Перелік класів тут і був пасткою: `.card` ужито 96 разів і ЖОДНОГО разу з
   обробником, `.inv-row` — 14 разів і теж жодного. Клас каже, як воно
   виглядає, а не що станеться.

   Тому питаємо не назву, а наявність обробника. Гра вішає їх інлайном, тож
   `[onclick]` — це рівно перелік того, що відповідає на дотик, і він не
   застаріє від наступної картки. */
/* Анімацію натискання (стиск, зсув) знято (власник, 31.10.2026: «дивна»):
   кнопки, картки й аватарки не стискаються під пальцем. */
button:active, .btn:active, a:active,
[onclick]:active, [role="button"]:active {
  transform: none;
}

/* ── Поля вводу ─────────────────────────────────────────────────────────── */
input[type="text"], textarea, select {
  min-height: 42px;
  background: var(--mat-2);
  backdrop-filter: blur(12px) saturate(180%);
  -webkit-backdrop-filter: blur(12px) saturate(180%);
  border: 1px solid var(--edge);
  border-top-color: var(--edge-top);
  border-radius: var(--r-md);
  color: #fff;
}
input::placeholder, textarea::placeholder { color: rgba(255, 255, 255, .45); }
input:focus, textarea:focus, select:focus {
  background: var(--mat-3);
  border-color: rgba(var(--acid-rgb), .6);
  outline: none;
  box-shadow: 0 0 0 4px rgba(var(--acid-rgb), .16);
}

/* ── Аватар бота ────────────────────────────────────────────────────────── */
/* Кругла лінза зі скляною оправою: аватар має читатись як елемент інтерфейсу,
   а не як вставлена картинка. */
/* Лише аватар: `.portal-dot` — анімований спінер, і скляна оправа на ньому
   коштувала б кадрів саме тоді, коли їх найменше. */
.avatar {
  border-radius: 50%;
  border: 1px solid var(--edge-top);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .28),
              0 0 0 1px rgba(255, 255, 255, .08) inset;
  overflow: hidden;
  background: var(--mat);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
}
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.who-row .av { border-radius: 50%; border: 1px solid var(--edge); overflow: hidden; }

/* ── Повідомлення ───────────────────────────────────────────────────────── */
.err, .ok {
  background: var(--mat);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--edge);
  border-top-color: var(--edge-top);
  border-radius: var(--r-md);
  box-shadow: var(--sh);
  text-shadow: var(--tsh);
}
.err { border-color: rgba(255, 79, 139, .45); }
.ok  { border-color: rgba(var(--portal-rgb), .45); }

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

   `overflow-anchor: none` — бо позицію прокрутки ми відновлюємо самі; без
   цього браузер робить те саме вдруге й вони змагаються. */
#view {
  min-height: 60vh;
  overflow-anchor: none;
}

/* Зображення не розсовує верстку, поки вантажиться. Контейнери в цьому файлі
   майже всі мають власний розмір (`width/height` + `object-fit: cover`), але
   правило нижче страхує ті, що зʼявляться потім. */
img {
  max-width: 100%;
}

/* ── Поява екрана ───────────────────────────────────────────────────────── */
/* Каскад знизу: око встигає прочитати структуру екрана, замість того щоб
   отримати все одночасно.

   ПРОЗОРІСТЬ ЗВІДСИ ПРИБРАНО. Гравець описав це так: «коли відкриваєш,
   відразу вони більш прозорі, а потім стають менш прозорими», і показав два
   кадри вкладки «Ще» з різницею в частку секунди — на першому крізь картки
   «Мої герої», «Друзі», «Мій світ» просвічує тло.

   Це й був `opacity: 0 → 1` за півсекунди: картка справді напівпрозора всю
   анімацію, і на строкатому фоні це читається не як поява, а як недомальований
   екран. Матеріал .62 підбирали саме для читабельності — а фейд щоразу
   проводив картку через усі значення від нуля до нього.

   Лишився рух: він дає те саме відчуття появи, але картка від першого кадру
   тієї щільності, яку гравець і має бачити.

   Каскадні затримки прибрано разом із фейдом — без прозорості елемент під час
   затримки не «чекає невидимим», а видимо стоїть зміщеним, і це помітно
   гірше за одночасну появу. */
@keyframes glassUp {
  from { transform: translateY(14px) scale(.99); }
  to   { transform: translateY(0) scale(1); }
}
#view.in > * { animation: glassUp .26s var(--ease) both; }

/* Скелетони — того ж матеріалу, інакше момент завантаження виглядає як інший
   застосунок. */
.skel-card {
  background: var(--mat);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--edge);
  border-radius: var(--r-lg);
}
.skel-h, .skel-img, .skel-line {
  background: rgba(255, 255, 255, .1);
  border-radius: var(--r-sm);
}

/* ── Межі можливостей ───────────────────────────────────────────────────── */
/* Старий WebView без backdrop-filter показав би замість скла прозорий блок, у
   якому текст лежить просто на фото. Там матеріал стає непрозорим. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass, .card, .menucard, .topbar, .bottomnav, .hero, .modeswitch,
  .tablewrap, .chart, .uploader, .empty, .tip, .node, .step,
  .err, .ok, .skel-card, button.ghost, button.tiny {
    background: rgba(18, 19, 22, .95);
  }
  input[type="text"], textarea, select { background: rgba(18, 19, 22, .9); }
}

/* Рух — не для всіх. Це вимога доступності, а не налаштування. */
@media (prefers-reduced-motion: reduce) {
  #view.in > *, .skel-h, .skel-img, .skel-line { animation: none !important; }
  button:active, .btn:active, a:active,
  [onclick]:active, [role="button"]:active { transform: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ТИПОГРАФІКА — акцидентна пара

   Дві гарнітури з різних світів, і саме контраст між ними робить заголовок
   заголовком: Unbounded — широкий геометричний гротеск, який читається як
   вивіска; Playfair Display Italic — курсивна антиква з високим контрастом
   штрихів. Поставлені поруч в одному слові, вони дають те саме, що в наборі
   зветься зміною накреслення: око бачить, де головне.

   Текст, який читають (а не впізнають), лишається системним: у Mini App
   рідний шрифт телефона виграє і в швидкості, і у відчутті «свого».
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Unbounded набагато ширший за звичайний гротеск, тож кегль для нього
     менший — інакше «МУЛЬТИВСЕСВІТ» не влазить в екран телефона. */
  --t-display: clamp(24px, 7vw, 34px);
  --font-display: "Unbounded", "Segoe UI", system-ui, sans-serif;
  --font-accent:  "Playfair Display", Georgia, "Times New Roman", serif;
}

/* ── Назва в шапці ──────────────────────────────────────────────────────── */
/* Половина слова гротеском, половина курсивною антиквою. Це та сама «одна
   назва», але око читає її як знак, а не як рядок тексту. */
.brand {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(15px, 4.4vw, 20px);
  letter-spacing: -.02em;
  line-height: 1;
  text-transform: uppercase;
  text-shadow: var(--tsh);
}
.brand span {
  font-family: var(--font-accent);
  font-style: italic;
  font-weight: 900;
  font-size: 1.16em;
  letter-spacing: 0;
  text-transform: none;
  color: var(--magenta);
  text-shadow: 0 0 18px rgba(255, 106, 213, .5), var(--tsh);
}

/* ── Заголовок екрана ───────────────────────────────────────────────────── */
h1.screen {
  font-family: var(--font-display);
  font-size: var(--t-display);
  font-weight: 900;
  letter-spacing: -.035em;
  line-height: .94;
  text-transform: uppercase;
  text-wrap: balance;
}
/* Ключове слово — курсивною антиквою в нижньому регістрі: різниця в накресленні
   ТА в регістрі, тож акцент видно навіть краєм ока. */
h1.screen em {
  font-family: var(--font-accent);
  font-style: italic;
  font-weight: 900;
  font-size: 1.2em;
  letter-spacing: -.01em;
  text-transform: none;
  color: var(--violet);
}
h1.screen small {
  font-family: var(--font-body);
  text-transform: none;
  font-weight: 500;
}

/* Рубрики — розрідженим гротеском: вони мають читатись як покажчики, а не
   змагатися із заголовком. */
.sec {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 13px;
  letter-spacing: .18em;
  text-transform: uppercase;
}

/* Назви карток і плиток — тим самим акцидентом, але дрібно. */
.card h3, .menucard b, .node b, .step b {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -.02em;
}

/* Числа лишаються моноширинними: у статистиці колонки мають шикуватись. */
.stat b, .who b, .pill { font-variant-numeric: tabular-nums; }

/* ── Сфера аватара бота ─────────────────────────────────────────────────── */
/* Порожня — світиться порталом; із фото — стає лінзою в скляній оправі.
   Обидва стани однакового розміру, щоб шапка не сіпалась при завантаженні. */
.avatar {
  width: 44px; height: 44px; flex: none;
  border-radius: 50%;
}
.avatar {
  border: 1.5px solid var(--edge-top);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .35),
              0 0 22px rgba(var(--portal-rgb), .3),
              0 0 0 1px rgba(255, 255, 255, .1) inset;
  background: var(--mat);
  overflow: hidden;
}

/* ═══════════════════════════════════════════════════════════════════════════
   КАРТКА ПЕРСОНАЖА
   Портрет ліворуч, стан праворуч — так само, як влаштований будь-який
   документ із фото: спершу обличчя, потім дані.
   ═══════════════════════════════════════════════════════════════════════════ */
.idcard {
  display: flex;
  align-items: center;
  gap: var(--s4);
  margin-bottom: 14px;
}
.idcard-meta { flex: 1; min-width: 0; }

/* Порожня рамка — це не «немає фото», а запрошення його поставити, тому вона
   клікабельна і показує це виглядом. */
.portrait-slot {
  position: relative;
  width: 92px; height: 92px; flex: none;
  border-radius: var(--r-lg);
  overflow: hidden;
  cursor: pointer;
  background: var(--mat-1);
  border: 1px solid var(--edge);
  border-top-color: var(--edge-top);
  box-shadow: var(--sh);
  display: flex; align-items: center; justify-content: center;
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease), transform .12s var(--ease);
}
.portrait-slot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.portrait-slot .ph { font-size: 40px; opacity: .5; }
.portrait-slot .edit {
  position: absolute; right: 5px; bottom: 5px;
  width: 26px; height: 26px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px;
  background: var(--mat-thick);
  backdrop-filter: blur(12px) saturate(180%);
  -webkit-backdrop-filter: blur(12px) saturate(180%);
  border: 1px solid var(--edge-top);
}

@media (hover: hover) {
  .portrait-slot:hover { border-color: rgba(var(--acid-rgb), .55); box-shadow: var(--sh-lift); }
}
.portrait-slot:active { transform: none; }
/* Чужа анкета: дивитись можна, міняти — ні, і це має бути видно. */
.portrait-slot.ro { cursor: default; }

@media (hover: hover) {
  .portrait-slot.ro:hover { border-color: var(--edge); box-shadow: var(--sh); }
}
.portrait-slot.ro:active { transform: none; }

/* Рядок сусіда веде до анкети, тож у нього є стрілка — без неї
   клікабельність доводиться вгадувати. */
.who-row.player { cursor: pointer; }
.who-row .chev {
  margin-left: auto;
  font-size: 22px; line-height: 1;
  color: var(--ink-3);
  padding-left: 8px;
}
.who-row .av img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ═══════════════════════════════════════════════════════════════════════════
   ГРАФ ЛОКАЦІЙ
   Вузол — локація, ребро — перехід. Кольором і формою закодовано те, що
   справді треба знати: де вхід, куди лише в один бік, що недосяжне.
   ═══════════════════════════════════════════════════════════════════════════ */
.graphwrap {
  position: relative;
  height: 62vh; min-height: 320px; max-height: 560px;
  margin: 12px -6px 4px;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: rgba(0, 0, 0, .18);
  border: 1px solid var(--edge-soft);
  /* Тягнемо граф пальцем, тож вертикальний скрол сторінки тут вимкнено. */
  touch-action: none;
  cursor: grab;
}
.graphwrap:active { cursor: grabbing; }
.graph { width: 100%; height: 100%; display: block; }

.edge {
  stroke: rgba(255, 255, 255, .22);
  stroke-width: 2;
}
/* Односторонній перехід виділено: «увійшов і не вийшов» — це властивість
   локації, а не дрібниця оформлення. */
.edge.oneway {
  stroke: rgba(245, 227, 92, .55);
  stroke-dasharray: 7 5;
}
.arrowhead { fill: rgba(245, 227, 92, .8); }

.gnode { cursor: pointer; }
.gnode circle {
  fill: rgba(30, 30, 30, .72);
  stroke: rgba(255, 255, 255, .3);
  stroke-width: 1.5;
  transition: fill .2s var(--ease), stroke .2s var(--ease), r .2s var(--ease);
}
.gnode:active circle { stroke-width: 3; }
.gnode.spawn circle {
  fill: rgba(var(--mid-rgb), .8);
  stroke: var(--acid);
  stroke-width: 2.5;
}
.gnode.deadend circle { stroke: rgba(245, 227, 92, .6); stroke-dasharray: 4 3; }
.gnode.orphan  circle { stroke: rgba(255, 79, 139, .75); stroke-dasharray: 3 3; }
.gnode.sel circle { fill: rgba(var(--portal-rgb), .55); stroke: var(--acid); stroke-width: 3; }

/* «Ти тут» — головне, заради чого дивляться на карту. Пульсуюче кільце, а не
   заливка: заливкою вже позначені спавн і вибір, і третій колір на тому
   самому місці читався б як четвертий стан. */
.gnode.here circle {
  stroke: var(--acid);
  stroke-width: 3.5;
}
.here-ring {
  fill: none;
  stroke: var(--acid);
  stroke-width: 2;
  opacity: .5;
}
@media (prefers-reduced-motion: no-preference) {
  .here-ring { animation: hereBeat 2.4s var(--ease) infinite; }
}
/* Пульсуємо прозорістю й товщиною, а НЕ радіусом.
   `r` — геометрична властивість SVG, і хоч сучасні браузери її анімують,
   вебвʼю Telegram не той майданчик, де варто це припускати: непрацююча
   анімація тут не впаде з помилкою, вона просто мовчки не зʼявиться. */
@keyframes hereBeat {
  0%, 100% { opacity: .55; stroke-width: 2; }
  50%      { opacity: .15; stroke-width: 4; }
}

/* Вкладене місце: кімната в домі, підвал у таверні. Менше коло й тонка
   привʼязка до того, всередині чого воно. */
.gnode.nested circle { stroke-dasharray: none; opacity: .92; }
.nestlink {
  stroke: rgba(255, 255, 255, .18);
  stroke-width: 1.5;
  stroke-dasharray: 2 4;
}

/* Прохід, який не відкрити самому. Гравець має бачити це ДО того, як
   упреться: `requires_players` існує в базі з першого дня, а на карті його
   не було. */
.edge.gated {
  stroke: rgba(120, 190, 255, .7);
  stroke-dasharray: 10 4;
  stroke-width: 3;
}
.gatelabel {
  fill: rgba(120, 190, 255, .95);
  font-size: 13px; font-weight: 700;
  text-anchor: middle; pointer-events: none;
  font-family: var(--font-data);
}

.gnum {
  fill: #fff; font-size: 15px; font-weight: 700;
  text-anchor: middle; pointer-events: none;
  font-family: var(--font-data);
}
.glabel {
  fill: rgba(255, 255, 255, .92);
  font-size: 13px; font-weight: 600;
  text-anchor: middle; pointer-events: none;
  paint-order: stroke;
  stroke: rgba(0, 0, 0, .75); stroke-width: 3px; stroke-linejoin: round;
}

/* Клікабельні виходи в деталях вузла — ними ходять по графу, не гортаючи. */
.exits-list .exit { cursor: pointer; padding: 11px 14px; }

/* ═══════════════════════════════════════════════════════════════════════════
   ДАШБОРД СВІТІВ
   Два стовпчики на світ, бо це два різні питання: скільки грають і скільки
   це коштує. Одна шкала на двох злила б їх в одне безглузде число.
   ═══════════════════════════════════════════════════════════════════════════ */
.wlist { display: flex; flex-direction: column; gap: var(--s3); margin-top: 14px; }

.wrow {
  padding: 12px 14px;
  border-radius: var(--r-lg);
  background: var(--mat-2);
  border: 1px solid var(--edge-soft);
  cursor: pointer;
  transition: background .2s var(--ease), border-color .2s var(--ease), transform .12s var(--ease);
}

@media (hover: hover) {
  .wrow:hover { background: var(--mat-3); border-color: var(--edge); }
}
/* `.wrow` — рядок довідки, не кнопка: жодного обробника на ньому немає. */

.wname b {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -.02em;
  text-shadow: var(--tsh);
}
.wname span { font-size: 13px; color: var(--ink-3); }

.wbars { display: flex; flex-direction: column; gap: var(--s2); margin-top: 10px; }
.wbar {
  position: relative;
  height: 22px;
  border-radius: var(--r-sm);
  background: rgba(0, 0, 0, .28);
  overflow: hidden;
}
.wbar > i {
  position: absolute; inset: 0 auto 0 0;
  background: linear-gradient(90deg, rgba(var(--mid-rgb), .85), rgba(var(--portal-rgb), .85));
  border-radius: var(--r-sm);
}
.wbar.cost > i {
  background: linear-gradient(90deg, rgba(196, 168, 40, .8), rgba(245, 227, 92, .85));
}
/* Дорожчий за середнє — рожевим. Це не «погано», це «подивись сюди». */
.wbar.cost.hot > i {
  background: linear-gradient(90deg, rgba(196, 40, 90, .8), rgba(255, 79, 139, .9));
}
.wbar > span {
  position: relative; z-index: 1;
  display: block; padding: 3px 10px;
  font-size: 13px; font-weight: 700;
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .85);
}

/* Мітка живих даних: спалахує, коли екран сам перемалювався. Постійно світити
   не можна — це перетворило б корисний сигнал на шум. */
.livedot {
  width: 7px; height: 7px; flex: none;
  border-radius: 50%;
  background: var(--acid);
  opacity: 0;
  margin-left: 6px;
}
.livedot.on { animation: livePulse 1.9s var(--ease); }
@keyframes livePulse {
  0%   { opacity: 0; transform: scale(.4); box-shadow: 0 0 0 0 rgba(var(--acid-rgb), .6); }
  18%  { opacity: 1; transform: scale(1); box-shadow: 0 0 0 6px rgba(var(--acid-rgb), 0); }
  100% { opacity: 0; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) { .livedot.on { animation: none; } }

/* ═══════════════════════════════════════════════════════════════════════════
   ХАОТИЧНА ТИПОГРАФІКА — розлом між всесвітами

   Вісім варіантів літери: три гарнітури з різних світів плюс обведення, зсув
   базової лінії, розтягнення і зміна регістру. Межі підібрані так, щоб
   зламаною була ФОРМА, а не читабельність: нахил до 6°, зсув до .08em,
   масштаб .9–1.16. Далі починається не стиль, а неможливість прочитати.

   Сила ефекту задається кількістю дозволених варіантів (див. CHAOS_TARGETS):
   заголовок отримує всі вісім, підпис під цифрою — лише перші чотири.
   ═══════════════════════════════════════════════════════════════════════════ */
.chaos { display: inline; }
.chaos i { font-style: normal; display: inline-block; }

/* c0 — спокійна: перша літера кожного слова, за неї око чіпляється першим. */
.chaos i.c0 { font-family: var(--font-display); font-weight: 900; }

/* c1 — курсивна антиква, кислотним. Найпомітніший розрив у ряду. */
.chaos i.c1 {
  font-family: var(--font-accent);
  font-style: italic; font-weight: 900;
  transform: rotate(-4deg) translateY(-.03em) scale(1.1);
  /* Кольору тут немає навмисно: за колір відповідають окремі класи, і коли
     форма фарбувала сама, зелений просочувався в акценти. */
}
/* c2 — технічна моноширинна: літера з іншої, інженерної реальності. */
.chaos i.c2 {
  font-family: "JetBrains Mono", var(--font-data);
  font-weight: 800;
  transform: rotate(3deg) translateY(.04em) scale(.92);
  letter-spacing: -.04em;
}
/* c3 — розтягнення: та сама літера, але з всесвіту з іншою силою тяжіння. */
.chaos i.c3 {
  font-family: var(--font-display);
  font-weight: 700;
  transform: scaleY(1.16) scaleX(.94);
}
/* c4 — курсив у нижньому регістрі серед капсу: зміна не лише форми, а й ладу. */
.chaos i.c4 {
  font-family: var(--font-accent);
  font-style: italic; font-weight: 700;
  transform: rotate(5deg) translateY(.05em) scale(1.04);
  text-transform: lowercase;
}
/* c5 — моноширинна жовтим, збільшена. */
.chaos i.c5 {
  font-family: "JetBrains Mono", var(--font-data);
  font-weight: 800;
  transform: rotate(-2.5deg) scale(1.14);
}
/* c6 — порожня літера: лише контур, ніби її речовина лишилась у своєму світі. */
.chaos i.c6 {
  font-family: var(--font-display);
  font-weight: 900;
  color: transparent;
  -webkit-text-stroke: 1px var(--cyan);
  text-stroke: 1px var(--cyan);
  transform: translateY(-.05em) scale(1.02);
}
/* c7 — зсунута базова лінія: літера провалилась крізь рядок. */
.chaos i.c7 {
  font-family: var(--font-accent);
  font-weight: 900;
  transform: translateY(.09em) rotate(-6deg) scale(1.06);
}

/* Дрібний текст обведенням не беремо: на 11–13px контур зʼїдає саму літеру. */
.stat span .chaos i.c6,
.who-row b .chaos i.c6,
button .chaos i.c6 {
  color: inherit;
  -webkit-text-stroke: 0;
}

/* ── Глітч ────────────────────────────────────────────────────────────────
   Розшарування на канали спрацьовує рідко і коротко: постійний глітч читається
   як зламаний екран, а не як ефект. Раз на дванадцять секунд — та частота, на
   якій його помічають, але не втомлюються від нього. */
h1.screen .chaos { animation: rift 12s steps(1) infinite; }
@keyframes rift {
  0%, 92%, 100% { text-shadow: 0 2px 4px rgba(0, 0, 0, .45); }
  93% { text-shadow: -2px 0 rgba(255, 79, 139, .9), 2px 0 rgba(53, 224, 245, .9), 0 2px 4px rgba(0,0,0,.45); }
  94% { text-shadow: 3px 0 rgba(53, 224, 245, .9), -3px 0 rgba(var(--acid-rgb), .9), 0 2px 4px rgba(0,0,0,.45); }
  95% { text-shadow: -1px 0 rgba(255, 79, 139, .8), 0 2px 4px rgba(0, 0, 0, .45); }
}

/* Рубрики глітчать у свою фазу — щоб розломи не збігалися в один спалах. */
.sec .chaos { animation: rift 19s steps(1) 4s infinite; }

/* Назва в шапці на екрані постійно, тож тут ефект ще стриманіший. */
.brand { animation: riftBrand 17s steps(1) infinite; }
@keyframes riftBrand {
  0%, 96%, 100% { transform: none; text-shadow: var(--tsh); }
  97% { transform: translateX(-1.5px) skewX(-3deg);
        text-shadow: 2px 0 rgba(53, 224, 245, .8), -2px 0 rgba(255, 79, 139, .8); }
  98% { transform: translateX(1.5px) skewX(2deg);
        text-shadow: -2px 0 rgba(var(--acid-rgb), .8); }
}

/* Рубрики зсунуті з осі: підпис, що трохи «зʼїхав», читається як слід зсуву
   між шарами, а не як помилка верстки. */
.sec { transform: translateX(-2px) rotate(-.4deg); transform-origin: left center; }
.sec:nth-of-type(even) { transform: translateX(3px) rotate(.35deg); }

/* Картки теж ледь збиті з сітки — рівний стос виглядав би як таблиця, а не як
   уламки світів. Кут мікроскопічний: помітно на стосі, непомітно на одній. */
.card:nth-of-type(3n+1)  { transform: rotate(-.22deg); }
.card:nth-of-type(3n+2)  { transform: rotate(.18deg); }
.menucard:nth-child(odd) { transform: rotate(-.4deg); }
.menucard:nth-child(even){ transform: rotate(.35deg); }

@media (prefers-reduced-motion: reduce) {
  h1.screen .chaos, .sec .chaos, .brand { animation: none; }
  .chaos i { transform: none !important; }
  .card, .menucard, .sec { transform: none !important; }
}


/* ── Колір як окремий вимір розлому ───────────────────────────────────────
   Раніше колір ішов у комплекті з гарнітурою, і поєднань було рівно стільки,
   скільки варіантів. Тепер відтінок призначається окремо, тож одна й та сама
   форма може прийти з різного світу. Палітра — портальна: усі відтінки
   тримають контраст ≥ 7:1 на склі, тож це розлом, а не втрата читабельності. */
.chaos i.k1 { color: var(--cyan); }
.chaos i.k2 { color: var(--amber); }
.chaos i.k3 { color: var(--info); }
.chaos i.k4 { color: #ff9ec4; }
.chaos i.k5 { color: #a8e84a; }
.chaos i.k6 { color: #eef7e6; }

/* На головній кнопці тло світло-зелене, тож світлі відтінки там нечитабельні —
   лишаємо власний темний колір кнопки. */
button .chaos i[class*="k"] { color: inherit; }

/* ── Назва застосунку ─────────────────────────────────────────────────────
   «МУЛЬТИ» гротеском, «ВСЕСВІТ» курсивною антиквою — і кожна літера свого
   кольору й нахилу. Це не заголовок, це знак: його впізнають, а не читають,
   тож розлому тут можна більше, ніж будь-де. */
.brand { display: inline-flex; align-items: baseline; gap: .02em; }
.brand .chaos i {
  transition: transform .25s var(--ease), color .25s var(--ease);
}

@media (hover: hover) {
  .brand:hover .chaos i:nth-child(odd)  { transform: translateY(-.08em) rotate(-4deg); }
}

@media (hover: hover) {
  .brand:hover .chaos i:nth-child(even) { transform: translateY(.08em) rotate(4deg); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ЧИТАБЕЛЬНІСТЬ І ПЕРЕНОСИ
   ═══════════════════════════════════════════════════════════════════════════ */

/* Слово не рветься навпіл. Кожна літера — окремий inline-block, тож без цього
   браузер має право перенести рядок між будь-якими двома з них. */
.chaos .w { white-space: nowrap; display: inline-block; }

/* Назва застосунку мусить лишатись в один рядок і просто зменшуватись:
   перенесене навпіл імʼя виглядає як помилка, а не як стиль. */
.brand {
  white-space: nowrap;
  font-size: clamp(13px, 3.6vw, 19px);
  min-width: 0;
}
.topbar { gap: var(--s3); }
.who { flex: none; }

/* Довгі назви світів на обкладинці — теж без розривів усередині слова. */
.banner .cap { overflow-wrap: break-word; hyphens: none; }
.card h3, .menucard b, .wname b { overflow-wrap: anywhere; }

/* ── Контраст приглушеного тексту ─────────────────────────────────────────
   Ці відтінки бралися для темного тла. Під склом, крізь яке просвічує світле
   фото, вони зливаються з поверхнею — саме той текст, що «надто напівпрозорий».
   Піднімаємо світлість і додаємо тінь: тінь тут працює не як прикраса, а як
   межа між літерою і плямою фону, що проходить під склом. */
:root {
  --ink-2: #d3e8cd;
  --ink-3: #a6c2a2;
}
h1.screen small,
.card p,
.bar-label,
.who,
.legend,
.wname span,
.who-row span,
.stat span,
.step span {
  color: var(--ink-2);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6);
}
.pill.dim {
  background: var(--mat-1);
  border-color: rgba(255, 255, 255, .22);
  color: #e4f3e0;
}
.empty { color: var(--ink-2); }

/* Плитки і підписи в нижньому меню — теж світліші: вони дрібні й лежать на
   найщільнішому склі, де контраст падає найпомітніше. */
.navitem { color: #bcd6b8; }
.navitem.active { color: var(--acid); }

/* ═══════════════════════════════════════════════════════════════════════════
   АНОМАЛІЇ — рух на межі між світами

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

/* Скляні літери: прозорі, з відблиском по контуру. Ставляться зрідка — там,
   де слово має читатись як уламок, а не як текст. */
.chaos i.c8 {
  font-family: var(--font-display);
  font-weight: 900;
  color: rgba(255, 255, 255, .14);
  -webkit-text-stroke: .5px rgba(255, 255, 255, .55);
  text-stroke: .5px rgba(255, 255, 255, .55);
  text-shadow: 0 1px 0 rgba(255, 255, 255, .25), 0 -1px 0 rgba(0, 0, 0, .35);
  transform: skewX(-6deg);
}
/* На дрібному кеглі контур зʼїдає саму літеру — там скло вимикається. */
.stat span .chaos i.c8, .navitem .chaos i.c8, .who-row b .chaos i.c8 {
  color: inherit; -webkit-text-stroke: 0; text-shadow: var(--tsh);
}

/* Дрейф однієї літери: ледь помітне гойдання, ніби її тягне крізь розлом. */
@keyframes drift {
  0%, 88%, 100% { transform: translateY(0) rotate(0); }
  92% { transform: translateY(-.09em) rotate(-5deg); }
  96% { transform: translateY(.05em) rotate(3deg); }
}
.chaos i.c1 { animation: drift 23s var(--ease) infinite; }
.chaos i.c5 { animation: drift 31s var(--ease) 7s infinite; }
.chaos i.c7 { animation: drift 29s var(--ease) 13s infinite; }

/* Мерехтіння скляної літери: відблиск проходить по контуру. */
@keyframes glassSheen {
  0%, 90%, 100% { -webkit-text-stroke-color: rgba(255, 255, 255, .55); }
  95% { -webkit-text-stroke-color: rgba(255, 106, 213, .95); }
}
.chaos i.c8 { animation: glassSheen 37s steps(1) 3s infinite; }

/* Портал у порожній обкладинці дихає: картка без фото не має виглядати
   зламаною — вона має виглядати як ще не відкритий світ. */
@keyframes breathe {
  0%, 100% { transform: scale(1) rotate(0); opacity: .55; }
  50% { transform: scale(1.08) rotate(6deg); opacity: .8; }
}
.banner .ph { animation: breathe 11s ease-in-out infinite; display: inline-block; }

/* Скляний відблиск, що раз на хвилину проходить по картці — як світло іншого
   всесвіту крізь шов. Дорога операція, тож лише на картках, не на кожному рядку. */
.card::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 40%,
              rgba(255, 255, 255, .09) 48%, rgba(var(--acid-rgb), .07) 52%, transparent 60%);
  background-size: 260% 100%;
  background-position: 200% 0;
  animation: seam 43s linear infinite;
}
.card { position: relative; }
.card:nth-of-type(2n)::after { animation-delay: 17s; }
.card:nth-of-type(3n)::after { animation-delay: 29s; }
@keyframes seam {
  0%, 82% { background-position: 200% 0; }
  92%     { background-position: -60% 0; }
  100%    { background-position: -60% 0; }
}

/* Пігулки ледь підстрибують по черзі — маленький слід того, що світ живий. */
@keyframes nudge {
  0%, 94%, 100% { transform: translateY(0); }
  97% { transform: translateY(-2px); }
}
.pill { animation: nudge 19s var(--ease) infinite; }
.pill:nth-child(2n) { animation-delay: 5s; }
.pill:nth-child(3n) { animation-delay: 11s; }

@media (prefers-reduced-motion: reduce) {
  .chaos i, .banner .ph, .pill { animation: none !important; }
  .card::after { animation: none; opacity: 0; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ПАЛІТРА ЗІТКНЕННЯ

   Фон зелений, тож акценти взяті НЕ зеленими: колір, який повторює тло,
   акцентом бути не може. Взято протилежний бік кола — пурпур, фуксія, блакить —
   плюс жовтий і червоний як іскри розлому. Усі відтінки перевірені на склі:
   контраст до 7:1 і вище.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --violet:  #b98cff;
  --magenta: #ff4f8b;
  --cyan:    #35e0f5;
  --amber:   #f5e35c;
  --ember:   #ff6b5e;
  --starlit: #fff6c9;
}

/* Кольори літер тепер із протилежного боку кола — на зеленому фоні саме вони
   читаються як розлом, а не як його продовження. */
.chaos i.k1 { color: var(--cyan); }
.chaos i.k2 { color: var(--amber); }
.chaos i.k3 { color: var(--violet); }
.chaos i.k4 { color: var(--magenta); }
.chaos i.k5 { color: var(--ember); }
.chaos i.k6 { color: var(--starlit); }

/* Акцентні елементи теж переїжджають із зеленого. Портальний зелений лишається
   лише там, де він означає «твоє»: активна вкладка й головна дія. */
.pill        { border-color: rgba(185, 140, 255, .45); }
.pill.info   { background: rgba(79, 227, 255, .16);  border-color: rgba(79, 227, 255, .45);  color: #d5f7ff; }
.pill.warn   { background: rgba(255, 209, 102, .16); border-color: rgba(255, 209, 102, .45); color: #fff0c9; }
.pill.hot    { background: rgba(255, 107, 94, .16);  border-color: rgba(255, 107, 94, .45);  color: #ffdcd8; }
/* Рубрики — БІЛИМ. Кольоровий заголовок на темному склі читався гірше за
   текст під ним: власник 21.09.2026 назвав їх нечитабельними. Рубрика вказує
   на розділ, а не змагається з ним за увагу, тож колір їй ні до чого. */
.sec         { color: #fff; }
.card h3     { color: var(--starlit); }
.stat b      { color: var(--cyan); }
h1.screen em { color: var(--magenta); }

/* ── Зорі ─────────────────────────────────────────────────────────────────
   Розкидані по фону, різного розміру й ритму. Вони не несуть інформації, тож
   лежать під вмістом і не перехоплюють дотиків. */
.star {
  position: fixed;
  z-index: 0;
  pointer-events: none;
  border-radius: 50%;
  background: var(--starlit);
  box-shadow: 0 0 6px currentColor;
  color: var(--starlit);
  animation: twinkle var(--dur, 7s) ease-in-out var(--delay, 0s) infinite;
}
.star.c { background: var(--cyan);    color: var(--cyan); }
.star.m { background: var(--magenta); color: var(--magenta); }
.star.v { background: var(--violet);  color: var(--violet); }
@keyframes twinkle {
  0%, 100% { opacity: .18; transform: scale(.7); }
  50%      { opacity: .85; transform: scale(1.25); }
}

/* Хрестики-спалахи, як на ілюстрації розлому. */
.spark {
  position: fixed; z-index: 0; pointer-events: none;
  width: var(--s, 14px); height: var(--s, 14px);
  background:
    linear-gradient(var(--starlit), var(--starlit)) center/2px 100% no-repeat,
    linear-gradient(var(--starlit), var(--starlit)) center/100% 2px no-repeat;
  opacity: .5;
  animation: sparkPulse var(--dur, 9s) ease-in-out var(--delay, 0s) infinite;
}
@keyframes sparkPulse {
  0%, 100% { opacity: .12; transform: rotate(0) scale(.6); }
  50%      { opacity: .7;  transform: rotate(45deg) scale(1.1); }
}

/* ── Астероїди ────────────────────────────────────────────────────────────
   Пропливають екраном раз на кілька хвилин. Рідко навмисно: об'єкт, який
   постійно повзе перед очима, читається як несправність. */
.rock {
  position: fixed; z-index: 0; pointer-events: none;
  font-size: var(--s, 26px);
  opacity: .32;
  animation: floatBy var(--dur, 90s) linear var(--delay, 0s) infinite;
  filter: drop-shadow(0 0 8px rgba(185, 140, 255, .5));
}
@keyframes floatBy {
  from { transform: translate(-12vw, 0) rotate(0deg); }
  to   { transform: translate(115vw, -18vh) rotate(320deg); }
}

@media (prefers-reduced-motion: reduce) {
  .star, .spark, .rock { animation: none; opacity: .3; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   КНОПКИ — матове скло замість зеленої заливки

   Зелена кнопка на зеленому фоні втрачала межу. Матове скло з підсвіченим
   контуром видно на будь-якому тлі: воно не змагається з фоном кольором,
   а відрізняється від нього матеріалом.
   ═══════════════════════════════════════════════════════════════════════════ */
button, .btn {
  background: var(--mat-2);
  backdrop-filter: blur(18px) saturate(180%);
  -webkit-backdrop-filter: blur(18px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, .3);
  border-top-color: rgba(255, 255, 255, .45);
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .55);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .28),
              0 0 18px rgba(185, 140, 255, .25),
              0 0 1px 0 rgba(255, 255, 255, .5) inset;
  position: relative;
  overflow: hidden;
}

@media (hover: hover) {
  button:hover {
    background: var(--mat-3);
    border-color: rgba(255, 255, 255, .45);
    box-shadow: 0 8px 26px rgba(0, 0, 0, .34),
                0 0 26px rgba(255, 106, 213, .35),
                0 0 1px 0 rgba(255, 255, 255, .6) inset;
  }
}

/* Головна дія відрізняється не кольором заливки, а свіченням по краю: так вона
   лишається склом і водночас читається як «саме сюди». */
button:not(.ghost):not(.tiny):not(.danger)::before {
  content: "";
  position: absolute; inset: -1px;
  border-radius: inherit;
  pointer-events: none;
  /* Кант тими самими зеленими, що й заливка головної дії. Був
     бірюза → фіолет → рожевий → жовтий і ще й крутив увесь спектр
     (`hue-rotate(360deg)` за 14 с): кнопку зробили зеленою, а її край
     кожні кілька секунд однаково ставав синім. */
  background: linear-gradient(120deg,
    rgba(var(--acid-rgb), .60), rgba(var(--portal-rgb), .45),
    rgba(var(--mid-rgb), .40), rgba(var(--acid-rgb), .60));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  padding: 1px;
  opacity: .85;
}
/* Анімацію кольору знято зовсім: вона оберталась по всьому колу відтінків,
   тож будь-який кант рано чи пізно ставав синім. apple-design §14 до того ж
   радить уникати нескінченних повільних циклів — око щоразу відволікається
   на них, а на головній кнопці це ще й заважає прочитати напис. */

/* ── Піксельні мешканці ───────────────────────────────────────────────────
   Кіт, прибулець, НЛО й привид — намальовані box-shadow'ами по одному пікселю.
   Жодних зовнішніх файлів: це чистий CSS, тож вони не додають запитів і
   масштабуються зміною одного числа.

   Сидять на декоративних місцях і не перекривають нічого клікабельного. */
/* Мешканці живуть у власному шарі поверх фону, але під вмістом: вони
   декорація, а не інтерфейс, тож дотиків не перехоплюють. */
@media (prefers-reduced-motion: reduce) {
  button::before { animation: none; }
}

/* Небо лежить під вмістом і не перехоплює дотиків. */
#sky { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }

/* Небо ПОВЕРХ вуалі, але під вмістом. Раніше і воно, і вуаль мали z-index 0,
   а псевдоелемент малюється пізніше за вузол — тож зорі й астероїди були
   намальовані, але сховані під затемненням. */
#sky { z-index: 1; }

/* Зум вимкнено і на рівні стилів: подвійний тап у WebKit масштабує навіть при
   user-scalable=no, якщо не заборонити жест явно. */
html { touch-action: pan-y; -webkit-text-size-adjust: 100%; }

/* Астероїди мають бути ПОМІТНІ: вони й були надто блідими, щоб їх побачити. */
.rock { opacity: .55; font-size: var(--s, 30px); }
.star { box-shadow: 0 0 8px currentColor, 0 0 16px currentColor; }
.spark { opacity: .75; }

/* ═══════════════════════════════════════════════════════════════════════════
   МЕРЕХТІННЯ ЗАГОЛОВКІВ
   Світло проходить по літерах, ніби крізь розлом. Ефект накладається на
   градієнт тексту, тож не з'їдає контраст: під ним лишається та сама заливка.
   ═══════════════════════════════════════════════════════════════════════════ */
h1.screen .chaos i.c0,
h1.screen .chaos i.c3 {
  background-image: linear-gradient(100deg,
    currentColor 0%, currentColor 38%,
    var(--starlit) 48%, var(--cyan) 52%,
    currentColor 62%, currentColor 100%);
  background-size: 300% 100%;
  background-position: 120% 0;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: sweep 9s var(--ease) infinite;
}
@keyframes sweep {
  0%, 70%, 100% { background-position: 120% 0; }
  85%           { background-position: -60% 0; }
}
/* Кожен третій заголовок ловить хвилю у свою фазу — інакше всі спалахують разом. */
h1.screen .chaos i.c0:nth-child(3n) { animation-delay: 3s; }
h1.screen .chaos i.c3:nth-child(2n) { animation-delay: 5s; }

/* Рубрики: тонка лінія світла пробігає підкресленням. */
.sec { position: relative; overflow: visible; }
.sec::before {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -3px; height: 1px;
  background: linear-gradient(90deg, transparent,
              var(--violet), var(--magenta), var(--cyan), transparent);
  background-size: 250% 100%;
  opacity: .75;
  animation: secSweep 13s linear infinite;
}
.sec:nth-of-type(2n)::before { animation-delay: 4s; }
.sec:nth-of-type(3n)::before { animation-delay: 8s; }
@keyframes secSweep {
  0%   { background-position: 200% 0; }
  100% { background-position: -100% 0; }
}

/* Пульс навколо активної вкладки — єдиний постійний рух унизу, і він
   позначає стан, а не прикрашає. */
.navitem.active .ic {
  animation: activePulse 3.4s ease-in-out infinite;
  filter: drop-shadow(0 0 6px var(--acid));
}
@keyframes activePulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.14); }
}

@media (prefers-reduced-motion: reduce) {
  h1.screen .chaos i, .sec::before, .navitem.active .ic { animation: none !important; }
  h1.screen .chaos i.c0, h1.screen .chaos i.c3 { -webkit-text-fill-color: currentColor; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ВИДИМІСТЬ АНОМАЛІЙ

   Зорі, астероїди й мешканці лежали ПІД картками. Скло з `backdrop-filter`
   розмиває все, що позаду, тож вони були намальовані, але перетворені на
   рівний фон — а сторінка майже цілком укрита картками.

   Тепер вони поверх вмісту й не перехоплюють дотиків. Порядок такий, бо це
   аномалії: вони й мають проходити крізь інтерфейс, а не ховатись за ним.
   ═══════════════════════════════════════════════════════════════════════════ */
/* Над текстом вони приглушені, щоб не заважати читати: помітно, але не
   конкурує з вмістом. */
#sky,
.star  { opacity: .75; }
.spark { opacity: .6; }
.rock  { opacity: .42; }
/* ═══════════════════════════════════════════════════════════════════════════
   ЗАГОЛОВКИ-НАКЛЕЙКИ
   Обведення відділяє літеру від будь-якого фону, а зміщена тінь дає товщину.
   Разом вони роблять із заголовка наклейку, яку видно на чому завгодно.
   ═══════════════════════════════════════════════════════════════════════════ */
h1.screen .chaos i {
  paint-order: stroke fill;
  -webkit-text-stroke: 3px rgba(9, 10, 11, .92);
  text-stroke: 3px rgba(9, 10, 11, .92);
  text-shadow:
    2px 3px 0 rgba(9, 10, 11, .9),
    0 6px 18px rgba(0, 0, 0, .55);
}
/* Скляна літера обведення вже має власне — не подвоюємо. */
h1.screen .chaos i.c8 { -webkit-text-stroke: 1px rgba(255, 255, 255, .7); }

.banner .cap .chaos i,
.brand .chaos i {
  paint-order: stroke fill;
  -webkit-text-stroke: 2px rgba(9, 10, 11, .85);
  text-shadow: 1px 2px 0 rgba(9, 10, 11, .85), 0 4px 12px rgba(0, 0, 0, .5);
}

/* ═══════════════════════════════════════════════════════════════════════════
   МЕНШЕ ЗЕЛЕНОГО, БІЛЬШЕ ГРАДІЄНТІВ

   Зелений лишається кольором ФОНУ і стану «твоє». Літери беруть увесь інший
   спектр: суцільні відтінки плюс градієнтні переливи — так у слові майже не
   трапляється двох однакових літер.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ПАЛІТРА ЛІТЕР ПРИХОДИТЬ ІЗ ФОНУ.

   `--k1…--k6` ставить `palitraLiter()` з домінантного відтінку картинки за
   гармоніями: два аналогові, розщеплений комплемент, тріада і майже-білий.
   Значення тут — запасні: вони діють до того, як картинка завантажиться, і
   тоді, коли її немає зовсім. */
:root {
  --k1: var(--cyan);
  --k2: var(--amber);
  --k3: var(--violet);
  --k4: var(--magenta);
  --k5: var(--ember);
  --k6: var(--starlit);
  --g1a: var(--cyan);   --g1b: var(--violet);
  --g2a: var(--magenta); --g2b: var(--amber);
  --g3a: var(--starlit); --g3b: var(--ember);
}

.chaos i.k1 { color: var(--k1); }
.chaos i.k2 { color: var(--k2); }
.chaos i.k3 { color: var(--k3); }
.chaos i.k4 { color: var(--k4); }
.chaos i.k5 { color: var(--k5); }
.chaos i.k6 { color: var(--k6); }

/* Градієнтні літери. Обрізка по тексту працює лише без обведення, тож у
   заголовках-наклейках вони отримують тінь замість контуру. */
.chaos i.g1, .chaos i.g2, .chaos i.g3 {
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  -webkit-text-stroke: 0;
}
.chaos i.g1 { background-image: linear-gradient(160deg, var(--g1a), var(--g1b)); }
.chaos i.g2 { background-image: linear-gradient(160deg, var(--g2a), var(--g2b)); }
.chaos i.g3 { background-image: linear-gradient(160deg, var(--g3a), var(--g3b)); }

/* ── РУХ ЗАГОЛОВКА ────────────────────────────────────────────────────────

   Літери вже мають свій номер (`--i`), тож черга дається безкоштовно.

   Дві різні речі, і кожна коротка:
     · ПОЯВА — літери спливають знизу по черзі, 28 мс одна за одною. Це читає
       заголовок як слово, що складається, а не як готовий напис;
     · ПЛАВАННЯ — три цикли ледь помітного коливання, і спокій. Саме три:
       вічний цикл у цьому проєкті вже прибирали (блік по шапці раз на девʼять
       секунд), бо рух, який не закінчується, перетягує увагу на себе назавжди.

   Обидві — лише на заголовку екрана й назві застосунку: там, де хаос уже є
   твердженням. */
@keyframes litera-vplyv {
  from { opacity: 0; transform: translateY(0.34em) rotate(-4deg); }
  to   { opacity: 1; transform: none; }
}

@keyframes litera-plavannia {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-0.07em) rotate(1.2deg); }
}

h1.screen .chaos i,
.brand .chaos i {
  animation:
    litera-vplyv .34s var(--ease, ease-out) both calc(var(--i, 0) * 28ms),
    litera-plavannia 2.6s ease-in-out 3 calc(.34s + var(--i, 0) * 28ms);
}

@media (prefers-reduced-motion: reduce) {
  h1.screen .chaos i,
  .brand .chaos i { animation: none; }
}
h1.screen .chaos i.g1, h1.screen .chaos i.g2, h1.screen .chaos i.g3 {
  filter: drop-shadow(2px 3px 0 rgba(9, 10, 11, .9)) drop-shadow(0 5px 14px rgba(0, 0, 0, .5));
}

/* ═══════════════════════════════════════════════════════════════════════════
   ІНДИКАТОР АКТИВНОЇ ВКЛАДКИ
   Замість лінії — підсвічена комірка, що повторює форму панелі: заокруглена
   зверху, притиснута донизу. Так видно, ЯКА саме вкладка активна, а не просто
   що десь угорі є риска.
   ═══════════════════════════════════════════════════════════════════════════ */
.navitem { border-top: 0 !important; position: relative; }
/* Смужка-підпис зверху повторює заокруглення комірки. */

/* ═══════════════════════════════════════════════════════════════════════════
   ЧИТАБЕЛЬНІСТЬ ФОРМ І ТАБЛИЦЬ

   У панелі світу текст вилазив за межі полів і зливався зі склом: підписи були
   надто блідими, а довгі назви не мали куди переноситись. Форма, у якій не
   видно, що написано, — це не форма.
   ═══════════════════════════════════════════════════════════════════════════ */
label.field { min-width: 0; }
label.field > span {
  color: #e8f6e4;
  font-weight: 600;
  font-size: 13px;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .7);
  opacity: 1;
}
input[type="text"], textarea, select {
  color: #fff;
  font-size: 15px;
  /* Довге значення в select обрізається трьома крапками замість того, щоб
     розсувати колонку і ламати сітку. */
  text-overflow: ellipsis;
  max-width: 100%;
}
select option { background: #101a12; color: #fff; }

/* Дві колонки на телефоні перетворювали поля на щілини. */
@media (max-width: 480px) {
  .grid2 { grid-template-columns: 1fr; }
}

/* Таблиці: довгий текст переноситься, а сама таблиця гортається вбік замість
   того, щоб розпихати сторінку. */
table { width: 100%; border-collapse: collapse; }
th, td {
  color: #eaf7e6;
  font-size: 13.5px;
  padding: 9px 10px;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6);
  overflow-wrap: anywhere;
  vertical-align: middle;
}
th {
  color: #dceed7;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: .06em;
  text-transform: uppercase;
}
tr + tr td { border-top: 1px solid var(--edge-soft); }
.tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Рядки списків: довге ім'я не має накривати число праворуч. */
.inv-row, .exit {
  display: flex; align-items: center; gap: var(--s3);
  color: #eaf7e6;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6);
}
.inv-row > span:first-child, .exit { min-width: 0; overflow-wrap: anywhere; }
.inv-row .q { margin-left: auto; flex: none; white-space: nowrap; }
.inv-row code {
  font-family: var(--font-data);
  font-size: 13px;
  background: var(--mat-1);
  padding: 2px 6px; border-radius: var(--r-sm);
  overflow-wrap: anywhere;
}

/* Абзаци-пояснення в панелях були найблідішими з усього. */
.card p, .tip { color: #dceed7; text-shadow: 0 1px 3px rgba(0, 0, 0, .55); }
.wname span, .legend { color: #cfe4ca; }

/* ── Дрібні заголовки більші ──────────────────────────────────────────────
   Рубрики й назви карток були на межі впізнаваності: 11–15px акцидентом, який
   сам по собі широкий і через це здається дрібнішим за звичайний гротеск. */
.sec { font-size: 14px; letter-spacing: .1em; }
.card h3 { font-size: 18px; }
.menucard b { font-size: 15px; }
.stat b { font-size: 26px; }
.stat span { font-size: 13px; }
.bar-label { font-size: 13px; }
.navitem { font-size: 13px; }
.wname b { font-size: 16px; }

/* ── Аномалії помітніші й такі, що лопаються ──────────────────────────────
   Вони на найвищому шарі й перехоплюють дотик — це єдина декорація, з якою
   можна взаємодіяти, і саме тому їй дозволено трохи заважати. */
#sky, .star, .spark, .rock, .star  { opacity: .95; }
.spark { opacity: .9; }
.rock  { opacity: .8; font-size: var(--s, 42px); }
/* Лопання: спалах і розліт. Після анімації елемент прибирається з DOM. */
@keyframes pop {
  0%   { transform: scale(var(--z, 1)); opacity: 1; filter: brightness(1); }
  40%  { transform: scale(calc(var(--z, 1) * 2.4)); opacity: 1; filter: brightness(2.6); }
  100% { transform: scale(calc(var(--z, 1) * 3.6)); opacity: 0; filter: brightness(3); }
}
.popping { animation: pop .42s ease-out forwards !important; pointer-events: none; }

/* Уламки, що розлітаються від місця лопання. */
.shard {
  position: fixed; z-index: 41; pointer-events: none;
  width: 4px; height: 4px; border-radius: 1px;
  animation: shardFly .55s ease-out forwards;
}
@keyframes shardFly {
  from { transform: translate(0, 0) scale(1); opacity: 1; }
  to   { transform: translate(var(--dx), var(--dy)) scale(.2); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .popping { animation: none !important; opacity: 0 !important; }
  .shard { display: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ВИПРАВЛЕННЯ ЗА ЖИВИМ ЕКРАНОМ
   ═══════════════════════════════════════════════════════════════════════════ */

/* 1. Рядки заголовка налазили один на одного. Причина складалась із трьох:
      міжрядковий .94, вертикальне розтягнення літер до 1.16 і зсуви базової
      лінії. Кожне окремо було терпимим, разом — нечитабельним. */
h1.screen {
  line-height: 1.12;
  -webkit-text-stroke: 0;      /* обведення живе на літерах, не на блоці */
}
h1.screen .chaos i {
  -webkit-text-stroke-width: 2px;
  /* Зсуви по вертикалі всередині заголовка приборкані: у великому кеглі
     0.09em — це вже цілий рядок. */
  --shift: .03em;
}
h1.screen .chaos i.c3 { transform: scaleY(1.06) scaleX(.96); }
h1.screen .chaos i.c7 { transform: translateY(.03em) rotate(-4deg) scale(1.02); }
h1.screen .chaos i.c4 { transform: rotate(3deg) translateY(.02em) scale(1.02); }
h1.screen .chaos i.c1 { transform: rotate(-3deg) scale(1.06); }

/* 2. Порожня літера ставала чорною плямою: правило наклейки перебивало її
      світлий контур темним, а заливки в неї немає за задумом. */
/* Контурній літері задаємо лише ТОВЩИНУ: колір контуру лишається за класами
   k*, інакше всі порожні літери в заголовку виходили однаково блакитними. */
h1.screen .chaos i.c6,
.banner .cap .chaos i.c6,
.brand .chaos i.c6 {
  -webkit-text-stroke-width: 2px !important;
  -webkit-text-stroke-color: var(--cyan);
  text-shadow: 0 2px 6px rgba(0, 0, 0, .8);
}
h1.screen .chaos i.c8 { -webkit-text-stroke: 1.5px var(--starlit) !important; }

/* 3. Мінімалістичний індикатор вкладки: тонка риска під іконкою замість
      залитої комірки. Позначати активність має найменша можлива позначка. */
.navitem.active .ic { animation: none; filter: none; }

/* 4. Астероїди більші й непрозорі — на екрані вони мають читатись як обʼєкти,
      а не як бліді плями. */
.rock { opacity: 1; font-size: var(--s, 54px); filter: drop-shadow(0 3px 10px rgba(0, 0, 0, .6)); }
.star { opacity: 1; }
.spark { opacity: .95; }

/* 5. Аномалії ЇДУТЬ разом зі сторінкою, а не висять перед очима.
      Постійно нерухомий обʼєкт поверх тексту заважає читати; той самий обʼєкт,
      що зникає при гортанні, лишається знахідкою. */
/* ═══════════════════════════════════════════════════════════════════════════
   ШВИДКОДІЯ
   Постійних анімацій було понад 160 — кожна змушує композитор працювати
   щокадру. Лишаємо ефект, але на порядок меншій кількості елементів: помітно
   так само, коштує вчетверо менше.
   ═══════════════════════════════════════════════════════════════════════════ */
#sky,
.chaos i.c1, .chaos i.c5, .chaos i.c7 { animation: none; }
h1.screen .chaos i.c1 { animation: drift 23s var(--ease) infinite; }
h1.screen .chaos i.c5 { animation: drift 31s var(--ease) 7s infinite; }

.pill { animation: none; }
.card::after { content: none; }        /* шов світла коштував більше, ніж додавав */
.chaos i.c8 { animation: none; }
.sec::before { animation: none; opacity: .6; }

/* Обіцяємо браузеру, що рухаються лише ці шари — тоді він виносить їх на GPU
   і не перемальовує решту сторінки. */
.star, .spark, .rock { will-change: transform, opacity; }

/* Міжрядковий із запасом на обведення: контур у 2px виступає за межі рядка
   вгору й вниз, тож 1.12 ще давав дотик між рядками у довгих назвах. */
h1.screen { line-height: 1.3; }
h1.screen .chaos i.c3 { transform: scaleY(1.03) scaleX(.97); }

/* Кольоровий клас поверх контурної літери має фарбувати САМЕ контур, а не
   заливку, якої в неї немає. */
.chaos i.c6.k1 { -webkit-text-stroke-color: var(--cyan) !important; }
.chaos i.c6.k2 { -webkit-text-stroke-color: var(--amber) !important; }
.chaos i.c6.k3 { -webkit-text-stroke-color: var(--violet) !important; }
.chaos i.c6.k4 { -webkit-text-stroke-color: var(--magenta) !important; }
.chaos i.c6.k5 { -webkit-text-stroke-color: var(--ember) !important; }
.chaos i.c6.k6 { -webkit-text-stroke-color: var(--starlit) !important; }
.chaos i.c6[class*="k"] { color: transparent !important; }

/* ═══════════════════════════════════════════════════════════════════════════
   ЦІНА КАДРУ

   Кожна поверхня з `backdrop-filter` — окремий прохід GPU. Їх набралось 46,
   і 35 із них — кнопки та поля всередині карток, які вже розмиті. Розмиття
   всередині розмитого не видно взагалі: воно лише коштує кадрів.

   Правило, якого я тримався від початку і сам же порушив, коли робив кнопки:
   розмиття живе ЛИШЕ на контейнерах, що лежать просто на фоні.
   ═══════════════════════════════════════════════════════════════════════════ */
button, .btn,
button.ghost, button.tiny,
input[type="text"], textarea, select {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* ── Кнопка мусить виступати з картки, а не зливатися з нею ───────────────
   Головна дія була залита тим самим темним склом, що й картка під нею
   (.52 проти .62) — різниця в один відтінок, тож кнопка читалась як ділянка
   фону з текстом. Тепер у неї власна поверхня: підсвічений градієнт із
   акцентних кольорів поверх темної основи плюс світла верхня грань.

   Другорядна дія лишається темною й тихою. Різниця між ними тепер видна
   з одного погляду — це і є ієрархія, якої бракувало.                     */
button, .btn {
  background:
    linear-gradient(180deg, rgba(var(--portal-rgb), .30) 0%, rgba(var(--mid-rgb), .22) 100%),
    linear-gradient(180deg, rgba(21, 22, 25, .92), rgba(13, 13, 15, .94));
  border: 1px solid rgba(255, 255, 255, .34);
  border-top-color: rgba(255, 255, 255, .52);
  box-shadow:
    0 6px 18px rgba(0, 0, 0, .38),
    0 0 0 1px rgba(0, 0, 0, .25),
    inset 0 1px 0 rgba(255, 255, 255, .22);
}

@media (hover: hover) {
  button:hover {
    background:
      linear-gradient(180deg, rgba(var(--portal-rgb), .40) 0%, rgba(var(--mid-rgb), .30) 100%),
      linear-gradient(180deg, rgba(27, 29, 33, .94), rgba(17, 18, 21, .96));
    border-color: rgba(255, 255, 255, .5);
  }
}
/* Другорядна: та сама форма, менше ваги. Прозорою вона не виглядає — під нею
   щільна темна основа, а не просто плівка. */
button.ghost, button.tiny {
  background: linear-gradient(180deg, rgba(29, 31, 35, .88), rgba(17, 18, 20, .92));
  border: 1px solid rgba(255, 255, 255, .24);
  border-top-color: rgba(255, 255, 255, .34);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .34), inset 0 1px 0 rgba(255, 255, 255, .12);
}

@media (hover: hover) {
  button.ghost:hover, button.tiny:hover {
    background: linear-gradient(180deg, rgba(41, 43, 49, .92), rgba(25, 27, 30, .95));
    border-color: rgba(255, 255, 255, .4);
  }
}
button.danger {
  background: linear-gradient(180deg, rgba(60, 20, 34, .92), rgba(34, 14, 22, .94));
  border-color: rgba(255, 107, 148, .55);
  color: #ffd9e4;
}

@media (hover: hover) {
  button.danger:hover {
    background: linear-gradient(180deg, rgba(84, 26, 46, .94), rgba(48, 18, 30, .96));
    border-color: rgba(255, 107, 148, .8);
  }
}
input[type="text"], textarea, select { background: var(--mat-2); }

/* Аватар лежить у шапці, яка вже розмита. */
.avatar { backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(30, 30, 30, .6); }

/* ═══════════════════════════════════════════════════════════════════════════
   ВИПРАВЛЕННЯ ЗА ДРУГИМ ЕКРАНОМ
   ═══════════════════════════════════════════════════════════════════════════ */

/* 1. Шар аномалій розтягував сторінку. Абсолютний блок висотою 300vh усередині
      body додає ці 300vh до прокрутки — на коротких екранах виходило поле
      порожнечі під вмістом. Повертаємось до fixed, а «відліт» дає зсув при
      гортанні (див. parallaxSky), а не висота блоку. */
/* 2. Зорі прибрані: на строкатому фоні вони читались як бруд, а не як небо. */
#sky,
.star, .spark { display: none; }

/* 3. Обведення на літерах заголовка прибрано — воно давало чорні плями замість
      контуру. Замість нього під заголовком лежить темна підкладка: вона
      відділяє текст від фону цілим блоком, а не обмальовує кожну літеру. */
h1.screen .chaos i,
.banner .cap .chaos i,
.brand .chaos i {
  -webkit-text-stroke: 0 !important;
  text-stroke: 0 !important;
  text-shadow: 0 2px 6px rgba(0, 0, 0, .95), 0 0 22px rgba(0, 0, 0, .8);
}
h1.screen .chaos i.c6 {
  /* Контурній літері контур потрібен за задумом — лишаємо, але тонкий. */
  -webkit-text-stroke: 1.5px currentColor !important;
  color: transparent;
}
h1.screen {
  position: relative;
  isolation: isolate;
  padding: 10px 14px 12px;
  margin-left: -14px; margin-right: -14px;
  -webkit-text-stroke: 0;
}
h1.screen::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, rgba(11, 12, 13, .82), rgba(11, 12, 13, .62));
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid var(--edge-soft);
}
/* Те саме для назви на обкладинці — там фон найстрокатіший. */
.banner .cap {
  background: linear-gradient(180deg, transparent, rgba(9, 10, 11, .75));
  padding: 18px 14px 10px;
  left: 0; right: 0; bottom: 0;
}

/* 4. Індикатор вкладки: під ПІДПИСОМ, а не під іконкою, і власним кольором —
      блакить видно на зеленому фоні краще за зелений на зеленому. */
.navitem { padding-bottom: 12px; }
.navitem.active { color: var(--cyan); }

/* ═══════════════════════════════════════════════════════════════════════════
   АНОМАЛІЇ ГОРТАЮТЬСЯ РАЗОМ ЗІ СТОРІНКОЮ

   Були `fixed` і зсувались скриптом — через це висіли на місці, поки скрипт
   не спрацював, і взагалі не рухались там, де подія прокрутки не долітала.
   Тепер вони абсолютні ВСЕРЕДИНІ контейнера вмісту: він уже має потрібну
   висоту, тож обʼєкти їдуть самі, без жодного рядка коду.
   ═══════════════════════════════════════════════════════════════════════════ */
#sky { position: absolute; inset: 0; height: 100%; }
.rock { position: absolute; }

/* Астероїд пропливає по своїй смузі, а не через увесь екран: усередині
   контейнера «115vw» вело б його далеко за межі вмісту. */
@keyframes floatBy {
  from { transform: translateX(-8%) rotate(0deg); }
  to   { transform: translateX(108%) rotate(300deg); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ЧИТАБЕЛЬНІСТЬ ЗАГОЛОВКІВ БЕЗ ОБВЕДЕННЯ

   Обведення кожної літери на строкатому фоні збиралось у чорні згустки й
   псувало саме те, заради чого його ставили. Замість нього — багатошарова
   тінь: вона повторює форму літери, темніє під нею і не торкається самого
   контуру. Плюс підкладка під блоком заголовка.
   ═══════════════════════════════════════════════════════════════════════════ */
h1.screen .chaos i,
.banner .cap .chaos i,
.brand .chaos i,
.card h3 .chaos i,
.sec .chaos i,
.menucard b .chaos i,
.wname b .chaos i {
  -webkit-text-stroke: 0 !important;
  text-stroke: 0 !important;
  text-shadow:
    0 1px 0 rgba(6, 7, 8, .9),
    0 2px 3px rgba(6, 7, 8, .85),
    0 4px 12px rgba(0, 0, 0, .75),
    0 0 26px rgba(0, 0, 0, .55);
}
/* Порожня і скляна літери без контуру зникли б — їм контур і є формою. */
h1.screen .chaos i.c6 { -webkit-text-stroke: 1.5px currentColor !important; color: transparent; }
h1.screen .chaos i.c8 { -webkit-text-stroke: 1px var(--starlit) !important; }

/* ── Підкладки під усі заголовки, а не лише під головний ─────────────────── */
.sec {
  display: inline-flex;
  padding: 5px 12px;
  border-radius: var(--r-sm);
  background: rgba(11, 12, 13, .62);
  border: 1px solid var(--edge-soft);
  backdrop-filter: none;
}
.sec::after { display: none; }
.card h3, .wname b, .menucard b { text-shadow: 0 2px 4px rgba(6, 7, 8, .9); }

/* ── Основний текст: тінь скрізь, де він лягає на скло ──────────────────── */
.card p, .tip, .inv-row, .exit, td, th, .stat span, .stat b,
.bar-label, .who-row b, .who-row span, .legend, .empty, .step b, .step span {
  text-shadow: 0 1px 3px rgba(6, 7, 8, .85), 0 2px 8px rgba(0, 0, 0, .5);
}

/* Картки трохи щільніші: на строкатому фоні матеріал .40 пропускав забагато
   візуального шуму саме туди, де лежить текст. */
:root { --mat: rgba(22, 23, 26, .62); --mat-thick: rgba(16, 17, 20, .8); }

/* ═══════════════════════════════════════════════════════════════════════════
   ВИПРАВЛЕННЯ ЗА ТРЕТІМ ЕКРАНОМ
   ═══════════════════════════════════════════════════════════════════════════ */

/* 1. Літери зникали цілком («АД  І» замість «АДМІН»).
      Причина: у порожньої літери заливка прозора за задумом, а контур я задав
      як `currentColor` — тобто теж прозорий. Літера ставала невидимою. Контур
      мусить мати ВЛАСНИЙ колір, ніколи не похідний від заливки. */
.chaos i.c6,
h1.screen .chaos i.c6,
.banner .cap .chaos i.c6,
.brand .chaos i.c6 {
  color: transparent !important;
  -webkit-text-stroke: 1.6px var(--cyan) !important;
  text-stroke: 1.6px var(--cyan) !important;
}
.chaos i.c6.k1 { -webkit-text-stroke-color: var(--cyan) !important; }
.chaos i.c6.k2 { -webkit-text-stroke-color: var(--amber) !important; }
.chaos i.c6.k3 { -webkit-text-stroke-color: var(--violet) !important; }
.chaos i.c6.k4 { -webkit-text-stroke-color: var(--magenta) !important; }
.chaos i.c6.k5 { -webkit-text-stroke-color: var(--ember) !important; }
.chaos i.c6.k6 { -webkit-text-stroke-color: var(--starlit) !important; }

.chaos i.c8,
h1.screen .chaos i.c8 {
  color: rgba(255, 255, 255, .16) !important;
  -webkit-text-stroke: 1.2px var(--starlit) !important;
  text-stroke: 1.2px var(--starlit) !important;
}

/* 2. Мешканці накривали текст. Вони декорація, тож ідуть ЗА картки: у зазорах
      і на полях їх видно, а прочитати вони не заважають. Читабельність важить
      більше за помітність декору — це не компроміс, а порядок пріоритетів. */
/* 2. Мешканці прибрані з гри; тут лишається лише шар неба.

   ЦЕ МІСЦЕ ВЖЕ ЛАМАЛОСЬ: прибираючи створіння регуляркою, я зʼїв закриваючу
   дужку і лишив обірваний селектор `:not(`. Розбір CSS від цього рядка й до
   кінця файлу помирає мовчки — сторінка просто втрачає половину стилів, і
   виглядає це як «дизайн поламався», а не як синтаксична помилка. */
#sky { z-index: 30; }
/* ШАПКУ ЦЕ ПРАВИЛО НЕ ЧІПАЄ.
   `:not(#sky)` бере ваговитість ідентифікатора, тож селектор важить (1,1,0)
   і перебиває будь-яке `.topbar`. Саме через це спроба зробити шапку липкою
   окремим правилом мовчки програвала: у файлі стояло `position: sticky`, а в
   браузері лишалось `relative`, і жодної помилки ніде.
   Виключаємо шапку явно — і поруч віддаємо їй власний шар. */
.wrap > *:not(#sky):not(.topbar):not(#hdrmask) { position: relative; z-index: 1; }
.wrap > .topbar { z-index: 30; }

/* 3. Індикатор вкладки лежав ПОВЕРХ підпису: у відступ знизу вже закладено
      безпечну зону, а я додав її вдруге — і риска піднялась на 34px угору,
      просто на текст. */
.navitem { padding-bottom: 14px; }
.bottomnav { padding-bottom: env(safe-area-inset-bottom, 0px); }

/* 4. Підпис під графіком розповзався на три колонки: жирні шматки всередині
      флексу ставали окремими елементами. Це суцільний рядок тексту. */
.legend {
  display: block;
  line-height: 1.5;
  font-size: 13px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
}
.legend b { display: inline; font-weight: 700; color: var(--starlit); }

/* 5. Рубрика мала і підкладку, і залишок підкреслення — лишаємо тільки
      підкладку, бо разом вони давали зайву риску під блоком. */
.sec::before { display: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   ЗАГОЛОВОК НЕ ЗАЛЕЖИТЬ ВІД ГРАДІЄНТА

   Мерехтіння працювало через обрізку фону по тексту: заливка літери робилась
   прозорою, а видимість давав градієнт. Достатньо одному пізнішому правилу
   перебити фон — і літера зникає повністю. Саме так і сталося з «АДМІН», де
   зникли дві літери з пʼяти.

   Ефект не вартий того, щоб від нього залежала видимість головного тексту.
   Літери фарбуються звичайним кольором; мерехтіння лишається на підкладці
   заголовка, де його зникнення нікому не шкодить.
   ═══════════════════════════════════════════════════════════════════════════ */
h1.screen .chaos i,
h1.screen .chaos i.c0,
h1.screen .chaos i.c3,
.chaos i.g1, .chaos i.g2, .chaos i.g3 {
  background-image: none !important;
  -webkit-text-fill-color: currentColor !important;
  /* `animation: none` тут БУЛО і глушило танець літер. Мерехтіння через
     градієнт прибрано разом із фоном вище, тож глушити більше нічого. */
}
/* Порожня і скляна літери — виняток: у них заливки немає за задумом. */
.chaos i.c6 { -webkit-text-fill-color: transparent !important; }
.chaos i.c8 { -webkit-text-fill-color: rgba(255, 255, 255, .16) !important; }

/* Мерехтіння переїхало на підкладку: світло проходить під заголовком, а не
   крізь самі літери. */
h1.screen::before {
  background:
    linear-gradient(100deg, transparent 35%, rgba(79, 227, 255, .1) 48%,
                    rgba(185, 140, 255, .12) 55%, transparent 68%),
    linear-gradient(180deg, rgba(11, 12, 13, .84), rgba(11, 12, 13, .66));
  background-size: 260% 100%, 100% 100%;
  background-position: 200% 0, 0 0;
  animation: plateSweep 11s var(--ease) infinite;
}
@keyframes plateSweep {
  0%, 72%, 100% { background-position: 200% 0, 0 0; }
  88%           { background-position: -60% 0, 0 0; }
}
@media (prefers-reduced-motion: reduce) { h1.screen::before { animation: none; } }

/* ═══════════════════════════════════════════════════════════════════════════
   ЛІТЕРИ БЕЗ ЗАЛИВКИ ПРИБРАНІ

   Порожня і скляна літери тримались на самому контурі. Це виявилось джерелом
   одного й того самого дефекту тричі поспіль: досить одному правилу зачепити
   колір контуру — і літера зникає повністю, як зникли «О» і «Л» у «Моралес».

   Варіант, у якому видимість тримається на одній властивості, крихкий за
   будовою. Замінюємо їх на заливні: ефект «іншого світу» дають гарнітура,
   нахил і колір, а не відсутність тіла.
   ═══════════════════════════════════════════════════════════════════════════ */
.chaos i.c6 {
  color: var(--cyan) !important;
  -webkit-text-fill-color: var(--cyan) !important;
  -webkit-text-stroke: 0 !important;
  font-family: var(--font-data);
  font-weight: 800;
  transform: skewX(-8deg) scale(1.04);
}
.chaos i.c8 {
  color: var(--starlit) !important;
  -webkit-text-fill-color: var(--starlit) !important;
  -webkit-text-stroke: 0 !important;
  font-family: var(--font-accent);
  font-style: italic;
  font-weight: 900;
  transform: rotate(4deg) scale(1.06);
}
.chaos i.c6[class*="k"], .chaos i.c8[class*="k"] {
  color: inherit;
  -webkit-text-fill-color: currentColor !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   ТІНЬ БЕЗ ЧОРНОГО ДВІЙНИКА

   Різка тінь зі зсувом на піксель малювала темну копію літери. Літери
   нахилені й налазять на сусідні, тож ця копія лягала ПОВЕРХ сусідки — звідси
   «чорні літери поверх нормальних». Лишаємо тільки мʼяке затемнення довкола:
   воно відділяє текст від фону, не малюючи нічого поверх.
   ═══════════════════════════════════════════════════════════════════════════ */
h1.screen .chaos i,
.banner .cap .chaos i,
.brand .chaos i,
.card h3 .chaos i,
.sec .chaos i,
.menucard b .chaos i,
.wname b .chaos i {
  text-shadow: 0 0 8px rgba(6, 7, 8, .95), 0 0 20px rgba(0, 0, 0, .7) !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   ЗАГОЛОВОК ПОМІЩАЄТЬСЯ В СВОЮ ПІДКЛАДКУ
   Літери нахилені й збільшені, тож займають більше, ніж каже кегль. Даємо
   запас з боків і дозволяємо їм виступати за рядок, не обрізаючись.
   ═══════════════════════════════════════════════════════════════════════════ */
:root { --t-display: clamp(26px, 7.4vw, 42px); }
h1.screen {
  padding: 14px 18px 16px;
  overflow: visible;
  letter-spacing: -.02em;
}
h1.screen .chaos { overflow: visible; }
h1.screen .chaos i { padding: 0 .01em; }

/* Заголовки другого й третього порядку були надто дрібними для акциденту. */
.sec { font-size: 16px; padding: 6px 14px; }
.card h3 { font-size: 20px; }
.menucard b { font-size: 16px; }
.wname b { font-size: 17px; }
.banner .cap { font-size: clamp(19px, 5.4vw, 26px); }
.stat span { font-size: 13px; }

/* ═══════════════════════════════════════════════════════════════════════════
   ЛІТЕРИ ТАНЦЮЮТЬ
   Постійний, дуже малий рух: кожна літера гойдається у свою фазу. Амплітуда
   навмисно мікроскопічна — заголовок має жити, а не стрибати.
   ═══════════════════════════════════════════════════════════════════════════ */
@keyframes dance {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  25%      { transform: translateY(-.05em) rotate(-2.5deg); }
  50%      { transform: translateY(.02em) rotate(1.5deg); }
  75%      { transform: translateY(-.03em) rotate(2deg); }
}
h1.screen .chaos i {
  animation: dance 4.5s ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * .12s);
}
/* Варіанти зі своїм нахилом танцюють від нього, а не від нуля. */
h1.screen .chaos i.c1, h1.screen .chaos i.c4,
h1.screen .chaos i.c7, h1.screen .chaos i.c8 { animation-name: danceTilt; }
@keyframes danceTilt {
  0%, 100% { transform: rotate(-3deg) translateY(0) scale(1.04); }
  30%      { transform: rotate(1deg) translateY(-.06em) scale(1.07); }
  60%      { transform: rotate(-5deg) translateY(.03em) scale(1.02); }
}

/* Індикатор вкладки під підписом: даємо панелі реальну висоту, інакше риска
   не має де стати і лягає на текст. */
.bottomnav { padding-bottom: calc(10px + var(--tg-bottom) + env(safe-area-inset-bottom, 0px)); }
.navitem { padding: 9px 4px 6px; }

@media (prefers-reduced-motion: reduce) {
  h1.screen .chaos i { animation: none !important; }
}

/* Танець вмикається останнім правилом, щоб його не перебило нічим раніше. */
h1.screen .chaos i { animation: dance 4.5s ease-in-out infinite !important; }
h1.screen .chaos i.c1, h1.screen .chaos i.c4,
h1.screen .chaos i.c7, h1.screen .chaos i.c8 {
  animation: danceTilt 5.5s ease-in-out infinite !important;
}
@media (prefers-reduced-motion: reduce) {
  h1.screen .chaos i { animation: none !important; }
}

/* Затримку задаємо ОКРЕМИМ правилом: скорочений запис `animation` скидає
   animation-delay у нуль, і всі літери починали гойдатись в такт — виходив
   не танець, а спільний стрибок. */
h1.screen .chaos i { animation-delay: calc(var(--i, 0) * .11s) !important; }

/* ═══════════════════════════════════════════════════════════════════════════
   ЧОРНА ЗАЛИВКА ПОВЕРХ ЛІТЕР — ДОБИВАЄМО ПРИЧИНУ

   Правил, що ставили тінь чи обведення на літери заголовка, накопичилось
   кілька в різних місцях файлу, і пізніші не завжди перебивали ранні. Тут
   ОДНЕ фінальне правило на всі акцентні написи: жодного контуру, жодного
   зсуву — лише мʼяке затемнення довкола.
   ═══════════════════════════════════════════════════════════════════════════ */
.chaos i {
  -webkit-text-stroke: 0 !important;
  text-stroke: 0 !important;
  text-shadow: 0 0 7px rgba(5, 5, 6, .98), 0 0 18px rgba(0, 0, 0, .72) !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   ШАПКА: НАЗВА ГОЛОВНІША ЗА ВСЕ ІНШЕ

   Раніше назва була дрібнішою за заголовок екрана — ієрархія стояла на голові.
   Тепер вона найбільша в шапці, з власним мерехтінням і бліками на склі.
   ═══════════════════════════════════════════════════════════════════════════ */
.topbar {
  /* ЛИПКА, А НЕ ПРОСТО RELATIVE.
     Назва гри, баланс ходів і перемикач мови — єдине, що тримає орієнтацію
     на довгих екранах; прокрутивши інвентар і квести, гравець лишався без
     усіх трьох, а щоб поповнити ходи, мусив прокрутити весь екран назад.
     `relative` тут стояв заради бліку в `::after` — `sticky` дає той самий
     контекст позиціювання, тож блік не постраждав.
     Правило правиться ТУТ, а не додається новим у кінець файлу: спроба
     перебити його дописаним правилом мовчки програла, і це рівно той
     випадок, від якого застерігає правило проєкту — не перебивай, а правь
     джерело. */
  position: sticky;
  top: var(--tg-top, 0px);
  z-index: 30;
  overflow: hidden;
  padding: 14px 16px;
}
/* Блік: смуга світла раз на 9 секунд проходить по всій плашці. */
.topbar::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(105deg,
    transparent 38%, rgba(255, 255, 255, .16) 46%,
    rgba(79, 227, 255, .2) 50%, rgba(255, 106, 213, .16) 54%,
    transparent 62%);
  background-size: 240% 100%;
  background-position: 200% 0;
  animation: topSheen 9s var(--ease) infinite;
}
@keyframes topSheen {
  0%, 66%, 100% { background-position: 200% 0; }
  86%           { background-position: -70% 0; }
}

.brand {
  letter-spacing: -.03em;
  z-index: 1;
}
/* «МУЛЬТИ» холодним, «ВСЕСВІТ» теплим — дві частини читаються як два світи,
   що зіткнулись, а не як одне слово з випадковими кольорами. */
.brand > .chaos i:nth-child(odd)  { color: var(--cyan); }
.brand > .chaos i:nth-child(even) { color: var(--violet); }
.brand span .chaos i:nth-child(odd)  { color: var(--amber); }
.brand span .chaos i:nth-child(even) { color: var(--magenta); }
.brand span { font-size: 1.1em; }

/* Баланс у шапці не має сперечатися з назвою за увагу. */
.who b { font-size: 13px; }
.who { font-size: 13px; }

/* ═══════════════════════════════════════════════════════════════════════════
   ПЛАВАЮЧІ ОБʼЄКТИ: ОДНАКОВІ ПРАВИЛА НА ВСІХ СТОРІНКАХ

   Були то над вмістом, то під ним, і лопались не всюди. Причина: шар сіявся
   один раз при завантаженні, а при переході між вкладками вміст перемальовував
   контейнер — шар лишався в старому місці стопки або взагалі губився.
   ═══════════════════════════════════════════════════════════════════════════ */
/* Самі обʼєкти дотик перехоплюють — інакше лопнути їх неможливо. */
#sky > * { pointer-events: auto; cursor: crosshair; }

/* ═══════════════════════════════════════════════════════════════════════════
   ІЄРАРХІЯ: ЛОГОТИП, ЗАГОЛОВОК, РУБРИКА

   Три різні речі, які досі виглядали однаково — той самий розлом літер, той
   самий блиск, схожі кеглі. Через це око не могло сказати, що головніше.

   Розводимо їх по РІЗНИХ ознаках, а не лише по кеглю:
   • логотип — постійний, малий, спокійний, з власним холодним світінням;
   • заголовок екрана — найбільший і єдиний, хто танцює;
   • рубрика — дрібна, розріджена, без жодного руху.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ── Шапка: назва більше нічого не перекриває ──────────────────────────── */
.topbar {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: nowrap;
}
.avatar { flex: 0 0 auto; }
.brand {
  flex: 1 1 auto;
  min-width: 0;
  /* Назва тепер стискається сама і не наїжджає на баланс: раніше вона мала
     фіксовану ширину й лізла на число зверху. */
  overflow: hidden;
  text-overflow: clip;
}
.who {
  flex: 0 0 auto;
  margin-left: 0;
  text-align: right;
  white-space: nowrap;
}
.livedot { flex: 0 0 auto; }

/* Логотип не танцює і не глітчить — він точка спокою, до якої око
   повертається. Рух у постійному елементі втомлює. */
.brand, .brand .chaos i {
  animation: none !important;
}
.brand .chaos i {
  /* Холодне світіння замість танцю: помітно, але нерухомо. */
  text-shadow: 0 0 6px rgba(5, 5, 6, .95), 0 0 14px rgba(79, 227, 255, .45) !important;
}

/* ── Заголовок екрана — єдиний головний ────────────────────────────────── */
:root { --t-display: clamp(30px, 8.6vw, 46px); }
h1.screen { font-size: var(--t-display); }

/* ── Рубрика: дрібна й тиха ────────────────────────────────────────────── */
.sec {
  font-size: 13px;
  letter-spacing: .16em;
  padding: 5px 11px;
  opacity: .96;
}
.sec .chaos i {
  /* Рубрики не ламаємо кольором: строкатий підзаголовок сперечається із
     заголовком за увагу, а має вести до нього. */
  color: #dceed7 !important;
  -webkit-text-fill-color: #dceed7 !important;
  font-family: var(--font-display) !important;
  transform: none !important;
  animation: none !important;
}

/* Назви карток — між заголовком і рубрикою, теж без руху. */
.card h3 { font-size: 19px; }
.card h3 .chaos i, .menucard b .chaos i, .wname b .chaos i {
  animation: none !important;
}

/* Блиск лишається ЛИШЕ на плашці шапки й під заголовком екрана. Скрізь інде
   він перетворював сторінку на суцільне мерехтіння. */
.card::after, .pill { animation: none !important; }

/* ═══════════════════════════════════════════════════════════════════════════
   ПАНЕЛЬ СВІТУ: З КАТАЛОГУ В РОБОЧИЙ ІНСТРУМЕНТ

   Вона показувала NPC і локації тими самими великими обкладинками, що й
   вітрину світів. Але вітрину РОЗДИВЛЯЮТЬСЯ, а панель — ГОРТАЮТЬ у пошуках
   потрібного: 42 NPC по半-екрана кожен це не каталог, а стрічка.

   Тому тут фото стають мініатюрами, картки — рядками, а між змістовими
   блоками зʼявляється повітря, якого бракувало.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Мініатюра замість обкладинки на весь екран. */
#ownerBody .banner {
  aspect-ratio: auto;
  height: 92px;
  border-radius: var(--r-md) var(--r-md) 0 0;
}
#ownerBody .banner.portrait { height: 92px; }
/* Портрет мешканця чи місця в розгортці рядка — квадратна мініатюра 72 px,
   а не смуга на всю ширину над формою (25.10.2026). */
#ownerBody .ryadok-tilo .banner.portrait {
  width: 72px; height: 72px; border-radius: var(--r-sm); margin: 2px 0 10px;
}
#ownerBody .ryadok-tilo .banner.portrait .ph .ic { width: 26px; height: 26px; }
#ownerBody .banner .ph { font-size: 30px; }
#ownerBody .banner .cap {
  font-size: 14px;
  padding: 10px 10px 7px;
}

/* Сітка щільніша: на екрані має вміщатись більше одиниць, а не більше пікселів
   однієї. */
#ownerBody .grid2 {
  grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: var(--s3);
}
#ownerBody .grid2 .card { margin-bottom: 0; }
#ownerBody .grid2 .card .body { padding: 10px 11px; }
#ownerBody .grid2 .card h3 { font-size: 14px; margin-bottom: 4px; }
#ownerBody .grid2 .card p {
  font-size: 13px;
  /* Опис NPC скорочуємо до двох рядків: у списку потрібно впізнати, а не
     прочитати цілком. Повний текст — у редагуванні. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ── Повітря між блоками ────────────────────────────────────────────────── */
#ownerBody > .sec,
#ownerBody .sec { margin: 26px 0 12px; }
#ownerBody > article.card { margin-bottom: 18px; }
#ownerBody .card .body { padding: 16px; }
#ownerBody .card .body > * + * { margin-top: 12px; }
#ownerBody label.field { display: block; margin-bottom: 12px; }
#ownerBody label.field > span { display: block; margin-bottom: 6px; }
#ownerBody .actions { margin-top: 16px; gap: var(--s3); }
/* Кнопка «Відкрити на компʼютері» стоїть між полем світу, лічильником гравців і
   панеллю: без власних відступів вона липла до сусідів. */
/* КАБІНЕТ НА ТЕЛЕФОНІ (04.11.2026): перший екран мусить показувати налаштування,
   а не шапку. ПК — один рядок-підказка замість кнопки на всю ширину; матеріал —
   наявний `.tip`, кнопка — `.tiny.ghost`. Своє тут лише розкладка. */
.kab-svit { width: 100%; margin: 0 0 6px; }
.tip.kabinet-pk { display: flex; align-items: center; gap: var(--s2); margin: 8px 0 10px; }
.tip.kabinet-pk > span { flex: 1 1 auto; min-width: 0; }
.tip.kabinet-pk > button { flex: none; }
.kabinet-pk-riadok { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2); }
/* Обкладинка в кабінеті нижча: без фото це лише рамка з кнопкою «＋ фото», і
   16:9 забирало пів екрана телефона. */
#ownerBody > article.card:first-child .banner { aspect-ratio: 3 / 1; }
#ownerBody p { line-height: 1.55; margin-bottom: 10px; }
#ownerBody table td, #ownerBody table th { padding: 10px 12px; }

/* Довгі списки прокручуються всередині свого блоку, а не розтягують сторінку
   на кілометр: 42 NPC підряд робили панель непридатною для роботи. */
#ownerBody .grid2.long {
  max-height: 62vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-right: 4px;
}
#ownerBody .inv-list { max-height: 46vh; overflow-y: auto; }

/* Заголовок розділу показує кількість — щоб було видно масштаб до гортання. */
#ownerBody .sec { justify-content: space-between; }

/* Дрібні кнопки все одно натискають пальцем: 34px із відступами між ними —
   нижня межа (25.10.2026, разом із головною кнопкою 48 → 40). Тут стояло
   44 і перебивало розмір, заданий вище, — два числа для однієї кнопки. */
button.tiny { min-height: 34px; padding: 7px 12px; }

/* ═══════════════════════════════════════════════════════════════════════════
   СПИСКИ NPC І ЛОКАЦІЙ: БЕЗ ВКЛАДЕНОЇ ПРОКРУТКИ

   Обмеження висоти з внутрішнім скролом різало картки по межі контейнера —
   кнопка «Змінити» зникала на півслові. Плюс вкладена прокрутка на телефоні
   краде жести: палець не знає, що він гортає.

   Замість цього список показує перші кілька одиниць, а решта розгортається
   кнопкою. Так екран лишається коротким, а нічого не обрізається.
   ═══════════════════════════════════════════════════════════════════════════ */
#ownerBody .grid2.long {
  max-height: none;
  overflow: visible;
  padding-right: 0;
}
#ownerBody .inv-list { max-height: none; overflow: visible; }

/* Приховані одиниці згорнутого списку. */
#ownerBody .grid2.long.collapsed > .card:nth-child(n+7) { display: none; }

/* Картка в списку має СТАЛУ будову: обкладинка, назва, підпис, дія знизу.
   Різна висота карток у сітці — головна причина, чому список виглядає
   зламаним: кнопки опиняються на різних рівнях. */
#ownerBody .grid2 > .card {
  display: flex;
  flex-direction: column;
  min-height: 208px;
}
#ownerBody .grid2 > .card .body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--s2);
}
/* Дія притискається донизу — тоді всі кнопки в ряд стоять на одній лінії. */
#ownerBody .grid2 > .card .actions {
  margin-top: auto;
  padding-top: 8px;
}
#ownerBody .grid2 > .card p { margin: 0; }

/* Кнопка розгортання — на всю ширину під списком. */
.more-btn {
  width: 100%;
  margin-top: 10px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   АСТЕРОЇДИ: ЧОМУ ВОНИ СТОЯЛИ І ЧОМУ НЕ ЛОПАЛИСЬ

   Дві окремі причини, обидві мої.

   1. Не летіли. Я переписав анімацію на `translateX(108%)`, а відсоток у
      translate рахується від РОЗМІРУ САМОГО ЕЛЕМЕНТА, не контейнера. Для
      емодзі в 50px це 54 пікселі замість екрана — рух був, але непомітний.

   2. Не лопались. Шар лежав під вмістом (z-index 0), а картки скла над ним:
      дотик діставався картки, а не астероїда. І видно їх майже не було з тієї
      самої причини.

   Ставимо шар НАД вмістом. Так, вони інколи перетнуть текст — але це рідкий
   рухомий об'єкт, а не постійна перешкода, і саме цього ефекту й хотіли.
   ═══════════════════════════════════════════════════════════════════════════ */
/* Політ через увесь екран: відлік у vw, а не у відсотках від самої емодзі:
   відсоток там рахується від розміру САМОЇ емодзі, тобто 54 пікселі. */
.rock {
  left: -70px;
  animation-name: flyAcross;
}
@keyframes flyAcross {
  from { transform: translate(0, 0) rotate(0deg); }
  to   { transform: translate(calc(100vw + 140px), -14vh) rotate(300deg); }
}

/* Мешканці лишаються на місці, але тепер їх видно й вони натискаються. */
/* ═══════════════════════════════════════════════════════════════════════════
   СІТКА СТАТИСТИКИ: ТРИ КОЛОНКИ НЕ ЗАВЖДИ ПОМІЩАЮТЬСЯ

   `.sheet` була прибита до трьох колонок. На екрані 375px це працювало, поки
   підписи були короткі («Сила», «Розум»), і зламалось на нових блоках, де вони
   довші: «Ходів лишилось», «Почали грати». Вміст вилазив на 84 пікселі й
   обрізався — саме це й було видно як «контент обривається».

   Колонки тепер підлаштовуються: три, коли влазить, дві або одна, коли ні.
   ═══════════════════════════════════════════════════════════════════════════ */
.sheet {
  display: grid;
  /* 76, а не 92: підпис «ЛИШИЛОСЬ» у 10px з трекінгом ледве вміщається в 90,
     і на 375px третя цифра падала на другий рядок сиротою. */
  grid-template-columns: repeat(auto-fit, minmax(76px, 1fr));
  gap: var(--s2);
}
.stat {
  min-width: 0;
  padding: 12px 6px;
  overflow: hidden;
}
.stat b {
  display: block;
  /* Число підлаштовується під ширину комірки: $0.0043 і 334 не мають
     однакової довжини, а місце в них одне. */
  font-size: clamp(17px, 5.6vw, 26px);
  line-height: 1.1;
  overflow-wrap: anywhere;
}
.stat span {
  display: block;
  font-size: 13px;
  line-height: 1.25;
  overflow-wrap: anywhere;
  hyphens: auto;
}

/* Поля форм не мають вилазити за картку. */
label.field, label.field > input, label.field > select, label.field > textarea {
  max-width: 100%;
  box-sizing: border-box;
}
input[type="range"] { width: 100%; }

/* Прев'ю зображення в брендингу не має схлопуватись у смужку. */
.uploader .prev { min-height: 64px; overflow: hidden; }

/* Підписи під цифрами переносяться вільно: у комірці 85px довге слово мусить
   ламатись, інакше воно просто вилазить. */
.stat span, .bar-label {
  overflow-wrap: anywhere;
  word-break: break-word;
  white-space: normal;
}
.stat span .w, .bar-label .w { white-space: normal; }

/* Повзунок затемнення разом із підписом не має вилазити за картку. */
label.field { box-sizing: border-box; padding-right: 2px; }

/* ═══════════════════════════════════════════════════════════════════════════
   СМУЖКА ГЕРОЇВ

   Обличчя й імена, нічого більше. Її завдання не розповісти про персонажа, а
   дати до нього дійти одним тапом — подробиці нижче, в аркуші обраного.
   Горизонтальна прокрутка тут доречна: список короткий і однорідний, а місця
   вертикально шкода.
   ═══════════════════════════════════════════════════════════════════════════ */
.roster {
  display: flex;
  gap: var(--s3);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* Смужка йде ВІД КРАЮ ДО КРАЮ екрана, а не від поля до поля.

     Гравець: «каруселька трохи не доходить до краю сторінки». Так і було:
     вона лежить у `.wrap` з бічним полем, і остання обкладинка впиралась у
     невидиму межу за чотирнадцять пікселів від краю. Смужка, що прокручується,
     цим ще й бреше: вона виглядає закінченою там, де насправді ще є вміст.

     Витягуємо на поле назовні й повертаємо його всередину як відступ: перша
     й остання картки стоять на одній лінії з рештою екрана, а сама прокрутка
     доходить до краю. */
  /* СВІТІННЯ ВИБРАНОГО НЕ МАЄ ЧИМ ВИЙТИ ЗА СМУЖКУ.
     Кільце активного героя — `box-shadow: 0 0 14px`, тобто йому треба
     щонайменше шістнадцять пікселів угору. Тут стояло чотири, а
     `overflow-x: auto` ріже й ПО ВЕРТИКАЛІ — тож плашка над смужкою
     виглядала так, ніби вона обрізає світіння. Відступ повертаємо
     відʼємним полем, щоб розкладка не поїхала. */
  margin: -12px calc(-1 * var(--gutter)) 6px;
  padding: 16px var(--gutter) 14px;
  scroll-padding-inline: var(--gutter);
  scrollbar-width: none;
}
.roster::-webkit-scrollbar { display: none; }

/* ЧИТАБЕЛЬНІСТЬ СМУЖКИ — БЕЗ ПЛАНКИ ЗА НЕЮ.

   Спершу я підклав під смужку повносмугову панель: на графіті імена зникали
   зовсім. Панель допомогла й одразу стала зайвою стіною впоперек екрана —
   власник попросив її прибрати.

   Тому контраст тримають самі елементи, а не підкладка: тінь під підписом і
   темний диск з яскравим кільцем під обличчям. Це коштує нічого й працює на
   будь-якому фоні, бо не залежить від того, що під ним. */
.rost b,
.rost span {
  text-shadow: 0 1px 4px rgba(0, 0, 0, .9), 0 0 2px rgba(0, 0, 0, .8);
}

.rost b { color: #fff; }

.rost {
  flex: 0 0 auto;
  width: 76px;
  text-align: center;
  cursor: pointer;
  /* Неактивні герої притлумлені, але ЧИТАБЕЛЬНІ. Було .62 — на світлому фоні
     обкладинки світу імена зливались, і смужка виглядала як ряд вимкнених
     кнопок. Активного тепер видно не тим, що решта бліда, а кільцем довкола
     обличчя й повною яскравістю. */
  opacity: .82;
  transition: opacity .2s var(--ease), transform .12s var(--ease);
}

@media (hover: hover) {
  .rost:hover { opacity: .95; }
}
.rost:active { transform: none; }
/* Активний персонаж не тьмяний — саме за цим його й знаходять поглядом. */
.rost.on { opacity: 1; cursor: default; }

.rost-face {
  width: 58px; height: 58px;
  margin: 0 auto 6px;
  border-radius: 50%;
  /* Кільце й тінь відділяють обличчя від фону надійніше за будь-яку панель
     позаду: вони належать самому елементу й не залежать від того, що під ним. */
  box-shadow: 0 0 0 2px rgba(0, 0, 0, .55), 0 3px 10px rgba(0, 0, 0, .55);
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  font-size: 26px;
  background: var(--mat-1);
  border: 1px solid var(--edge-soft);
}
.rost.on .rost-face {
  border: 2px solid var(--cyan);
  box-shadow: 0 0 14px rgba(79, 227, 255, .55);
}
.rost-face img { width: 100%; height: 100%; object-fit: cover; }

.rost b {
  display: block;
  font-size: 13px;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .8);
}
.rost span {
  display: block;
  font-size: 13px;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════════════════
   СПОКІЙНА ТИПОГРАФІКА ТАМ, ДЕ ЧИТАЮТЬ І НАТИСКАЮТЬ

   Кнопка, рубрика, назва картки — це не місце для розлому. Їх читають на
   ходу, і кожна зайва варіація коштує частки секунди впізнавання. Розлом
   лишається заголовкам; решта набрана однією гарнітурою й одним кольором.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Кнопки: звичайний білий текст, без різнобою. */
button, .btn {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 0;
  color: #fff;
  text-transform: none;
}
button.tiny { font-size: 13.5px; }

/* Рубрики: білі, більші, розріджені. Фіолетовий на склі втрачав контраст
   саме на дрібному кеглі — там, де його найважче читати. */
.sec {
  color: #f2fbef;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: .1em;
  padding: 7px 14px;
  background: var(--mat-1);
  border: 1px solid var(--edge);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .8);
  transform: none;
}
.sec:nth-of-type(even) { transform: none; }

/* Назви карток і плиток — акцидент, але одним кольором. */
.card h3, .menucard b, .wname b, .node b, .step b {
  color: #f4fbf2;
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -.01em;
}

/* Нижнє меню й рядки списків — системним шрифтом: їх читають боковим зором. */
.navitem, .exit, .inv-row, .who-row b, .who-row span {
  font-family: var(--font-body);
  letter-spacing: 0;
}

/* Числа статистики — моноширинні й білі: вони для порівняння, а не для краси. */
.stat b { color: #fff; font-family: var(--font-data); }
.stat span { color: #cfe4ca; letter-spacing: .04em; }

/* ── Рубрики: остаточно ───────────────────────────────────────────────────
   Правил для `.sec` за час роботи накопичилось шість у різних місцях файлу, і
   вони перебивали одне одного непередбачувано. Це останнє і навмисно
   безумовне: фіолетовий на дрібному кеглі втрачав контраст саме там, де його
   найважче читати.

   Шість правил на один селектор — сама по собі ознака, що файл час
   упорядкувати; поки що фіксуємо результат.

   21.09.2026 колір тут став білим. Попередній `--ink-2` — зеленувата
   крейда, і на темному склі рубрика читалась гірше за текст під нею:
   власник назвав заголовки нечитабельними. Саме ЦЕ правило вирішує колір
   (у нього id у селекторі), тож правиться воно, а не додається сьоме. */
#view .sec,
#ownerBody .sec,
.sec {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .12em;
  background: none;
  border: 0;
  padding: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  text-shadow: none;
  transform: none;
}

/* ═══════════════════════════════════════════════════════════════════════════
   ІНДИКАТОР ВІДКРИТОЇ ВКЛАДКИ — одне правило

   Їх було пʼять у різних місцях файлу: залита комірка, риска зверху, дві з
   подвійним урахуванням безпечної зони і остання з відʼємним відступом. Кожна
   писалась як виправлення попередньої, але жодна не прибирала її, тож вигравала
   просто найнижча — і смужка опинилась НИЖЧЕ вкладки, у порожньому відступі
   панелі, відірвана від підпису.

   Тут вона одна. Прив'язка до низу САМОЇ вкладки, а не до панелі: безпечна
   зона вже врахована відступом .bottomnav, і додавати її вдруге означає
   виштовхнути смужку за межі того, що вона позначає.
   ═══════════════════════════════════════════════════════════════════════════ */
.navitem.active::after {
  content: "";
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 1px;
  width: 24px;
  height: 3px;
  border-radius: 3px;
  background: var(--cyan);
  box-shadow: 0 0 10px rgba(79, 227, 255, .9);
}
/* ═══════════════════════════════════════════════════════════════════════════
   НАЗВА ЗʼЯВЛЯЄТЬСЯ ВЖЕ ЗЛАМАНОЮ

   Назва — єдиний хаотичний напис у статичному HTML: решту екрана малює скрипт,
   і до того часу гарнітури вже на місці. Тому показуємо її аж тоді, коли по
   ній пройшовся applyChaos — інакше видно проміжний стан, у якому вона ще
   звичайна.

   Розкриття продубльоване анімацією із затримкою: якщо скрипт з якоїсь причини
   не виконався, назва все одно зʼявиться за 1.2 с. Ховати текст назавжди
   заради усунення мерехтіння — гірше за саме мерехтіння.
   ═══════════════════════════════════════════════════════════════════════════ */
.brand { animation: brandReveal .18s ease 1.2s both; }
.brand[data-chaos] { animation: none; opacity: 1; }
@keyframes brandReveal { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .brand { animation-duration: .01s; }
}
/* ═══════════════════════════════════════════════════════════════════════════
   ІКОНКИ

   Контурний набір лежить у самому документі (див. index.html). Розмір задаємо
   тут, а колір успадковується від тексту — тож іконка завжди в тон підпису
   поруч, і не треба тримати окремі варіанти під кожен стан.
   ═══════════════════════════════════════════════════════════════════════════ */
.ic {
  width: 19px; height: 19px;
  flex: none;
  display: inline-block;
  vertical-align: -.28em;
  /* Тонкий контур на строкатому фоні губиться, тож під ним лежить та сама
     мʼяка тінь, що й під текстом поруч. */
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .75));
}
.ic.big { width: 25px; height: 25px; }
.navitem .ic { width: 21px; height: 21px; vertical-align: 0; }
.navitem.active .ic { filter: drop-shadow(0 0 7px rgba(79, 227, 255, .85)); }
.menucard .ic { display: block; margin: 0 auto 10px; }
.modeswitch .ic { width: 18px; height: 18px; vertical-align: -.24em; margin-right: 4px; }
.banner .ph .ic, .portrait-slot .ph .ic { width: 38px; height: 38px; opacity: .75; }
.portrait-slot .edit .ic { width: 15px; height: 15px; }

/* ═══════════════════════════════════════════════════════════════════════════
   НАЗВА В ШАПЦІ — ГОЛОВНИЙ ЗНАК, А НЕ ПІДПИС

   Заголовок екрана виглядав цікавіше за саму назву застосунку: у нього 46px і
   темна підкладка, у назви — 19px і нічого. Вийшло, що назва програє власному
   вмісту. Даємо їй ту саму підкладку й більший кегль: вона має бути першим,
   що впізнають, а не дрібним написом над контентом.
   ═══════════════════════════════════════════════════════════════════════════ */
.brand {
  font-size: clamp(19px, 6vw, 28px) !important;
  letter-spacing: -.035em;
  padding: 4px 2px;
}
.brand .chaos i {
  /* Літери назви більші за сусідні елементи шапки, тож і розкид між ними
     помітніший — саме за це око чіпляється як за знак. */
  font-size: 1.02em;
}
.topbar {
  /* Місця під більшу назву: баланс і аватар тиснуться, назва отримує решту. */
  gap: var(--s2);
  padding: 12px 14px;
}
.who b { font-size: 13px; }
.who { font-size: 9.5px; opacity: .8; }
/* ═══════════════════════════════════════════════════════════════════════════
   ЗАГОЛОВОК НЕ ВИЛАЗИТЬ ЗА КРАЙ

   Підкладка була розтягнута негативними полями до самого краю екрана, а літери
   в ній нахилені й трохи збільшені — тобто малюються ЗА межами свого рядка.
   Разом це давало обрізану останню літеру: місця для виступу просто не
   лишалось. Тепер плашка стоїть у колонці вмісту, як і решта панелей, і запас
   на виступ бере з її ж відступів.
   ═══════════════════════════════════════════════════════════════════════════ */
h1.screen {
  margin-left: 0;
  margin-right: 0;
  border-radius: var(--r-lg);
}
/* ═══════════════════════════════════════════════════════════════════════════
   ДІАГРАМИ АДМІНКИ

   Кільце — не прикраса: воно показує ЧАСТКУ, а частку око читає з кута краще,
   ніж із числа в таблиці. Тому в центрі стоїть сума, а поруч у легенді —
   обидва відсотки одразу (ходів і витрат): уся суть саме в їхній розбіжності.
   ═══════════════════════════════════════════════════════════════════════════ */
.donut-wrap { display: flex; gap: var(--s4); align-items: center; flex-wrap: wrap; }
.donut {
  width: 132px; height: 132px; flex: none;
  border-radius: 50%;
  position: relative;
  box-shadow: 0 6px 22px rgba(0, 0, 0, .45);
}
.donut-hole {
  position: absolute; inset: 26px;
  border-radius: 50%;
  background: rgba(11, 12, 13, .94);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
}
.donut-hole b {
  font-family: var(--font-data); font-size: 19px; color: #fff; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.donut-hole span { font-size: 13px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }

.legend-list { flex: 1; min-width: 168px; display: flex; flex-direction: column; gap: var(--s2); }
.lg-row {
  display: grid;
  grid-template-columns: 12px 1fr auto;
  grid-template-areas: "dot name cost" ". turns cost";
  gap: 2px 8px;
  align-items: center;
  font-size: 13px;
}
.lg-row b { grid-area: dot; width: 11px; height: 11px; border-radius: 3px; }
.lg-row span { grid-area: name; color: #eaf7e6; font-weight: 600; overflow-wrap: anywhere; }
.lg-row i { grid-area: turns; font-style: normal; font-size: 13px; color: var(--ink-3); }
.lg-row u {
  grid-area: cost; text-decoration: none;
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: 13px; font-weight: 700; color: var(--amber);
}

/* Доба: 24 стовпчики, пік підсвічений. Решта тиха — інакше графік читається як
   гірлянда, а не як розподіл. */
.chart.hours { gap: var(--s1); height: 96px; }
.chart.hours .col i { background: linear-gradient(180deg, rgba(79, 227, 255, .75), rgba(79, 227, 255, .2)); }
.chart.hours .col i.peak { background: linear-gradient(180deg, var(--amber), rgba(255, 209, 102, .3)); }

/* Воронка: довжина смуги — частка від першого кроку, тож видно саме падіння. */
.funnel { display: flex; flex-direction: column; gap: var(--s2); }
.fn-row { display: flex; align-items: center; gap: var(--s3); }
.fn-bar {
  height: 34px;
  border-radius: var(--r-sm);
  background: linear-gradient(90deg, rgba(79, 227, 255, .38), rgba(185, 140, 255, .3));
  border: 1px solid rgba(255, 255, 255, .18);
  display: flex; align-items: center;
  padding: 0 10px;
  min-width: 0;
}
.fn-bar span {
  font-size: 13px; font-weight: 600; color: #fff; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .85);
}
.fn-num {
  flex: none; text-align: right;
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: 15px; font-weight: 700; color: #fff; line-height: 1.05;
}
.fn-num i { display: block; font-style: normal; font-size: 13px; color: var(--ink-3); }
.fn-drop {
  flex: none;
  font-family: var(--font-data); font-size: 13px; font-weight: 700;
  color: #ff9ab4;
}

/* ═══════════════════════════════════════════════════════════════════════════
   НАЗВА — ЛОГОТИП У ДВА РЯДКИ

   Учора я збільшив її до 28px, не перевіривши, що в шапці стільки місця немає:
   поруч стоять аватар і баланс. Рядок не переносився, тож `overflow: hidden`
   просто зрізав хвіст — на екрані лишалось «МУЛЬТИВСЕ».

   Замість гри з кеглем робимо те, що робить будь-який знак у такій ситуації:
   ставимо дві частини одна під одною. «МУЛЬТИ» і «ВСЕСВІТ» — і так дві різні
   гарнітури, тож розділення читається як задум, а не як перенос. Кожна частина
   вдвічі коротша, отже вміщається із запасом і може бути більшою.
   ═══════════════════════════════════════════════════════════════════════════ */
.brand {
  display: flex;
  align-items: baseline;
  justify-content: flex-start;
  /* Назву не переносимо й не розриваємо НІКОЛИ: розділене навпіл імʼя читається
     як помилка верстки, а не як знак. Замість цього кегль підганяється під
     наявне місце (див. fitBrand у app.js) — тоді вона завжди ціла і завжди
     настільки велика, наскільки дозволяє шапка. */
  white-space: nowrap;
  /* Ховаємо переповнення як страхувальну сітку: якщо підбір кегля з якоїсь
     причини не спрацював, назва радше обріжеться, ніж наїде на баланс. У
     нормі до цього не доходить. */
  overflow: hidden;
  line-height: 1.05;
  font-size: 22px;
  gap: 0;
  transform-origin: left center;
}
.brand > span { display: inline; }
/* Друга частина трохи більша й зі зсувом — так пара читається як лігатура
   логотипа, а не як два незалежні слова. */
.brand span .chaos { margin-left: .06em; }

.topbar { align-items: center; padding: 10px 14px; }

/* ═══════════════════════════════════════════════════════════════════════════
   РУБРИКИ: ПЛАШКА МУСИТЬ ТРИМАТИ ТЕКСТ

   Матеріал .38 задумувався для плиток ВСЕРЕДИНІ карток, де під ним уже лежить
   темне скло. Рубрика ж стоїть просто на фотографії, і там та сама щільність
   пропускає весь малюнок — світлі ділянки фону проходять крізь неї й
   зʼїдають літери.

   Тоді в рубрики зробили власну, найщільнішу підкладку — і вона ж її й
   згубила: плашка з рамкою, тінню та розмиттям стала на вигляд така сама, як
   кнопка під нею («ХОДИ Й ТАРИФ» і «Поповнити ходи» в однакових рамках).
   apple-design §16: однакові на вигляд речі мусять однаково поводитись,
   інакше людина тисне на напис і перестає вірити формі.

   Читабельність поверх фону тепер тримає не підкладка, а тихіший колір і
   розріджений напис: рубрика більше не сперечається з текстом за увагу.
   Правило вище — єдине, що задає її вигляд.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
   ЛЕГЕНДА ГРАФІКА: КОЛЬОРОВІ ПОЗНАЧКИ ПОВЕРНУЛИСЬ

   Селектор `.legend b` означав дві різні речі одночасно: квадратик кольору під
   графіком динаміки і просто жирне слово в підписі під дашбордом світів.
   Пізніше правило зробило його `display: inline` — і квадратики зникли, бо
   ширина й висота на рядковому елементі не діють. Підпис лишився цілим,
   а легенда перетворилась на «AI-ходи безкоштовні» без жодної позначки.

   Розводимо за ознакою, яка вже є в розмітці: у квадратика власний колір
   у style, у жирного слова — ні.
   ═══════════════════════════════════════════════════════════════════════════ */
.legend b[style] {
  display: inline-block;
  width: 11px; height: 11px;
  border-radius: 3px;
  margin-right: 6px;
  vertical-align: -1px;
  border: 1px solid rgba(255, 255, 255, .25);
}
/* Пункти легенди йдуть у рядок і не злипаються. */
.legend span { display: inline-block; margin-right: 16px; white-space: nowrap; }

/* ═══════════════════════════════════════════════════════════════════════════
   СМУЖКА ГЕРОЇВ: ІКОНКА ЗАМІСТЬ ЕМОДЗІ
   ═══════════════════════════════════════════════════════════════════════════ */
.rost-face .ic { width: 26px; height: 26px; opacity: .55; }
.rost.on .rost-face .ic { opacity: .9; }

/* Підпис під обличчям не має обриватись на півслові там, де є місце. */
.rost { width: 82px; }
.rost b { font-size: 13px; }

/* Іконка в пігулці й у порожньому стані. Пігулка дрібна, тож іконка в ній
   помітно менша за навігаційну — інакше вона перебиває саме число.       */
.pill .ic { width: 14px; height: 14px; vertical-align: -.2em; margin-right: 2px; }
.empty .big .ic { width: 52px; height: 52px; opacity: .6; }
.card p .ic { width: 16px; height: 16px; vertical-align: -.24em; margin-right: 4px; }
.tip .ic { width: 16px; height: 16px; vertical-align: -.24em; margin-right: 4px; }
.card h3 .ic { width: 19px; height: 19px; vertical-align: -.2em; margin-right: 5px; }
.bar-label .ic { width: 15px; height: 15px; vertical-align: -.22em; margin-right: 3px; }

/* Правила білінгу приходять готовою розміткою з того самого сервісу, що й
   у чаті. Тут лише даємо їй дихати: суцільна стіна тексту в картці
   нечитабельна, а це саме той текст, який мусять дочитати.            */
.policy { line-height: 1.6; font-size: 14px; }
.policy b { color: #f4fbf2; }
.policy code { font-family: var(--font-data); font-size: 13px; background: var(--mat-1);
  padding: 2px 6px; border-radius: var(--r-sm); }

/* Підписи осі не переносяться: «08-03» у два рядки читається як два числа. */
.chart-x span { white-space: nowrap; font-size: 9.5px; letter-spacing: -.02em; }

/* ── Світ-передпокій ──────────────────────────────────────────────────────
   Виглядає інакше НАВМИСНО: приглушений, без акценту, з поясненням замість
   лічильників. Якби він виглядав як звичайна картка, різницю довелося б
   вгадувати з того, чого на ній НЕМАЄ, — а відсутність помічають найгірше. */
.card.hub { opacity: .92; border-style: dashed; }
.card.hub .banner { filter: grayscale(.55) brightness(.85); }
.hub-note {
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-2);
  border-left: 2px solid rgba(255, 255, 255, .22);
  padding-left: 10px;
  margin: 10px 0;
}

/* На найвужчих екранах (SE, складані) місця не вистачає обом. Прибираємо
   баланс, а не назву: баланс видно ще у двох місцях — на вкладці «Ходи» і в
   блоці «Ходи й тариф», — а назва в застосунку одна. */
@media (max-width: 359px) {
  .who { display: none; }
}
/* ═══════════════════════════════════════════════════════════════════════════
   ВІКНО ВВЕДЕННЯ

   Замінює браузерний prompt(). Стоїть по центру, затемнює все під собою і
   тримає фокус: поки воно відкрите, іншої дії в застосунку немає — саме тому
   в нього можна класти незворотні дії, які раніше йшли через системне вікно.
   ═══════════════════════════════════════════════════════════════════════════ */
.modal-wrap {
  position: fixed; inset: 0; z-index: 90;
  /* ШАР ГОРТАЄТЬСЯ САМ, І САМЕ ТОМУ `flex-start` + `margin: auto`.
     Було `align-items: center` без прокрутки: панель, вища за екран,
     вилазила за обидва краї — заголовок зрізався зверху, а кнопка внизу
     ставала недосяжною (власник 19.09.2026: «кнопка назад вилізла за
     екран»). Центрувати через `align-items` і гортати водночас не можна:
     верх вилізлого вмісту в такому контейнері недоступний назавжди —
     прокрутка до відʼємних координат не доходить. `margin: auto` центрує
     так само, але лишає верх у межах смуги прокрутки. */
  display: flex; align-items: flex-start; justify-content: center;
  overflow-y: auto;
  /* Догорнувши панель, палець не тягне сторінку під нею: у вебвʼю Telegram
     зайвий рух угорі — це жест закриття застосунку. */
  overscroll-behavior: contain;
  /* Поля Telegram: у повному екрані поверх застосунку висять рідні кнопки,
     і без цього запасу заголовок панелі ліз би просто під них. */
  padding: calc(20px + var(--tg-top)) 20px
           calc(20px + var(--tg-bottom) + env(safe-area-inset-bottom, 0px));
  background: rgba(5, 6, 7, .72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  animation: modalIn .16s var(--ease) both;
}
@keyframes modalIn { from { opacity: 0; } to { opacity: 1; } }
.modal {
  margin: auto;
  width: 100%; max-width: 420px;
  background: linear-gradient(180deg, rgba(25, 26, 29, .98), rgba(15, 16, 18, .99));
  border: 1px solid rgba(255, 255, 255, .22);
  border-top-color: rgba(255, 255, 255, .34);
  border-radius: var(--r-lg);
  box-shadow: 0 20px 60px rgba(0, 0, 0, .6);
  padding: 18px;
  animation: modalUp .2s var(--ease) both;
}
@keyframes modalUp { from { transform: translateY(14px) scale(.98); } to { transform: none; } }
.modal h3 {
  margin: 0 0 8px;
  font-family: var(--font-display); font-weight: 700; font-size: 18px;
  color: #f4fbf2;
}
.modal-hint { font-size: 13px; line-height: 1.55; color: var(--ink-2); margin: 0 0 12px; }
.modal input, .modal textarea { width: 100%; }
.modal textarea { min-height: 88px; }
.modal .actions { margin-top: 14px; }
.modal .actions button { flex: 1; }
.modal-err { color: #ff9ab4; font-size: 13px; min-height: 16px; margin-top: 6px; }

@media (prefers-reduced-motion: reduce) {
  .modal-wrap, .modal { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ПОТЯГНУТИ ВНИЗ — ОНОВИТИ

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

   Стоїть ВИЩЕ за шапку (z-index 40 проти 20): жест починається на самому
   верху екрана, тобто рівно там, де шапка, і знак під нею був би невидимий
   саме в ту мить, коли він потрібен.
   ═══════════════════════════════════════════════════════════════════════════ */
#pull {
  /* НА ВСЕ ВІКНО, хоч знак і завбільшки з монету. Маска рахується від коробки
     елемента, а згасати вона мусить рівно на верхньому краї шапки — у
     власній коробці 36px таке місце описати нічим. */
  position: fixed; inset: 0; z-index: 40;
  pointer-events: none;
  opacity: 0;
  /* Верхній край шапки — він же й край згасання. Їде вниз разом із нею. */
  --shapka-verkh: calc(var(--tg-top, 0px) + 10px + var(--pull-y, 0px));
  -webkit-mask-image: linear-gradient(
    to bottom, #000 0, #000 calc(var(--shapka-verkh) - 16px),
    transparent var(--shapka-verkh));
  mask-image: linear-gradient(
    to bottom, #000 0, #000 calc(var(--shapka-verkh) - 16px),
    transparent var(--shapka-verkh));
}
/* Запасний кружечок — якщо клітинки не доїхали. */
/* Піксельний портал із вебгри. Розмір у ЦІЛИХ клітинках (12 × 3 = 36px):
   дробовий коефіцієнт розмив би межі, і піксель перестав би бути пікселем. */
/* МІСЦЕ — НА ОБГОРТЦІ, ПОВОРОТ — НА КАРТИНЦІ.
   Один `transform` не може робити і те, і те: анімація задає його цілком, і
   браузер інтерполює зсув у поворот як одну матрицю — знак за цикл сповзає
   назад під шапку. Тому шари розділені. */
.pull-obid {
  position: absolute; left: 50%; margin-left: -18px;
  width: 36px; height: 36px; display: block;
  /* Спокій знака — рівно під верхнім краєм шапки, де його зʼїдає маска;
     тягнучи, ми піднімаємо його звідти на видне місце. */
  top: calc(var(--shapka-verkh) - 2px);
  transform: translateY(calc(var(--pull-t, 0) * -46px));
}
#pull .px,
#pull .krutylka-zapas {
  display: block; width: 36px; height: 36px; margin: 0;
  fill: var(--acid);
  filter: drop-shadow(0 0 10px rgba(var(--portal-rgb), .55));
  /* Крутиться ВЕСЬ ЧАС, поки видно. Кроками, а не безперервно: піксельний
     спрайт на проміжному куті перестає лежати на сітці й розмивається.

     ВІСЬ — НЕ ЦЕНТР КОРОБКИ. Малюнок 12×12, але портал займає рядки 1–8, а
     три нижні порожні: поворот навколо середини коробки возив би його по
     колу замість обертання. Середина самого кола — 5/12 висоти. */
  transform-origin: 50% 41.7%;
  animation: pixkrut .9s steps(12) infinite;
}
#pull.hotovo .px, #pull.kruty .px { animation-duration: .45s; }
#pull.kruty { opacity: 1; }
/* `from` названо явно: без нього браузер бере за початок ПОТОЧНИЙ transform
   елемента й інтерполює його в поворот — саме так зсув і подорожував. */
@keyframes pixkrut { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* ЗСУВ НА ЧАС ЖЕСТУ. Шапка, вміст і край маски під шапкою їдуть разом —
   кожен читає `--pull-y` сам. Возити `.wrap` не можна: `transform` на предку
   робить його точкою відліку для `fixed` і скасовує `sticky`. */
.topbar { transform: translateY(var(--pull-y, 0px)); }
/* ЗСУВ ВМІСТУ — ЛИШЕ НА ЧАС ЖЕСТУ. Постійний `translateY(0px)` це теж
   `transform`, а він робить елемент точкою відліку й ламає `position: sticky`
   всередині: панель каталогу перестала б прилипати під шапкою. */
:root.ie-pull #view,
:root.pull-plavno #view { transform: translateY(var(--pull-y, 0px)); }
/* Під пальцем — без згладжування, інакше картинка відстає від руки.
   Плавність вмикається лише на повернення. */
:root.pull-plavno .topbar,
:root.pull-plavno #view { transition: transform .22s var(--ease); }
:root.pull-plavno #pull { transition: opacity .22s var(--ease); }

@media (prefers-reduced-motion: reduce) {
  #pull .px, #pull .krutylka-zapas { animation: none !important; }
  :root.pull-plavno .topbar, :root.pull-plavno #view { transition: none; }
}

/* ЗАПАСНИЙ ВИХІД — ЛИШЕ ТАМ, ДЕ НЕМАЄ РІДНОГО.
   Власник 19.09.2026: «кнопку назад від самої панельки прибери, те ж саме
   зроби для всіх подібних контекстних меню». Він має рацію: у Telegram
   панель закриває рідна «←» у шапці, і друга кнопка всередині — це те саме
   рішення вдруге, тільки далі від пальця й на дні довгого списку.

   Але поза Telegram рідної кнопки НЕМАЄ (стенд, браузер), і видалена кнопка
   лишила б панель без виходу взагалі. Тому не видаляємо, а ховаємо — і лише
   тоді, коли оболонка справді дає свою: клас ставить `app.js`, побачивши
   `TG.BackButton`. */
:root.ie-ridnyi-back .zapasnyi-vykhid { display: none; }
/* ═══════════════════════════════════════════════════════════════════════════
   БОНУСИ

   Список, а не картки: три-чотири рядки з однаковою будовою читаються швидше
   за стос коробок. Отриманий бонус приглушений, але НЕ прихований — питання
   «звідки в мене ці ходи» так само важливе, як «що я ще не забрав».
   ═══════════════════════════════════════════════════════════════════════════ */
.bon-list { display: flex; flex-direction: column; gap: var(--s1); }
.bon-row {
  display: flex; align-items: center; gap: var(--s3);
  padding: 12px 2px;
  border-bottom: 1px solid var(--edge-soft);
}
.bon-row:last-child { border-bottom: 0; }
.bon-row.done { opacity: .62; }
.bon-main { flex: 1; min-width: 0; }
.bon-main b { display: block; font-size: 14.5px; color: #f4fbf2; }
.bon-main span { display: block; font-size: 13px; line-height: 1.45; color: var(--ink-3); margin-top: 2px; }
.bon-side { flex: none; display: flex; align-items: center; gap: var(--s2); }
.bon-side i {
  font-style: normal;
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: 16px; font-weight: 700; color: var(--amber);
}
.bon-row.done .bon-side i { color: var(--ink-2); }
/* ═══════════════════════════════════════════════════════════════════════════
   НАСТУПНИЙ КРОК

   Головний елемент першого екрана. Новачок має побачити ОДНУ дію, а не список
   із шести — список читається як домашнє завдання, крок виконується.
   ═══════════════════════════════════════════════════════════════════════════ */
.card.nowstep {
  border-color: rgba(79, 227, 255, .45);
  box-shadow: 0 8px 30px rgba(0, 0, 0, .4), 0 0 24px rgba(79, 227, 255, .16);
}
.nowstep-head { display: flex; align-items: center; gap: var(--s3); margin-bottom: 10px; }
.nowstep-num {
  flex: none;
  font-family: var(--font-data);
  font-size: 22px; font-weight: 700; color: var(--cyan);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.nowstep-num i { font-style: normal; font-size: 13px; color: var(--ink-3); }
.nowstep-head b {
  font-family: var(--font-display); font-weight: 700; font-size: 19px;
  color: #f4fbf2; letter-spacing: -.01em;
}
/* Сама дія — найбільший текст у картці: її читають і виконують. */
.nowstep-do { font-size: 15.5px; line-height: 1.5; color: #fff; margin: 0 0 8px; }
.nowstep-why { font-size: 13px; line-height: 1.5; color: var(--ink-2); margin: 0; }
.card.nowstep .actions button { width: 100%; }
/* ═══════════════════════════════════════════════════════════════════════════
   ЕКСКУРСІЯ КАБІНЕТОМ

   Затемнення робить не окремий шар, а САМА рамка — велетенською тінню назовні.
   Чотири прямокутники довкола цілі давали б щілини на стиках і розʼїжджались
   при прокрутці; тут отвір завжди рівно там, де ціль.
   ═══════════════════════════════════════════════════════════════════════════ */
.tour-veil { position: fixed; inset: 0; z-index: 100; pointer-events: auto; background: transparent; }
/* Затемнення зазвичай дає САМА рамка (`box-shadow` на 9999px довкола цілі).
   На кроці без цілі рамки немає — темніє вуаль, тим самим кольором, щоб перехід
   між кроками не зчитувався як спалах. */
.tour-veil.solid { background: rgba(5, 5, 6, .82); transition: background .22s var(--ease); }

.tour-ring {
  position: fixed;
  z-index: 101;
  border-radius: var(--r-md);
  border: 2px solid var(--cyan);
  box-shadow: 0 0 0 9999px rgba(5, 5, 6, .82), 0 0 22px rgba(79, 227, 255, .75);
  pointer-events: none;
  transition: top .22s var(--ease), left .22s var(--ease),
              width .22s var(--ease), height .22s var(--ease);
  animation: tourPulse 1.8s ease-in-out infinite;
}
@keyframes tourPulse {
  0%, 100% { box-shadow: 0 0 0 9999px rgba(5, 5, 6, .82), 0 0 18px rgba(79, 227, 255, .6); }
  50%      { box-shadow: 0 0 0 9999px rgba(5, 5, 6, .82), 0 0 30px rgba(79, 227, 255, .95); }
}

.tour-tip {
  position: fixed;
  z-index: 102;
  left: 14px; right: 14px;
  max-width: 460px;
  margin: 0 auto;
  padding: 16px;
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, rgba(25, 26, 29, .99), rgba(15, 16, 18, 1));
  border: 1px solid rgba(255, 255, 255, .24);
  border-top-color: rgba(255, 255, 255, .36);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .6);
  animation: modalUp .2s var(--ease) both;
}
.tour-count {
  font-family: var(--font-data);
  font-size: 13px; letter-spacing: .12em;
  color: var(--cyan);
  margin-bottom: 6px;
}
.tour-tip b {
  display: block;
  font-family: var(--font-display); font-weight: 700; font-size: 18px;
  color: #f4fbf2; margin-bottom: 6px;
}
.tour-tip p { margin: 0; font-size: 14px; line-height: 1.55; color: var(--ink-2); }
.tour-tip .actions { margin-top: 14px; }
.tour-tip .actions button { flex: 1; }
/* Картка без цілі: ставити її «під» або «над» нічим, тож ставимо посеред
   екрана. Верх і низ задаємо обидва — так вона лишається в межах екрана й на
   низькому пристрої, де інакше поїхала б за край. */
.tour-tip.mid {
  top: 50%; bottom: auto;
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  /* Власна поява, а не спільний modalUp: той закінчується на `transform: none`
     і, лишаючись на елементі (`fill-mode: both`), стирав би зсув на пів висоти.
     Картка тоді провисала б нижче середини — саме тим «сіпанням», яке видно
     на око. Центрування мусить жити ВСЕРЕДИНІ анімації. */
  animation: tourMid .2s var(--ease) both;
}
@keyframes tourMid {
  from { transform: translateY(calc(-50% + 14px)) scale(.98); }
  to   { transform: translateY(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .tour-ring { animation: none; transition: none; }
  .tour-tip { animation: none; }
  /* Без анімації зсув нема кому задати — повертаємо його простим правилом. */
  .tour-tip.mid { animation: none; transform: translateY(-50%); }
  .tour-veil.solid { transition: none; }
}

/* ── Рекомендований світ ──────────────────────────────────────────────────
   Одна позначка на весь каталог. Дві вже не підказка, а шум: якщо виділено
   все, не виділено нічого. */
.card.pick {
  border-color: rgba(79, 227, 255, .5);
  box-shadow: 0 10px 34px rgba(0, 0, 0, .42), 0 0 26px rgba(79, 227, 255, .2);
}
.pick-tag {
  display: inline-block;
  font-family: var(--font-data);
  font-size: 13px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase;
  color: #062028;
  background: linear-gradient(135deg, var(--cyan), #8ef0ff);
  padding: 4px 10px;
  border-radius: 999px;
  margin-bottom: 10px;
}
/* ── Смужка кроку ─────────────────────────────────────────────────────────
   Один рядок замість цілого екрана-орієнтира. Стоїть над списком, зникає
   разом із виконаним кроком і нічого не вимагає натискати — просто каже, що
   тут робити далі. */
.stepstrip {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  padding: 11px 14px;
  margin: 0 0 14px;
  border-radius: var(--r-md);
  background: linear-gradient(90deg, rgba(79, 227, 255, .16), rgba(185, 140, 255, .1));
  border: 1px solid rgba(79, 227, 255, .32);
  font-size: 14px;
  line-height: 1.45;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .8);
}
.stepstrip-num {
  flex: none;
  font-family: var(--font-data);
  font-size: 13px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--cyan);
}
/* ── Екскурсія: вихід має бути очевидним ──────────────────────────────────
   Шар, що накриває екран і ловить дотики, ЗОБОВʼЯЗАНИЙ мати помітний вихід.
   Інакше людина, яка не влучила в кнопку, вважає застосунок зламаним — і має
   рацію, бо для неї він саме такий. */
.tour-veil { cursor: pointer; }
.tour-tip { position: fixed; cursor: default; }
.tour-x {
  position: absolute;
  top: 8px; right: 8px;
  width: 32px; height: 32px;
  min-height: 32px;
  padding: 0;
  border-radius: 50%;
  font-size: 20px; line-height: 1;
  background: rgba(255, 255, 255, .1);
  border: 1px solid rgba(255, 255, 255, .2);
  color: #fff;
  box-shadow: none;
}

@media (hover: hover) {
  .tour-x:hover { background: rgba(255, 255, 255, .2); }
}
.tour-tip .tour-count { padding-right: 40px; }
.tour-hint {
  margin-top: 10px;
  text-align: center;
  font-size: 13px;
  color: var(--ink-3);
}

/* ── Правила білінгу: текст приходить рядками, а не абзацами ──────────────
   Сервіс віддає готовий текст із переносами `\n` — у чаті Telegram вони
   працюють, у HTML схлопуються в один суцільний абзац. Через це блок правил
   виглядав як стіна тексту. Зберігаємо переноси, не дублюючи розмітку. */
.policy { white-space: pre-line; }
/* ── Досьє персонажа ───────────────────────────────────────────────────────
   Вкладки, а не довгий сувій: «що про мене памʼятають» і «хто мене любить» —
   різні питання, і змішані в одному потоці вони заважають одне одному. */
.modal.wide { max-width: 560px; width: calc(100vw - 28px); }

/* Необовʼязкові поля створення світу згорнуті: форма з чотирьох полів лякає
   менше за форму з дванадцяти секцій, а хто хоче — розгорне. */
.nwmore {
  margin: 2px 0 10px;
  border: 1px solid var(--edge-soft);
  border-radius: 12px;
  padding: 0 12px;
  background: var(--mat-1);
}
.nwmore > summary {
  cursor: pointer;
  padding: 10px 0;
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--ink-2);
  list-style: none;
}
.nwmore > summary::-webkit-details-marker { display: none; }
.nwmore > summary::before { content: "＋ "; opacity: .7; }
.nwmore[open] > summary::before { content: "－ "; }
.nwmore[open] { padding-bottom: 4px; }

.dossier-tabs {
  display: flex; gap: var(--s2);
  margin: 4px 0 14px;
  overflow-x: auto;
  /* Смужка вкладок гортається вбік, але сама сторінка — ні: інакше на вузькому
     екрані від дотику їде весь застосунок. */
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.dossier-tabs::-webkit-scrollbar { display: none; }

.dossier-tab,
.mem-chip {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: var(--s2);
  padding: 8px 13px;
  border-radius: 999px;
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--ink-2);
  background: var(--mat-1);
  border: 1px solid var(--edge-soft);
  cursor: pointer;
  white-space: nowrap;
  transition: background .16s var(--ease), color .16s var(--ease), border-color .16s var(--ease);
}
.dossier-tab .ic { width: 16px; height: 16px; }
.dossier-tab.on,
.mem-chip.on {
  color: #061109;
  background: var(--acid);
  border-color: var(--acid);
  font-weight: 700;
}

/* Імена NPC у «Памʼяті» — той самий вигляд, що й вкладки досьє (правила вище
   спільні), але окремий клас: dossierRender() перемикає `.on` у всіх
   `.dossier-tab` за DOSSIER_TAB, і чіпи, які носили б той клас, він гасив би
   при кожному перемальовуванні. */
.mem-chips {
  display: flex; flex-wrap: wrap; gap: var(--s2);
  margin: 2px 0 12px;
}

.dossier-body {
  max-height: min(62vh, 520px);
  overflow-y: auto;
  /* Місце під смугу прокрутки, щоб вміст не стрибав при її появі. */
  padding-right: 4px;
}
.dossier-body .sec:first-child { margin-top: 0; }
.dossier-body .who-row { margin-bottom: 8px; }
.dossier-body .who-row span { display: block; margin-top: 3px; }
.dossier-body .pill { margin-right: 5px; }

/* ── Донат: ID гравця важливіший за посилання ─────────────────────────────
   Без ID у коментарі платіж анонімний, і адмін не знає, кому нараховувати
   ходи. Тому число велике, моноширинне й копіюється в один тап. */
/* Курс донату. Таблиця, а не текст: гравець порівнює суми поглядом, і
   вирівняні колонки роблять це за секунду. */
/* Обкладинка в майстрі створення світу. Той самий вигляд, що й у банера
   готового світу, — щоб людина одразу бачила, як це виглядатиме в списку. */
.nwphoto {
  position: relative;
  height: 140px;
  margin: 12px 0 4px;
  border-radius: 14px;
  overflow: hidden;
  display: grid;
  place-items: center;
  background: rgba(255, 255, 255, .05);
  border: 1px dashed rgba(255, 255, 255, .18);
  cursor: pointer;
}
.nwphoto img { width: 100%; height: 100%; object-fit: cover; }
.nwphoto .veil {
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, .72), transparent 60%);
}
.nwphoto .cap {
  position: absolute; left: 12px; right: 12px; bottom: 10px;
  font-size: .82rem; color: #fff;
}

@media (hover: hover) {
  .nwphoto:hover { border-color: rgba(var(--portal-rgb), .45); }
}

.tiers {
  list-style: none;
  margin: 12px 0;
  padding: 0;
  display: grid;
  gap: 6px;
}
.tiers li { display: block; }
.tiers .tier {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 12px 14px;
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 12px;
  background: rgba(255, 255, 255, .04);
  color: inherit;
  font: inherit;
  text-align: left;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

@media (hover: hover) {
  .tiers .tier:hover { background: rgba(var(--portal-rgb), .14); }
}
/* Фокус із клавіатури не залежить від миші — лишається поза умовою наведення. */
.tiers .tier:focus-visible { background: rgba(var(--portal-rgb), .14); }
.tiers .tier b { font-size: 1.05rem; }
.tiers-old {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 8px 12px;
  border-radius: 10px;
  background: rgba(255, 255, 255, .04);
  font-variant-numeric: tabular-nums;
}
.tiers li span { color: var(--muted, #9aa8a0); }

.idbox {
  margin: var(--s4) 0 var(--s3);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  background: rgba(var(--portal-rgb), .10);
  border: 1px dashed var(--portal-mid);
  cursor: pointer;
  text-align: center;
  transition: background .16s var(--ease);
}

@media (hover: hover) {
  .idbox:hover { background: rgba(var(--portal-rgb), .16); }
}
.idbox:active { transform: none; }
.idbox span {
  display: block;
  font-size: var(--t-small);
  color: var(--ink-3);
}
.idbox b {
  display: block;
  margin: var(--s1) 0;
  font-family: var(--font-data);
  font-size: 26px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--acid);
  font-variant-numeric: tabular-nums;
}
.idbox i {
  font-size: 13px;
  color: var(--ink-3);
  font-style: normal;
}
.warnline {
  margin: 0 0 var(--s3);
  padding: var(--s2) var(--s3);
  border-radius: var(--r-sm);
  border-left: 3px solid var(--warn, #e0a355);
  background: rgba(224, 163, 85, .10);
  font-size: var(--t-small);
  color: var(--ink-2);
}

/* ── Ціна: гривня головна, долар довідковий ───────────────────────────────
   Гравець платить у гривні через банку, тож саме вона має читатись першою.
   Долар лишається, бо ціни в пакетах задані в ньому й так їх легше звіряти. */
.pricerow {
  display: flex; align-items: baseline; gap: var(--s2);
  margin: 0 0 var(--s1);
}
.pricerow b {
  font-family: var(--font-display);
  font-size: 24px; font-weight: 800;
  color: var(--acid);
  font-variant-numeric: tabular-nums;
}
.pricerow span { font-size: var(--t-small); color: var(--ink-3); }
.pricenote {
  margin: 0 0 var(--s2);
  font-size: var(--t-small);
  color: var(--ink-3);
}
.pricenote b { color: var(--acid); }

/* ── Зріз за добу: лійка утримання ─────────────────────────────────────────
   Стовпчик відсотків читається гірше за смуги: різницю між 73% і 36% око
   бачить одразу, а між двома числами — лише прочитавши обидва. Тут потрібне
   саме перше: питання до цього блоку не «скільки», а «де обривається». */
.sec2 {
  font-family: var(--font-data);
  font-size: var(--t-label); letter-spacing: 2px; text-transform: uppercase;
  color: var(--ink-3); font-weight: 700;
  margin: 20px 0 10px;
}
.funnel { display: flex; flex-direction: column; gap: 7px; }
.funrow { display: grid; grid-template-columns: 76px 1fr 62px; align-items: center; gap: 8px; }
/* На вузькому екрані смуга стискається до крапки й перестає бути смугою —
   тобто перестає робити те єдине, заради чого вона тут. Тоді підпис і числа
   йдуть у рядок над нею, а смузі лишається вся ширина. */
@media (max-width: 340px) {
  .funrow { grid-template-columns: 1fr auto; gap: 2px 8px; }
  .funbar { grid-column: 1 / -1; }
}
.funlab { font-size: var(--t-small); color: var(--ink-2); }
.funbar {
  height: 9px; border-radius: 5px; overflow: hidden;
  background: rgba(255, 255, 255, .07);
}
.funbar > i {
  display: block; height: 100%; border-radius: 5px;
  background: linear-gradient(90deg, var(--portal), rgba(120, 220, 170, .55));
  min-width: 2px;
}
.funval {
  font-family: var(--font-data); font-variant-numeric: tabular-nums;
  font-size: var(--t-small); color: var(--ink-3); text-align: right;
}

/* ── Скарги та архів геймплею ──────────────────────────────────────────────
   Обидва блоки показують ЧУЖИЙ текст — репліку гравця й відповідь гри. Тому
   вони мусять читатись як цитата, а не як інтерфейс: інакше око не відрізняє,
   де слова людини, а де підписи панелі. */
.complaint, .storycard {
  border-top: 1px solid var(--line);
  padding: 14px 0 4px;
}
.complaint.isnew { border-left: 2px solid var(--portal); padding-left: 10px; }
.cbody { margin: 8px 0; font-size: var(--t-body); }
.turnbox, .leadup {
  margin: 8px 0; padding: 10px 12px;
  background: rgba(255, 255, 255, .04);
  border-radius: 8px;
}
.tlab {
  font-family: var(--font-data); font-size: var(--t-label);
  letter-spacing: 1px; text-transform: uppercase; color: var(--ink-3);
  margin-bottom: 4px;
}
.tsaid { color: var(--portal); font-size: var(--t-small); margin: 6px 0; }
.tgame { color: var(--ink-2); font-size: var(--t-small); line-height: 1.55; }
.leadrow { color: var(--ink-3); font-size: var(--t-small); margin: 2px 0; }

/* ── Гортання довгих списків ───────────────────────────────────────────────
   Керування стоїть і зверху, і знизу списку: після п'яти карток із повними
   текстами до верхньої кнопки вже не докрутитись, а до нижньої — не докрутитись
   заздалегідь. */
.pager {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 0; border-top: 1px solid var(--line);
}
.pager:first-child { border-top: 0; padding-top: 0; }
.pgnum {
  font-family: var(--font-data); font-size: var(--t-small);
  color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.tiny[disabled] { opacity: .35; pointer-events: none; }
.tiny.ghost { margin-left: auto; opacity: .75; }

/* Створення світу згорнуте, бо вкладка «Світи» — це передусім КАТАЛОГ.

   Форма стояла першою й займала екран цілком: людина відкривала світи й
   бачила не те, у що можна зайти, а анкету. Власник сказав прямо: «перше що
   ми бачимо це оце створення світу, а мали б бачити чужі».

   Згорнутий рядок лишається зверху навмисно: створити свій світ — найсильніша
   причина залишитись, і ховати її на третій екран було б іншою крайністю. */
/* Створення світу — ДІЯ, а не налаштування, і виглядати має як дія.
   Успадкована від `.nwmore` майже прозора плитка на фоновому фото читалась
   ледве: власник сказав «кнопку не такою прозорою треба зробить, бо погано
   видно». */
.nwfold {
  margin-bottom: 12px;
  background: rgba(18, 63, 22, .55);
  border-color: rgba(var(--portal-rgb), .45);
  box-shadow: 0 0 0 1px rgba(var(--portal-rgb), .10), var(--glow);
}
.nwfold > summary {
  font-weight: 700;
  font-size: 15px;
  color: var(--acid);
  text-transform: none;
  letter-spacing: .01em;
  padding: 13px 0;
}
.nwfold[open] {
  padding: 0 8px 8px;
  background: rgba(18, 63, 22, .38);
}

/* Заголовки блоків анкети. Чотири короткі кроки читаються як шлях, а той
   самий набір полів суцільною стрічкою — як стіна. */
.nwsec {
  margin: 16px 0 8px;
  font-family: var(--font-data);
  font-size: 13px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* Відповідь одним тапом замість поля вводу. */
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 10px; }
.chip {
  padding: 7px 12px;
  border-radius: 999px;
  border: 1px solid var(--edge-soft);
  background: var(--mat-1);
  color: var(--ink-2);
  font-size: 13px;
  cursor: pointer;
}
.chip.on {
  border-color: rgba(var(--portal-rgb), .55);
  color: var(--acid);
  background: rgba(var(--portal-rgb), .16);
}

/* ── Легенда карти й кнопка «вся карта» ─────────────────────────────────────
   Було: суцільний рядок «◉ вхід у світ · → лише в один бік · цифра — скільки
   NPC» плюс кнопка, втиснута в той самий рядок. На телефоні воно
   переносилось де завгодно, і кнопка опинялась посеред тексту.

   Тепер це список: кожен знак поруч зі своїм поясненням, а кнопка живе НАД
   картою, у її правому верхньому куті, — там, де такі кнопки й шукають. */
ul.legend {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 6px 12px;
  margin: 10px 0 0;
  padding: 10px 12px;
  list-style: none;
  font-size: 13px;
  line-height: 1.35;
  color: var(--ink-3);
}
ul.legend li { display: flex; align-items: center; gap: 7px; }
ul.legend i {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px;
  font-style: normal; font-size: 13px; font-family: var(--font-data);
}
.lg-spawn {
  border-radius: 50%;
  background: rgba(var(--portal-rgb), .22);
  border: 2px solid var(--portal);
}
.lg-arrow { color: var(--ink-2); font-size: 15px; }
.lg-num {
  border-radius: 50%;
  background: var(--mat-1);
  border: 1px solid var(--edge-soft);
  color: var(--ink-2); font-weight: 700;
}
.lg-ring {
  border-radius: 50%;
  border: 1px dashed rgba(168, 201, 164, .45);
}

.mapfit {
  position: absolute; top: 10px; right: 10px; z-index: 3;
  width: 34px; height: 34px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; line-height: 1;
  border-radius: 10px;
  color: var(--ink-2);
  background: rgba(16, 17, 20, .82);
  border: 1px solid var(--edge-soft);
  backdrop-filter: blur(6px);
}
.mapfit:active { background: rgba(var(--portal-rgb), .18); color: var(--acid); }

/* Надіте видно в рюкзаку одразу: щит у назві й кнопка «зняти» замість
   «надіти». Без цього єдиний спосіб дізнатись, що на тобі, — рядок «нічого
   не надіто» в картці, який мовчить про те, ЩО саме можна надіти. */
.inv-row.worn { background: rgba(var(--portal-rgb), .10); }
.inv-row .q { display: inline-flex; align-items: center; gap: 8px; }
.inv-row .q button { padding: 3px 10px; font-size: 13px; }

/* ────────────────────────────────────────────────────────────────────────
   ВІДСТУПИ Й ІНВЕНТАР · 10.09.2026
   ──────────────────────────────────────────────────────────────────────── */

/* Скарга власника: «додати відступи уніфіковані між плитками бо вони всюди
   злиплися». Причина видна з файлу: `.sec` і `.card` перевизначені десятком
   шарів, і кожен наступний правив вигляд, не чіпаючи відстані. Тому відстані
   зібрані ТУТ, в одному місці, і взяті з однієї змінної: далі змінювати
   доведеться одне число, а не десять правил. */
:root {
  --gap-tile: 14px;   /* між сусідніми плитками одного рівня */
  --gap-sec: 24px;    /* перед заголовком розділу */
}

/* Заголовок розділу відсуває від попереднього блока, а не від наступного:
   він належить тому, що ПІД ним. Перший у списку зайвого відступу не дістає. */
.sec { margin: var(--gap-sec) 0 10px; }
.sec:first-child { margin-top: 4px; }

.card { margin-bottom: var(--gap-tile); }
.card:last-child { margin-bottom: 0; }

/* Плитки, які раніше злипалися, бо відступу не мали зовсім. */
.tip + .tip,
.who-row + .who-row,
.inv-list + .inv-list,
.actions + .sec,
.card + .card { margin-top: var(--gap-tile); }
/* Усередині панелі порад проміжку немає: рядки розділяє волосінь, а не
   повітря. Тут стояв `gap`, і він розсипав панель назад на плашки. */
.tips { gap: 0; }

/* ── Інвентар ───────────────────────────────────────────────────────────
   Було: список має і зазор між рядками, і волосинку-роздільник — два різні
   способи розділити те саме, тож рядки виглядали то злиплими, то рваними.
   Лишаємо ОДИН: суцільна коробка з волосинками, як у списках iOS. */
.inv-list { gap: 0; margin-top: 0; }

.inv-list .inv-row {
  min-height: 44px;              /* палець влучає з першого разу */
  padding: 10px 14px;
  gap: var(--s3);
}

/* Назва предмета — головне в рядку, кількість і кнопка тримаються праворуч
   і не стрибають від довжини назви. */
.inv-list .inv-row > span:first-child { flex: 1 1 auto; line-height: 1.35; }
.inv-list .inv-row .q { flex: 0 0 auto; gap: 10px; }
.inv-list .inv-row .q button { min-height: 30px; border-radius: var(--r-sm); }

/* Надіте позначаємо смужкою збоку, а не заливкою на всю ширину: заливка
   робила рядок схожим на виділення, тобто на щось тимчасове. */
.inv-list .inv-row.worn {
  background: rgba(var(--portal-rgb), .07);
  box-shadow: inset 3px 0 0 var(--acid);
}

/* ── Згортання довгих блоків ────────────────────────────────────────────
   Памʼять оповідача — стіна тексту на пів екрана. Згорнуте видно рядком,
   розгорнуте видно ПОВНІСТЮ: нічого не обрізаємо назавжди. */
.fold {
  margin-bottom: var(--gap-tile);
  border: 1px solid var(--edge-soft);
  border-radius: var(--r-md);
  background: var(--mat-2);
  overflow: hidden;
}
.fold > summary {
  cursor: pointer;
  list-style: none;
  display: flex; align-items: center; gap: var(--s2);
  padding: 12px 14px;
  font-family: var(--font-data);
  font-size: 13px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--portal); font-weight: 700;
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::before { content: "＋"; opacity: .75; font-size: 14px; }
.fold[open] > summary::before { content: "－"; }
.fold[open] > summary { border-bottom: 1px solid var(--edge-soft); }
.fold > summary:active { background: rgba(var(--portal-rgb), .08); }

/* Довідка про оплату — та сама згортка, лише з полями для тексту.

   Тут стояв голий `details` із класом `tinyhelp`, якого в стилях не
   існувало ЗОВСІМ: браузер малював власний сірий трикутник, текст ліз
   упритул до країв, і блок виглядав приліпленим до сторінки збоку.
   Свого матеріалу не вигадуємо — рамка, фон і шапка з `.fold`. */
.tinyhelp > p,
.tinyhelp > .actions {
  padding: 0 14px;
  margin: 12px 0;
}
.tinyhelp > p { color: var(--ink-2); font-size: var(--t-small); line-height: 1.55; }
.tinyhelp > .actions { padding-bottom: 14px; }

/* Скільки там усередині — щоб рішення «розгортати чи ні» ухвалювалось до
   натискання, а не після. */
.foldsize {
  margin-left: auto;
  font-size: 13px; letter-spacing: .04em; text-transform: none;
  color: var(--ink-3); font-weight: 400;
}

.fold > .policy { margin: 0; padding: 14px; }
.fold > .inv-list { border: 0; border-radius: 0; background: transparent; }

/* Картка запрошення (04.11.2026): посилання, кнопки й рядок «Увійшло…» —
   окремі шари з однаковим проміжком. Досі рядок лип до кнопок: `.inv-row`
   не має власного відступу, а `.actions` дає його лише зверху. */
.zapr-kartka { display: flex; flex-direction: column; gap: var(--s2); }
.zapr-kartka > .actions,
.zapr-kartka > .inv-row { margin: 0; }
.zapr-kartka + .zapr-kartka { margin-top: var(--s3); padding-top: var(--s3); border-top: 1px solid var(--edge-soft); }
.zapr-kartka + .nwmore, .tip + .zapr-kartka, .tip + .actions { margin-top: var(--s3); }
.zapr-kod > .field { margin-top: var(--s2); }

/* ── Досьє героя на телефоні (04.11.2026) ─────────────────────────────────
   Аркуш, а не коробка посеред екрана: шапка з назвою, хрестиком і вкладками
   стоїть, гортається лише вміст. Досі гортався весь шар — вкладки відʼїжджали
   вгору, а «Закрити» жило в самому низу сувою на 5 700 px. Матеріал увесь
   наявний (.modal, .mem-card, .who-row, .fold, .dossier-tab); тут розкладка. */
.dosie-wrap { padding-left: 10px; padding-right: 10px; }
.modal.dosie {
  display: flex; flex-direction: column;
  max-height: calc(100vh - 40px - var(--tg-top, 0px) - var(--tg-bottom, 0px));
  max-height: calc(100dvh - 40px - var(--tg-top, 0px) - var(--tg-bottom, 0px));
  width: 100%; padding: 0; overflow: hidden;
}
.dosie-shapka {
  position: relative;
  padding: 14px 14px 10px;
  border-bottom: 1px solid var(--edge-soft);
}
.dosie-shapka h3 { margin: 0 44px 12px 0; }
.dosie-shapka .tour-x { top: 12px; right: 12px; }
.dosie-shapka .dossier-tabs { margin: 0; gap: 3px; }
/* П'ять вкладок у ширину телефона; вужчий екран — гортання, як і досі. */
.dosie-shapka .dossier-tab { flex: 1 0 auto; justify-content: center; padding: 7px 6px; }
.modal.dosie .dossier-body {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 14px 14px 18px;
}
.modal.dosie .dossier-body > .sec:first-child { margin-top: 0; }
.modal.dosie .dossier-body > .pricenote { margin: 0 0 var(--s3); }
.modal.dosie .dossier-body > .mem-card + .sec,
.modal.dosie .dossier-body > .dh-grupa + .sec { margin-top: var(--s4); }

/* Розділ досьє оповідача: заголовок з емодзі, під ним людина на рядок. */
.dh-grupa { padding: 12px 14px; border: 1px solid var(--edge-soft); border-radius: var(--r-md); background: var(--mat-2); }
.dh-grupa + .dh-grupa { margin-top: var(--s2); }
.dh-zah { font-weight: 700; font-size: var(--t-body); margin-bottom: 6px; }
.dh-punkt { display: flex; flex-direction: column; gap: 2px; padding: 8px 0; font-size: var(--t-small); line-height: 1.5; color: var(--ink-2); }
.dh-punkt + .dh-punkt { border-top: 1px solid var(--edge-soft); }
.dh-punkt b { color: var(--ink); font-size: var(--t-body); }
.dh-porozhno { margin: 0; color: var(--ink-3); font-size: var(--t-small); }

/* Літопис: вкладене — без власної рамки, лише відступ і лінія ліворуч. */
.dh-z-choho { margin-top: 10px; }
.dh-z-choho > summary {
  cursor: pointer; list-style: none;
  font-family: var(--font-data); font-size: 13px; color: var(--portal);
}
.dh-z-choho > summary::-webkit-details-marker { display: none; }
.dh-z-choho > summary::before { content: "＋ "; opacity: .75; }
.dh-z-choho[open] > summary::before { content: "－ "; }
.dh-vkladena { margin-top: 10px; padding-left: 12px; border-left: 2px solid var(--edge-soft); }

/* Очікування досьє — ASCII-хвиля всередині аркуша: без підкладки й без
   вертикальних полів цілого екрана, порожній підпис не займає місця. */
.modal.dosie .az { padding: 32px 0; min-height: 0; }
.modal.dosie .az-blok { background: none; border: 0; padding: 0; }
.modal.dosie .az-napys:empty { display: none; }
.dh-bits { font-family: var(--font-data); font-size: 13px; color: var(--acid); }

/* ── Спогади NPC ──────────────────────────────────────────────────────────
   Було: імʼя, пігулка довіри, пігулка часу й сам спогад в одному потоці з
   `<br>` посередині. Нічого не вирівнювалось — час висів на іншій висоті,
   ніж імʼя, а текст починався з випадкового відступу. І дві пігулки поруч
   важили однаково, хоч довіра тут головна, а час — довідка.

   Тепер: шапка окремим рядком (flex), тіло окремим абзацом, час прибитий
   праворуч і приглушений. Відступи — з тих самих змінних, що й решта плиток. */
.mem-card {
  padding: 12px 14px;
  border: 1px solid var(--edge-soft);
  border-radius: var(--r-md);
  background: var(--mat-2);
}
.mem-card + .mem-card { margin-top: var(--s2); }

.mem-head {
  display: flex; align-items: center; gap: var(--s2);
  margin-bottom: 6px;
  min-height: 22px;
}
.mem-who {
  color: #f4fbf2;
  font-size: 14px;
  /* Довге імʼя не має відтісняти час за край. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 55%;
}
/* Час — довідка, а не подія: жене праворуч і не сперечається з довірою. */
.mem-when {
  margin-left: auto;
  flex: none;
  font-family: var(--font-data);
  font-size: 13px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.mem-body {
  margin: 0;
  font-size: var(--t-small);
  line-height: 1.5;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
/* Пігулка довіри в шапці — компактніша за звичайну: вона тут акцент, а не
   самостійний елемент. */
.mem-head .pill {
  flex: none;
  padding: 2px 8px;
  font-size: 13px;
  /* У досьє стоїть `.pill { margin-right: 5px }` — воно ламало б `gap`
     шапки, додаючи відступ понад нього. Тут інтервал задає flex. */
  margin-right: 0;
}

/* Рамка кидка моноширинна — інакше стовпчики розповзаються, і саме тому
   вона взагалі рамка. */
.turn-dm pre {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px; line-height: 1.35;
  overflow-x: auto; margin: 0 0 8px;
}
.turn-wait { color: var(--ink-3); font-style: italic; }
.turn-dm.err { border-color: var(--bad, #c66); }

/* Тумблер мови в шапці.

   Мова інтерфейсу належить гравцю, а не його телефону, і вибір мусить бути
   видимий. Стоїть у шапці, а не в налаштуваннях: він потрібен рівно тоді,
   коли людина бачить не свою мову, тобто ще до того, як здогадається шукати
   меню. */
.mova-tumbler {
  flex: none;
  margin-left: 8px;
  padding: 3px 8px;
  border: 1px solid var(--line, #3a3a3a);
  border-radius: 6px;
  background: transparent;
  color: var(--ink-2, #9a9a9a);
  font: 600 11px/1 system-ui, sans-serif;
  letter-spacing: .04em;
  cursor: pointer;
}

@media (hover: hover) {
  .mova-tumbler:hover { color: var(--ink, #d2d2d2); }
}
.mova-tumbler[disabled] { opacity: .5; cursor: default; }

/* Вивіска «тестові онлайн-світи» — попередження, а не реклама: тихий колір,
   тонка рамка, без заливки. */
.card.note-test { border-style: dashed; }
.card.note-test .body p { margin: 0 0 6px; color: var(--ink-2, #9a9a9a); font-size: 13px; }
.card.note-test .body p:last-child { margin-bottom: 0; }

/* Режим світу в ряду характеристик — головний факт картки, тому він бере
   інформаційний тон (`.pill.info`), а повний світ — тривожний (`.pill.hot`);
   обидва кольори гра вже вживає. Пунктир звідси знято: у грі пунктирна рамка
   означає попередження (`.card.note-test`), і на звичайній пігулці читалась
   як помилка. */
.pill.mode { font-variant-numeric: tabular-nums; }

/* Пошук у вітрині світів.

   Каталог виріс, і вибирати очима в довгому списку стало неможливо. Поле
   стоїть над списком і фільтрує на льоту — тому воно й не всередині картки:
   перемальовується лише список, а фокус лишається в полі. */
.searchbar { margin: 0 0 10px; }
.searchbar input[type="search"] {
  width: 100%; background: var(--void-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 9px 12px; font-family: var(--font-body); font-size: var(--t-body);
}
.searchbar input[type="search"]:focus {
  outline: none; border-color: var(--portal); box-shadow: var(--glow);
}
/* Підзаголовок розділу вітрини: чий це список і за яким правилом. */
.sec small { font-size: 13px; margin-top: 2px; }


/* ── Вітрина світів ───────────────────────────────────────────────────────
   Власник: «панельки надто прозорі, з розділами незручно». Обидві скарги про
   одне — вітрину не можна прочитати з першого погляду.

   Прозорість: спільний матеріал панелей — скло (`--mat` ≈ 0.62) поверх
   фонового фото. Для тексту в кабінеті цього досить, а для списку з
   тринадцяти карток — ні: фон просвічує крізь кожну, і сусідні картки
   зливаються. Вітрина бере щільний матеріал і не розмиває тло.

   Розділи: два заголовки й два стоси карток означали довгу прокрутку, щоб
   дійти до другого. Замість них — вкладки з лічильниками: список один, а
   перемикання миттєве. Так це роблять каталоги, які працюють (itch.io). */
/* Вкладки й фільтри — ТИМИ САМИМИ кнопками, що вся гра.

   Власник 18.09.2026: «надтопрозорі кнопки по типу соло спільні… кнопки оці
   нові некрасиві, уніфікуй їх до інших кнопок у грі». Вони й були чужі:
   `.chip` стоїть на `--mat-1` (0.38) — це матеріал для написів усередині
   панелі, а не для того, на що тиснуть пальцем. Тут не заводиться нового
   вигляду взагалі: невибране — звичайна `button.tiny` гри, вибране — звичайна
   ГОЛОВНА кнопка гри. Нижче лише розкладка. */
/* ДВІ КАТЕГОРІЇ — ТИМ САМИМ ТУМБЛЕРОМ, ЩО В «ЩЕ».

   Спершу тут були три кнопки, потім дві, і кожна світилась власною заливкою.
   Власник показав на готовий тумблер «Гра / Початок»: «ось у нас дуже красивий
   тумблер, чого такий же не використовувати». Він має рацію — матеріал для
   одного екрана в цьому проєкті вже двічі виявлявся зайвим.

   Тому розмітка тепер `.modeswitch`, а тут лишається рівно те, чого тумблеру
   бракує: число світів під назвою. */
.modeswitch.wtabs .wtab {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 7px 8px;
  border-radius: 999px;
  cursor: pointer;
  /* Шрифт — дисплейний, як у назв екранів і заголовків карток: тумблер це
     назва розділу, а не підпис до поля. Емодзі тут немає — їх малює
     операційна система, і на кожному пристрої вони різні, через що набір із
     чужих деталей і виглядає збірним. Іконка з власного набору однакова
     скрізь. */
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .01em;
  color: var(--ink-3);
  transition: color .18s, background .18s, border-color .18s, transform .18s;
  min-width: 0;
}

.modeswitch.wtabs .wtab .ic {
  width: 17px; height: 17px;
  flex: none;
  opacity: .9;
}

.modeswitch.wtabs .wtab span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.modeswitch.wtabs .wtab.on {
  background: linear-gradient(135deg, var(--portal-deep), var(--portal));
  color: #05230a;
}



/* Жанр і мова на картці — тихі ярлики, а не кнопки.

   Жанр каже, ЩО це за історія; мова — чи вона твоєю. Обидва раніше жили лише
   в описі, і щоб їх дізнатись, доводилось прочитати абзац на кожній із
   тринадцяти карток. */
.pill.gen {
  border-style: dashed;
  text-transform: none;
  letter-spacing: 0;
}

.pill.lang {
  flex: none;
  font-family: var(--font-data);
  font-size: 13px;
  letter-spacing: .08em;
  opacity: .8;
}

/* Пошук і фільтри — ОДНИМ рядком.

   Спершу кнопка фільтрів стояла окремим рядком під тумблером, і екран
   починався з чотирьох смуг поспіль: пошук, тумблер, фільтри, список.
   Власник: «ту кнопку треба біля пошуку поставить в рядочок». Так і
   правильніше за змістом — пошук і фільтр роблять одне: звужують список. */
/* ПАНЕЛЬ КАТАЛОГУ ПЛИВЕ ПІД ШАПКОЮ.
   Каталог — єдиний екран, де гортають довго, і дія над списком (пошук,
   фільтр, перемикач розділу) потрібна саме посеред гортання. Повертатись по
   неї нагору — та сама втрата місця, через яку колись зробили липку шапку.

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

   Матеріал не вигадуємо — беремо ту саму смугу, що й під шапкою: ті ж
   розмиття й межа, тож панель читається як продовження шапки, а не як третя
   планка. Вертикальне поле від'ємне, щоб між нею і шапкою не лишалось щілини,
   крізь яку видно вміст. */
.wsticky {
  position: sticky;
  /* Рівно нижній край шапки, без проміжку: у щілину навіть у чотири пікселі
     видно вміст, що проїжджає між двома планками. */
  top: calc(var(--tg-top, 0px) + var(--topbar-h));
  z-index: 15;
  margin: -6px 0 10px;
  padding: 6px 0 2px;
  /* САМ ОБГОРТКА НІЧОГО НЕ МАЛЮЄ.

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

     Тому скло переїхало на самі елементи: у кожного вже є своя форма й свій
     радіус, тож і розмиття лягає рівно по ній. Між ними й по боках лишається
     порожнеча, крізь яку видно список, що проїжджає. */
  background: none;
  pointer-events: none;
}
/* Але тапати по них треба — порожнеча непроникна лише там, де нічого немає. */
.wsticky > * { pointer-events: auto; }

.wsticky .modeswitch { margin-bottom: 8px; }
/* Скло — ПО ФОРМІ елемента. Радіус свій у кожного, тож окремих правил три:
   пігулка тумблера, поле пошуку й квадратна кнопка фільтрів. */
.wsticky .modeswitch,
.wsticky .searchbar input[type="search"],
.wsticky .fbtn {
  backdrop-filter: blur(12px) saturate(1.15);
  -webkit-backdrop-filter: blur(12px) saturate(1.15);
}
/* Під склом мусить бути ще й власна щільність: саме розмиття не ховає
   контрастних плям, і назва картки, що проїжджає, читалась би крізь тумблер. */
.wsticky .modeswitch { background: rgba(10, 11, 13, .82); }

.searchrow { display: flex; gap: 8px; align-items: stretch; margin: 0 0 10px; }
.searchrow .searchbar { flex: 1; min-width: 0; margin: 0; }
.searchrow .tiny { flex: 0 0 auto; white-space: nowrap; }

/* КНОПКА ФІЛЬТРІВ — ЗНАЧОК У МАТЕРІАЛІ ПОЛЯ ПОШУКУ.
   Власник 19.09.2026: «лиши там тільки значок, зафарбуй у колір поля пошуку
   зліва». Слово «Фільтри» поруч із полем пошуку з'їдало чверть рядка й
   змагалося з ним за увагу, а значок із лічильником каже те саме. Підпис
   лишився в `aria-label` і `title` — для голосового доступу й підказки. */
.searchrow .fbtn {
  display: grid; place-items: center;
  width: 42px; padding: 0;
  background: var(--void-2);
  border: 1px solid var(--line);
  color: var(--ink-2);
  border-radius: var(--r-sm);
}
.searchrow .fbtn .ic { width: 20px; height: 20px; }
/* Лічильник обраних фільтрів — поверх значка, а не поруч: місця вже немає. */
.searchrow .fbtn b {
  position: absolute; margin: 0;
  transform: translate(14px, -13px);
  font-family: var(--font-data); font-size: 13px; line-height: 1;
  padding: 2px 5px; border-radius: 999px;
  background: var(--portal); color: #05230a;
}
.searchrow .fbtn { position: relative; }
.searchrow .tiny b { font-weight: 700; margin-left: 6px; }
.searchrow .tiny b:empty { display: none; }

/* У панелі фільтри стоять сіткою, а не рядком із прокруткою: там є місце. */
.modal .wfilters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  overflow: visible;
  margin: 0 0 14px;
}

.wfilters button.on {
  /* Вибране бере заливку головної кнопки гри — з 30.10.2026 вона пласка. */
  background: var(--acid);
  color: #06240b;
  border: 0;
  box-shadow: none;
}

/* Картка вітрини — те саме скло, що й решта панелей гри, лише щільніше.

   Спершу вона була на спільних 0.62: крізь тринадцять карток просвічувало
   фонове фото, і сусідні зливались в одну пляму. Тоді я зробив її майже
   чорною (0.96 без розмиття) — і вона випала зі стилю гри, про що власник
   сказав відразу. Щільність без втрати матеріалу: градієнт 0.80→0.88,
   розмиття й грані лишаються від `.card`. */
.card.wcard {
  background: linear-gradient(180deg, rgba(21, 22, 25, .80) 0%, rgba(14, 15, 17, .88) 100%);
  display: grid; grid-template-columns: 84px 1fr; align-items: stretch;
  margin-bottom: 8px; border-radius: 14px;
}
.wcard-cover {
  background: linear-gradient(150deg, var(--portal-dark), #0b1a0e 70%);
  background-size: cover; background-position: center;
  border-right: 1px solid var(--edge-soft);
}
.card.wcard .body { padding: 10px 12px; min-width: 0; }
.wcard-top { display: flex; align-items: center; gap: 8px; justify-content: space-between; }
.card.wcard h3 {
  margin: 0; font-size: 15px; line-height: 1.25;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.card.wcard p {
  margin: 3px 0 7px; font-size: 13px; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* Рядок про заявку: не `p`, бо `.card.wcard p` обрізає до двох рядків, а тут
   гравець має прочитати все — що з ним і куди писати далі. Колір і розмір — з
   `.pricenote`, тут лише відступ і посилання поруч (як «Карта»). */
.card.wcard .zaiavka-riadok { margin: 0 0 8px; line-height: 1.4; }
.zaiavka-riadok a { color: var(--ink-3); text-decoration: underline; text-underline-offset: 3px; }
.zaiavka-nota { display: block; margin-top: 2px; color: var(--ink-3); white-space: pre-wrap; overflow-wrap: anywhere; }
.card.wcard .stats { gap: 5px; margin: 0 0 9px; flex-wrap: wrap; }
.card.wcard .stats .pill { font-size: 13px; padding: 3px 8px; white-space: nowrap; }
.card.wcard .actions { margin-top: 0; gap: 10px; align-items: center; }
.card.wcard .actions button { padding: 8px 16px; font-size: 13px; border-radius: 10px; }
/* «Карта» — не друга головна дія, а посилання поруч. Знімаємо з неї все, що
   робить кнопку кнопкою: висоту під палець (48px лишали порожню коробку
   навколо напису) і верхній блиск, який домальовує `button::before`. */
.card.wcard .actions .wmap {
  background: none; border: none; box-shadow: none; padding: 2px 4px;
  min-height: 0;
  color: var(--ink-3); font-size: 13px; text-decoration: underline; text-underline-offset: 3px;
}
.card.wcard .actions .wmap::before { display: none; }
.wcard-kind { font-size: 13px; padding: 2px 7px; flex: 0 0 auto; }


/* ═══════════════════════════════════════════════════════════════════════════
   ДОТИК: ВІДГУК БЕЗ СЛІДІВ БРАУЗЕРА

   Гра живе у вебвʼю Telegram на телефоні, а виглядала як сайт у браузері.
   Три сліди, які видають сайт, і жодного з них не було прибрано:

   1. сіра плашка поверх кнопки на тапі (`-webkit-tap-highlight-color`) —
      вона зʼявляється ПІСЛЯ пальця й гасне сама, тобто суперечить нашому
      власному відгуку (стиск `scale(.96)`, який уже є);
   2. ~300 мс очікування другого тапу перед тим, як браузер визнає перший
      (`touch-action: manipulation` знімає це очікування);
   3. довгий натиск виділяє напис кнопки синім, як текст статті.

   Натиск і без того відповідає правилу «відгук на натисканні, не на
   відпусканні»: стиск стоїть на `:active`, а не на `click`. */
button, .btn, .navitem, .menucard, .rost, .wrow, .chip, .tier, .idbox,
.exit, .inv-row, .who-row, .node, .portrait-slot, .mapfit, summary {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
button, .btn, .navitem, .wtab, .chip, .tier, .mapfit {
  -webkit-user-select: none;
  user-select: none;
}

/* ── Ряд дій: рівні кнопки, а не рвана драбина ──────────────────────────────
   `.actions` був `flex-wrap: wrap` із кнопками за шириною тексту: «Поповнити
   ходи» й «Ходи й витрати детально» ставали різної довжини, третя падала в
   наступний ряд і висіла обрубком. Тепер дві дії ділять ряд порівну, а
   єдина — займає всю ширину картки: це головна дія екрана, і потрапити в неї
   великим пальцем має бути неможливо не влучити. */
/* Лише в картці ГОЛОВНОГО КРОКУ екрана (`.nowstep`: «Можна грати»,
   «Оживити»). Перша версія цього правила стояла на `.card` загалом — і в
   кабінеті власника кожна з десяти форм («Зберегти канон», «Створити NPC»…)
   дістала кнопку на всю ширину: сторінка стала стосом однакових широких
   смуг, тобто рівно тим «усе кричить», від чого правило й мало рятувати.
   `flex: 1` розтягує й одиноку кнопку, тож обмежувати треба обидва правила. */
.card.nowstep .body > .actions > button:not(.tiny) {
  flex: 1 1 auto;
  min-width: 45%;
}
/* На всю ширину — ЛИШЕ головна дія. Другорядна, розтягнута на весь рядок,
   важить очима стільки ж, скільки головна, і ієрархія, заради якої її й
   робили тихішою, зникає. Тому `ghost` лишається завширшки зі свій напис. */
.card.nowstep .body > .actions > button:not(.tiny):not(.ghost):not(.danger):only-child {
  flex-basis: 100%;
}
.card.nowstep .body > .actions > button.ghost:not(.tiny) {
  flex: 0 1 auto;
  min-width: 0;
}

/* ── Край прокрутки замість волосинки ───────────────────────────────────────
   Нижня панель — плаваюче скло, під яким їде вміст. Різка межа читалась як
   «сторінка тут закінчилась»; мʼяке затемнення каже правду: там ще є вміст,
   він просто заходить під панель. */
.bottomnav::before {
  content: "";
  position: absolute; left: 0; right: 0; top: -20px; height: 20px;
  background: linear-gradient(180deg, rgba(7, 8, 9, 0), rgba(7, 8, 9, .5));
  pointer-events: none;
}

/* ── Матеріали, коли прозорість або контраст вимкнено ───────────────────────
   Скло — це наш спосіб показати шар, а не прикраса, тож при
   `prefers-reduced-transparency` воно не зникає, а стає щільним: та сама
   ієрархія, лише без просвічування. Розмиття вимикається одним місцем —
   змінною `--blur`, бо через неї воно й роздається. */
@media (prefers-reduced-transparency: reduce) {
  :root {
    --blur: none;
    --mat:       rgba(16, 17, 20, .97);
    --mat-thick: rgba(12, 13, 14, .98);
    --mat-hover: rgba(34, 36, 40, .97);
    --mat-1:     rgba(16, 17, 20, .93);
    --mat-2:     rgba(16, 17, 20, .96);
    --mat-3:     rgba(33, 35, 39, .97);
  }
  .card.wcard { background: rgba(14, 15, 17, .98); }
}

/* Більше контрасту — виразніші межі: рамка, а не лише світліша грань. */
@media (prefers-contrast: more) {
  button, .btn, button.ghost, button.tiny, button.danger,
  .card, .pill, input, textarea, select {
    border-color: rgba(255, 255, 255, .58);
  }
  button, .btn { border-top-color: rgba(255, 255, 255, .72); }
  .navitem { color: var(--ink); }
}


/* ── Заголовок розділу — це напис, а не кнопка ──────────────────────────────

   `.sec` обріс плашкою, рамкою, тінню й розмиттям — і став схожий на кнопку
   рівно там, де кнопкою не є: «ХОДИ Й ТАРИФ» посеред екрана в такій самій
   скляній рамці, що й «Поповнити ходи» під ним. apple-design §16
   (familiarity): однакові на вигляд речі мусять однаково поводитись, інакше
   людина тисне на напис і перестає вірити формі взагалі.

   Плашку знято в самому правилі, що її малювало (шукати `#view .sec`), а не
   перебито ще одним шаром: у цьому файлі вже лежать вісім правил на `.sec`, і
   кожен новий шар робив наступний грубішим. Тут лишилась тільки волосинка до
   краю екрана — так розділ читається як розділ, а кнопкою на екрані виглядає
   лише кнопка. */
.sec::after {
  display: block;
  content: "";
  flex: 1 1 40px;
  height: 1px;
  background: linear-gradient(90deg, rgba(255, 255, 255, .14), transparent);
}
/* Підзаголовок розділу — з нового рядка, ще тихіше. */
.sec small {
  flex: 1 0 100%;
  color: var(--ink-3);
  letter-spacing: 0;
  text-transform: none;
}


/* ═══════════════════════════════════════════════════════════════════════════
   ВЕСЬ МІНІАП ПІД ТЕЛЕФОН (аудит за skills/apple-design і skills/mobile-native)

   Далі — не смак, а речі, які на телефоні поводяться інакше, ніж у браузері
   на столі, і жоден тест на рядки їх не бачить.
   ═══════════════════════════════════════════════════════════════════════════ */

/* 1. ПОЛЕ ВВОДУ МЕНШЕ 16px ЗУМИТЬ СТОРІНКУ.
      iOS збільшує весь екран, коли фокус іде в поле з дрібнішим кеглем, — і
      назад уже не повертає. Гравець бачив це щоразу, коли вводив назву світу
      чи ім'я героя: інтерфейс «стрибав». 16px — поріг, нижче якого зум
      вмикається; це не про читабельність, а про поведінку. */
input[type="text"], input[type="search"], input[type="number"],
input[type="email"], input[type="tel"], textarea, select {
  font-size: 16px;
}

/* 2. ВИСОТА ЕКРАНА НА ТЕЛЕФОНІ ЗМІННА.
      `100vh` рахується від висоти БЕЗ адресного рядка, тож нижній край
      контейнера ховався під ним. `dvh` міряє те, що видно зараз. */
@supports (height: 100dvh) {
  /* ЧАСТКА, А НЕ ВЕСЬ ЕКРАН. Тут стояло `calc(100dvh - 32px)` — і це
     переписувало `min(62vh, 520px)` на повну висоту вікна. Сам список ставав
     заввишки з екран, а над ним і під ним лишались заголовок, вкладки, чіпи
     імен і ряд кнопок — тож панель гарантовано була вища за екран, і кнопка
     закриття з неї випадала. 62dvh — та сама частка, що й була, тільки
     міряна від видимої висоти. */
  .dossier-body { max-height: min(62dvh, 520px); }
}

/* 3. ПРОКРУТКА НЕ ТЯГНЕ ЗА СОБОЮ СТОРІНКУ — АЛЕ ЛИШЕ ВСЕРЕДИНІ СПИСКІВ.
      Догорнувши список до кінця, палець починав тягнути сторінку під ним, а
      у вебвʼю Telegram зайвий рух угорі — це жест закриття застосунку.
      `contain` лишає жест усередині списку, і цього досить.

      `overscroll-behavior: none` НА СТОРІНЦІ тут був, і саме він 18.09.2026
      забрав прокрутку на Android: мініап гортався лише смужкою біля нижнього
      краю екрана. Дати не лишили сумніву — повний екран стоїть із 01.09 і
      сімнадцять днів працював, `disableVerticalSwipes` є з першого коміту, а
      це правило приїхало рівно того дня, коли прокрутка зникла.

      Урок ширший за один рядок: чекліст «як зробити сайт схожим на застосунок»
      писався не для вебвʼю Telegram, і його поради тут не безкоштовні. */
html, body { overscroll-behavior: auto; }
.tablewrap, .inv-list, .wfilters, .dossier-body, .modal, .graphwrap,
#ownerBody .inv-list { overscroll-behavior: contain; }

/* 4. ДОВГИЙ НАТИСК НЕ ВІДКРИВАЄ МЕНЮ БРАУЗЕРА.
      На кнопці й на обкладинці світу iOS показував «Скопіювати / Зберегти
      зображення» — меню сайту поверх гри. */
button, .btn, .navitem, .menucard, .rost, .wrow, .chip, .tier, .idbox,
.exit, .inv-row, .who-row, .node, .portrait-slot, .nwphoto, .mapfit,
.dossier-tab, .tour-x, .wcard-cover, .banner img, summary {
  -webkit-touch-callout: none;
}

/* 5. ВІДГУК НА НАТИСКАННІ — СКРІЗЬ, А НЕ ЛИШЕ НА КНОПКАХ.
      apple-design §1: щойно зʼявляється затримка між дотиком і реакцією,
      відчуття прямої дії «падає з обриву». Ці шість елементів натискаються
      так само часто, як кнопки, а відповідали лише після завершення дії. */
/* Ці шість елементів натискаються так само часто, як кнопки. Окремого
   правила їм більше не треба: у кожного є свій обробник, тож їх уже бере
   правило вище — а те, що обробника не має, стискатись і не повинно. */

/* 6. МОДАЛКА ЗʼЯВЛЯЄТЬСЯ Й ЗНИКАЄ ОДНІЄЮ ДОРОГОЮ.
      apple-design §7: «якщо щось зникло в один бік, ми чекаємо, що звідти
      воно й вийде». Вікно вїжджало знизу з розмиттям, а закривалось миттєвим
      зникненням — наче не закрилось, а пропало. Тепер шлях дзеркальний.
      §12: скло має «матеріалізуватись» — розмиття наростає разом із
      масштабом, а не вмикається одразу. */
@keyframes modalIn {
  from { opacity: 0; backdrop-filter: blur(0px); -webkit-backdrop-filter: blur(0px); }
  to   { opacity: 1; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
}
.modal-wrap.closing { animation: modalOut .14s var(--ease) both; }
.modal-wrap.closing .modal { animation: modalDown .14s var(--ease) both; }
@keyframes modalOut  { from { opacity: 1; } to { opacity: 0; } }
@keyframes modalDown { from { transform: none; } to { transform: translateY(10px) scale(.985); } }

@media (prefers-reduced-motion: reduce) {
  .modal-wrap.closing, .modal-wrap.closing .modal { animation: none; opacity: 0; }
  .dossier-tab:active, .tour-x:active, .nwphoto:active,
  .tiers .tier:active, .chip:active, .wmap:active { transform: none; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   СЦЕНА: ДЕ Я, КУДИ ЗВІДСИ, ХТО ТУТ

   Стара сцена витрачала перший екран на назву локації гігантськими літерами
   в три рядки — і на все інше лишалось два речення. Тут назва — звичайний
   заголовок, а перший екран належить карті й головній дії.
   ═══════════════════════════════════════════════════════════════════════════ */
h1.screen.misce { font-size: clamp(20px, 6vw, 26px); line-height: 1.12; letter-spacing: -.5px; }
h1.screen.misce small { margin-top: 4px; }

/* ПЛАШКИ СТАНУ ГЕРОЯ В СЦЕНІ БІЛЬШЕ НЕМАЄ.
   Власник 19.09.2026: «прибирай взагалі плашку цю». Імʼя, серця, рівень,
   гроші й ходи стояли між назвою локації й картою — і відповідали не на те
   питання: сцена питає «де я і що звідси», а плашка розказувала, хто я. Те
   саме є на «Я» й у шапці кожного екрана, а карту через неї доводилось
   відкручувати вниз. Правила `.scene-hero`, `.sh-row` і `.sh-hp` знято
   разом із розміткою: мертвий CSS — це наступна година чийогось пошуку. */

/* ОПИС СЦЕНИ ЛЕЖАВ ПРОСТО НА ФОНІ.

   Тло сторінки — обкладинка, яку ставить адмін у панелі, і в кожного світу
   вона своя. Опис локації був єдиним текстом цього екрана поза карткою: на
   спокійному фоні це минало непоміченим, а на графіті світу «Про моє
   переродження в слизня» текст став нечитабельним зовсім.

   Лікуємо не вуаллю, а структурою: текст, який лежить на тлі, не має
   існувати. Картка та сама, що й у решти блоків екрана, — власного матеріалу
   тут не вигадуємо. */
.scene-desc { margin: 0; color: var(--ink-2); font-size: 14px; line-height: 1.5; }

/* Карта в сцені — нижча за окремий екран карти: вона частина сторінки. */
.scene-map .body { padding: 8px; }
/* КАРТКА В КАРТЦІ — ЦЕ ДВІ РАМКИ ПІДРЯД.
   `.graphwrap` носить власну межу й підкладку, бо на екрані «Уся карта» він
   стоїть сам по собі. Усередині картки сцени це давало другий заокруглений
   прямокутник за пів сантиметра від першого — саме те, що читається як
   недбалість. Межа й заливка належать картці; карта всередині лишається
   малюнком, а не ще одним обʼєктом. */
.scene-map .graphwrap {
  height: 250px;
  margin: 2px 0 0; border: 0; background: transparent;
}

/* КАРТА У «СЦЕНІ» НЕ СМІЄ ЇСТИ ПРОКРУТКУ.

   `.graphwrap` вимикає жести браузера (`touch-action: none`), бо на екрані
   «Уся карта» граф тягають пальцем. У «Сцені» його не тягають ЗОВСІМ:
   `enableGraphPan()` там не викликається — карта там показ, а не інструмент.
   Але правило успадкувалось, і разом із ним — заборона гортати.
   
   Карта стоїть одразу під заголовком головного екрана, тобто саме там, де
   палець починає рух. На Android це означало, що мініап не гортається взагалі:
   кожен свайп починався на карті й нікуди не йшов. */
.scene-map .graphwrap { touch-action: auto; cursor: auto; }
.scene-map-foot {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 8px 6px 2px; font-size: 13px; color: var(--ink-3);
}
.scene-map-foot button { margin-left: auto; }
.scene-map-foot i {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  margin-right: 6px; vertical-align: -1px;
}
.lg-here { background: var(--portal); box-shadow: 0 0 8px rgba(var(--portal-rgb), .8); }
.lg-next { border: 2px solid var(--acid); }

/* Сусіди, куди можна піти, — обведені; дорога до них — яскравіша. */
.gnode.next circle { stroke: var(--acid); stroke-width: 3; }
/* Підпис НЕ всередині вузла, тож і селектор не через вузол: він лежить
   окремим шаром поверх усіх кіл, щоб сусіднє коло його не накривало. */
.glabel.next { fill: var(--ink); font-weight: 700; }
.edge.hot { stroke: var(--acid); stroke-width: 3; opacity: .9; }

/* Решта світу в сцені — тло, а не зміст: приглушена й без підписів. Питання
   сцени — «де я і куди звідси»; хто хоче всю карту, має кнопку «Уся карта».
   Без цього підписи далеких місць налазили на підписи сусідів. */
.scene-map .gnode:not(.here):not(.next) { opacity: .35; }
.scene-map .gnode:not(.here):not(.next) .gnum { display: none; }
/* Це правило мовчало. Підписи винесли окремим шаром — і селектор «підпис
   усередині далекого вузла» перестав до чогось підходити, бо такого вкладення
   більше немає. Приглушення зникло без жодної помилки, і в сцені проступили
   назви всього світу разом: вони налазили одна на одну, на дороги й за край
   картки («Сад Кеі» обрізаний рамкою). Тепер стан питається в самого підпису. */
.scene-map .glabel:not(.here):not(.next) { display: none; }
.scene-map .edge:not(.hot), .scene-map .nestlink { opacity: .22; }
.scene-map .gatelabel { opacity: .5; }

/* Головна дія — одразу під картою, у зоні великого пальця, а не під трьома
   списками. */
.actions.scene-go { margin: 4px 0 6px; }
.actions.scene-go button { flex: 1 1 100%; }

/* Рядки виходів і людей — один ритм. */
.scene-list { padding-top: 4px; padding-bottom: 4px; }
.xrow .av { font-size: 18px; color: var(--acid); }
.xrow small { display: block; color: var(--ink-3); font-size: 13px; margin-top: 2px; line-height: 1.35; }
.dim-note { color: var(--ink-3); font-size: 13px; margin: 6px 2px; }
/* Зараз у грі (ekrany/zaraz-hraie.js): пігулки наявні, тут лише відступ і крапка. */
.stats.zaraz-hraie { margin: 2px 0 8px; }
.zaraz-hraie i { color: var(--acid); font-style: normal; font-size: 9px; vertical-align: 1px; }

.scene-quests .q-row + .q-row { margin-top: 10px; }
.scene-quests .q-row b { display: block; font-size: 14px; }
.scene-quests .q-row span { display: block; color: var(--ink-3); font-size: 13px; line-height: 1.4; margin-top: 2px; }

/* Списки сцени — одна картка з рядками через волосинку, як згрупований
   список iOS, а не стос окремих плиток. Кожна плитка мала власну рамку,
   фон і круг-аватар на 42px — і шість виходів займали півтора екрана. */
.scene-list .who-row {
  background: none; border: 0; border-radius: 0; box-shadow: none;
  padding: 8px 2px; margin: 0; min-height: 44px;
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
.scene-list .who-row + .who-row { border-top: 1px solid rgba(255, 255, 255, .08); margin-top: 0; }
.scene-list .who-row > div:nth-child(2) { flex: 1; min-width: 0; }
.scene-list .who-row .av { width: 32px; height: 32px; font-size: 15px; }
.scene-list .xrow .av { background: none; border: 0; font-size: 18px; width: 22px; }
.scene-list .xrow small {
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
}
.scene-list .who-row .pill { flex: none; font-size: 13px; padding: 3px 8px; }

/* ═══════════════════════════════════════════════════════════════════════════
   ЦИФРА — ДАНІ, А НЕ ДІЯ

   Плитки «37 ходів лишилось / 412 усього / 29 за тиждень» стояли в рамках
   тієї самої форми, що й кнопки, — і на них тиснули. apple-design §16:
   однакове на вигляд мусить однаково поводитись. Тепер цифри — рядок у
   картці з волосинками між собою, як підсумки в «Здоровʼї» чи «Налаштуваннях».
   ═══════════════════════════════════════════════════════════════════════════ */
.sheet .stat {
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  padding: 4px 4px 2px;
}
.sheet .stat + .stat { border-left: 1px solid rgba(255, 255, 255, .10); }

/* Речення під смугою («З них 318 через AI · 94 безкоштовних») — шрифтом
   тексту. Моноширинний із трекінгом лишається для коротких міток-даних, а
   ціле речення ним читалось як рядок коду. */
.bar-label {
  font-family: var(--font-body);
  letter-spacing: 0;
}

/* Блік по шапці й заголовку — двічі на вході, а не вічно кожні 9 с.
   apple-design §14: нескінченні повільні цикли щоразу тягнуть око на себе,
   хоч нічого не змінилось. Ефект лишився — він просто не нагадує про себе
   весь час, поки людина читає. */
.topbar::after { animation-iteration-count: 2; }
/* `[class]` — щоб вага селектора зрівнялась із `h1.screen .chaos i.c1`, де
   анімацію задано скороченням з `infinite`; без цього правило програвало.
   ІМʼЯ ГЕРОЯ — ОДИН РАЗ ПРИ ВІДКРИТТІ (04.11.2026, власник: «анімація
   перезапускається кожного разу, коли гортаєш»). Двічі → один прохід, і глітч
   `rift` теж один, а не кожні 12 с. */
h1.screen .chaos i[class] { animation-iteration-count: 1; }
h1.screen .chaos { animation-iteration-count: 1; }
/* Фонове оновлення вкладки інколи перемальовує екран цілком, і новий вузол
   заголовка програвав появу, блік і глітч заново — на телефоні якраз під час
   гортання. Заголовок, який уже показувався, позначає `applyChaos`. */
#view.in > h1.screen.vzhe-bachyv,
h1.screen.vzhe-bachyv .chaos,
h1.screen.vzhe-bachyv .chaos i[class] { animation: none; }

/* Монограма героя без портрета — див. `monohrama` у app.js. Темний диск
   того самого відтінку, що й світлі літери: на склі гри читається, а поруч
   із справжніми фото не кричить. Розмір літер — від рамки, куди її поставили.

   `span.mono`, а не `.mono`: у смужці героїв стоїть `.rost span` (підпис
   світу під іменем — дрібний, сірий, блоком), у рядках — `.who-row span`, і
   обидва чіпляли монограму — літера липла до верху кола, диск зникав. */
span.mono {
  display: grid; place-items: center;
  width: 100%; height: 100%;
  border-radius: inherit;
  /* Диск темніший і насиченіший, ніж був: заглушка мусить читатись як
     обличчя навіть на строкатому фоні. */
  background: linear-gradient(160deg, hsl(var(--h) 42% 26%), hsl(var(--h) 52% 13%));
  color: hsl(var(--h) 80% 82%);
  -webkit-user-select: none; user-select: none;
}

/* Іконка всередині — рівно на дві третини диска, щоб лишався кант. */
span.mono .ic {
  width: 58%; height: 58%;
  opacity: .92;
}


/* ═══════════════════════════════════════════════════════════════════════════
   НАЗВА СТОРІНКИ — НЕ ЗАГОЛОВОК

   Власник 19.09.2026: «оці заголовки з назвою сторінки прибери всюди крім
   сцени і я, бо там не назви сторінок, а назва героя і локації… користувач
   розуміє й так, на якій сторінці він знаходиться».

   Він має рацію: унизу стоїть панель вкладок із підсвіченою поточною, тобто
   сторінка називає себе двічі. На телефоні це коштує півтори сотні пікселів
   висоти — і саме їх бракувало, щоб побачити вміст.

   Лишились три заголовки, і жоден із них не назва сторінки: імʼя героя з
   локацією, імʼя NPC і імʼя гравця в адмінці. Там, де назва була зайвою, а
   підпис ні (карта світу, історія персонажа, новий герой), лишився підпис.
   ═══════════════════════════════════════════════════════════════════════ */
.screen.only-sub {
  margin-bottom: 10px;
}
.screen.only-sub > small {
  /* Підпис більше не підпис під назвою, а сам рядок: власний розмір і
     повна непрозорість, інакше він читається як загублений хвіст. */
  display: block;
  font-size: var(--t-small);
  opacity: .9;
}

/* ═══════════════════════════════════════════════════════════════════════════
   СТВОРЕННЯ СВІТУ — ПЛИТКА В КАТАЛОЗІ

   Власник 19.09.2026: «кнопку створити світ прибираємо, робимо її карткою в
   каталозі світів, щоб вона стояла така ж сама». Окрема кнопка над списком
   змагалась із тумблером «Від студії / Спільноти» і пошуком за увагу.

   Далі він подивився на неї в телефоні: «зроби цю планку розміром як картка
   світу нижче… розгортається це меню некрасиво… зроби обводку приривчастою
   лінією голубенькою і виправ помилки з відступами і заокругленнями».

   Три помилки, і всі три про ОДНЕ — плитка й розгорнута анкета виглядали як
   два різні предмети:
     • плитка зелена, а панель `.card.nowstep` бірюзова, з власним сяйвом;
     • у панелі власне заокруглення з усіх боків, тож на стику виходили дві
       округлі межі одна під одною;
     • між ними лишалось поле `.card`, тобто видима щілина.

   Тепер це ОДИН предмет: суцільна пунктирна бірюзова межа, спільне
   заокруглення тільки зовні, нуль щілини всередині. Пунктир тут не окраса —
   він каже «цього ще немає», на відміну від суцільних меж наявних світів.
   ═══════════════════════════════════════════════════════════════════════════ */
details.wcard-new {
  /* МЕЖА — НА ВСЬОМУ КОМПОНЕНТІ, А НЕ НА ЧАСТИНАХ.
     Спершу пунктир малювали окремо `summary` і окремо панель, стикуючись
     межа в межу. На екрані власника вони не зійшлись: у місці стику
     лишались обриви, бо кожен пунктир починає відлік від СВОГО кута.
     Одна межа на `details` не може не зійтись — вона одна. */
  margin: 0 0 8px;
  padding: 0;
  border: 1px dashed rgba(79, 227, 255, .55);
  border-radius: 14px;
  overflow: hidden;
  background: none;

  /* Висота як у картки світу поруч. Точного числа тут бути не може — картка
     світу росте від свого вмісту (опис, жанри, кнопки), — тож беремо
     заміряне: 173px на широкому екрані й 200px на телефоні. */
  --wnew-h: 173px;
}
@media (max-width: 520px) {
  details.wcard-new { --wnew-h: 200px; }
}

details.wcard-new > summary {
  /* СІТКА — У ВНУТРІШНЬОМУ КОНТЕЙНЕРІ, а не на самому `summary`.
     Коли `summary` стає grid-контейнером, його МАРКЕР займає першу клітинку:
     плюс зʼїжджає в другу колонку, а текст падає в наступний рядок на 84px
     і стає стовпчиком із літер. Помилки при цьому немає — лише розсипана
     верстка й псевдоелемент, якого в розмітці не видно. */
  display: block;
  list-style: none;
  cursor: pointer;
  /* `.nwmore > summary` дає власне поле 13px зверху й знизу — для рядка
     згортки правильно, тут зайве: розкладку несе внутрішній контейнер, а ці
     26px робили плитку вищою за картку світу, під яку її й підганяли. */
  padding: 0;
  border: 0;
  background: linear-gradient(180deg, rgba(21, 22, 25, .80) 0%, rgba(14, 15, 17, .88) 100%);
  /* Шрифт як у картці світу: `.nwmore` ставить моноширинний 13px, і поруч зі
     світами назва читалась як службовий рядок. */
  font-family: var(--font-body);
  font-size: inherit;
}
details.wcard-new > summary::-webkit-details-marker { display: none; }
/* `.nwmore` домальовує власне «＋» перед текстом згортки — тут воно зайве:
   плюс уже стоїть плиткою на місці обкладинки, і другий, дрібний, у кутку
   читається як сміття. */
details.wcard-new > summary::before,
details.wcard-new[open] > summary::before { content: none; }

details.wcard-new > summary > .wcard-new-in {
  display: grid;
  grid-template-columns: 84px 1fr;
  align-items: stretch;
  min-height: calc(var(--wnew-h) - 2px);
}

/* ── розгорнуто: плитка й анкета — один предмет ─────────────────────────── */
details.wcard-new[open] > summary > .wcard-new-in {
  /* Розгорнутій анкеті висота плитки вже не потрібна: там і так є що
     читати, а порожнє поле над текстом виглядало б як помилка. */
  min-height: 74px;
  /* Єдина лінія всередині — між шапкою й анкетою; тим самим пунктиром, тож
     вона читається як частина того самого малюнка. */
  border-bottom: 1px dashed rgba(79, 227, 255, .40);
}
details.wcard-new > .card {
  /* Панель не приносить власної межі, кутів і сяйва: усе це вже є в
     компонента. `.nowstep` дає бірюзове світіння, доречне для «зроби це
     зараз» і зайве тут — воно обводило панель другим контуром. */
  margin: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.wcard-new-plus {
  display: grid; place-items: center;
  font-family: var(--font-data); line-height: 1;
  font-size: 38px;
  color: var(--cyan);
  /* Пунктир повторює межу компонента, тож поділ читається як частина того
     самого малюнка, а не як ще одна лінія. */
  border-right: 1px dashed rgba(79, 227, 255, .40);
  background: linear-gradient(150deg, rgba(79, 227, 255, .10), rgba(17, 18, 20, .9) 70%);
}
.wcard-new-txt {
  display: flex; flex-direction: column; gap: 4px; justify-content: center;
  padding: 14px; min-width: 0;
}
.wcard-new-txt b { font-size: 16px; line-height: 1.25; color: var(--ink); }
.wcard-new-txt small { font-size: var(--t-label); color: var(--ink-3); line-height: 1.4; }

/* ═══════════════════════════════════════════════════════════════════════════
   СПОВІЩЕННЯ НЕ РУХАЄ СТОРІНКУ

   Власник 19.09.2026: «зʼявляється вгорі сайту, рухає всю сторінку й
   примусово скролить угору з того місця, де був користувач».

   Обидві скарги — про одне: плашка жила в потоці, між шапкою й екраном.
   Поява вставляла блок, і все нижче стрибало; а щоб її взагалі побачили,
   код одразу прокручував сторінку вгору — тобто забирав у людини місце, на
   якому вона стояла.

   Тепер вона плаває: у потоці не займає нічого, рухати нічого не треба.
   Позицію по вертикалі ставить `note()` — біля останнього дотику.
   ═══════════════════════════════════════════════════════════════════════════ */
#toast {
  position: fixed;
  left: var(--gutter); right: var(--gutter);
  /* Стос плашок знизу, над вкладками (31.10.2026): усі сповіщення — плашки з
     орбом. Контейнер прозорий для дотиків, клікабельні лише самі плашки. */
  bottom: calc(96px + var(--tg-bottom, 0px) + env(safe-area-inset-bottom, 0px));
  z-index: 60;
  pointer-events: none;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
}
#toast.on { opacity: 1; transform: translateY(0); }
#toast > .ok,
#toast > .err {
  margin: 0;
  /* Щільніший матеріал, ніж у плашки в потоці: вона лежить поверх вмісту, і
     напівпрозорою на ній не прочитати ні тексту, ні того, що під нею. */
  background: var(--mat-3, rgba(25, 26, 29, .97));
  backdrop-filter: var(--blur);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .55);
}
@media (prefers-reduced-motion: reduce) {
  #toast { transition: none; }
}

/* Плитка без слотів — той самий розмір, але не зелена: вона вже не
   запрошення, а пояснення, чому запрошення немає. */
/* Плитка без слотів — той самий малюнок, але не бірюзова: вона вже не
   запрошення, а пояснення, чому запрошення немає. */
details.wcard-new.nema-slotiv { border-color: rgba(245, 227, 92, .40); }
details.wcard-new.nema-slotiv[open] > summary > .wcard-new-in {
  border-bottom-color: rgba(245, 227, 92, .30);
}
details.wcard-new.nema-slotiv .wcard-new-plus {
  color: var(--splash);
  border-right-color: rgba(245, 227, 92, .30);
  background: linear-gradient(150deg, rgba(245, 227, 92, .08), rgba(14, 15, 17, .9) 70%);
}
details.wcard-new.nema-slotiv .wcard-new-plus .ic { width: 30px; height: 30px; }


/* ═══════════════════════════════════════════════════════════════════════════
   ЗА ШАПКОЮ ЗНИКАЄ ВМІСТ, А НЕ ФОН

   Перша спроба залила смугу довкола шапки суцільним кольором сторінки — і
   власник одразу побачив, що саме я зробив: «ти перекрив задній фон, я хочу,
   щоб у мене Морті було видно, а все, що заходить за хедер, просто зникало».

   Він має рацію: фон — це фіксоване зображення (`body::before`) під вуаллю
   (`body::after`), і воно НЕ прокручується. Закрити смугу кольором означало
   вирізати з картинки прямокутник.

   Тому смуга малює ТЕ САМЕ, що й сторінка: те саме зображення, ту саму
   вуаль, ту саму геометрію — і лежить між вмістом (z-index 1) і шапкою (30).
   Вміст, що заїжджає під неї, зникає; фон лишається суцільним, бо це
   буквально той самий фон.

   Хитрість із розміром: блок розтягнутий на все вікно, як `body::before`, —
   інакше градієнт вуалі не збігся б, — а показана лише верхня смужка
   заввишки до нижньої межі шапки.

   Висоту спершу рахував JS на кожен кадр прокрутки. Це була помилка: будь-яке
   значення, пораховане в кадрі, відстає на цей кадр, і відставання видно як
   смугу, що заходить на вміст. Тепер висота шапки стала (`--topbar-h`), і
   смуга кінчається рівно там, де шапка, без жодного обчислення.
   ═══════════════════════════════════════════════════════════════════════════ */
#hdrmask {
  position: fixed; inset: 0; z-index: 20; pointer-events: none;
  /* Та сама підкладка, що й у сторінки: зображення лежить поверх неї з
     власною непрозорістю, і саме так виходить остаточний колір. Рахувати
     «скільки темряви домішати» арифметикою — означало б промахнутись на
     кожній зміні `--dim` чи `--bg-opacity`. */
  background: var(--void);
  /* КРАЙ М'ЯКИЙ, А НЕ РІЗАНИЙ.
  
     Тут стояв `clip-path: inset(...)` — прямокутник на всю ширину. Він робив
     рівно те, що написано: рубав усе по одній лінії. Власник побачив це на
     збільшеному знімку — «голубенька лінія надто рано пропадає, бо там щось
     під хедером прямокутне різко обрізає; зроби там розмите обрізання».
  
     Він має рацію двічі. По-перше, різаний край сам по собі видно як межу,
     хоч ми й хотіли, щоб її не було. По-друге, шапка — картка із
     заокругленими кутами, і по її боках лишаються поля, де вміст мав би
     просто згасати, а не зникати стрибком.
  
     Тому замість обрізання — маска-градієнт: смуга щільна там, де стоїть
     шапка, і за 22 пікселі сходить у прозорість. Вміст під нею не
     обривається, а розчиняється.
  
     22px підібрані за товщиною того, що по ній їде: рамка картки й рядок
     тексту. Менше — і згасання читається як та сама лінія, тільки сіра.

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

     Він має рацію, і мій страх був безпідставний: під шапкою стоїть
     `backdrop-filter: blur(10px)`, тож те, що проступає в її нижній половині,
     і є розмиттям — саме тією тінню, заради якої все й робилось. А згасання
     на самому краї читалось як друга межа одразу під першою.

     Півтора десятка пікселів у кожен бік від середини: згасання цілком
     уміщається в шапку й не виходить на вміст під нею. */
  /* `--pull-y` — зсув на час жесту «потягнути вниз»: шапка їде вниз, і край
     згасання мусить їхати з нею, інакше вміст обривався б там, де шапки вже
     немає. Саму смугу при цьому не рухаємо: вона малює КОПІЮ фону сторінки,
     і зсунута копія розійшлася б з оригіналом. */
  --hdr-seredyna: calc(var(--tg-top, 0px) + var(--topbar-h) / 2 + var(--pull-y, 0px));
  -webkit-mask-image: linear-gradient(
    to bottom,
    #000 0,
    #000 calc(var(--hdr-seredyna) - 11px),
    transparent calc(var(--hdr-seredyna) + 11px)
  );
  mask-image: linear-gradient(
    to bottom,
    #000 0,
    #000 calc(var(--hdr-seredyna) - 11px),
    transparent calc(var(--hdr-seredyna) + 11px)
  );
}
#hdrmask::before {
  /* Точна копія `body::before`, включно з виходом на 12% за край: інакше
     `cover` дав би інший кадр зображення, і смуга не збіглася б із фоном. */
  content: ""; position: absolute; inset: -12%;
  background-image: var(--bg-image);
  background-position: center; background-size: cover; background-repeat: no-repeat;
  opacity: var(--bg-opacity);
  filter: saturate(1.15) contrast(1.02);
}
#hdrmask::after {
  /* ТА САМА вуаль, що й у сторінки — змінною, а не копією чисел: інакше на
     нижній межі шапки була б видна сходинка в яскравості. */
  content: ""; position: absolute; inset: 0;
  background: var(--vual);
}

/* ПЛАВУЧА ПАНЕЛЬ КАТАЛОГУ ХОВАЄТЬСЯ ПІД АНКЕТОЮ СТВОРЕННЯ.

   Тумблер і пошук плавають під шапкою, щоб дія над списком була під рукою
   посеред гортання, — і це правильно, поки внизу список. Коли розгорнуто
   анкету створення світу, списку немає, а панель лягає просто на її поля
   (власник 20.09.2026: «на меню створення світу налазять тумблер і поле
   пошуку з кнопкою фільтрів»). Шукати по каталогу в цю мить нікому не
   потрібно, тож панель іде геть, а не бʼється за місце. */
body.nw-vidkryta .wsticky { display: none; }

/* КНОПКА СТВОРЕННЯ НА ЧАС РОБОТИ — СМУГА ПОСТУПУ.

   Смуга лежить ПІД написом усередині самої кнопки, а не окремою планкою:
   матеріал інтерфейсу тут не вигадують, а чекання стосується саме цієї дії,
   тож і показувати його треба в тому місці, де по ній тиснули. */
button.prohres { position: relative; overflow: hidden; }
button.prohres > span { position: relative; z-index: 1; }
.prohres-lin {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--p, 0%);
  /* Не суцільний колір, а просвітлення самої кнопки: смуга має читатись як
     та сама кнопка, що наповнюється, а не як чужа деталь поверх неї. */
  background: linear-gradient(90deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, .26));
  transition: width .12s linear;
  pointer-events: none;
  z-index: 0;
}
/* Рух — єдине, що тут анімується. Кому анімації протипоказані, той бачить
   смугу, яка так само зростає, просто без плавності між тиками. */
@media (prefers-reduced-motion: reduce) {
  .prohres-lin { transition: none; }
}

/* МІСЦЕ ПІД ОБКЛАДИНКУ — КОЛИ ОБКЛАДИНКИ НЕМАЄ.

   До 20.09.2026 світ без фото просто не показувався у вітрині: порожня
   смужка збоку читалась як зламана картка. Ворота коштували дорожче за ваду
   — троє публічних світів були невидимі, і жоден автор про це не знав.

   Тепер смужка малює значок порталу на власному тлі. Відтінок виведено з
   назви світу тим самим хешем, що й обличчя-заглушка в героїв без портрета:
   однакова назва — однаковий колір, сусідні назви — різні. Так місце під
   обкладинку виглядає задуманим, а не забутим. */
.wcard-cover.nofoto {
  display: grid;
  place-items: center;
  background:
    radial-gradient(120% 100% at 30% 0%,
      hsl(var(--h, 140) 42% 26% / .95), transparent 70%),
    linear-gradient(150deg, var(--portal-dark), #0b1a0e 70%);
}
.wcard-cover.nofoto .ic {
  width: 26px; height: 26px;
  /* Значок приглушений навмисно: це підказка «тут буде фото», а не малюнок,
     що змагається з назвою світу поруч. */
  color: hsl(var(--h, 140) 55% 72% / .5);
}

/* ПІДПИС ПОЛЯ Й ДІЯ НАД НИМ — В ОДНОМУ РЯДКУ.

   Кнопка «Запит для ШІ» стояла окремою плиткою на всю ширину між поясненням
   і полем, і читалась як загублена: власник 20.09.2026 «некрасива кнопка
   копіювання». Причина не в самій кнопці, а в тому, що `.actions` розтягує
   все, що в ній лежить, — правило слушне для головних дій картки й хибне для
   дрібної дії над одним полем.

   Матеріал не вигадуємо: рядок повторює пару «поле пошуку + кнопка фільтрів»,
   яка вже є в каталозі. Свій тут лише розкладковий CSS. */
.lblrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
}
/* Підпис — той самий, що й у `label.field > span`, тільки без нижнього поля:
   його тепер тримає сам рядок. */
.lblrow .lbl {
  font-family: var(--font-data);
  font-size: var(--t-label);
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-3);
  min-width: 0;
}
.lblrow > button {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.lblrow > button .ic { width: 15px; height: 15px; }

/* ОСТАННЯ ПЛИТКА НЕ СТОЇТЬ СИРОТОЮ.

   Плитки «Ще» лягають у дві колонки. Адмін бачить чотири — рівно дві пари;
   звичайний гравець три, і третя («Про гру») займала пів рядка, лишаючи
   поруч порожнє місце (власник 21.09.2026: «в "ще" гравець не має адмін
   панелі, тому кнопку про гру треба розширити на всю ширину»).

   Умова рахується, а не прибивається до ролі: плиток може стати більше чи
   менше, і правило «непарна остання займає рядок» лишиться правильним. */
.menucard.shyroka { grid-column: 1 / -1; }

/* Картка створення світу ховає поля атрибутом hidden (анкета / через ШІ).
   Але label.field, .actions і .lblrow мають власний display, і він перебивав
   hidden браузера: у режимі ШІ поля анкети лишались на екрані (24.09.2026). */
.wcard-new [hidden] { display: none; }
.nwkroky { padding-left: 1.2em; margin: 0 0 12px; }
.nwkroky li { margin-bottom: 4px; }

/* Загиблий герой у смужці: червоне кільце, притлумлене обличчя й череп
   поверх нього. Червоний — той самий --danger, що в кнопок «Видалити». */
.rost.dead .rost-face,
.rost.dead.on .rost-face {
  position: relative;
  border: 2px solid var(--danger);
  box-shadow: 0 0 12px rgba(255, 79, 139, .45);
}
.rost.dead.on .rost-face { box-shadow: 0 0 18px rgba(255, 79, 139, .8); }
.rost.dead .rost-face img { filter: grayscale(1) brightness(.5); }
.rost-cherep { position: absolute; font-style: normal; font-size: 26px; line-height: 1; }
.rost.dead span { color: var(--danger); }
.rost.dead.on { cursor: pointer; }

/* ═══ ЩІЛЬНІ ПАНЕЛІ: адмінка й кабінет власника світу (24.09.2026) ═══════════
   Власник: «зроби все більш мініатюрним і компактним». Екрани гравця лишаються
   просторими (кнопки на всю ширину там — рішення 19.09); щільність вмикається
   лише класом .shchilno на контейнері панелі — як «compact density» у робочих
   таблицях. Тільки розкладка й відступи: матеріал той самий. */
.vkladky {
  position: sticky;
  top: calc(var(--tg-top, 0px) + var(--topbar-h));
  z-index: 20;
  margin: 0 0 var(--s2);
  padding: 4px;
  /* Суцільний фон картки замість розмиття: backdrop-filter на липкій стрічці
     перемальовувався на кожному кадрі прокрутки й гальмував її на телефоні. */
  background: rgba(12, 13, 15, .96);
  border: 1px solid var(--edge-soft);
  border-radius: 999px;
}
/* Кнопки гри мають min-height 48 px; вкладкам досить 40 — компактно, але
   пальцем не промахнешся. */
.vkladky .dossier-tab { padding: 6px 11px; font-size: 13px; min-height: 40px; }
/* П'ять вкладок кабінету на 375 px — без краю, за яким ховались «Гравці» й
   «Скарги» (04.11.2026). Ширші за екран (адмінка, 320 px) і далі гортаються. */
.vkladky { gap: 4px; }
.vkladky .dossier-tab { flex: 1 0 auto; justify-content: center; padding: 6px 8px; }

.shchilno .sec { margin: 14px 0 6px; }
.shchilno .card .body { padding: 10px 12px; }
.shchilno .card p { margin-bottom: 6px; }
.shchilno label.field { margin-bottom: 8px; }
.shchilno .actions { margin-top: 8px; }
.shchilno .actions > button,
.shchilno .actions > .btn,
.shchilno .actions > a.btn { flex: 0 1 auto; }
.shchilno .card > .body > button,
.shchilno .card > .body > .btn { width: auto; }
.shchilno table { font-size: 13px; }
.shchilno th,
.shchilno td { padding: 6px 6px; }
.shchilno .inv-row { padding: 7px 10px; }
.shchilno .nwmore { margin: 6px 0; }

/* Світи в розрізі, хто витрачає: назва й дії в один рядок, смуги поруч. */
.shchilno .wlist { gap: 6px; margin-top: 10px; }
.shchilno .wrow {
  padding: 8px 10px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--s2);
  align-items: center;
}
.shchilno .wrow .wname b { font-size: 14px; }
.shchilno .wrow .wbars { grid-column: 1 / -1; flex-direction: row; gap: 6px; margin-top: 6px; }
.shchilno .wrow .wbar { flex: 1 1 0; height: 18px; }
.shchilno .wrow .wbar > span { padding: 1px 6px; font-size: 13px; }
.shchilno .wrow .actions { grid-column: 2; grid-row: 1; margin: 0; flex-wrap: nowrap; }

/* Рядок із розгортанням: місця (з відступом за глибиною дерева), NPC, постаті. */
.ryadok { border-bottom: 1px solid var(--edge-soft); }
.ryadok:last-child { border-bottom: 0; }
.ryadok > summary {
  list-style: none;
  display: flex; align-items: center; gap: var(--s2);
  min-height: 40px;
  padding: 7px 12px 7px calc(12px + var(--gl, 0) * 14px);
  cursor: pointer;
}
.ryadok > summary::-webkit-details-marker { display: none; }
.ryadok > summary::after {
  content: "›";
  color: var(--ink-3);
  transition: transform .16s var(--ease);
}
.ryadok[open] > summary::after { transform: rotate(90deg); }
.ryadok-imia { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.ryadok-imia b { font-size: 14px; overflow-wrap: anywhere; }
.ryadok-imia small { font-size: 13px; color: var(--ink-3); }
.ryadok-meta { display: flex; gap: 4px; flex-wrap: wrap; justify-content: flex-end; }
.ryadok-meta .pill { font-size: 13px; padding: 2px 7px; }
/* Підпис рядка — в один рядок (25.10.2026): роль постаті з досьє на сім рядків
   робила згорнутий рядок вищим за розгорнутий. Повний текст — у розгортці;
   це показ, а не обрізання даних. Мітка праворуч не відбирає в імені більше
   половини рядка. */
.ryadok-imia small.odyn-riadok { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ryadok-meta { flex: none; max-width: 45%; min-width: 0; }
.ryadok-meta .pill { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.npc-chysla { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 8px; }
.npc-chysla .ic { width: 13px; height: 13px; }
.ryadok-tilo { padding: 2px 12px 12px calc(12px + var(--gl, 0) * 14px); }
/* Дія рядка іконкою: дві текстові кнопки забирали 210 px із 322, і назва
   світу розпадалась на шість рядків. Підпис — у title й aria-label. */
.shchilno .ikonka { padding: 6px; min-width: 40px; justify-content: center; }
.shchilno .ikonka .ic { width: 18px; height: 18px; }
/* Назва світу й дії — перший рядок, хто власник і скільки гравців — другий, на
   всю ширину: поруч із діями вони розпадались на три рядки. */
.shchilno .wrow .wname { display: contents; }
.shchilno .wrow .wname span { grid-column: 1 / -1; }
.shchilno .ryadok > summary { min-height: 36px; padding-top: 5px; padding-bottom: 5px; }

/* Акордеон вкладки: заголовок розділу і є перемикач. */
.rozdil > summary { list-style: none; cursor: pointer; }
.rozdil > summary::-webkit-details-marker { display: none; }
.rozdil > summary.sec::before { content: "›"; transition: transform .16s var(--ease); }
.rozdil[open] > summary.sec::before { transform: rotate(90deg); }
.shchilno .poshuk { margin: 0 0 var(--s2); }
.shchilno .ryadok[hidden] { display: none; }
/* Позначка в рядку — одним рядком: «Майстерня гнома-коваля» розпадалась на
   три. Повна назва — у розгорнутому рядку. */
.ryadok-meta .pill { white-space: nowrap; max-width: 42vw; overflow: hidden; text-overflow: ellipsis; }

/* Рядок даних замість рядка таблиці: назва й підпис ліворуч, число й дія праворуч. */
.rdk { gap: var(--s2); }
.rdk-l { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.rdk-l b { font-weight: 600; overflow-wrap: anywhere; }
.rdk-l small { font-size: 13px; color: var(--ink-3); overflow-wrap: anywhere; }
.rdk > .q { white-space: nowrap; }
.rdk > button { flex: 0 0 auto; }
.ikonka { padding: 6px; min-width: 40px; justify-content: center; }

/* КАРУСЕЛІ ГОРТАЮТЬСЯ, А НЕ ТИСНУТЬСЯ (власник, 24.09.2026: «на кнопках у
   каруселях висять ефекти натискання, і через це важко гортати — вони не
   плавні, я весь час відчуваю роздратування»). Кожен початок гортання — це
   дотик, і загальний стиск `[onclick]:active { scale(.96) }` смикав картку під
   пальцем щоразу, коли людина просто гортала. У стрічках, що гортаються вбік,
   відгуку натиску немає: вибір і так видно — активне світиться. */
.dossier-tabs > .dossier-tab:active,
.dossier-tabs > .mem-chip:active,
.roster > .rost:active { transform: none; }
.dossier-tabs,
.roster {
  overscroll-behavior-x: contain;
  touch-action: pan-x pan-y;
}

/* Атлас — у atlas.css (спільний із ПК-кабінетом, 25.10.2026). */

ul.legend .lg-here, ul.legend .lg-next { width: 12px; height: 12px; border-radius: 50%; }
ul.legend .lg-road {
  width: 22px; height: 12px; border-radius: 6px;
  border: 1.2px dashed rgba(245, 227, 92, .7); background: rgba(36, 30, 8, .88);
}

/* ── Карта в кабінеті власника (26.09.2026) ──────────────────────────────
   Той самий атлас, що в гравця; своє тут лише розкладка переходу в
   редакторі й стан кнопки режиму — матеріал узято з .chip.on. */
.vlasnyk-karta { height: 52vh; min-height: 300px; }
#vlZiednaty.on {
  border-color: rgba(var(--portal-rgb), .55);
  color: var(--acid);
  background: rgba(var(--portal-rgb), .16);
}
.perekhody { display: flex; flex-direction: column; gap: var(--s2); }
.perekhid {
  padding: var(--s2) 0 var(--s3);
  border-bottom: 1px solid var(--edge-soft);
}
.perekhid:last-child { border-bottom: 0; }
.perekhid .grid2 { align-items: end; }

/* Адмінка → Гравці (ekrany/admin-hravtsi.js): лише розкладка рядка — імʼя й
   баланс угорі, підпис, і швидка видача ходів одним рівним рядком. Кнопки —
   наявні .tiny.ghost; тут тільки ширина, щоб пʼять стали в ряд на телефоні. */
.hr-riadok { display: flex; flex-direction: column; align-items: stretch; gap: 6px; }
.hr-verkh { display: flex; align-items: center; gap: 8px; }
.hr-verkh b { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.hr-pidpys { opacity: .75; line-height: 1.35; }
.hr-knopky { display: flex; gap: 6px; }
.hr-knopky .tiny { flex: 1 1 0; min-width: 0; padding-left: 0; padding-right: 0; }


/* ── Оформлення: ASCII-фон і вибір гами (30.10.2026) ──────────────────────
   Полотно лежить МІЖ фото з вуаллю (z 0) і вмістом (`.wrap`, z 2): вуаль
   затемнила б символи, якби вони були під нею. Дотики пропускає. */
#asciiFon {
  position: fixed; inset: 0; width: 100%; height: 100%;
  z-index: 1; pointer-events: none;
}
/* Гами — кружечки з підписом. Лише розкладка: кнопка, поле й межі — ті, що вже
   є в системі стилів. */
.ofm-palitry {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: 10px; margin: 10px 0 16px;
}
.ofm-pal {
  display: grid; justify-items: center; gap: 6px; padding: 8px 4px;
  min-height: 44px;
  background: transparent; border: 1px solid transparent; border-radius: 14px;
  color: var(--ink-2); font-size: 13px;
}
.ofm-pal i {
  width: 38px; height: 38px; border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .18);
}
.ofm-pal[aria-pressed="true"] { border-color: rgba(var(--portal-rgb), .6); color: var(--acid); }
.chip[aria-pressed="true"] {
  border-color: rgba(var(--portal-rgb), .55);
  color: var(--acid);
  background: rgba(var(--portal-rgb), .16);
}

/* Копія ASCII-фону всередині смуги під шапкою: сама смуга залита суцільним
   кольором і лежить вище за фон, тож без копії шапка була голою. Вище за вуаль
   смуги (її ::after), щоб яскравість збігалась з основним фоном. */
#asciiFonShapka {
  position: absolute; top: 0; left: 0; width: 100%; height: 280px;
  z-index: 1; pointer-events: none;
}
.ofm-kolory { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 10px 0 16px; }
.ofm-krapka {
  position: relative; width: 32px; height: 32px; padding: 0; border-radius: 50%;
  background: var(--k); border: 2px solid rgba(255, 255, 255, .18);
  min-height: 0; flex: none;
}
.ofm-krapka[aria-pressed="true"] { border-color: #fff; box-shadow: 0 0 0 2px rgba(var(--portal-rgb), .6); }
.ofm-vlasnyi {
  background: conic-gradient(#ff6b6b, #f5b942, #8fd93f, #35e0f5, #a78bfa, #ff6b6b);
  overflow: hidden;
}
.ofm-vlasnyi input { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; }

/* Кнопка налаштувань у шапці: той самий вигляд, що й тумблер мови поруч, лише
   зі значком; хіт-зона не менша за 32px. */
.nalashtuvannia-knopka { display: inline-flex; align-items: center; justify-content: center; min-width: 32px; min-height: 28px; }
.nalashtuvannia-knopka .ic { width: 16px; height: 16px; }


/* ── КНОПКИ В ASCII-СТИЛІСТИЦІ (30.10.2026) ──────────────────────────────────
   Власник: «прибери окантовку і скляний ефект в кнопок». Кнопка — пласка
   заливка без межі, тіні, розмиття і градієнта; підпис моноширинний, як у
   терміналі. Ієрархія тримається на заливці: головна — акцентна, другорядна й
   чіпи — ледь помітна світла плашка, небезпечна — тінь червоного.

   Правила кнопок розкидані по файлу шарами (кожен новий перебивав
   попередній); цей блок стоїть ОСТАННІМ і однаково специфічний, тож перемагає
   без форсування пріоритету. Стан наведення прописано окремо: `button.ghost:hover`
   важчий за `button.ghost`, тож без нього старе скло поверталось би на hover. */
button, .btn, button.ghost, button.tiny, button.danger {
  border: 0;
  box-shadow: none;
  text-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  font-family: var(--font-data);
  letter-spacing: .01em;
}
button, .btn { background: var(--acid); color: #06240b; }
/* Другорядна кнопка й чіп — НЕПРОЗОРА заливка темним відтінком акценту (власник:
   «кнопок напівпрозорих не має бути, вони мають бути непрозорі з акцентним
   кольором», передусім на «Я» / «Мій герой»). Колір іде за гамою через
   `--portal-dark`, тож змінюється разом з темою. */
button.ghost, button.tiny { background: var(--portal-dark); color: var(--acid); }
button.danger { background: color-mix(in srgb, var(--danger) 26%, var(--void-2)); color: var(--danger); }
/* Кант-градієнт головної кнопки був її «склом» — прибрано разом з усім. */
button:not(.ghost):not(.tiny):not(.danger)::before { content: none; }
@media (hover: hover) {
  button:hover, .btn:hover { background: var(--portal); border: 0; box-shadow: none; transform: none; }
  button.ghost:hover, button.tiny:hover { background: var(--portal-deep); color: #fff; box-shadow: none; }
  button.danger:hover { background: color-mix(in srgb, var(--danger) 38%, var(--void-2)); }
}
.chip { border: 0; background: var(--portal-dark); color: var(--acid); font-family: var(--font-data); }
.chip[aria-pressed="true"], .chip.on { border: 0; background: var(--acid); color: #06240b; }
.ofm-pal[aria-pressed="true"] { border-color: transparent; background: rgba(var(--portal-rgb), .18); }
.ofm-krapka { border: 0; }

/* ── ASCII-скелетон (ekrany/skeleton.js) ─────────────────────────────────────
   Чорнило скіла береться з гами теми: так скелетон перефарбовується разом із
   нею. Макет вантаження ховає власний текст і колишню CSS-хвилю — малює лише
   символьне поле поверх. */
:root { --ascii-ink: var(--portal); --ascii-ink-strong: var(--acid); }
.skel-ascii [data-block] { color: transparent; background: none; animation: none; }
.skel-ascii h3, .skel-ascii p { margin: 0; }

/* ── Вікно оплати: щільні плашки й відступи (30.10.2026) ─────────────────────
   Списки пакетів, слотів і історії лежали прямо на фоні напівпрозорим склом
   (`--mat-2`, .52), і крізь них проступав рухомий ASCII-фон — текст рядків
   читався гірше, ніж на картках. Тепер вони затоновані тим самим темним
   градієнтом, що й `.card`. Вище стоять кнопки-пакети: дрібніший напис, щоб
   «Купити за 100 грн» не відбирало в підпису півширини рядка. */
.inv-list { margin-bottom: 14px; }
.inv-list.shchilni {
  background: linear-gradient(165deg, rgba(20, 22, 25, .975) 0%, rgba(12, 13, 15, .985) 100%);
  border: 1px solid var(--line);
}
.inv-list.shchilni .inv-row { padding: 12px 14px; }
.rdk > button.tiny { font-size: 13px; padding: 8px 12px; }
.skel-grupa { display: block; }

/* ── Плашки сповіщень з орбом (ekrany/anim.js) ──────────────────────────────
   Усі сповіщення — одна форма: орб стану, текст, хрестик «сховати»; змах убік
   теж ховає. Матеріал — те саме матове скло, що й у всіх панелей. */
.orb-kartka {
  pointer-events: auto; touch-action: pan-y;
  display: flex; align-items: center; gap: 12px;
  max-width: min(100%, 520px);
  padding: 8px 8px 8px 12px; border-radius: var(--r-md);
  background: var(--mat-skl); border: 1px solid var(--line);
  backdrop-filter: var(--blur-mat); -webkit-backdrop-filter: var(--blur-mat);
  box-shadow: 0 8px 28px rgba(0, 0, 0, .45);
  font-family: var(--font-data); font-size: var(--t-small); color: var(--ink);
  transition: opacity .18s ease, transform .18s ease;
  animation: plashkaVkhid .2s var(--ease) both;
}
.orb-kartka.vykhid { opacity: 0; transform: translateY(6px); }
@keyframes plashkaVkhid { from { opacity: 0; transform: translateY(8px); } }
.orb-slot { width: 40px; height: 40px; flex: none; }
.orb-tekst { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; line-height: 1.4; }
.orb-kartka .orb-x {
  flex: none; min-height: 32px; width: 32px; padding: 0;
  background: transparent; color: var(--ink-3); font-size: 18px; line-height: 1;
}
@media (hover: hover) { .orb-kartka .orb-x:hover { background: transparent; color: var(--ink); } }
.orb-kartka[data-stan="error"] .orb-tekst { color: var(--danger); }
.orb-kartka[data-stan="success"] .orb-tekst { color: var(--acid); }
@media (prefers-reduced-motion: reduce) { .orb-kartka { animation: none; transition: none; } }

/* Одометр (ekrany/anim.js) кладе цифри у власні `span`; правило `.stat span`
   (підписи по 10px, капсом, трекінг) без цього відтворювало б і їх. */
[data-odo], .stat b[data-odo] span, [data-odo] span {
  font: inherit; letter-spacing: inherit; text-transform: none; color: inherit;
}


/* ── ЄДИНИЙ МАТЕРІАЛ ПАНЕЛЕЙ І ЄДИНА ФОРМА КНОПОК (31.10.2026) ───────────────
   Власник: «у всіх кнопок на всіх сторінках — однакові закріплення кутів,
   формат і стиль; планшети між усіма сторінками — однаково скляні,
   напівпрозорі, затоновані, матові». Панелі, що лежать просто на фоні, беруть
   одне скло; вкладені в них рядки — без власної заливки, щоб не темніти
   шарами. Кнопки — один радіус, один шрифт, одна вага, без прозорості. */
.card, .inv-list, .inv-list.shchilni, .exits-list, .menucard, .bottomnav {
  background: var(--mat-skl);
  backdrop-filter: var(--blur-mat);
  -webkit-backdrop-filter: var(--blur-mat);
}
:root { --r-knopky: var(--r-sm); }
button, .btn, .chip, button.tiny, button.ghost, button.danger,
.card.wcard .actions button, .inv-list .inv-row .q button {
  border-radius: var(--r-knopky);
  font-family: var(--font-data);
  font-weight: 700;
  letter-spacing: .01em;
}
.tiny.ghost { opacity: 1; }

/* ── ASCII-ІНТЕРФЕЙС (ekrany/ascii-ui.js, 31.10.2026) ──────────────────────── */
/* Підтвердження свайпом: доріжка з підписом і пальцем-повзунком. */
.svaip-tekst { white-space: pre-line; }
.svaip {
  position: relative; height: 52px; margin: 14px 0 4px;
  border-radius: var(--r-knopky);
  background: var(--mat-1); border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  touch-action: none; user-select: none; -webkit-user-select: none;
}
.svaip-napys { font-family: var(--font-data); font-size: var(--t-small); color: var(--ink-2); padding: 0 56px; text-align: center; }
.svaip-palets {
  position: absolute; left: 4px; top: 4px; width: 44px; height: 42px;
  display: grid; place-items: center; cursor: grab;
  border-radius: var(--r-knopky);
  background: var(--acid); color: #06240b; font-weight: 700; font-size: 18px;
}
/* Знак оновлення — орб на темній монеті з акцентним обідком (31.10.2026,
   власник: «надто неконтрастний, зливається з фоном»). Без підкладки зелені
   символи орба лягали на такий самий зелений ASCII-фон і губились. */
#pull[data-kit] .pull-obid {
  width: 46px; height: 46px; margin-left: -23px;
  border-radius: 50%;
  background: rgba(8, 10, 12, .92);
  box-shadow: 0 0 0 1.5px var(--acid), 0 0 18px rgba(var(--acid-rgb), .55), 0 6px 18px rgba(0, 0, 0, .6);
}
.pull-orb { display: block; width: 100%; height: 100%; }


/* ДАНІ КАРТКИ СВІТУ — КОЛЬОРОВІ ПІДПИСИ, А НЕ БУЛЬБАШКИ (31.10.2026).
   Власник: «бульбашки виглядають дешево», а потім «крапка-роздільник теж
   негарна, хай різнокольорові типи підписів будуть». Кожен тип — свій колір
   і тонка риска того ж кольору перед текстом: жанр — фіалковий, режим —
   акцент, доступ — блакитний, мій стан — зелений, «заявка чекає» —
   бурштин, «місць немає» — червоний. Розмітка та сама (rezhymPill,
   stanPill…), тож інші екрани не зачеплено. */
.wmeta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px;
  margin: 4px 0 12px;
  font-family: var(--font-data); font-size: 13px; line-height: 1.3;
}
.wmeta .pill {
  display: inline-flex; align-items: center; white-space: nowrap;
  padding: 0 0 0 7px; margin: 0; min-height: 0;
  background: none; border: 0; box-shadow: none; border-radius: 0;
  border-left: 2px solid currentColor;
  font: inherit; font-weight: 600; letter-spacing: 0; text-transform: none;
}
.wmeta .pill.gen  { color: var(--violet); }
.wmeta .pill.mode { color: var(--acid); }
.wmeta .pill.dim  { color: var(--cyan); }
.wmeta .pill:not(.gen):not(.mode):not(.dim):not(.hot):not(.warn) { color: var(--portal); }
.wmeta .pill.warn { color: var(--amber); }
.wmeta .pill.hot  { color: var(--danger); }
.wcard-top .pill.lang {
  background: none; border: 0; box-shadow: none; padding: 0;
  font-family: var(--font-data); font-size: 13px; letter-spacing: .08em; color: var(--ink-3);
}


/* ── ПІГУЛКИ БЕЗ БУЛЬБАШОК (31.10.2026) ──────────────────────────────────────
   Власник: «бульбашки прибрати». Кожен тип — кольоровий підпис з тонкою
   рискою зліва, без заливки, рамки й заокруглення. Розмітка не міняється,
   тож зачеплено всі екрани одразу. */
.pill, .pill.dim, .pill.warn, .pill.hot, .pill.info, .pill.ok, .pill.gen, .pill.mode {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 0 0 0 7px; min-height: 0; margin: 0;
  background: none; border: 0; border-left: 2px solid currentColor; border-radius: 0;
  box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none;
  animation: none; white-space: nowrap;
  font-family: var(--font-data); font-weight: 600; letter-spacing: 0; text-transform: none;
}
.pill       { color: var(--portal); }
.pill.dim   { color: var(--cyan); }
.pill.info  { color: var(--cyan); }
.pill.warn  { color: var(--amber); }
.pill.hot   { color: var(--danger); }
.pill.ok    { color: var(--acid); }
.pill.gen   { color: var(--violet); }
.pill.mode  { color: var(--acid); }
.pill.lang  { border-left: 0; padding: 0; color: var(--ink-3); }

/* ── БЕЗ ПЛАШОК УСЕРЕДИНІ ПЛАШОК (31.10.2026) ────────────────────────────────
   Інвентар у картці мав власну коробку з рамкою всередині коробки картки.
   Усередині картки список — просто рядки з волосинками, без другої плашки. */
.card .inv-list, .card .exits-list {
  background: none; border: 0; border-radius: 0; box-shadow: none;
  backdrop-filter: none; -webkit-backdrop-filter: none; margin: 0;
}
.card .inv-list .inv-row, .card .exits-list .exit { padding-left: 0; padding-right: 0; }


/* ── ДОДАТКОВО ЗНЯТО ПЛАШКИ В ПЛАШКАХ І ПЕРЕНОС СЛОВА (01.11.2026) ───────────
   Рядки світів у «Ходах» лежали плашками всередині картки. Тепер усередині
   картки рядок — це волосинка, як і в інвентарі. Назви в кутових меню
   («Налаштування») рубало посеред слова через `overflow-wrap: anywhere`:
   слово не ламаємо, а зменшуємо під ширину екрана. */
.card .wlist { gap: 0; margin-top: 8px; }
.card .wrow, .card .who-row {
  background: none; border: 0; border-radius: 0; box-shadow: none;
  border-bottom: 1px solid var(--edge-soft);
  padding-left: 0; padding-right: 0;
}
.card .wrow:last-child, .card .who-row:last-child { border-bottom: 0; }
.menucard b { overflow-wrap: normal; word-break: keep-all; hyphens: manual; font-size: clamp(12px, 3.5vw, 16px); }


/* ═══ ЕКСПЕРТИЗА 01.11.2026: ШВИДКОДІЯ, ДРІБНИЙ ТЕКСТ, ЗОНИ НАТИСКАННЯ ═════════
   1. Скло. На одному екрані стояло 73 шари `backdrop-filter`, а фон під ними
      перемальовується 20 разів на секунду — телефон щокадру перераховував
      розмиття під усіма картками. Розмиття лишаємо там, де є що розмивати
      над чимось, що рухається: шапка, нижня панель, модальні вікна, сповіщення.
      Картки, рядки, кнопки й поля — однотонні, щоб символи фону не читались
      крізь текст, матеріал трохи щільніший. */
.card, .menucard, .inv-list, .exits-list, .tablewrap, .chart, .uploader, .empty,
.tip, .node, .step, .hero, .glass, .skel-card, .err, .ok, .avatar,
button, .btn, button.ghost, button.tiny,
.portrait-slot .edit, .modeswitch, .wsticky .modeswitch, .wsticky .fbtn,
.wsticky .searchbar input[type="search"] {
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
.card, .menucard, .inv-list, .exits-list, .tablewrap, .chart, .uploader, .empty,
.tip, .hero, .glass {
  background: rgba(14, 16, 18, .9);
}
.card .inv-list, .card .exits-list { background: none; }

/* 2. Текст: нижня межа 13px (було 9–12). Підписи з розрядкою стискаємо, щоб
      не розпирали рядок. */
.who { font-size: 13px; }
.sec, .navitem span { letter-spacing: 1.5px; }
.navitem { font-size: 12px; }

/* 3. Зони натискання ≥ 44px: за правилами Apple палець влучає з першого разу.
      Візуально малі кнопки (мова, шестірня) лишаються малими, а клікабельна
      зона розширена прозорим ::after. */
button, .btn, summary, .chip, a.wmap, .wmap { min-height: 44px; }
button.tiny, .tiny { min-height: 36px; }
.mova-tumbler { min-height: 0; position: relative; }
.mova-tumbler::after, button.tiny::after, .wcard .actions button::after {
  content: ""; position: absolute; inset: -6px;
}
button.tiny, .wcard .actions button { position: relative; }

/* 4. Обертання карток і заголовків знято: нахил на ±0,4° розмиває текст
      на підпіксельному рівні й виглядає як вада, а не як стиль. */
.card:nth-of-type(3n+1), .card:nth-of-type(3n+2),
.menucard:nth-child(odd), .menucard:nth-child(even),
.sec, .sec:nth-of-type(even) { transform: none; }

/* 5. Назви в картках не обрізаємо трикрапкою: переносимо на другий рядок. */
.wcard h3, .wname b, .card h3 { white-space: normal; text-overflow: clip; overflow-wrap: break-word; }

/* Шапка: підпис «гравець» біля балансу знято — число й так зрозуміле, а
   підпис відбирав місце в назви, і її остання літера обрізалась. Аватар і
   тумблери стиснуті візуально, зона натискання лишається 44px (::after). */
.topbar { padding: 10px 12px; gap: 6px; }
.topbar .who { font-size: 0; }
.topbar .who b { font-size: 16px; }
.topbar .brand { min-width: 0; flex: 1 1 auto; }
.topbar .avatar { width: 40px; height: 40px; flex: none; }
.mova-tumbler { padding: 6px 8px; }
button.wmap, .card.wcard .actions button.wmap, .wtab, button.tiny.fbtn { min-height: 44px; }
.card.wcard h3, .card.wcard .wname b {
  white-space: normal; text-overflow: clip; overflow: visible; overflow-wrap: break-word;
}

/* Палітра пігулок: один нейтральний тон і лише три сигнальні — акцент
   (режим, «ок»), бурштин (увага), червоний (небезпека). Фіолетовий і
   блакитний знято: вони не несли смислу, лише множили кольори. */
.pill, .pill.dim, .pill.info, .pill.gen { color: var(--ink-2); }

/* Поля вводу: без розмиття й не дрібніше за 16px (інакше iOS зумить екран). */
input[type="text"], textarea, select {
  backdrop-filter: none; -webkit-backdrop-filter: none; font-size: 16px;
}

/* ═══ КАРТКИ СВІТІВ — ЩІЛЬНО, ЩОБ БАЧИТИ КІЛЬКА ЗА РАЗ (01.11.2026) ══════════
   Власник: «змінити стиль карток, щоб показувати відразу декілька світів».
   Картка була ~240px заввишки (великий опис, вузька колонка тексту біля
   порожньої обкладинки, кнопка на всю ширину) — на екран влазило півтора
   світи. Тепер: заглушка без фото зникає, обкладинка-фото вужча, назва до
   двох рядків, опис один рядок, «Грати» і «Карта» в одному рядку. */
.card.wcard { grid-template-columns: 64px 1fr; margin-bottom: 8px; }
.card.wcard .body { padding: 10px 12px; display: flex; flex-direction: column; gap: 4px; }
.card.wcard h3 {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  white-space: normal; overflow: hidden; text-overflow: clip; font-size: 15px;
}
.card.wcard p { margin: 0; -webkit-line-clamp: 1; }
.card.wcard .wmeta { margin: 0; }
.card.wcard .actions { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 8px; margin-top: 2px; }
.card.wcard .actions button:not(.wmap) { width: auto; flex: 0 0 auto; min-height: 40px; padding: 0 22px; }
.card.wcard .actions .wmap { min-height: 44px; padding: 0 4px; order: 2; }
details.wcard-new:not([open]) { --wnew-h: 92px; }
details.wcard-new:not([open]) > summary { min-height: 92px; }


/* ═══ КНОПКИ — ПЛОСКІ І ДРІБНІШІ (01.11.2026) ═════════════════════════════════
   Власник: «дизайн кнопок поменше». Кнопка мала чотири шари визначень
   (градієнт, скляний блиск, зовнішня тінь, внутрішня світла риска) — і
   кожен перемальовувався на кожному кадрі фону. Лишаємо одне: суцільна
   заливка, без тіні й блиску, висота 40, радіус 10. */
button, .btn {
  min-height: 40px; padding: 0 16px; border-radius: 10px;
  font-size: 14px; font-weight: 600; letter-spacing: 0;
  background: var(--acid); background-image: none;
  border: 0; color: #06240b; text-shadow: none; box-shadow: none;
}
button::before { display: none; }
button.ghost, button.tiny {
  background: transparent; color: var(--ink);
  border: 1px solid var(--edge); box-shadow: none; text-shadow: none;
}
button.tiny { min-height: 36px; padding: 0 12px; font-size: 13px; }
button.danger {
  background: transparent; color: var(--danger);
  border: 1px solid rgba(255, 79, 139, .45); box-shadow: none; text-shadow: none;
}

/* Тінь тексту (дві, одна з розмиттям 8px) стояла майже на кожному рядку —
   сотні перемальованих шарів. Картки тепер однотонні, тінь не потрібна. */
.card p, .tip, .inv-row, .exit, td, th, .stat span, .stat b, .bar-label,
.who-row b, .who-row span, .legend, .empty, .step b, .step span,
.card h3, .wname b, .menucard b { text-shadow: none; }


/* ЗНАК ОНОВЛЕННЯ — ПРОСТО ПІД ШАПКОЮ (01.11.2026). Нічого не їде, окрім самого
   знака: ні шапка, ні вміст, ні маски. Він виїжджає з-під нижнього краю шапки
   слідом за пальцем і нікуди від неї не відлітає. */
.topbar { transform: none; }
:root.ie-pull #view, :root.pull-plavno #view { transform: none; }
#pull { -webkit-mask-image: none; mask-image: none; will-change: opacity; }
.pull-obid {
  top: calc(var(--tg-top, 0px) + var(--topbar-h) + 26px);
  transform: translateY(calc((1 - var(--pull-t, 0)) * -30px));
  will-change: transform;
}


/* ═══ ПОШУК І ВКЛАДКИ КАТАЛОГУ — КОМПАКТНІ; ЗАГЛУШКА ОБКЛАДИНКИ (01.11.2026) ══
   Власник: «від студії / спільноти і пошук надто великі». Було: вкладки 44px
   із 14px шрифтом і поле пошуку з великими полями — разом ~110px липкої смуги
   під шапкою, а під нею лишалося пів екрана. Тепер 36 + 38 і менший відступ. */
.modeswitch.wtabs { padding: 3px; }
.modeswitch.wtabs .wtab { min-height: 34px; padding: 3px 8px; font-size: 13px; gap: 5px; }
.modeswitch.wtabs .wtab .ic { width: 15px; height: 15px; }
.wsticky { padding: 4px 0 0; margin-bottom: 6px; }
.wsticky .modeswitch { margin-bottom: 6px; }
.searchbar input[type="search"] { padding: 7px 12px; min-height: 38px; font-size: 16px; }
.searchrow .tiny, button.tiny.fbtn { min-height: 38px; min-width: 38px; padding: 0 10px; }

/* Заглушка: відтінок з назви, діагональна штрихівка й велика літера. */
.wcard-cover.nofoto {
  display: grid; place-items: center;
  background:
    repeating-linear-gradient(135deg, rgba(255,255,255,.045) 0 6px, transparent 6px 12px),
    linear-gradient(160deg, hsl(var(--h, 140) 45% 24%), hsl(var(--h, 140) 40% 11%));
}
.wcard-cover .monohrama {
  font-family: var(--font-display); font-weight: 800; font-size: 30px; line-height: 1;
  color: hsl(var(--h, 140) 70% 78% / .85); text-shadow: none;
}


/* ═══ ДОСЬЄ СВІТУ В ФОРМІ СТВОРЕННЯ — ПОЛЕ НА РОЗДІЛ (02.11.2026) ═══════════ */
.nw-dosie { display: flex; flex-direction: column; gap: 14px; margin: 6px 0 10px; }
.dos-pole { display: flex; flex-direction: column; gap: 4px; margin: 0; }
.dos-pole > span { font-family: var(--font-display); font-weight: 700; font-size: 15px; color: var(--ink); }
.dos-poiasn { font-size: 13px; line-height: 1.4; color: var(--ink-3); }
.dos-pole textarea { min-height: 76px; font-size: 16px; }
.obov { color: var(--danger); font-style: normal; }
.dos-pole textarea { min-height: 112px; }

/* ═══ РЕЖИМ «ЧЕРЕЗ СВІЙ ШІ» — КРОКИ-КАРТКИ (02.11.2026) ═══════════════════════
   Три кроки з номером зліва. Зроблений крок отримує галочку замість цифри й
   зеленішу рамку; перелік у третьому — рядки без власних плашок. */
.shi-krok {
  display: grid; grid-template-columns: 32px 1fr; gap: 12px; align-items: start;
  padding: 14px; margin: 0 0 10px;
  border: 1px solid var(--edge-soft); border-radius: var(--r-lg);
  background: rgba(14, 16, 18, .9);
}
.shi-krok[hidden] { display: none; }
.shi-n {
  width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-display); font-size: 15px; font-weight: 700;
  color: var(--acid); border: 1px solid var(--acid);
}
.shi-krok.zrobleno { border-color: rgba(var(--acid-rgb), .45); }
.shi-krok.zrobleno .shi-n { background: var(--acid); color: #06240b; font-size: 0; }
.shi-krok.zrobleno .shi-n::after { content: "✓"; font-size: 16px; }
.shi-tilo { min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.shi-tilo h4 { margin: 0; font-family: var(--font-display); font-size: 16px; color: var(--ink); }
.shi-tilo .actions { margin: 4px 0 0; }
.shi-tilo textarea { min-height: 112px; font-size: 16px; }
.shi-tilo button:disabled { opacity: .4; }
.shi-perelik { list-style: none; margin: 0; padding: 0; }
.shi-perelik li {
  display: flex; align-items: baseline; gap: 8px; padding: 7px 0;
  border-bottom: 1px solid var(--edge-soft); font-size: 14px;
}
.shi-perelik li:last-child { border-bottom: 0; }
.shi-perelik i { font-style: normal; width: 16px; flex: none; text-align: center; }
.shi-perelik li.ok i { color: var(--acid); }
.shi-perelik li.pusto { color: var(--ink-3); }
.shi-perelik small { margin-left: auto; font-size: 13px; color: var(--ink-3); text-align: right; }

/* ═══ СКРОЛ ДОВГОЇ ФОРМИ СТВОРЕННЯ СВІТУ (02.11.2026) ═════════════════════════
   Скарга: «довго вантажиться, при скролі стилі просальовуються». Форма —
   п'ять тисяч пікселів заввишки, і на неї діяли три речі, що змушують
   браузер малювати її цілком і заново:
   1. `#view.in > *` грав `glassUp` із `fill-mode: both`: після кінця анімації
      кожен блок екрана ЛИШАВСЯ з `transform: translateY(0) scale(1)` назавжди.
      Це окремий шар і контекст накладання на весь блок, у якому форма.
      Тепер `backwards`: стартовий стан до початку, а після кінця — нічого.
   2. `details.wcard-new` обрізав вміст заокругленням (`overflow: hidden` +
      `border-radius`) — для п'ятитисячного вмісту це обрізка через маску на
      кожному кадрі скролу. Відкритий блок більше не обрізає: нижні кути
      заокруглює сама панель всередині.
   3. Кожна піктограма мала `filter: drop-shadow`, тобто окремий прохід
      малювання; їх у формі десятки. Тінь під піктограмою — лишок від часів
      скла, тепер картки однотонні й вона нічого не дає.
   Окремо: поля досьє й кроки «через ШІ» малюються лише коли наближаються до
   екрана (`content-visibility`), а висота, яку браузер уже бачив, запам'ятана. */
#view.in > * { animation-fill-mode: backwards; }
.ic { filter: none; }
details.wcard-new[open] { overflow: visible; }
details.wcard-new[open] > .card { border-radius: 0 0 13px 13px; }
.nw-dosie > .dos-pole,
.shi-maister > .shi-krok {
  content-visibility: auto;
  contain-intrinsic-block-size: auto 190px;
}

/* ── ASCII-ЕКРАН ОЧІКУВАННЯ (02.11.2026) ──────────────────────────────────────
   Хвиля символів у `<pre>` (ekrany/ascii-chekannia.js). Лише розкладка й
   колір: чорнило — той самий `--portal`, що й в інших ASCII-елементів, а не
   нове. Без тіней і розмиття: екран стоїть саме тоді, коли телефон зайнятий. */
.az {
  display: flex; justify-content: center;
  padding: 14vh 0 10vh;
  min-height: 40vh;
}
/* Суцільна темна підкладка, як у знака «потягни, щоб оновити»: на живому
   ASCII-фоні голий підпис зливається з ним (власник уже скаржився на таке). */
.az-blok {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  align-self: flex-start;
  padding: 18px 20px;
  background: rgba(8, 10, 12, .92);
  border: 1px solid var(--edge-soft);
  border-radius: 14px;
}
.az-pole {
  margin: 0; padding: 0;
  font-family: var(--font-data); font-size: 13px; line-height: 1.15;
  white-space: pre; color: var(--portal);
  background: none; border: 0; text-shadow: none;
  user-select: none; -webkit-user-select: none;
  /* 30 символів ≈ 235 px: вміщається навіть у 320 px, а рядок не переноситься
     (`white-space: pre`), тож хвиля не рветься. */
  max-width: 100%; overflow: hidden;
}
.az-napys {
  margin: 0; max-width: 30ch;
  font-size: 13px; line-height: 1.4; text-align: center; color: var(--ink-3);
}

/* ── ASCII-МАКЕТ ОЧІКУВАННЯ: контраст (02.11.2026) ───────────────────────────
   Власник: «це треба контрастнішим зробити». Макет стоїть на живому
   ASCII-фоні, а карта світу була напівпрозорою — смуги тонули в чужих
   символах. Тепер під смугами суцільне темне тло, а чорнило — найяскравіше з
   теми (`--acid`). Рамка й радіус лишаються від справжньої картки (`.card`),
   тож контури збігаються з майбутнім вмістом. */
.skel-obhortka { display: block; }
.skel-grupa { --ascii-ink-strong: var(--acid); }
.skel-grupa .card,
.skel-grupa .card.wcard {
  background: #0a0b0d;
  border-color: var(--line);
}
/* Підказка «відповідь довга» зʼявляється сама, через вісім секунд. */
.skel-pidkazka {
  margin: 14px 0 0; text-align: center;
  font-size: 13px; line-height: 1.4; color: var(--ink-3);
  opacity: 0; animation: skel-pokaz .5s ease 8s forwards;
}
@keyframes skel-pokaz { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .skel-pidkazka { animation-duration: .01s; }
}
