/* rhiz.ru — тёмная кинематографичная тема (по мотивам storyforge):
   глубокий чёрный фон, тёплый светлый текст, янтарь-акцент (CTA) и
   киноварь для градиентов-декора. Заливка СВЕТЛЫМ = активное (инверсия
   старой ч/б схемы); пунктир = предостережение; «!» = ошибка.
   Логотип — logo.svg; в тёмной теме получает инверсию-подложку (.brand-mark). */
:root { color-scheme: dark; }
* { box-sizing: border-box; }
html, body, #app { height: 100%; }
:root {
  --bg: #131316;          /* страница */
  --bg-deep: #0d0d10;     /* глубина градиента */
  --card: #1b1b20;        /* поверхность: карточки, поля */
  --card-2: #22222a;      /* приподнятая поверхность */
  --sunken: #151519;      /* впадины: табы, ховеры-подложки */
  --hover: #26262e;       /* ховер-заливка */
  --line: rgba(255, 255, 255, .13);
  --line-strong: rgba(255, 255, 255, .3);
  --ink: #ece9e1;         /* основной текст / светлая «активная» заливка */
  --ink-on: #131316;      /* текст на светлой заливке */
  --ink-dim: #a29f97;     /* приглушённый текст */
  --ink-faint: #8a877f;   /* слабый текст/плейсхолдеры (AA 4.78 на card) */
  --acc: #fdb515;         /* янтарь: главные CTA */
  --acc-ink: #1a1405;     /* текст на янтаре */
  --hot: #e9213d;         /* киноварь: бренд-градиенты */
  --hot-ink: #ff6b7d;     /* киноварь как ТЕКСТ (6.25 на card) */
  --link: #ffd469;        /* ссылки в прозе (тёплый янтарь-свет) */
  --glow: rgba(233, 33, 61, .35);
  /* семантика: статусы и ошибки (не бренд) */
  --ok: #4ade80;
  --warn: #fb923c;
  --danger: #f87171;
  --info: #60a5fa;
  --violet: #a78bfa;
  /* роли сущностей (легенда, чипы .echip, точки): графика ≥3:1 на card */
  --role-hero: #2f9e58;
  --role-party: #60a5fa;    /* было #3f7fd6 (4.26) → поднято */
  --role-enemy: #d9534f;
  --role-neutral: #9a9a9a;
  --role-item: #c9a227;
  --role-mod: #2dd4bf;      /* модератор: #0f7b6c был 3.32 (провал текста) */
  /* высота декоративной полосы ПОД шапкой (предмет скина «верхняя панель»).
     На ПК это ровно тот зазор в 30px, который оставлен под висящий логотип
     (.tabs { margin-top: 30px }); на телефоне — 16px (там под лого 18px) */
  --tb-strip: 30px;
  /* нижняя навигация на телефоне: 2 ряда кнопок + запас на safe-area.
     Одно место правды и для отступа контента, и для игры во всю высоту */
  --tabsh: 0px;
}
body {
  margin: 0;
  background:
    radial-gradient(1200px 600px at 85% -10%, rgba(233, 33, 61, .12), transparent 60%),
    radial-gradient(900px 500px at -10% 30%, rgba(253, 181, 21, .07), transparent 55%),
    linear-gradient(180deg, var(--bg) 0%, var(--bg-deep) 100%);
  /* background-attachment: fixed здесь был лишним: body не скроллится
     (скроллится #pane), картинка и так стоит на месте — а браузер из-за
     fixed-фона вынужден перерисовывать его на каждом кадре прокрутки. */
  color: var(--ink);
  font: 15px/1.55 "Roboto Condensed", system-ui, -apple-system, "Segoe UI", sans-serif;
}
/* плёночное зерно: тонкий SVG-noise поверх всего фона (фаза 6, IV.4) —
   статика, 3% альфа, pointer-events:none; текст не задевает, но даёт
   «плёночность» плоским заливкам. fixed → не тянется при скролле. */
:root {
  /* та же текстура и для скин-панелей (нижняя навигация, вкладки инвентаря):
     мягче базовой (rect opacity .2), ложится blend-режимом overlay */
  --noise-soft: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.2'/%3E%3C/svg%3E");
}
body::after {
  content: "";
  position: fixed; inset: 0; z-index: -1;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
  opacity: .03;
  mix-blend-mode: overlay;
}
.morda { display: flex; flex-direction: column; height: 100%; }
button { font: inherit; cursor: pointer; }
input, select, textarea { font: inherit; color: inherit; }
img { display: block; }
/* атрибут hidden должен побеждать авторский display (классика: img{display:block}
   выше перебивал [hidden] UA-стиля — в шапке жил призрак-аватар) */
[hidden] { display: none !important; }

/* -------------------------------- шапка --------------------------------
   Шапка = прямоугольник + квадрат с лого, который свисает ниже её нижней
   рамки. Квадрат позиционируется абсолютно (на поток не влияет), .tabs
   отступает под него. */
.topbar {
  position: relative; display: flex; align-items: center; gap: 12px;
  padding: 8px 12px 8px 96px; background: var(--skin-panel, var(--card)); border-bottom: 1px solid var(--line);
  transition: background .3s;
  z-index: 70;   /* шапка (и выпадашка профиля) — над контентом панели: рамки аватарок из инвентаря не просвечивают поверх меню */
}
.brand-mark {
  position: absolute; left: 12px; top: 5px; width: 72px; height: 72px;
  overflow: hidden; z-index: 40;
  /* подложка логотипа = цвет панели скина; заливка лого — currentColor (ниже) */
  background: var(--skin-panel, var(--card)); border-radius: 10px;
  color: var(--skin-panel-ink, var(--ink));
  display: flex; align-items: center; justify-content: center; padding: 0;
  box-sizing: border-box;
}
.brand-mark svg { width: 100%; height: 100%; display: block; }
/* слой декора скина верхней панели (п.10): слизь/цифры/тон — за контентом */
.topbar-skin { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
/* brand-mark исключён: он сам absolutely (специфичность :not-правила его
   перебивала и он уезжал в поток на left-паддинг — см. .brand-mark выше) */
.topbar > *:not(.topbar-skin):not(.brand-mark) { position: relative; z-index: 1; }
/* слоган вместо названия: геометричный кириллический шрифт */
.brand { font-family: "Unbounded", system-ui, sans-serif; font-weight: 500; font-size: clamp(9px, 1.4vw, 13px); letter-spacing: .12em; min-width: 0; }
.brand span { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* знак «18+»: 436-ФЗ — на самом сервисе, не только в оферте */
.b18 {
  flex: none; border: 2px solid var(--line-strong); border-radius: 6px; padding: 1px 7px;
  font-size: 12px; font-weight: 800; letter-spacing: .06em; line-height: 1.5;
  background: var(--card);
}
.b18.big { font-size: 15px; margin: 0 auto 6px; }
/* пометка «ИИ» у реплики персонажа — обязанность обозначать сгенерированное ИИ */
.ai-tag {
  display: inline-block; margin-left: 6px; padding: 0 5px; vertical-align: middle;
  border: 1px solid var(--line-strong); border-radius: 4px; background: var(--hover);
  font-size: 9px; font-weight: 700; letter-spacing: .08em; color: var(--ink-dim);
  text-transform: uppercase; line-height: 1.6;
}
.acc { position: relative; display: flex; align-items: center; gap: 8px; }
.grow { flex: 1; }
.nick { font-weight: 600; }
.dash { border: 1px dashed var(--line-strong); border-radius: 999px; padding: 1px 10px; font-size: 12px; }
.pill:hover, .dash:hover { text-decoration: none; filter: brightness(1.35); }

/* ------------------------------- вкладки ------------------------------- */
.tabs { display: flex; gap: 2px; padding: 0 8px; background: var(--sunken); border-bottom: 1px solid var(--line); overflow-x: auto; margin-top: 30px; }
.tabs button { background: transparent; border: 0; border-bottom: 2px solid transparent; padding: 8px 14px; color: var(--ink-dim); white-space: nowrap; }
.tabs button.on { background: var(--ink); color: var(--ink-on); border-bottom-color: var(--ink); font-weight: 600; }
/* на телефоне табы уходят вниз (нижняя навигация) — сверху остаётся
   заглушка высотой под висящий лого */
.tabs-space { display: none; }

/* -------------------------------- панели ------------------------------- */
.pane { flex: 1; min-height: 0; overflow: auto; padding: 14px; }
/* переписка, лежащая прямо в панели: занимает панель ЦЕЛИКОМ — во всю
   ширину и до самого низа, минуя отступы (без вертикального скролла) */
.pane > .thread { height: calc(100% + 28px); margin: -14px; border-radius: 0; }
/* grid2 тянется во всю высоту окна (список слева скроллится сам,
   переписка справа занимает остаток) — раньше фиксированный vh-отступ
   оставлял внизу большую пустую полосу */
.grid2 { display: grid; grid-template-columns: 320px 1fr; gap: 14px; align-items: stretch; height: 100%; }
.grid2 > * { min-height: 0; min-width: 0; }
.grid2 > .card { max-height: 100%; overflow: auto; }
.grid2 .thread { height: 100%; }
/* планшет-книжка (768–1023px): фикс. 320px левой колонки — это 42% ширины,
   правая сжимается в тесноту; делаем левую пропорциональной с потолком */
@media (min-width: 768px) and (max-width: 1023px) {
  .grid2 { grid-template-columns: minmax(240px, 34%) 1fr; }
}
@media (max-width: 860px) { .grid2 { grid-template-columns: 1fr; height: auto; } }
/* статистика: графики колонками в ряд, без растягивания на высоту окна —
   нижние карточки живут по содержимому, без пустых строк */
.grid2.stats-top, .grid2.stats-bottom { height: auto; align-items: start; }
.grid2.stats-top > .card, .grid2.stats-bottom > .card { max-height: none; overflow: visible; }
@media (min-width: 861px) { .grid2.stats-top { grid-template-columns: 1fr 1fr; } }
.card { background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: 14px; }
.card + .card { margin-top: 12px; }
h4 { margin: 0 0 10px; font-size: 15px; }

/* ------------------------------- элементы ------------------------------ */
.btn { background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: 6px 14px; color: var(--ink); }
.btn:hover { background: var(--sunken); }
.btn.primary { background: var(--ink); color: var(--ink-on); }
.btn.primary:hover { background: #cfccc3; }
.btn:disabled { opacity: .4; cursor: default; }
.btn.small { padding: 3px 10px; font-size: 12px; border-radius: 5px; }
.btn.danger { border-style: dashed; }
.pill { display: inline-block; background: var(--ink); color: var(--ink-on); border-radius: 999px; padding: 1px 10px; font-size: 12px; font-weight: 600; }
/* «подтвердите почту» в шапке: заметно, но не спорит с балансом и ником.
   На узких экранах прячем — подтверждение доступно из аккаунта и диалогом. */
.mail-pill { border: 1px solid var(--line); background: transparent; color: var(--ink); font-weight: 600; }
.pill.ok { background: transparent; color: var(--ink); border: 1px solid currentColor; }
.pill.warn { background: transparent; color: var(--ink); border: 1px dashed currentColor; }
.mail-pill:hover { border-color: var(--ink); }
/* на узких экранах от плашки остаётся только конверт — иначе шапка не влезает */
@media (max-width: 700px) { .mail-pill .mp-t { display: none; } .mail-pill { padding: 1px 7px; } }
/* итог перехода по ссылке из письма (подтверждение / отписка) */
.mail-flash {
  position: fixed; left: 50%; top: calc(var(--topbar-h, 56px) + 14px); transform: translateX(-50%);
  z-index: 420; max-width: min(92vw, 460px); padding: 10px 16px; border-radius: 10px;
  background: var(--ink); color: var(--ink-on); font-size: 13px; line-height: 1.45;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35); text-align: center;
}
.mail-flash.bad { background: #7c1d1d; color: #fff; }
.row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dim { color: var(--ink-dim); }
.empty { color: var(--ink-faint); font-style: italic; padding: 14px; text-align: center; border: 1px dashed var(--line-strong); border-radius: 8px; }
.err { border: 2px solid var(--line-strong); border-radius: 6px; padding: 8px 10px; font-weight: 700; background: var(--card); }
.err::before { content: "! "; }
.ok-line { border: 1px solid var(--line); border-radius: 6px; padding: 8px 10px; }

/* -------------------------------- списки ------------------------------- */
.list { display: flex; flex-direction: column; gap: 6px; }
.item { text-align: left; width: 100%; background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: 8px 10px; color: inherit; }
.item:hover { background: var(--hover); }
.item.on { background: var(--ink); color: var(--ink-on); }
.item .t { font-weight: 600; }
.item .s { font-size: 12px; opacity: .75; margin-top: 2px; }
/* тег мира игры (снизу карточки): свой устав, свои ходы — чужой мир не течёт */
.item .gworld {
  display: inline-block; margin-top: 6px; font-size: 11px; line-height: 1.3;
  border: 1px solid var(--line); border-radius: 999px; padding: 1px 8px; background: var(--hover);
}
.item .desc { font-size: 12px; margin-top: 4px; line-height: 1.4; }

/* -------------------------------- переписка ----------------------------
   Современный мессенджер-вид: мягкий радиус нитки, светлый фон ленты,
   воздушные отступы; пузыри и стороны описаны в секции «комнаты и ЛС». */
/* высота с потолком: 420px на десктопе как раньше, но на невысоких экранах
   (телефон в альбоме ~375px) нитка выше экрана → двойная прокрутка */
.thread { display: flex; flex-direction: column; height: min(420px, calc(100dvh - 150px)); border: 1px solid var(--line); border-radius: 16px; overflow: hidden; background: var(--card); }
.thread-head { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--card-2); background: var(--card); }
.msgs { flex: 1; overflow: auto; padding: 16px 18px 10px; display: flex; flex-direction: column; gap: 12px; background: var(--sunken); }
/* разворот старой истории: кнопка над окном последних 30 сообщений */
.hist-more { display: flex; justify-content: center; padding: 2px 0 4px; }
.hist-more .chip { border: 1px dashed var(--line-strong); background: rgba(255,255,255,.85); font-size: 11px; padding: 8px 16px; opacity: .9; border-radius: 999px; }
.hist-more .chip:hover { background: var(--card); opacity: 1; border-color: var(--line-strong); }
/* .thread{overflow:hidden} — без этого ЛС не листается мышью, только скроллом кода */
#dmMsgs { overflow-y: auto; }
/* white-space:pre-wrap нужен только тексту реплики (.msg .text) — на всём
   .msg он превращает переносы строк ВНУТРИ разметки в пустые строки */
.msg { display: flex; gap: 10px; max-width: 85%; word-break: break-word; align-items: flex-start; }
.msg.user { align-self: flex-end; }
.msg.char { align-self: flex-start; }
.composer { display: flex; gap: 8px; padding: 8px; border-top: 1px solid var(--line); background: var(--hover); }
.composer input[type="text"] { flex: 1; }
.composer select { max-width: 190px; }
/* тонкий скролл в ленте чата */
.msgs::-webkit-scrollbar { width: 10px; }
.msgs::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 8px; border: 3px solid var(--sunken); background-clip: content-box; }
.msgs::-webkit-scrollbar-thumb:hover { background-color: #bdbdbd; }

/* --------------------------------- формы ------------------------------- */
.field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; }
.field span { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-dim); }
input[type="text"], input[type="password"], input[type="email"] {
  border: 1px solid var(--line); border-radius: 6px; padding: 7px 9px; background: var(--card); outline: none; width: 100%;
}
input:focus { box-shadow: inset 0 0 0 1px var(--line-strong); }
select { border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px; background: var(--card); }

/* ------------------------ экран ожидания ------------------------------ */
/* Пока app.js не отрисовал первый экран, вместо голого «загрузка…» — знак
   и тонкая полоса. Ничего не грузит по сети: инлайн-SVG + CSS-анимация. */
.boot {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px; padding: 24px;
  background:
    radial-gradient(900px 500px at 50% 0%, rgba(233, 33, 61, .20), transparent 62%),
    radial-gradient(700px 420px at 85% 110%, rgba(253, 181, 21, .10), transparent 55%),
    linear-gradient(180deg, var(--bg), var(--bg-deep));
  color: var(--ink);
}
.boot-mark { width: min(132px, 38vw); color: var(--ink); animation: boot-pulse 2.4s ease-in-out infinite; }
.boot-mark svg { width: 100%; height: auto; aspect-ratio: 544 / 512; display: block; filter: drop-shadow(0 0 18px rgba(233, 33, 61, .35)); }
.boot-name { font-size: 15px; letter-spacing: .22em; text-transform: lowercase; color: var(--ink-dim); }
.boot-name span { color: var(--hot-ink); }
.boot-line { width: min(196px, 54vw); height: 2px; border-radius: 2px; background: rgba(255, 255, 255, .10); overflow: hidden; }
.boot-line i { display: block; width: 40%; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--hot), var(--acc)); animation: boot-sweep 1.5s cubic-bezier(.4, 0, .2, 1) infinite; }
@keyframes boot-sweep { from { transform: translateX(-100%); } to { transform: translateX(250%); } }
@keyframes boot-pulse { 0%, 100% { opacity: .75; transform: scale(.985); } 50% { opacity: 1; transform: scale(1); } }
@media (prefers-reduced-motion: reduce) {
  .boot-mark, .boot-line i { animation: none; }
  .boot-mark { opacity: 1; }
  .boot-line i { width: 55%; opacity: .85; }
}
/* без JavaScript сайт не оживёт — говорим об этом текстом, а не пустым экраном */
.boot-noscript {
  position: fixed; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: 24px; text-align: center; color: var(--ink-dim); font-size: 15px; line-height: 1.5;
  background: linear-gradient(180deg, var(--bg), var(--bg-deep));
}

/* --------------------------- экран входа ------------------------------ */
.login-screen { position: fixed; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; background: var(--card); z-index: 50; padding: 24px 16px 0; overflow: auto; }
.login-wrap { width: 344px; max-width: 100%; }
.auth-logo { display: flex; justify-content: center; margin-bottom: 10px; color: var(--ink); }
/* лого инлайн-SVG (currentColor), компактное — не шире карточки */
.auth-logo svg { width: min(148px, 42vw); height: auto; aspect-ratio: 544 / 512; display: block; }
/* вкладки как в папке: активная сливается с формой, неактивная уходит назад */
.auth-tabs { display: flex; gap: 4px; padding-left: 10px; align-items: flex-end; }
.auth-tab {
  border: 1px solid var(--line); border-bottom: none; border-radius: 8px 8px 0 0;
  background: var(--hover); color: var(--ink-faint); padding: 7px 16px 8px; font-size: 13px;
  transform: translateY(-2px); transition: background .15s, color .15s, transform .15s;
}
.auth-tab:not(.on):hover { background: var(--card-2); color: var(--ink); }
.auth-tab.on {
  background: var(--card); color: var(--ink); font-weight: 700;
  transform: translateY(0); position: relative; z-index: 2;
  margin-bottom: -1px;   /* наезд на линию карточки: полоса обрывается у активной */
}
.login-card { width: 100%; max-width: 100%; border: 1px solid var(--line); border-radius: 0 8px 8px 8px; padding: 20px 24px 18px; background: var(--card); display: flex; flex-direction: column; gap: 10px; }
/* галки согласий: квадрат и текст В ОДНУ строку, текст обычным регистром
   (у .field span он был капсом — длинное согласие читалось плохо) */
.field.ck { flex-direction: row; align-items: flex-start; gap: 8px; margin-bottom: 6px; }
.field.ck input[type="checkbox"] { margin: 2px 0 0; flex: none; }
.field.ck span { font-size: 13px; text-transform: none; letter-spacing: 0; color: var(--ink); line-height: 1.35; }
.auth-foot { border-top: 1px solid var(--card-2); margin-top: 6px; padding-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.auth-foot .legal { font-size: 11px; line-height: 1.45; color: var(--ink-faint); }
.auth-foot .legal a { color: var(--link); text-decoration: underline; text-underline-offset: 3px; }
.auth-foot .auth-publinks { text-align: center; font-size: 12.5px; color: var(--ink-dim); }
.auth-foot .auth-publinks a { color: var(--link); font-weight: 600; display: inline-block; padding: 11px 6px; }
.auth-contacts { display: flex; align-items: center; gap: 10px; font-size: 12px; color: var(--ink-dim); flex-wrap: wrap; }
.auth-contacts a { color: var(--link); text-decoration: underline; text-underline-offset: 3px; }
.vk-grp { display: inline-flex; }
.vk-grp svg { display: block; }
/* подвал страницы входа: правовой текст и контакты — в потоке, прижат к низу
   (margin-top:auto); НЕ fixed — на телефоне fixed-футер перекрывал кнопки */
.login-foot {
  margin-top: auto; width: 100%; flex: none;
  padding: 10px 16px 14px;
  background: var(--card); border-top: 1px solid var(--card-2);
}
.login-foot .auth-foot { border-top: 0; margin-top: 0; align-items: center; }
.login-foot .auth-contacts { justify-content: center; }
.login-foot .legal { text-align: center; }
.vk-cap { color: var(--ink-dim); }
/* телефонный футер игры: слева «игра», по центру плашка, справа «пати» */
.ghf-t { border: 1px solid var(--line); background: var(--card); border-radius: 999px; padding: 4px 12px; font-size: 12px; cursor: pointer; flex: none; }
.ghf-t.on { background: var(--ink); color: var(--ink-on); font-weight: 600; }
.ghf-mid { flex: 1; min-width: 0; text-align: center; }
/* телефон: пати-режим вместо чата игры */
.m-party { flex: 1; min-height: 0; overflow-y: auto; background: var(--card); padding: 10px; }
.m-party[hidden] { display: none; }
.center { text-align: center; }

/* модалки confirmDlg/promptDlg/alertDlg — вместо отключённого prompt() */
/* Модалка обязана влезать в экран: раньше у карточки не было max-height, и
   длинный диалог («Сборка персонажа» с десятком параметров) вырастал выше
   окна — нижние строки и кнопки становились недостижимы, прокрутки не было.
   Теперь карточка ограничена вьюпортом, заголовок и кнопки стоят на месте,
   а середина (.dlg-body) прокручивается. dvh — чтобы на телефоне не мешала
   адресная строка. */
.dlg-mask {
  position: fixed; inset: 0; z-index: 250; background: rgba(17, 17, 17, .38);
  display: flex; align-items: center; justify-content: center; padding: 16px;
  overflow-y: auto; overscroll-behavior: contain;
}
.dlg-card {
  width: 420px; max-width: 100%; background: var(--card); border: 1px solid var(--line);
  border-radius: 10px; padding: 16px; box-shadow: 0 14px 44px rgba(0, 0, 0, .3);
  display: flex; flex-direction: column; gap: 12px;
  max-height: calc(100vh - 32px); max-height: calc(100dvh - 32px);
  overflow: hidden;
}
/* карточка без прокручиваемого тела (простой вопрос/ввод) — скроллим целиком */
.dlg-card:not(:has(.dlg-body)) { overflow-y: auto; }
.dlg-title { font-size: 14px; line-height: 1.45; font-weight: 600; word-break: break-word; flex: none; }
.dlg-titlerow { display: flex; align-items: flex-start; gap: 8px; flex: none; }
.dlg-titlerow .dlg-title { flex: 1; min-width: 0; }
.dlg-titlerow .mini { flex: none; font-size: 14px; padding: 0 6px; line-height: 1.6; }
.dlg-body {
  min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  /* запас справа, чтобы скроллбар не наезжал на кнопки «+»/«−» */
  padding-right: 2px;
}
.dlg-body input.dlg-inp {
  width: 100%; border: 1px solid var(--line); border-radius: 6px; padding: 8px 10px; font: inherit;
}
.dlg-btns { display: flex; gap: 8px; justify-content: flex-end; flex: none; }
/* совсем узкий экран: отступы меньше — карточке достаётся больше высоты */
@media (max-width: 700px) {
  .dlg-mask { padding: 8px; }
  .dlg-card { max-height: calc(100vh - 16px); max-height: calc(100dvh - 16px); padding: 12px; gap: 8px; }
}

/* =============== покупки · статистика · дашборд игры =============== */
.clickable { cursor: pointer; }
.clickable:hover { text-decoration: underline; }
.ok { border: 1px solid var(--line); border-radius: 6px; padding: 6px 10px; font-weight: 600; }
.err-slot { font-size: 12px; }
.err-slot:empty { display: none; }
.typing { min-height: 16px; padding: 0 10px; margin: 4px 0 0; font-size: 12px; opacity: 0.8; font-style: italic; }
.typing[hidden] { display: none; }

/* покупки */
.pk-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; margin-top: 10px; }
/* баннер «привяжите ВК» над сеткой тарифов: акцентная плашка, не кричит */
.pk-banner {
  margin-top: 10px; padding: 12px 14px; border-radius: 8px; line-height: 1.5;
  border: 1px solid var(--line); background: var(--sunken);
}
.pk-trial { font-size: 12px; color: var(--ink-dim); }
.pk.cur .pk-trial { color: color-mix(in srgb, var(--ink-on) 72%, var(--ink)); }
.pk { border: 1px solid var(--line); border-radius: 8px; padding: 14px; display: flex; flex-direction: column; gap: 6px; }
.pk .v { font-size: 26px; font-weight: 800; }
.pk .p { font-size: 13px; color: var(--ink-dim); }
.pk.cur { background: var(--ink); color: var(--ink-on); }
/* приглушённый текст на залитой карточке: мешаем --ink-on с фоном (--ink),
   а не var(--line) — тот белый «на чёрном», а фон в тёмной теме СВЕТЛЫЙ (--ink)
   → белый по белому. color-mix адаптируется обеим темам. */
.pk.cur .p, .pk.cur .dim, .pk.cur .pk-sub { color: color-mix(in srgb, var(--ink-on) 72%, var(--ink)); }
/* фичи тарифа — чтобы сетки сравнивались глазами (витрина like likoteka) */
.pk-feat { list-style: none; margin: 2px 0 6px; padding: 0; font-size: 13px; color: var(--ink-dim); line-height: 1.55; }
.pk-feat li::before { content: "✓ "; font-weight: 700; color: var(--ink); }
.pk.cur .pk-feat { color: color-mix(in srgb, var(--ink-on) 78%, var(--ink)); }
.pk.cur .pk-feat li::before { color: var(--ink-on); }

/* статистика */
.banner { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; border: 2px dashed var(--line-strong); border-radius: 8px; padding: 12px 14px; font-weight: 600; background: var(--hover); }
.chart-wrap { border: 1px solid var(--line); border-radius: 8px; padding: 12px; margin-top: 12px; overflow-x: auto; }
.chart-wrap h5 { margin: 0 0 8px; font-size: 13px; text-transform: uppercase; letter-spacing: .05em; }
.chart svg { display: block; }
.chart .grid { stroke: var(--line); }
.chart .bar { fill: var(--ink); }
.chart .lbl { font-size: 10px; fill: var(--ink-dim); }
.chart .limit { stroke: var(--ink-dim); stroke-dasharray: 7 5; stroke-width: 1.5; fill: none; }
.chart .limit-lbl { font-size: 10px; fill: var(--ink); font-weight: 700; }

/* дашборд: сетка и панели */
.thread > .game-grid { flex: 1; min-height: 0; }
.game-grid { display: flex; }
.dash-left { width: 260px; min-width: 140px; border-right: 1px solid var(--line); display: flex; flex-direction: column; background: var(--sunken); }
.dash-tabs { display: flex; gap: 2px; padding: 6px 6px 0; border-bottom: 1px solid var(--line); overflow-x: auto; }
.dash-tabs button { background: transparent; border: 1px solid transparent; border-bottom: 0; padding: 4px 7px; font-size: 11px; color: var(--ink-dim); white-space: nowrap; }
.dash-tabs button.on { background: var(--card); border-color: var(--line-strong); border-radius: 5px 5px 0 0; color: var(--ink); font-weight: 700; }
.dash-body { flex: 1; overflow: auto; padding: 8px; font-size: 12px; }
.dash-head { display: flex; gap: 4px; align-items: center; margin-bottom: 6px; }
.dash-person { margin-bottom: 8px; border: 1px solid var(--line); border-radius: 6px; padding: 6px; background: var(--card); }
.dash-person b { display: block; font-size: 12px; }
.dash-person .cls { font-size: 10px; color: var(--ink-dim); text-transform: uppercase; letter-spacing: .05em; }
.dash-row { display: flex; align-items: center; gap: 6px; margin-top: 3px; }
.dash-row .k { width: 74px; color: var(--ink-dim); font-size: 11px; }
.dash-row .v { font-weight: 700; font-size: 11px; min-width: 26px; text-align: right; }
.dash-row .bar { position: relative; flex: 1; height: 6px; background: var(--card-2); border: 1px solid var(--line); border-radius: 3px; }
.dash-row .bar i { position: absolute; top: 0; bottom: 0; background: var(--ink); border-radius: 2px; }
.divider { width: 5px; cursor: col-resize; background: var(--card-2); border-left: 1px solid var(--line); }
.divider:hover { background: var(--ink); }
.dash-right { width: 240px; min-width: 160px; border-left: 1px solid var(--line); overflow: auto; padding: 8px; background: var(--sunken); font-size: 12px; }
.dash-right h5 { margin: 0 0 6px; font-size: 11px; text-transform: uppercase; letter-spacing: .05em; }

/* дельты «что изменило» — цвет характеристики, ВЕРХНИЙ РЕГИСТР.
   Контраст по WCAG AA (≥4.5:1 на белом): дельты набираются 11px bold и лежат
   на белом пузыре — Lighthouse красил четыре цвета (3.84, 3.73, 3.44, 2.48).
   Оригиналы оставляю в -orig на случай тёмной темы (там нужны светлые). */
:root {
  --st-trust: #28803a; --st-comfort: #1971c2; --st-attraction: #cf2a5e;
  --st-respect: #b45309; --st-affection: #7048e8;
  --st-excitement: #d92d20; --st-arousal: #ae3ec9;
  --st-trust-orig: #2f9e44; --st-attraction-orig: #e64980;
  --st-respect-orig: #f08c00; --st-excitement-orig: #f03e3e;
  /* Светлый набор для ТЁМНЫХ поверхностей (дашборд, графики, точки):
     ≥6:1 на --card. Тёмные выше — только для белых стикеров .delta. */
  --st-trust-d: #4ade80; --st-comfort-d: #60a5fa; --st-attraction-d: #f472b6;
  --st-respect-d: #fbbf24; --st-affection-d: #a78bfa;
  --st-excitement-d: #f87171; --st-arousal-d: #e879f9;
}
.deltas { display: flex; flex-wrap: wrap; gap: 4px; margin: 3px 0; }
.delta {
  background: #fff; font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em;
  color: var(--c, var(--ink));
  border: 1px solid var(--c, var(--ink)); border-left-width: 4px; border-radius: 4px;
  padding: 1px 6px; background: var(--card);
}

/* сообщения с аватаром (как в соцсетях) */
.msg { align-items: flex-start; }
.msg .mb { min-width: 0; flex: 1; }
.msg .text { white-space: pre-wrap; word-break: break-word; }
/* аватарки (фото/буква человека) — ВСЕГДА круглые: и40px база, и56px превью */
.mavatar { width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--line); object-fit: cover; cursor: zoom-in; flex: none; }
.mavatar-ph { width: 40px; height: 40px; border-radius: 50%; border: 1px dashed #999; flex: none; display: inline-block; }
.mavatar-ph.big { width: 56px; height: 56px; }
.avatar-preview { width: 56px; height: 56px; border-radius: 50%; border: 1px solid var(--line); object-fit: cover; }
.game-main { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; }
.game-main .msgs { background: transparent; gap: 14px; }

/* игровой чат: карточка с картинкой висит НАД своим сообщением, слегка
   заходя на него (~14px), и уходит вверх в зазор между репликами —
   у персонажа слева, у юзера справа. САМИ СООБЩЕНИЯ ОДНОЙ ШИРИНЫ — во всю
   колонку чата (.msgs), которая сама меняется, когда двигаешь панели.
   Зазор (150px) + низ сообщения (40px) дают карточке место, чтобы не
   закрыть текст предыдущей реплики. */
.game-main .msgs { gap: 150px; padding-top: 200px; }
/* Реплики: персонаж слева, юзер справа; каждая занимает 68% колонки чата
   (не доезжает до противоположной стороны) и выровнена по своей стороне. */
.game-main .msg {
  position: relative; display: block;
  /* px-потолок: на широком десктопе 68% колонки = строка 1500px нечитаемо */
  width: min(68%, 760px); max-width: min(68%, 760px);
  padding: 16px 10px 40px; border: 1px solid var(--line); background: var(--card);
}
.game-main .msg.char { align-self: flex-start; text-align: left; }
.game-main .msg.user { align-self: flex-end; text-align: right; background: var(--hover); }
.game-main .msg.user .deltas { justify-content: flex-end; }
.game-main .mcard {
  position: absolute; bottom: calc(100% - 14px);
  width: 176px; z-index: 2;
  background: var(--card-2); border: 1px solid var(--line); overflow: hidden;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
}
.game-main .msg.char .mcard { left: 10px; }
.game-main .msg.user .mcard { right: 10px; }
.game-main .mportrait {
  display: block; width: 100%; height: 168px;
  object-fit: cover; cursor: zoom-in;
}
.game-main .mportrait-ph {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 168px; font-size: 44px; font-weight: 800; color: #b9b9b9; cursor: default;
}
/* ── Рамка (frame-avatar.png по умолчанию; в админке можно загрузить свою) ──
   Бокс меряем по прозрачному проёму самой рамки (--pw-*), а её прозрачные
   поля обрезаем масштабом --frame-bg — бордюр заполняет бокс, картинка
   крупнее (проём 49% бокса → 62%), «пустых» полей не остаётся. Значения ниже —
   для кадра 300×300 (проём 76/62/148/176, поля L/R 10%, T 3.33%, B 4.33%);
   JS переопределяет их под любую загруженную в админке рамку. Картинка чуть
   шире проёма (×1.05): край уходит под бордюр на 2,5% с каждой стороны —
   зазора между рамкой и картинкой не будет. */
:root {
  --frame-img: url("frame-avatar.png");
  --frame-bg: 125% 108.3%;
  --pw-x: 19.16%; --pw-y: 18.78%;
  --pw-w: 61.66%; --pw-h: 63.54%;
}
/* ── Рамка портрета/сцены: border-image 9-slice ПО КРАЮ бокса (как у
   картинных рамок ниже). Арт нарезается на углы+полосы: углы идут без
   искажений, толщина бордюра одинакова со всех сторон — на квадрате и на
   16:9 одинаково. Картинка занимает весь бокс, край прячется под бордюр.
   Раньше здесь фон --frame-bg натягивался 125%/108% — границы растягивало. */
.game-main .mfr { position: relative; display: block; width: 100%; height: 168px; }
.game-main .mfr .mportrait,
.game-main .mfr .mportrait-ph {
  position: absolute; inset: 0; width: 100%; height: 100%;
}
.game-main .mfr .mportrait-ph { font-size: 30px; }
.game-main .mfr::before {
  content: ""; position: absolute; inset: 0; z-index: 1;
  border: var(--fr-w, 6px) solid transparent;
  border-image-source: var(--frame-img);
  border-image-slice: var(--fr-slice, 14);
  border-image-repeat: stretch;
  pointer-events: none;
}
/* ── Рамка сцены/события в сообщении (та же техника) ──
   бокс — во всю ширину страницы, 4:3 (чтобы не выситься колонкой); сцена
   ложится cover на весь бокс, край уходит под бордюр без зазора */
.game-main .sfr {
  position: relative; display: block;
  width: 100%; aspect-ratio: 4 / 3; margin: 10px 0;
}
.game-main .sfr .msg-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; border: 0; border-radius: 0;
  max-width: none; margin: 0;
}
.game-main .sfr::before {
  content: ""; position: absolute; inset: 0; z-index: 1;
  border: var(--fr-w, 8px) solid transparent;
  border-image-source: var(--frame-img);
  border-image-slice: var(--fr-slice, 14);
  border-image-repeat: stretch;
  pointer-events: none;
}
/* угловая рамка (лоза) на сцене/портрете: квадратные углы по краям */
body.fr-corner .game-main .mfr::before, body.fr-corner .game-main .sfr::before {
  border: none;
  background-image: var(--fr-tl), var(--fr-br);
  background-repeat: no-repeat, no-repeat;
  background-position: left top, right bottom;
  background-size: var(--fr-cs, 96px) var(--fr-cs, 96px);
}
/* сообщение со сценой — во всю ширину страницы (обычные остаются 92%/68%) */
.game-main .msg:has(.sfr) { width: 100%; max-width: 100%; }
@media (max-width: 700px) {
  /* на телефоне сцена держит те же боковые отступы, что и остальные
     объекты чата — иначе широкая картинка «вылезала за рамки» соседей */
  .game-main .msg:has(.sfr) { width: calc(100% - 20px); margin-left: 10px; margin-right: 10px; }
}
/* имя — большими буквами ПОД картинкой, той же стороной */
.game-main .mname {
  padding: 5px 8px; background: var(--card); border-top: 1px solid var(--line);
  font-size: 14px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  text-align: left; line-height: 1.2;
}
.game-main .msg.user .mname { background: var(--hover); text-align: right; }
.game-main .msg .mb { min-width: 0; }
.game-main .msg .who { margin-bottom: 4px; }

@media (max-width: 700px) {
  .game-main .msgs { gap: 110px; padding-top: 160px; }
  .game-main .msg { width: 92%; max-width: 92%; padding-bottom: 30px; }
  .game-main .mcard { width: 132px; }
  .game-main .mfr { height: 128px; }
  .game-main .mportrait-ph { font-size: 24px; }
  .game-main .mname { font-size: 12px; }
}

/* аватар на весь экран: z-index выше ВСЕХ окон и кнопки «баг» (260) —
   иначе из «Друзей» картинка открывалась ПОД окном друзей и её не было видно */
#fs { position: fixed; inset: 0; background: rgba(10, 10, 13, .96); z-index: 400; display: flex; align-items: center; justify-content: center; cursor: zoom-out; }
#fs::after {
  content: "нажмите или Esc, чтобы закрыть";
  position: absolute; left: 50%; bottom: 24px; transform: translateX(-50%);
  font-size: 12px; color: var(--ink-dim); background: var(--card); border: 1px solid var(--line);
  border-radius: 999px; padding: 4px 12px;
}
#fs img { max-width: 96vw; max-height: 90vh; object-fit: contain; }

/* шапка игры: день/ночь, место, погода */
.gh-chip { display: inline-block; border: 1px solid var(--line); border-radius: 999px; padding: 1px 9px; font-size: 11px; background: var(--card); white-space: nowrap; /* сцена бывает длинной («День 1 · ночь · 📍 улица у ломбарда…»): nowrap без потолка распирал min-content grid-трека и ВЕСЬ экран игры уезжал вправо на телефоне (515px в 382px) */ max-width: 100%; overflow: hidden; text-overflow: ellipsis; vertical-align: bottom; }
.gh-scene { color: var(--ink-dim); font-size: 11px; font-style: italic; }

/* настройки игры (⚙) и картинка/фон при создании */
.game-cfg { display: flex; gap: 6px; padding: 8px; background: var(--hover); border-bottom: 1px dashed var(--line-strong); }
/* настройки игры — колонка: картинка/фон, описание для роутера, выбор роутера */
.game-cfg { flex-direction: column; align-items: stretch; }
.game-cfg .cfg-line { display: flex; gap: 6px; }
.game-cfg .cfg-line input { flex: 1; width: auto; }
.game-cfg textarea, .game-cfg select {
  width: 100%; border: 1px solid var(--line); border-radius: 6px; padding: 7px 9px;
  background: var(--card); font: inherit;
}
.game-cfg textarea { resize: vertical; }
.game-cfg .f { margin-top: 4px; }

/* подсказка роутера над полем ввода */
.route-hint {
  padding: 5px 10px; font-size: 12px; color: var(--ink);
  background: var(--sunken); border-top: 1px dashed #999;
}
.route-hint[hidden] { display: none; }
/* display:flex из .game-cfg/.row перебивает атрибут hidden из коробки —
   без этих двух правок поля «картинка/фон» видны всегда, а кнопка-шестерёнка
   ничего не скрывает. */
.game-cfg[hidden] { display: none; }
.row[hidden] { display: none; }
.game-cfg input, .row.card-cfg input { flex: 1; }
.row.card-cfg { margin-top: 6px; }
.row.card-cfg[hidden] { display: none; }
.btn.small { padding: 2px 8px; font-size: 12px; }

/* ловушка ошибок страницы */
.wm-err {
  position: fixed; left: 10px; right: 10px; bottom: 10px; z-index: 300;
  background: var(--ink); color: var(--ink-on); border: 2px solid var(--line-strong); border-radius: 6px;
  padding: 8px 12px; font: 12px/1.5 ui-monospace, monospace; word-break: break-word;
}

/* растяжение игры на экран: чат занимает всё окно, панели скроллятся сами */
#threadSlot { display: flex; flex-direction: column; height: auto; min-height: 0; }
#threadSlot > .thread { height: auto; flex: 1; min-height: 0; }
#threadSlot .game-grid { flex: 1; min-height: 0; }
#threadSlot .game-main { min-width: 0; display: flex; flex-direction: column; min-height: 0; }
#threadSlot .game-main .msgs { flex: 1; min-height: 0; overflow-y: auto; }
/* ТЕЛЕФОН (≤860px): .grid2 получил height:auto, из-за чего игра росла по
   содержимому (замер: threadSlot 1673px при панели 907px) — вся сцена вместе
   с композером скроллилась страницей, композер уезжал вниз длинного скролла.
   Возвращаем игре высоту панели: лента скроллится ВНУТРИ, композер липит внизу
   под пальцем. Дашборд при этом сворачивается за «▼ дашборд». */
@media (max-width: 860px) {
  /* Раньше здесь стояло calc(100dvh - 150px) — догадка «шапка + бар в две
     строки». Ширина меняется, и догадка врёт: на широком телефоне/окне бар в
     ОДИН ряд, игра выходила короче доступного места, снизу оставалась пустая
     полоса (юзер: «снизу отступ большой»).

     Теперь высота НЕ считается, а берётся из раскладки. Проценты внутри
     скроллящейся .pane не резолвятся (проверено: height:100% дал высоту по
     содержимому), поэтому включаем flex на самой панели: .grid2 — flex-элемент
     с flex:1, его единственный grid-ряд растягивается (align-content: stretch),
     #threadSlot получает ровно остаток, .thread — flex:1 внутри него. */
  .pane:has(#threadSlot) { display: flex; flex-direction: column; }
  .pane:has(#threadSlot) > .grid2 { flex: 1 1 auto; min-height: 0; }
  #threadSlot { height: auto; min-height: 0; }
}
.dash-left { overflow: hidden; }
/* свёрнутые панели остаются у краёв тонкими полосками с кнопкой-стрелкой */
.dash-left.collapsed, .dash-right.collapsed {
  display: flex; flex-direction: column; padding: 0; overflow: hidden;
}
.dash-left.collapsed { width: 26px !important; min-width: 0; border-right: 1px solid var(--line); }
.dash-right.collapsed { width: 26px !important; min-width: 0; border-left: 1px solid var(--line); }
.dash-left.collapsed .dash-head, .dash-left.collapsed .dash-tabs, .dash-left.collapsed .dash-body,
.dash-right.collapsed .dash-head, .dash-right.collapsed .dash-body { display: none; }

/* правая панель: параметры персонажа (trust/comfort/... и pulse) */
.st-row { display: flex; align-items: center; gap: 6px; margin-top: 5px; }
.st-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; border: 1px solid rgba(255, 255, 255, .25); }
.st-k { flex: 1; min-width: 0; color: var(--ink); font-size: 11px; }
.st-bar { position: relative; flex: 1.1; height: 7px; background: var(--card-2); border: 1px solid var(--line); border-radius: 4px; }
.st-bar i { position: absolute; top: 0; bottom: 0; background: var(--ink); border-radius: 3px; }
.st-v { min-width: 24px; text-align: right; font-weight: 700; font-size: 11px; }
.st-note { font-size: 11px; line-height: 1.45; margin-top: 5px; color: var(--ink-dim); }
.st-note b { color: var(--ink); }
.pulse { font-size: 11px; color: var(--ink); }

/* «пентагон с кругом»: круг = ноль, пять точек = показатели */
.penta-wrap { display: flex; justify-content: center; margin: 6px 0 4px; }
.penta { overflow: visible; }

/* свёрнутая правая панель остаётся полоской у края */
.edge-btn {
  width: 100%; min-height: 46px; flex: 1; background: var(--sunken); border: 0;
  border-radius: 0; cursor: pointer; font-size: 15px; color: var(--ink);
  display: flex; align-items: center; justify-content: center; padding: 8px 0;
}
.edge-btn:hover { background: var(--ink); color: var(--ink-on); }
/* единообразие панелей (ПК): свёртывание — та же рейка-кнопка по БОКУ
   панели, что и разворачивание; контент отступает под неё */
.dash-left, .dash-right { position: relative; }
.edge-btn.rail {
  position: absolute; top: 0; bottom: 0; width: 26px; min-height: 0;
  flex: none; z-index: 6; padding: 0;
}
.dash-left .edge-btn.rail { left: 0; border-right: 1px solid var(--line); }
.dash-right .edge-btn.rail { right: 0; border-left: 1px solid var(--line); }
@media (min-width: 701px) {
  .dash-left:not(.collapsed) .dash-tabs,
  .dash-left:not(.collapsed) .dash-body { margin-left: 26px; }
  .dash-right:not(.collapsed) .dash-head,
  .dash-right:not(.collapsed) .dash-body { margin-right: 26px; }
}

/* строки «истории изменений» в левой панели */
.delta-line { border-left: 3px solid var(--c, var(--ink)); padding-left: 7px; margin: 4px 0; color: var(--c, var(--ink)); }


/* ================= шапка: аватар, выпадашка, ЛС ================= */
.hbtn {
  position: relative; background: var(--card); border: 1px solid var(--line); border-radius: 6px;
  padding: 3px 9px; font-size: 16px; cursor: pointer; line-height: 1.2;
}
.hbtn:hover { background: var(--ink); color: var(--ink-on); }
/* кнопка «баг» — фиксированно под шапкой справа: видна всегда, в том числе
   поверх открытых окон (z-index выше .overlay = 200) */
.bug-fab {
  position: fixed; right: 12px; top: calc(var(--topbar-h, 88px) + 10px);
  z-index: 260; width: 34px; height: 34px; padding: 0;
  border-radius: 50%; box-shadow: 0 4px 14px rgba(0, 0, 0, .28);
  background: var(--card); border: 1px solid var(--line);
}
.bug-fab:hover { background: var(--ink); color: var(--ink-on); }
/* иконпак: эмодзи, заменённый картинкой из админки (см. applyIcons в app.js).
   Размер — со строчный текст, чтобы иконка не раздувала кнопку и строку
   списка (натуральный размер PNG/SVG был бы 100–500 px). */
img.ico {
  width: 1.15em; height: 1.15em; object-fit: contain;
  vertical-align: -0.2em; display: inline-block;
  max-width: 1.6em; max-height: 1.6em;
  pointer-events: none;
}
button img.ico, a img.ico { pointer-events: none; }
/* в круглой плавающей кнопке «баг» иконка крупнее текста */
.bug-fab img.ico { width: 1.25em; height: 1.25em; }
/* ссылка на группу ВК — слева от «✉» в шапке; читается как кнопка, но ведёт наружу */
.vk-grp {
  display: inline-flex; align-items: center; justify-content: center;
  text-decoration: none; font-size: 12px; font-weight: 700; letter-spacing: .5px;
  min-width: 34px; height: 30px;
}
/* на телефоне шапка вплотную к панели: под шапкой кнопка перекрыла бы
   заголовок комнат и «ЛС», поэтому там она уходит вниз — над нижним
   таббаром (две строки по 40px + отступ). Окна (z-index 200+) она всё
   равно перекрывает. */
@media (max-width: 700px) {
  .bug-fab {
    top: auto;
    bottom: calc(96px + env(safe-area-inset-bottom, 0px) + 8px);
    right: 10px;
    width: 40px; height: 40px;
  }
  /* «установить приложение» — только на ПК. На телефоне кнопка в шапке
     лишняя: сайт ставится из меню браузера, а место в шапке дорогое. */
  #pwaBtn { display: none !important; }
}
.dm-badge {
  position: absolute; top: -7px; right: -7px; min-width: 17px; height: 17px;
  background: var(--ink); color: var(--ink-on); border: 2px solid #fff; border-radius: 999px;
  font-size: 10px; font-weight: 700; display: flex; align-items: center; justify-content: center;
  padding: 0 3px;
}
.dm-badge[hidden] { display: none; }
.dm-badge.inline { position: static; display: inline-flex; border-color: var(--line-strong); }
/* непрочитанное, где меня цитируют/ответили — заметнее обычного счётчика */
.dm-badge.mention { background: #e8590c; border-color: #fff; }
.havatar { width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--line); object-fit: cover; }
.havatar-ph {
  width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--line);
  background: var(--ink); color: var(--ink-on); display: flex; align-items: center; justify-content: center;
  font-weight: 700;
}
.havatar-ph[hidden] { display: none; }
.dropdown {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  background: var(--card); border: 2px solid var(--line-strong); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .18); max-height: 78vh; overflow: auto; min-width: 340px;
}
.dropdown[hidden] { display: none; }
.dropdown .card { border: 0; margin: 0; }

/* ==================== каталог: сетка карточек ===================== */
/* auto-fill + minmax: на десктопе колонок столько, сколько влезает (≥240px),
   шире 1400px карточки не растягиваются в бесконечные полосы; узкие
   700–900px получают 2–3 колонки вместо тесных трёх. ≤900px — одна колонка
   (медиазапрос ниже) */
.grid-games {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 10px; margin-top: 8px;   /* stretch: карточки строки — одинаковой высоты */
}
.gcell {
  position: relative; border: 1px solid var(--line); border-radius: 8px; padding: 8px;
  display: flex; flex-direction: column; gap: 6px; background: var(--card);
  cursor: pointer; transition: transform .16s ease, box-shadow .16s ease;
  /* will-change: transform здесь снимали с каждой карточки каталога — это
     поднимало в отдельный композитный слой ВСЮ сетку (десятки-сотни слоёв),
     и прокрутка чем длиннее список, тем тяжелее. Подъём по hover и так
     анимируется без предварительной подсказки. */
}
.gcell:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 28px rgba(0, 0, 0, .16), 0 0 0 1px rgba(17, 17, 17, .25);
}
.gcell:hover .gplay { opacity: 1; transform: translate(-50%, -50%) scale(1); }
.gname { font-weight: 700; line-height: 1.25; padding-right: 34px; }
.gcover {
  position: relative; flex: none; aspect-ratio: 16 / 9; min-height: 120px;
  border: 1px solid var(--line); border-radius: 6px; overflow: hidden;
  background: var(--hover); display: flex; align-items: center; justify-content: center;
}
.gcover img { width: 100%; height: 100%; object-fit: cover; }
/* значок «плей» на ховере — по центру картинки */
.gplay {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%) scale(.8);
  width: 54px; height: 54px; border-radius: 50%;
  background: rgba(17, 17, 17, .72); color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: 20px;
  opacity: 0; transition: opacity .15s ease, transform .15s ease; pointer-events: none;
}
/* «i» в кружочке — правый верхний угол карточки */
.ginfo {
  position: absolute; top: 8px; right: 8px; width: 26px; height: 26px;
  border: 1px solid var(--line); border-radius: 50%; background: var(--card);
  font-size: 13px; font-weight: 800; font-style: italic; cursor: pointer;
  display: flex; align-items: center; justify-content: center; z-index: 3;
}
.ginfo:hover { background: var(--ink); color: var(--ink-on); }
.gph { font-size: 34px; font-weight: 800; color: var(--ink-faint); }
.gtags { position: absolute; left: 6px; right: 6px; bottom: 6px; display: flex; flex-wrap: wrap; gap: 4px; z-index: 2; }
.gt {
  font-size: 10px; border: 1px solid var(--line); border-radius: 999px;
  padding: 1px 7px; color: var(--ink); background: rgba(255, 255, 255, .92); font-weight: 600;
}
/* соцметрики под обложкой карточки (▶ игр / 👥 игроков) — как у likoteka,
   но цифры считает сервер по svc.games */
.gmeta { display: flex; gap: 12px; font-size: 12px; color: var(--ink-dim); }
.gmeta .gm { white-space: nowrap; }
.pager { display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 12px; }

/* поиск + чипы-фильтры над сеткой каталога (главная likoteka) */
.all-tools { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
/* строка поиска: поле + кнопка 🔍 + кнопка «теги» (только пока теги свёрнуты) */
.all-bar { display: flex; gap: 6px; align-items: stretch; }
.all-bar .all-q { flex: 1; min-width: 0; }
.all-btn { flex: none; padding: 9px 13px; }
.all-q {
  width: 100%; padding: 9px 14px; font: inherit; font-size: 14px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--card); color: var(--ink);
}
.all-q::placeholder { color: var(--ink-faint); }
.all-q:focus { outline: 2px solid var(--line-strong); outline-offset: 1px; }
/* фильтр тегов сворачиваемый: по умолчанию скрыт, разворачивается кнопкой «теги» */
.all-chips { display: none; flex-wrap: wrap; gap: 6px; }
.all-tools.tags-open .all-chips { display: flex; }
.all-tools.tags-open .all-tags-btn { display: none; }   /* пока теги открыты — кнопки «теги» нет */
.all-chips .chip { cursor: pointer; }
.all-collapse { border-style: dashed; }                 /* чип «свернуть» — визуально иной */
.all-res { font-size: 12px; min-height: 15px; }

/* ============ ролевая разметка в чате (*действия*, «речь») ============ */
.act { color: var(--ink-dim); }
.speech { font-weight: 600; }

/* спойлер «размышления»: <thinking> модели сворачивается в <details> */
details.thinking {
  border: 1px dashed #9a9a9a; border-radius: 6px; background: var(--hover);
  padding: 5px 9px; margin: 7px 0; font-size: 12px; color: var(--ink-dim);
}
details.thinking summary {
  cursor: pointer; font-weight: 700; font-size: 11px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-dim); user-select: none;
}
details.thinking summary:hover { color: var(--ink); }
details.thinking .th-body {
  white-space: pre-wrap; margin-top: 6px; padding-top: 6px;
  border-top: 1px dotted var(--line-strong); max-height: 40vh; overflow: auto; line-height: 1.45;
}
details.thinking[open] summary { margin-bottom: 2px; }

/* HTML-ответы персонажа (пресет Molfar, внутренний монолог): санитайзер в
   rich.js оборачивает блочную разметку в .rhtml — там white-space:normal
   (переводы строк модели — это переводы строк HTML, pre-wrap не нужен),
   абзацы/цитаты/разделители получают свои отступы. Инлайн-теги без блочных
   остаются в pre-wrap, как весь текст реплики. */
.msg .text .rhtml { white-space: normal; }
.msg .text .rhtml p { margin: .35em 0; }
.msg .text .rhtml p:first-child { margin-top: 0; }
.msg .text .rhtml p:last-child { margin-bottom: 0; }
.msg .text .rhtml blockquote { margin: .4em 0; padding: .1em 0 .1em .7em; border-left: 2px solid var(--line); color: var(--ink-dim); }
.msg .text .rhtml hr { border: 0; border-top: 1px solid var(--line); margin: .7em 0; }
.msg .text .rhtml h1, .msg .text .rhtml h2, .msg .text .rhtml h3,
.msg .text .rhtml h4, .msg .text .rhtml h5, .msg .text .rhtml h6 { font-size: 1.05em; margin: .6em 0 .3em; }
.msg .text .rhtml ul, .msg .text .rhtml ol { margin: .35em 0; padding-left: 1.5em; }
.msg .text .rhtml li { margin: .1em 0; }
.msg .text .rhtml pre { background: var(--card-2); border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px; overflow-x: auto; white-space: pre-wrap; font-size: .92em; }
.msg .text .rhtml code { font-size: .92em; }
.msg .text .rhtml table { border-collapse: collapse; margin: .4em 0; }
.msg .text .rhtml td, .msg .text .rhtml th { border: 1px solid var(--line); padding: 3px 7px; }
.msg .text .rhtml details { margin: .35em 0; }

/* ================== недостающие классы из разметки ===================== */
/* чипы (вкладки дашборда, «⚡ дашборд», статусы нитей) */
.chip {
  background: var(--card); border: 1px solid var(--line); border-radius: 999px;
  padding: 2px 10px; font-size: 12px; color: var(--ink); white-space: nowrap;
}
.chip:hover { background: var(--sunken); }
.chip.on { background: var(--ink); color: var(--ink-on); }

/* подписи секций и таблицы статистики */
.f { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-dim); margin-bottom: 6px; }
table.t { width: 100%; border-collapse: collapse; font-size: 13px; }
table.t td { padding: 5px 6px; border-bottom: 1px solid var(--line); }
table.t td:last-child.num, table.t td.num { text-align: right; font-weight: 700; }

/* карточки покупок */
.pk-amt { font-size: 26px; font-weight: 800; line-height: 1.1; }
.pk-sub { font-size: 13px; }
.pk-price { font-size: 15px; font-weight: 700; }
/* временная скидка: старая цена зачёркнута, рядом — ярлык процента */
.pk-price s { font-weight: 500; font-size: 13px; }
.off-badge {
  display: inline-block; margin-left: 4px; padding: 1px 6px; border-radius: 999px;
  background: #e8590c; color: #fff; font-size: 11px; font-weight: 800; vertical-align: 1px;
}

/* содержимое левой панели дашборда */
.dp-item {
  border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px;
  margin-bottom: 6px; background: var(--card); line-height: 1.45;
}
.dp-row { display: flex; align-items: center; gap: 6px; justify-content: space-between; margin-bottom: 3px; }
.dp-person {
  font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: .04em;
  margin: 12px 0 6px; padding-bottom: 3px; border-bottom: 1px solid var(--line);
}
.dp-person:first-child { margin-top: 0; }

/* легенда моделей под графиками и точка цвета в таблице */
.legend { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 8px; font-size: 12px; color: var(--ink); }
.legend .lg { display: inline-flex; align-items: center; gap: 6px; }
.legend i { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }
.lg-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 7px; vertical-align: middle; }

/* ---------- список игр: крестик удаления, свёрнутый список ------------ */
.item-wrap { position: relative; }
.item-wrap .item { padding-right: 36px; }
/* «⋯» у карточки комнаты (ховер) и выпадающее меню админа */
.room-more {
  position: absolute; top: 6px; right: 6px; width: 26px; height: 26px;
  border: 0; background: transparent; color: var(--ink-faint); border-radius: 6px;
  font-size: 15px; line-height: 1; opacity: 0; cursor: pointer; transition: opacity .12s;
}
.item-wrap:hover .room-more { opacity: 1; }
.room-more:hover { background: var(--hover); color: var(--ink); }
.room-lock { position: absolute; top: 7px; right: 38px; font-size: 12px; filter: grayscale(1); opacity: .75; }
.item-menu {
  position: absolute; top: 34px; right: 6px; z-index: 30; min-width: 170px;
  background: var(--card); border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .16); display: flex; flex-direction: column;
}
.item-menu[hidden] { display: none; }
.item-menu button { border: 0; background: transparent; text-align: left; padding: 8px 12px; font-size: 13px; cursor: pointer; }
.item-menu button:hover { background: var(--sunken); }
/* пати в правой панели игры: состав, приглашение, чат группы */
.party-meta { font-size: 12px; margin-bottom: 8px; }
.party-list { display: flex; flex-direction: column; gap: 4px; }
.party-row { display: flex; align-items: center; gap: 7px; border: 1px solid var(--line, #26262c); border-radius: 8px; padding: 4px 7px; background: var(--card); }
.party-av { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; flex: none; }
.party-av.party-ph { display: flex; align-items: center; justify-content: center; background: var(--card-2); color: var(--ink-dim); font-size: 11px; font-weight: 700; }
.party-nick { flex: 1; min-width: 0; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.party-inv { display: flex; gap: 5px; margin-top: 7px; }
.party-inv input { flex: 1; min-width: 0; border: 1px solid var(--line); border-radius: 6px; padding: 5px 7px; font-size: 12px; }
.party-msgs { border: 1px solid var(--line, #26262c); border-radius: 8px; background: var(--sunken); padding: 6px 8px; max-height: 260px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }
.party-msgs .pm { font-size: 12px; line-height: 1.4; word-break: break-word; }
.party-send { display: flex; gap: 5px; margin-top: 6px; }
.party-send input { flex: 1; min-width: 0; border: 1px solid var(--line); border-radius: 6px; padding: 5px 7px; font-size: 12px; }
.item-x {
  position: absolute; top: 7px; right: 7px; width: 22px; height: 22px; padding: 0;
  border: 1px solid var(--line); border-radius: 50%; background: var(--card); color: var(--ink);
  font-size: 11px; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.item-x:hover { background: var(--ink); color: var(--ink-on); }
/* список свёрнут (после выбора игры) — переписка занимает всю ширину */
.grid2.single { grid-template-columns: 1fr; }

/* ------------------ меню «⋮» в шапке переписки ------------------------ */
.menu-wrap { position: relative; }
.menu-drop { position: absolute; top: calc(100% + 6px); right: 0; min-width: 270px; }
/* меню композера («⋮ меню игры») всегда раскрывается ВВЕРХ — композер внизу экрана */
.composer .menu-drop { top: auto; bottom: calc(100% + 6px); }
.menu-drop .mi {
  display: block; width: 100%; text-align: left; background: var(--card); border: 0;
  border-bottom: 1px solid var(--line); padding: 9px 12px; font: inherit; color: inherit; cursor: pointer;
}
.menu-drop .mi:last-child { border-bottom: 0; }
.menu-drop .mi:hover { background: var(--sunken); }

/* ---------- комнаты и ЛС: современные пузыриessenger ---------- */
.msg.room, .msg.dm { align-items: flex-start; }
.msg .mavatar-ph { display: inline-flex; align-items: center; justify-content: center; font-weight: 800; color: var(--ink-faint); }
.who-link { color: inherit; text-decoration: none; border-bottom: 1px dotted #999; cursor: pointer; }
.who-link:hover { border-bottom-color: var(--ink); opacity: .8; }
/* действия сообщения — всплывающая стопка над пузырём (по ховеру) */
.msg-acts {
  display: flex; gap: 4px; align-items: center;
  position: absolute; bottom: calc(100% - 2px); left: 0;
  background: var(--card); border: 1px solid var(--hover); border-radius: 10px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .12); padding: 3px 5px;
  opacity: 0; pointer-events: none; transition: opacity .12s, transform .12s;
  transform: translateY(3px); z-index: 5;
}
.msg:hover .msg-acts { opacity: 1; pointer-events: auto; transform: translateY(0); }
/* ПК: кнопки действий в один ряд, текст кнопок без переноса */
@media (min-width: 701px) {
  .msg-acts { flex-wrap: nowrap; max-width: calc(100vw - 48px); overflow-x: auto; }
  .msg-acts .mini { white-space: nowrap; flex: none; }
}
/* ТАЧ-УСТРОЙСТВА (телефоны, планшеты, тач-мониторы): ховера НЕТ — всё, что
   пряталось за :hover, обязано быть видимым постоянно, иначе на планшете
   768–1024px кнопки «играть», «⋯» меню комнаты и действия сообщения
   НЕДОСТИЖИМЫ (opacity:0 без способа показать). Раньше фолбэка не было
   вовсе: @media (hover:none)/(pointer:coarse) не встречался ни разу. */
@media (hover: none), (pointer: coarse) {
  .gplay { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  .room-more { opacity: 1; }
  .msg-acts { opacity: 1; pointer-events: auto; transform: translateY(0); }
  /* :hover залипает после тапа — scale оставался до следующего клика */
  .btn.primary:hover { transform: none; }
}
.mini {
  background: transparent; border: 0; border-radius: 6px;
  padding: 2px 7px; font-size: 11px; color: var(--ink-dim); cursor: pointer; font-weight: 600;
}
.mini:hover { background: var(--sunken); color: var(--ink); }
.reply-bar {
  display: flex; align-items: center; gap: 8px; padding: 6px 14px;
  font-size: 12px; background: var(--hover); border-top: 1px solid var(--card-2);
}
.reply-bar[hidden] { display: none; }

/* --------- публичный профиль игрока (оверлей по клику на ник) -------- */
.prof { display: flex; gap: 16px; align-items: flex-start; }
.prof-av {
  width: 132px; height: 132px; border: 1px solid var(--line); border-radius: 50%;
  object-fit: cover; flex: none; cursor: zoom-in;
}
.prof-ph {
  display: flex; align-items: center; justify-content: center;
  background: var(--ink); color: var(--ink-on); font-size: 46px; font-weight: 800; cursor: default;
}
.prof-nick { font-size: 20px; font-weight: 800; }
.prof-stats { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
/* --------- друзья: кнопка 👥 в шапке, список в оверлее --------- */
.fr-list { display: flex; flex-direction: column; gap: 8px; }
.fr-row {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 10px;
  background: color-mix(in srgb, var(--sk-panel, transparent) 8%, var(--card));
}
.fr-row .fr-av { flex: none; }
.fr-row .fr-av .mavatar, .fr-row .fr-av .mavatar-ph { width: 40px; height: 40px; }
.fr-info { flex: 1; min-width: 0; }
.fr-nick { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fr-sub { font-size: 11px; color: var(--ink-dim); }
.fr-game { font-size: 12px; margin-top: 2px; }
.fr-row.skinned .fr-nick { color: var(--sk-accent, inherit); }
.fr-row.skinned .fr-sub, .fr-row.skinned .fr-game { color: var(--sk-color, var(--ink-dim)); }
.fr-on { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #2f9e44; margin-right: 4px; vertical-align: 1px; }
/* ==== задел под рамки и фоны меню: тема меняет три значения ==== */
:root {
  --menu-bg: #22222a;
  --menu-border: rgba(255, 255, 255, .14);
  --menu-shadow: 0 18px 50px rgba(0, 0, 0, .55);
  --menu-radius: 12px;
}
.dropdown, .menu-drop, .overlay .ov-card {
  background: var(--menu-bg);
  color: var(--ink);   /* тёмное стекло меню: основной светлый текст */
  border: 2px solid var(--menu-border);
  box-shadow: var(--menu-shadow);
  border-radius: var(--menu-radius);
}
.menu-drop { overflow: hidden; padding: 4px 0; }
.mi {
  display: block; width: 100%; text-align: left; background: transparent;
  border: 0; border-bottom: 1px solid rgba(0, 0, 0, .08);
  padding: 10px 12px; font: inherit; color: inherit; cursor: pointer;
}
.mi:last-child { border-bottom: 0; }
.mi:hover { background: rgba(0, 0, 0, .06); }

/* пента слева, её показатели справа — экономим высоту панели */
/* ПК: показатели под пентагоном столбиком (снизу); на телефоне — рядом
   справа (переключение в медиазапросе ниже, там же мелкая пента) */
.penta-row { display: flex; flex-direction: column; gap: 8px; }
.penta-row .penta-wrap { flex: none; justify-content: center; margin: 2px 0 0; }
.penta-row .penta-stats { flex: 1; min-width: 0; }

/* кнопка сворачивания панели на телефоне (планка сверху) — ≥40px для пальца */
.edge-btn.down { min-height: 40px; width: 100%; }

/* лица в шапке игры — только на телефоне (карточки в сообщениях там скрыты) */
.gh-faces { display: none; }

/* ===================== телефоны и планшеты ==================== */
@media (max-width: 900px) {
  .pane { padding: 8px; }
  .tabs { margin-top: 34px; padding: 0 4px; }
  .tabs button { padding: 8px 10px; font-size: 13px; }

  /* список игр и статистика — в одну колонку */
  .grid-games { grid-template-columns: 1fr; }

  /* шапка переписки переносится, кнопки не вылезают */
  .thread-head { flex-wrap: wrap; row-gap: 6px; }
  .thread-head .grow { display: none; }
  .thread-head > b { order: -1; width: 100%; }

  /* поле ввода: текст на всю ширину, модель и кнопка — рядом */
  .composer { flex-wrap: wrap; }
  .composer input[type="text"] { flex: 1 1 100%; }
  .composer select { flex: 1 1 55%; max-width: none; }
  .composer .btn.primary { flex: 1 1 35%; }
  /* комнатный композитор — всегда одной строкой (pill + круглая стрела) */
  .thread > .composer { flex-wrap: nowrap; }
  .thread > .composer input[type="text"] { flex: 1 1 auto; }
  .thread > .composer .btn.primary { flex: 0 0 42px; }

  /* дашборд на телефоне: левая панель — сверху во всю ширину колонки,
     содержимое правой панели живёт в её первой вкладке «Персонажи».
     ВАЖНО: у .thread стоит overflow:hidden (скругления) — он убивает
     position:sticky у панели: предок становится контекстом прокрутки,
     который сам не скроллится. На телефоне снимаем его. */
  .thread { overflow: visible; }
  .game-grid { display: flex; flex-direction: column; }
  .divider { display: none; }
  .dash-left {
    order: -1; position: sticky; top: -8px; z-index: 25;
    width: 100% !important; max-height: 42vh;
    border-right: 0; border-bottom: 1px solid var(--line); background: var(--sunken);
    /* верхний padding паны (8px) иначе остаётся щелью, сквозь которую
       при скролле видно чат; -8px поднимает панель под самый край */
  }
  .dash-left .dash-body { overflow-y: auto; }
  /* свёрнутая панель на телефоне не занимает места вовсе: дашборд разворачивает
     сама плашка HUD (она и есть кнопка), а плашка «▼ дашборд» дублировала её */
  .dash-left.collapsed {
    display: none; width: 100% !important; min-height: 0; max-height: none;
    background: var(--sunken);
  }
  .dash-left.collapsed .edge-btn { border-bottom: 1px solid var(--line); }
  /* свёртывание: такая же широкая плашка ПОД дашбордом (как рейка на ПК,
     только поперёк); плоская — иначе flex панели растянет её на всю высоту */
  .dash-left .edge-btn.dash-collapse {
    border-top: 1px solid var(--line); font-weight: 700; font-size: 13px;
    flex: none; min-height: 36px;
  }
  .dash-left .dash-body { flex: 1 1 auto; min-height: 0; }
  .dash-right { display: none !important; }
  .game-main { order: 0; }

  /* шапка комнаты/ЛС прилипает к верху экрана (как панель в играх):
     пока листаешь ленту, «◀ комнаты» всегда под рукой */
  .thread-head {
    position: sticky; top: -10px; z-index: 40;
    background: var(--card); box-shadow: 0 2px 6px rgba(0, 0, 0, .07);
  }
  /* шапка ИГРЫ — НЕ липкая: мобильное правило делает .thread-head sticky,
     игровая — обычный поток: уходит вверх при листании и возвращается при
     подъёме, без щели под панелью табов */
  .thread-head.gh-game { position: static; top: auto; }
  /* меню «⋮» в композере открывается ВВЕРХ (композер внизу экрана) */
  .composer .menu-drop { top: auto; bottom: calc(100% + 6px); }

  /* карточки-картинки в сообщениях убираем — они живут в шапке игры:
     слева персонаж, справа игрок, прямо под кнопками */
  .game-main .mcard { display: none; }
  .game-main .msgs { padding-top: 12px; gap: 26px; }
  .game-main .msg { padding-top: 8px; }
  /* ◀ + портрет персонажа группируются слева с зазором (не впритык к ◀),
     правый портрет уходит вправо через margin-left:auto */
  .gh-faces {
    display: flex; width: 100%; justify-content: flex-start;
    align-items: center; gap: 12px;
  }
  /* «◀» назад к списку живёт в шапке с персонажем и игроком: верхняя строка
     (название + кнопка дашборда) на телефоне убрана совсем */
  .gh-faces .gh-back { flex: none; font-size: 12px; padding: 5px 9px; }
  .gh-face {
    display: flex; align-items: center; gap: 6px; cursor: pointer;
    font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em;
  }
  .gh-face:active { opacity: .7; }
  /* экономим высоту: пента слева, её показатели справа */
  .penta-row { flex-direction: row; gap: 10px; align-items: flex-start; }
  .penta-row .penta-wrap { justify-content: flex-start; }
  .penta-row .penta { width: 148px; height: 148px; }
  /* бренд на телефоне не нужен: текст не виден, но занимает место */
  .brand { display: none; }
  /* отступ справа от висящей иконки (left:12 + 72 = 84): меньше 92 —
     плашка 18+ уезжала ПОД логотип (z:40) на ширинах 701–900 */
  .topbar { padding-left: 92px; }
  .gh-face.right { flex-direction: row; margin-left: auto; }
  .gh-face .gh-av, .gh-face .gh-ph {
    width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--line);
    object-fit: cover; cursor: zoom-in; flex: none;
  }
  .gh-face .gh-ph {
    display: flex; align-items: center; justify-content: center;
    background: var(--ink); color: var(--ink-on); cursor: default;
  }
  /* ── Рамка персонажа в шапке игры: это АВАТАР (фото/буква48px, рядом ник),
     поэтому бокс круглый, а кадр — КРУГЛЫЙ арт (--skin-fr, как у .mav-fr):
     квадратный9-slice (--frame-img) остаётся только на КАРТИНКАХ — портрет,
     сцена, обложка. Кадр ложится overlay'ем, бордюра нет ── */
  .gh-fw {
    position: relative; flex: none; width: 48px; height: 48px;
    border-radius: 50%; box-sizing: border-box;
  }
  .gh-fw::after {
    content: ""; position: absolute; inset: -9%;
    border-radius: 50%;
    background: var(--skin-fr, var(--frame-img)) center / 100% 100% no-repeat;
    pointer-events: none;
  }
  .gh-fw .gh-av, .gh-fw .gh-ph {
    position: absolute; inset: 0; width: 100%; height: 100%;
    border-radius: 50%; border: 0; font-size: 11px;
  }

  /* меню «⋮» и профили — во всю ширину экрана */
  .menu-drop { right: 0; left: 0; min-width: 0; }
  .dropdown { min-width: 0; width: calc(100vw - 20px); right: 0; }
  .ov-card { max-height: 92vh; }
}

@media (max-width: 700px) {
  /* крупные пальцы: основные кнопки не меньше 40px */
  .btn { padding: 10px 14px; }
  .hbtn { min-height: 40px; min-width: 40px; }
  /* нижняя навигация (уровень likoteka): табы всегда под пальцем и не
     уезжают за край. z-index: выше липких шапок (40) и логина (50),
     ниже overlay'ев (200+) — модалки перекрывают бар */
  .tabs {
    position: fixed; left: 0; right: 0; bottom: 0; margin-top: 0;
    z-index: 45; border-bottom: 0; border-top: 1px solid var(--line);
    padding: 0 8px env(safe-area-inset-bottom, 0);
    /* ПЕРЕНОС: шесть вкладок в один ряд уезжают за край на узком телефоне
       (nowrap → scrollW 508px в 382px — «Инвентарь»/«Статистика» были спрятаны
       за горизонтальным скроллом, о котором никто не догадывается) */
    flex-wrap: wrap; overflow-x: visible;
  }
  .tabs button { flex: 1 1 auto; min-width: 84px; }
  .tabs button { min-height: 40px; }
  /* место под висящий лого (низ лого ≈ 61px от верха) */
  .tabs-space { display: block; height: 18px; }
  /* габарит нижнего бара: 2 ряда по 40px + линия + safe-area.
     От него считаются и отступ контента, и высота игры «во весь экран» */
  :root { --tabsh: calc(84px + env(safe-area-inset-bottom, 0px)); --tb-strip: 16px; }
  /* контент не прячется за нижним баром */
  .pane { padding-bottom: var(--tabsh); }
  /* …кроме переписки: она и так тянется до низа — под ней не должно быть
     пустой полосы в 100px (юзер: «снизу отступ большой»). Игра заканчивается
     ровно НАД нижним баром */
  .pane:has(> .thread) { padding-bottom: 0; }
  .pane > .thread { height: calc(100% + 16px - var(--tabsh)); margin: -8px; border-radius: 0; }
  .btn.small { padding: 8px 12px; min-height: 40px; }
  .chip { padding: 7px 11px; }
  /* каталог: тапы чипов ≥40, шрифт поиска 16px — iOS не зумит инпут */
  .all-chips .chip { min-height: 40px; padding: 9px 14px; }
  .all-btn { min-height: 40px; }
  .all-q { font-size: 16px; padding: 11px 16px; }
  .mini { padding: 4px 9px; font-size: 12px; }
  /* на телефоне клика мимо ховера: действия сообщения — компактной строкой
     под пузырём (все мессенджеры прячут их за тап; у нас — строка чипов) */
  .msg-acts {
    position: static; opacity: 1; pointer-events: auto; transform: none;
    background: transparent; border: 0; box-shadow: none; padding: 0; margin-top: 3px;
    gap: 3px;
  }
  .msg.room, .msg.dm { max-width: 94%; }
  .msgs, #dmMsgs { padding: 10px 12px 8px; }
  .msg-acts { flex-wrap: wrap; }
  .item { padding: 11px 12px; }
  /* и пальцам их маловато: зоны нажатия ≥40px (WCAG 2.5.5 — раньше было
     22–34px, палец часто промахивался мимо «✕» и «⋯») */
  .item-x { width: 40px; height: 40px; top: 4px; right: 4px; font-size: 14px; }
  /* на тач-устройствах ховера нет: подсказки и «⋯», спрятанные за hover,
     иначе просто не существуют для игрока */
  .gplay { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  .room-more { opacity: 1; }
  .ginfo { width: 40px; height: 40px; font-size: 16px; }
  .room-more { width: 40px; height: 40px; font-size: 18px; }
  /* игровые чипы HUD (Статы/Скиллы/Сцена, «◀» назад, «⋮» меню) и кнопка 🖼 —
     тоже до 40px: жили 29–38px, палец промахивался. Чипы живут в .m-hud
     (мобильный HUD под лентой) и .hud-row (десктопная шапка) */
  .thread-head .hud-row .chip, .m-hud .chip { min-height: 40px; display: inline-flex; align-items: center; }
  .gh-faces .gh-back { min-width: 40px; min-height: 40px; display: inline-flex; align-items: center; justify-content: center; }
  #gameMenu { min-width: 40px; min-height: 40px; display: inline-flex; align-items: center; justify-content: center; }
  #imgSceneBtn { min-width: 40px; min-height: 40px; display: inline-flex; align-items: center; justify-content: center; }

  /* широкие таблицы прокручиваются, а не ломают экран. touch-action: pan-x —
     горизонтальный свайп по таблице крадётся страницей (вертикальный скролл
     при этом остаётся, pan-x+pan-y не мешают друг другу) */
  table.t { display: block; overflow-x: auto; white-space: nowrap; touch-action: pan-x pan-y; }

  /* формы панели API-лаб и памяти */
  .card { padding: 10px; }
  .stat { flex-wrap: wrap; }

  .reply-bar, .route-hint { font-size: 12px; }
  .prof { flex-direction: column; }
  .prof-av { width: 96px; height: 96px; font-size: 34px; }
  /* бренд и его отступ — в этом самом позднем блоке, иначе ранние
     media-правила перебивают padding сверху */
  .brand { display: none; }
  .topbar { padding-left: 68px; }
}

/* ---- узкие телефоны (≤430px, реальные 320–410): шапка не помещалась ----
   нерасширяемый контент (18+ + баланс + день + ✉ + ник) давал scrollWidth 416
   и езду страницы вбок. Ник прячем за аватаром (он и так кликабелен),
   «день» — за pill баланса; overflow-x на .topbar НЕ ставим: обрежет
   висящую иконку логотипа. */
@media (max-width: 430px) {
  .nick, .dash { display: none; }
}

/* --------- комнаты: пузыри мессенджера, роли, модерация ---------
   Свои справы с чёрной пузырём (акцент айдентики), чужие — белые
   с мягкой тенью; аватары круглые, действия всплывают по ховеру. */
.msg.room, .msg.dm { width: fit-content; min-width: 72px; max-width: 88%; position: relative; }
.msg.room .mb, .msg.dm .mb {
  background: var(--card); border: 1px solid var(--card-2); border-radius: 16px;
  padding: 8px 14px 8px; min-width: 0; flex: 0 1 auto; width: fit-content;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .06);
  text-align: left;
}
/* угловой «хвостик» в сторону аватара */
.msg.room.char .mb, .msg.dm.char .mb { border-top-left-radius: 6px; }
.msg.room.user .mb, .msg.dm.user .mb { border-top-right-radius: 6px; }
.msg .who {
  display: flex; align-items: baseline; gap: 8px;
  /* наследуем цвет текста пузыря: свой бабл (--ink-on на --ink) и чужой
     (--ink на --card) в ОБЕИХ темах контрастны; хардкод #222 в тёмной теме
     давал чёрное по чёрному */
  font-size: 12px; font-weight: 700; color: inherit; margin-bottom: 3px;
}
/* чужой игровой чат оставляем в прежней строгой манере */
.game-main .msg .who {
  font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-dim); margin-bottom: 4px;
}
.msg .ts { font-size: 10px; color: var(--ink-faint); font-weight: 400; letter-spacing: .02em; }
/* свои сообщения: пузырь #111, белый текст, аватар справа */
.msg.room.user, .msg.dm.user { margin-left: auto; flex-direction: row-reverse; }
.msg.room.user .mb, .msg.dm.user .mb { background: var(--ink); border-color: transparent; color: var(--ink-on); box-shadow: 0 2px 6px rgba(0, 0, 0, .16); }
.msg.room.user .who, .msg.dm.user .who { color: rgba(255, 255, 255, .82); }
.msg.room.user .ts, .msg.dm.user .ts { color: rgba(255, 255, 255, .55); }
.msg.room.user .who-link, .msg.dm.user .who-link { color: inherit; border-bottom-color: rgba(255,255,255,.4); }
/* роли на чёрном пузыре — светлые варианта */
.msg.room.user .role-tag.admin, .msg.dm.user .role-tag.admin { color: #ff9d94; }
.msg.room.user .role-tag.vip, .msg.dm.user .role-tag.vip { color: #cdb9ff; }
/* действия у своих — тоже над пузырём, прижаты к правому краю */
.msg.room.user .msg-acts, .msg.dm.user .msg-acts { left: auto; right: 0; }
/* роли: админ и vip — мягкие цветные подложки (только чужие пузыри) */
.msg.room.role-admin.char .mb { background: rgba(233,33,61,.10); border-color: rgba(233,33,61,.35); }
.msg.room.role-admin.char .who { color: var(--danger); }
.msg.room.role-vip.char .mb { background: rgba(167,139,250,.10); border-color: rgba(167,139,250,.35); }
.msg.room.role-vip.char .who { color: var(--violet); }
.msg.room.blocked { opacity: .55; }
.msg.room.role-admin .who-link { color: var(--danger); }
.msg.room.role-vip .who-link { color: var(--violet); }
/* …а на своём чёрном пузыре ник роли — светлым (контраст) */
.msg.room.user.role-admin .who-link, .msg.dm.user.role-admin .who-link { color: #ff9d94; }
.msg.room.user.role-vip .who-link, .msg.dm.user.role-vip .who-link { color: #cdb9ff; }
.role-tag {
  display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; border-radius: 4px; padding: 0 5px; border: 1px solid currentColor;
}
.role-tag.admin { color: var(--danger); }
.role-tag.moderator { color: var(--role-mod); }
.role-tag.vip { color: var(--violet); }
.role-tag.blocked { color: var(--ink-dim); }
/* пометка взрослой комнаты: бейдж в списке и в шапке */
.r18 { color: var(--danger); font-weight: 700; font-size: 11px; border: 1px solid rgba(248,113,113,.55); border-radius: 4px; padding: 0 4px; }
.mini.danger { color: var(--danger); }
.mini.danger:hover { background: var(--danger); color: var(--ink-on); }
.mini.ok { color: var(--ok); }
.mini.ok:hover { background: var(--ok); color: var(--ink-on); }
.prof-bio { margin-top: 8px; font-size: 13px; color: var(--ink); line-height: 1.5; }

/* ============================ чаты 2.0: аватары, композитор,
   список-контакты, «печатает…», мелочи ==================== */
/* круглые аватары в лентах комнат и ЛС (буква-заглушка — светлая плашка) */
.msg.room .mavatar, .msg.dm .mavatar,
.msg.room .mavatar-ph, .msg.dm .mavatar-ph {
  width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid var(--line); object-fit: cover; cursor: zoom-in;
}
.msg.room .mavatar-ph, .msg.dm .mavatar-ph {
  border: 0; background: var(--card-2); color: var(--ink-dim); font-size: 15px;
}
.msg.room.user .mavatar-ph, .msg.dm.user .mavatar-ph { background: #222; color: #eee; }
.mavatar-ph.big { width: 56px; height: 56px; border-radius: 50%; }

/* композитор современной комнаты: pill-поле + круглая чёрная кнопка-стрела */
.thread > .composer {
  border-top: 1px solid var(--card-2); background: var(--card);
  padding: 10px 12px; gap: 8px; align-items: center;
}
.thread > .composer input[type="text"] {
  border-radius: 22px; border-color: var(--line); background: var(--card-2);
  padding: 9px 16px; transition: border-color .15s, background .15s;
}
.thread > .composer input[type="text"]:focus {
  background: var(--card); border-color: var(--line-strong); box-shadow: none; outline: none;
}
.thread > .composer .btn.primary:not(.small), .row.composer .btn.primary:not(.small) {
  width: 42px; height: 42px; min-width: 42px; border-radius: 50%; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 17px; line-height: 1; flex: none;
  transition: transform .12s ease, background .15s;
}
.thread > .composer .btn.primary:not(.small):hover, .row.composer .btn.primary:not(.small):hover { transform: scale(1.06); background: #cfccc3; }
.thread > .composer .btn.primary:not(.small):active, .row.composer .btn.primary:not(.small):active { transform: scale(.94); }
/* ЛС-композитор: то же поле-pill */
.row.composer { gap: 8px; align-items: center; }
.row.composer input[type="text"] {
  border-radius: 22px; border-color: var(--line); background: var(--card-2); padding: 9px 16px;
}
.row.composer input[type="text"]:focus { background: var(--card); border-color: var(--line-strong); box-shadow: none; }

/* лента ЛС — такая же светлая, со скруглением; высота с потолком: 50vh на
   обычных экранах, но не выше 640px (иначе на широких десктопах лента
   выглядит обрубленной) и не ниже 320px (короткий телефон-альбом) */
#dmMsgs {
  background: var(--sunken); border: 1px solid var(--line); border-radius: 16px;
  padding: 16px 18px 10px; display: flex; flex-direction: column; gap: 12px;
  height: min(640px, max(320px, 50vh));
}

/* списка-контакты (комнаты и ЛС): круглая литера + две строки */
.item.conv {
  display: flex; gap: 10px; align-items: center; text-align: left;
  border: 0; border-radius: 12px; padding: 8px 10px;
  transition: background .12s;
}
.item.conv:hover { background: var(--hover); }
.item.conv.on { background: var(--sunken); color: var(--ink); box-shadow: inset 3px 0 0 var(--ink); border-radius: 12px; }
.conv .cav {
  width: 40px; height: 40px; border-radius: 50%; flex: none;
  background: var(--ink); color: var(--ink-on); font-weight: 800; font-size: 16px;
  display: inline-flex; align-items: center; justify-content: center;
}
.conv .cmain { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 1px; }
.conv .t { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.conv .s { font-size: 12px; color: var(--ink-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.conv.on .t { font-weight: 700; }
.conv.on .s { color: var(--ink-dim); }

/* «печатает…»: пульсирующая планка перед текстом */
.typing {
  min-height: 14px; padding: 0 18px; margin: 2px 0 2px; font-size: 12px;
  opacity: .75; font-style: italic; color: var(--ink-dim);
  display: flex; align-items: center; gap: 8px; animation: typingIn .16s ease;
}
.typing::before {
  content: ""; width: 22px; height: 4px; border-radius: 4px; flex: none;
  background: repeating-linear-gradient(90deg, #9a9a9a 0 4px, transparent 4px 8px);
  animation: typingPulse 1.1s ease-in-out infinite;
}
.typing[hidden] { display: none; }
@keyframes typingPulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
@keyframes typingIn { from { opacity: 0; transform: translateY(3px); } to { opacity: .75; } }
@keyframes popIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
/* новые реплики деликатно всплывают */
.msg.room, .msg.dm { animation: popIn .14s ease; }

/* ошибки комнат — мягкая плашка над композитором */
.thread .err-slot { padding: 0 14px 6px; font-size: 12px; color: var(--danger); }
.thread .err-slot:empty { display: none; }

/* ================= оверлей покупок (пиллы в шапке) ==================== */
.overlay {
  position: fixed; inset: 0; background: rgba(17, 17, 17, .45);
  z-index: 200; display: flex; align-items: center; justify-content: center; padding: 16px;
}
.overlay[hidden] { display: none; }
.ov-card {
  background: var(--card); border: 2px solid var(--line-strong); border-radius: 10px;
  width: min(780px, 100%); max-height: 86vh; display: flex; flex-direction: column; overflow: hidden;
}
.ov-head { display: flex; align-items: center; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--line); background: var(--hover); }
.ov-body { padding: 14px; overflow: auto; }
.ov-body .card + .card { margin-top: 12px; }

/* ===================== шапка на узких экранах ========================= */
@media (max-width: 700px) {
  .topbar { padding: 6px 8px 6px 68px; gap: 8px; }
  .brand-mark { left: 8px; top: 4px; width: 56px; height: 56px; }
  .brand { font-size: 16px; }
  .tabs { margin-top: 20px; }
  .dropdown { min-width: min(340px, calc(100vw - 16px)); right: 0; max-width: calc(100vw - 12px); }
}

/* ===== Устав (rpg): полосы героя, объекты сцены, выбор хода ===== */
.rpgrow { display: flex; align-items: center; gap: 8px; padding: 3px 0; font-size: 13px; }
.rpglab { flex: 0 0 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rpgbar-wrap { flex: 1 1 auto; height: 10px; background: var(--line, #e3e3e3); border-radius: 6px; overflow: hidden; }
.rpgbar { display: block; height: 100%; background: var(--acc, #7c4dff); border-radius: 6px; min-width: 3px; }
.rpgv { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.rpgtag { font-size: 13px; color: var(--muted, #8a8a8a); }
.rpgobj .rpgstate { font-size: 12px; color: var(--muted, #8a8a8a); text-align: right; max-width: 50%; }
.rpgsel { max-width: 170px; font-size: 13px; }


/* ============ HUD игры: статы / скиллы / действия / сцена ============= */
.thread-head .hud-row { width: 100%; display: flex; gap: 6px; flex-wrap: wrap; order: 9; padding-top: 4px; }
.thread-head .hud-row .chip { font-size: 12px; padding: 4px 10px; }
.hud-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.hud-tabs .btn { font-size: 13px; }
.hud-stat { display: flex; justify-content: space-between; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--card-2); font-size: 14px; }
.hud-stat b { white-space: nowrap; }
/* инвентарь героя в HUD: карточка предмета «в руках» */
.inv-item { border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; margin-bottom: 8px; background: var(--card); }
.inv-item-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.inv-item-head b { font-size: 14px; }
.inv-item-head i { font-style: normal; font-size: 11px; color: var(--ink-faint); }
.inv-item-desc { font-size: 12px; color: var(--ink-dim); line-height: 1.35; margin-top: 2px; }
.inv-mobj { text-align: left; }
.inv-mobj i { max-width: 46vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hud-note { margin-top: 10px; padding: 8px 10px; border-radius: 8px; background: var(--hover); font-size: 13px; line-height: 1.4; }
.hud-note.ok { background: rgba(74,222,128,.10); }
.hud-note.bad { background: rgba(248,113,113,.10); }
.zone { border: 1px solid var(--line); border-radius: 12px; padding: 8px 10px; margin-bottom: 8px; background: var(--sunken); }
.zone .zname { font-size: 12px; color: var(--ink-faint); margin-bottom: 6px; }
.zitems { display: flex; flex-wrap: wrap; gap: 6px; }
.echip { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--line); border-radius: 999px; padding: 3px 10px; font-size: 13px; background: var(--card); cursor: help; }
.echip .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--role-neutral); flex: 0 0 auto; }
.echip.hero { border-color: var(--role-hero); background: rgba(74,222,128,.10); }
.echip.hero .dot { background: var(--role-hero); }
.echip.enemy { border-color: var(--danger); background: rgba(248,113,113,.10); }
.echip.enemy .dot { background: var(--role-enemy); }
.echip.party { border-color: var(--role-party); background: rgba(96,165,250,.10); }
.echip.party .dot { background: var(--role-party); }
.echip.thing .dot { background: var(--role-item); }
.echip.neutral .dot { background: var(--role-neutral); }
.hud-legend { display: flex; gap: 12px; flex-wrap: wrap; font-size: 12px; color: var(--ink-dim); margin-top: 10px; align-items: center; }
.hud-legend .dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; margin-right: 4px; vertical-align: -1px; }
/* карточка персонажа: во что одет (одежда разобрана из описания spatial) */
.sd-worn { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; margin: 6px 0 8px; font-size: 12px; }
.sd-worn .worn-chip { border: 1px solid var(--line); border-radius: 999px; padding: 1px 9px; background: var(--sunken); color: var(--ink); font-size: 12px; }
/* карта локации: зоны и перенос предметов */
.wmap-bar { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.wmap-bar .dim { flex: 1; font-size: 12px; }
.wmap { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 8px; }
.wmap-zone { border: 1px solid var(--line); border-radius: 12px; padding: 8px 10px; background: var(--sunken); min-height: 70px; transition: border-color .15s, background .15s; }
.wmap-zone.drop { border-style: dashed; cursor: pointer; }
.wmap-zone.drop:hover { border-color: var(--accent); background: var(--card); }
.wmap-items { display: flex; flex-wrap: wrap; gap: 6px; }
.wmap-chip { cursor: pointer; font-size: 12px; }
.wmap-chip.sel { outline: 2px solid var(--accent); outline-offset: 1px; }
/* на телефоне зоны и предметы — пальцем: чипы не мельче 38 px, зона шире */
@media (max-width: 700px) {
  .wmap { grid-template-columns: 1fr; }
  .wmap-bar { flex-wrap: wrap; }
  .wmap-chip { min-height: 38px; padding: 6px 12px; font-size: 13px; }
  .wmap-zone { min-height: 84px; }
}

/* ============ HUD-глаз в композере: меню Устава с анимацией ============ */
.composer .hud-wrap { position: relative; flex: 0 0 auto; align-self: flex-start; }
.hud-eye { width: 42px; height: 42px; border-radius: 50%; padding: 0; overflow: hidden; border: 1px solid var(--line); background: var(--card); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; transition: transform .22s ease, box-shadow .22s ease; }
.hud-eye img { width: 30px; height: 30px; object-fit: contain; pointer-events: none; }
.hud-eye:hover { box-shadow: 0 2px 8px rgba(0,0,0,.15); }
.hud-eye.open { transform: rotate(90deg) scale(1.06); box-shadow: 0 3px 12px rgba(0,0,0,.2); }
.hud-menu { position: absolute; left: 0; bottom: calc(100% + 10px); min-width: 150px; display: flex; flex-direction: column; gap: 6px; padding: 8px; background: var(--card); border: 1px solid var(--line); border-radius: 14px; box-shadow: 0 8px 22px rgba(0,0,0,.14); transform-origin: bottom left; transform: translateY(10px) scale(.9); opacity: 0; pointer-events: none; transition: transform .22s ease, opacity .22s ease; z-index: 60; }
.hud-menu.open { transform: translateY(0) scale(1); opacity: 1; pointer-events: auto; }
.hud-menu .chip { justify-content: flex-start; text-align: left; font-size: 13px; padding: 7px 12px; opacity: 0; transform: translateY(6px); transition: opacity .18s ease, transform .18s ease; }
.hud-menu.open .chip { opacity: 1; transform: none; }
.hud-menu.open .chip:nth-child(1) { transition-delay: .04s; }
.hud-menu.open .chip:nth-child(2) { transition-delay: .08s; }
.hud-menu.open .chip:nth-child(3) { transition-delay: .12s; }
.hud-menu.open .chip:nth-child(4) { transition-delay: .16s; }

/* ======== вкладка «Персонажи»: тайлы общих, мини-карточки игр ============ */
img.char-ava, img.pl-av { object-fit: cover; display: block; }
.char-big { flex: none; width: 96px; height: 96px; border: 1px solid var(--line); border-radius: 50%; background: var(--sunken); display: flex; align-items: center; justify-content: center; overflow: hidden; font-size: 34px; font-weight: 800; color: var(--ink-faint); }
.char-big img { width: 100%; height: 100%; object-fit: cover; }
.char-tile { display: flex; align-items: center; gap: 10px; border: 1px solid var(--line, #26262c); border-radius: 12px; padding: 10px 12px 10px 10px; min-width: 230px; background: var(--card); cursor: default; transition: border-color .15s, box-shadow .15s; }
.char-tile:hover { border-color: #aaa; box-shadow: 0 1px 4px rgba(0,0,0,.05); }
.char-ava { flex: none; width: 46px; height: 46px; border-radius: 50%; background: var(--card-2); color: var(--ink-dim); display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 600; }
.char-tname { font-size: 14px; font-weight: 600; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.char-tbio { font-size: 12px; color: var(--ink-faint); max-width: 240px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.gmini { display: flex; align-items: center; gap: 10px; border: 1px solid var(--line, #26262c); border-radius: 12px; padding: 8px 10px; margin-bottom: 6px; background: var(--card); cursor: pointer; transition: border-color .15s, background .15s; }
.gmini:hover { border-color: #aaa; }
.gmini.open { border-color: var(--line-strong); }
.gmini-cover { flex: none; width: 40px; height: 40px; border-radius: 9px; object-fit: cover; background: var(--card-2); }
.gmini-ph { display: inline-flex; align-items: center; justify-content: center; color: var(--ink-dim); font-size: 17px; font-weight: 600; }
.gmini-t { flex: 1; min-width: 0; }
.gmini-name { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gmini-sub { font-size: 12px; color: var(--ink-faint); }
.gmini-arrow { flex: none; color: var(--ink-faint); font-size: 13px; transition: transform .15s; }
.gmini-chars { margin: -2px 0 10px; padding: 8px 10px; border: 1px solid var(--line, #26262c); border-top: 0; border-radius: 0 0 12px 12px; background: var(--sunken); }
.gmini + .gmini-chars { margin-top: -6px; }
.char-line { display: flex; align-items: center; gap: 8px; padding: 5px 2px; }
.char-line + .char-line { border-top: 1px dashed var(--line, #e5e5e5); }
.char-line .pl-av, .char-line .mav-fr, .char-tile .mav-fr { flex: none; }
.char-line-bio { flex: 1; min-width: 0; font-size: 12px; color: var(--ink-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ======== создание игры: сегмент-табы, тайлы игроков, карточки сцен ===== */
.seg { display: inline-flex; border: 1px solid var(--line, #26262c); border-radius: 12px; padding: 3px; gap: 3px; background: var(--hover); }
.seg-b { border: 0; background: transparent; padding: 5px 14px; border-radius: 9px; font-size: 13px; cursor: pointer; color: var(--ink-dim); transition: background .15s, color .15s; }
.seg-b:hover { color: var(--ink); }
.seg-b.on { background: var(--ink); color: var(--ink-on); }
/* вкладки диалога создания игры: Старт · Персонаж · Пригласить · Настройки */
.ov-tabs { display: flex; gap: 3px; border: 1px solid var(--line, #26262c); border-radius: 12px; padding: 3px; background: var(--sunken); margin-bottom: 12px; flex-wrap: wrap; }
.ov-tab { border: 0; background: transparent; padding: 6px 14px; border-radius: 9px; font-size: 13px; cursor: pointer; color: var(--ink-dim); }
.ov-tab:hover { color: var(--ink); }
.ov-tab.on { background: var(--ink); color: var(--ink-on); font-weight: 600; }
.pl-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.pl-tile { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--line, #26262c); border-radius: 10px; padding: 3px 4px 3px 3px; background: var(--card); }
.pl-av { width: 28px; height: 28px; border-radius: 50%; background: var(--card-2); color: var(--ink-dim); display: inline-flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 600; }
.pl-nick { font-size: 13px; max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-x { border: 0; background: transparent; color: var(--ink-faint); cursor: pointer; font-size: 12px; padding: 3px 5px; border-radius: 6px; }
.pl-x:hover { color: var(--danger); background: rgba(233,33,61,.10); }
.pl-add { flex: none; width: 40px; height: 36px; border: 1.5px dashed var(--line-strong); border-radius: 10px; background: var(--hover); color: var(--ink-dim); font-size: 20px; line-height: 1; cursor: pointer; transition: background .15s, color .15s, border-color .15s; }
.pl-add:hover { background: var(--ink); color: var(--ink-on); border-color: var(--line-strong); }
.pl-addrow { display: flex; gap: 6px; margin-top: 8px; align-items: center; }
.pl-frs { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 4px; align-items: center; padding: 8px 10px; border: 1px dashed var(--line, #26262c); border-radius: 10px; background: var(--sunken); }
/* слоты игроков: три больших прямоугольника; клик — окно выбора */
.pl-slots { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.pl-slot {
  position: relative; height: 104px; border: 1px dashed #999; border-radius: 10px;
  background: var(--sunken); display: flex; align-items: center; justify-content: center;
  overflow: hidden; transition: background .15s, border-color .15s;
}
.pl-slot.empty { cursor: pointer; }
.pl-slot.empty span { font-size: 30px; color: var(--ink-faint); line-height: 1; }
.pl-slot.empty:hover { background: var(--sunken); border-color: var(--line-strong); }
.pl-slot.filled { border-style: solid; border-color: var(--line-strong); background: var(--card); }
.pl-simg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.pl-sini { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 28px; font-weight: 800; color: var(--ink-faint); }
.pl-snick {
  position: absolute; left: 0; right: 0; bottom: 0; background: rgba(17, 17, 17, .78);
  color: #fff; font-size: 11px; padding: 2px 6px; text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pl-slot .pl-x { position: absolute; top: 3px; right: 3px; z-index: 2; background: rgba(255, 255, 255, .85); color: var(--ink-on); }
/* на светлой подложке крестик тёмный; ховер — инверсия (красный danger
   на белом = 2.77, провал — поэтому не он) */
.pl-slot .pl-x:hover { background: var(--ink-on); color: var(--ink); }
.pl-picker { margin-top: 8px; border: 1px solid var(--line); border-radius: 10px; padding: 10px; background: var(--card); }
.pl-picker[hidden] { display: none; }
.start-opt { display: flex; gap: 8px; align-items: flex-start; cursor: pointer; padding: 8px 10px; border: 1px solid var(--line, #26262c); border-radius: 10px; margin-bottom: 6px; background: var(--card); transition: border-color .15s, background .15s; }
.start-opt:hover { border-color: #aaa; }
.start-opt:has(input:checked) { border-color: var(--line-strong); background: var(--hover); }
.start-opt input { pointer-events: none; }

/* ======== дашборд: ховер пентагона, карусель персонажей ================= */
/* кружок = группа: невидимый хитбокс (в 3+ раза больше, БЕЗ трансформаций —
   ховер стабильный, без дрожи) + видимый .vis, который растёт внутри хитбокса */
.penta g.dot { cursor: pointer; }
.penta g.dot .hit { fill: transparent; pointer-events: all; }
.penta g.dot .vis { pointer-events: none; transform-box: fill-box; transform-origin: center; transition: transform .18s ease; }
.penta g.dot.on .vis { transform: scale(1.4); }
.penta-wrap { contain: paint; padding: 6px; }
.st-row { transition: background .16s ease, transform .16s ease; border-radius: 8px; padding: 4px 6px; margin: 0 -6px; cursor: pointer; }
.st-row.hl { background: rgba(96,165,250,.10); box-shadow: inset 0 0 0 1px rgba(96,165,250,.35); }
.char-c { position: relative; display: flex; align-items: stretch; gap: 4px; }
.char-card { flex: 1 1 auto; min-width: 0; }
.char-nav { flex: 0 0 auto; width: 26px; border: 1px solid var(--line); border-radius: 10px; background: var(--card); font-size: 17px; line-height: 1; color: var(--ink-dim); cursor: pointer; align-self: center; padding: 8px 4px; transition: background .15s, color .15s; }
.char-nav:hover { background: var(--ink); color: var(--ink-on); border-color: var(--line-strong); }
.char-dots { display: flex; gap: 5px; justify-content: center; padding: 6px 0 2px; }
.char-dots .cdot { width: 7px; height: 7px; border-radius: 50%; background: var(--line); display: inline-block; transition: background .15s, transform .15s; }
.char-dots .cdot.on { background: var(--ink); transform: scale(1.25); }

/* ===== колонка сообщения: аватар + НИК ПОД НИМ (узкая, не шире 62px) ==== */
.msg .mcol { flex: 0 0 auto; width: 62px; max-width: 62px; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.msg .mcol .who { display: flex; flex-direction: column; align-items: center; gap: 2px; width: 100%; font-size: 10px; line-height: 1.25; text-align: center; overflow-wrap: anywhere; }
.msg .mcol .who .who-link { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; }
.msg .mcol .who .ts { opacity: .6; font-size: 9px; }
.msg .mcol .who .role-tag { font-size: 9px; padding: 0 4px; transform: none; }

/* цитата со ссылкой на сообщение и подсветка перехода */
.qref { border-left: 3px solid var(--line-strong); background: var(--hover); border-radius: 0 8px 8px 0; padding: 4px 8px; font-size: 12px; color: var(--ink-dim); margin-bottom: 5px; cursor: pointer; }
.qref:hover { background: var(--card-2)eee; }
.msg.hl { outline: 2px solid var(--line-strong); outline-offset: 2px; border-radius: 8px; transition: outline-color .3s; }

/* ===== шапка игры: липкая, выезжает при скролле вверх, прячется вниз ===== */
.thread-head.gh-game { position: sticky; top: 0; z-index: 40; background: var(--card); box-shadow: 0 1px 4px rgba(0,0,0,.06); transition: max-height .2s ease, transform .2s ease; max-height: 360px; overflow: hidden; }
/* скрытая шапка схлопывается ВЫСОТОЙ в 0: прежний translateY(-103%) оставлял
   на её месте белую полосу своей высоты («треть экрана белая») */
.thread-head.gh-game.head-hide { transform: translateY(-4px); max-height: 0; box-shadow: none; padding-top: 0; padding-bottom: 0; border-width: 0; }
@media (max-width: 900px) {
  /* шапка ИГРЫ на телефоне — НЕ липкая (правило выше ломало задумку): она
     уходит вверх при листании, а широкая плашка дашборда остаётся сверху —
     иначе шапка (z-40) перекрывает плашку (z-25) и дашборд не виден */
  .thread-head.gh-game { position: static; top: auto; z-index: auto; }
}

/* ===== картинки сцены (a-images): вложение, заглушка, галки ===== */
.msg-img { display: block; max-width: min(100%, 420px); border-radius: 10px; border: 1px solid rgba(0,0,0,.1); margin: 8px 0; }
.imgph { display: flex; align-items: center; gap: 8px; padding: 8px 10px; margin: 8px 0; font-size: 12px; color: #6b7280; background: rgba(120,130,150,.07); border: 1px dashed rgba(120,130,150,.4); border-radius: 10px; }
.imgph-spin { width: 14px; height: 14px; flex: none; border-radius: 50%; border: 2px solid rgba(120,130,150,.3); border-top-color: #4f7cff; animation: imgspin .9s linear infinite; }
@keyframes imgspin { to { transform: rotate(360deg); } }
.imgfail { display: block; font-size: 11px; color: #a44; margin: 6px 0; opacity: .85; }
.game-cfg .chkline { display: flex; align-items: center; gap: 7px; font-size: 12.5px; margin: 3px 0; cursor: pointer; user-select: none; }
.game-cfg .chkline input { flex: none; width: auto; }
#imgSceneBtn { padding: 6px 11px; font-size: 15px; line-height: 1; }
#imgSceneBtn:disabled { opacity: .6; }
/* подвал страницы: плашка «День · место» на всю ширину */
.gh-foot { width: 100%; border-top: 1px solid var(--line); background: var(--hover); padding: 6px 12px; font-size: 12px; display: flex; justify-content: center; }
.gh-foot .gh-chip { font-size: 12px; }
.gh-foot .gh-scene { font-size: 11px; cursor: pointer; }
.gh-foot .gh-scene:hover { text-decoration: underline; }

/* ============ HUD игры: герой · состояние кадра · пентагон ==============
   Полоса под шапкой переписки. Панели дашборда по умолчанию свёрнуты, а тут
   главное всегда на виду: слева кто вы в этой игре, в центре часы Вертепа и
   сводка кадра, справа пентагон первого персонажа сцены. Текстура — та же,
   что у шапки: полоса читается как часть окна. */
.gh-hud {
  display: flex; align-items: center; gap: 14px;
  padding: 6px 12px; border-bottom: 1px solid var(--line);
  background: var(--hover); min-width: 0;
}
.gh-hud:empty { display: none; }
.ghu-hero { display: flex; align-items: center; gap: 9px; flex: none; min-width: 0; max-width: 34%; }
.ghu-av {
  position: relative;
  width: 42px; height: 42px; border-radius: 50%; flex: none; overflow: hidden;
  background: var(--sunken); display: inline-flex; align-items: center; justify-content: center;
  border: 2px solid var(--line-strong);
}
.ghu-av img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.ghu-ph { font-weight: 700; color: var(--ink-dim); }
.ghu-id { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.ghu-id b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13.5px; }
.ghu-id .dim { font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ghu-state { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ghu-clock { font-size: 13px; font-weight: 600; letter-spacing: .2px; }
.ghu-sub, .ghu-sum { font-size: 11.5px; color: var(--ink-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ghu-penta { display: flex; align-items: center; gap: 6px; flex: none; }
.ghu-penta svg.penta { width: 84px; height: 84px; flex: none; }
.ghu-penta.empty { font-size: 11px; color: var(--ink-dim); max-width: 130px; line-height: 1.3; }
.ghu-penta-cap { display: flex; flex-direction: column; font-size: 11.5px; line-height: 1.3; min-width: 0; }
.ghu-penta-cap b { max-width: 96px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 900px) {
  /* телефон: плашка HUD — ОДНА строка. Раньше пентагон уезжал вниз отдельной
     строкой с пунктиром, и полоса занимала ~1/4 экрана: игрового места почти
     не оставалось. Теперь герой · часы · пентагон справа, а сводка кадра
     (третья строка) скрыта — она и так в дашборде. */
  .gh-hud { flex-wrap: nowrap; gap: 8px; padding: 5px 10px; }
  .ghu-hero { max-width: none; }
  .ghu-av { width: 30px; height: 30px; }
  .ghu-state { flex: 1 1 auto; }
  .ghu-clock { font-size: 12px; }
  .ghu-sub { font-size: 11px; }
  .ghu-sum { display: none; }
  .ghu-penta { width: auto; flex: none; justify-content: flex-end; border-top: 0; padding-top: 0; }
  .ghu-penta svg.penta { width: 52px; height: 52px; }
  .ghu-penta-cap { display: none; }
}

/* ===== кнопка «вниз» ===== */
.jump-end { position: sticky; bottom: 8px; align-self: flex-end; margin: -34px 10px 6px 0; z-index: 30; width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--line); background: var(--card); font-size: 17px; cursor: pointer; box-shadow: 0 3px 10px rgba(0,0,0,.18); }
.jump-end:hover { background: var(--ink); color: var(--ink-on); }

/* ===== свайпы вариантов: «← 2/3 →» под последней репликой персонажа =====
   Кнопки ≥40px и видны всегда (не hover-only) — на телефоне их просто тапают.
   Счётчик мигает при смене варианта, чтобы глаз цеплялся за замену текста. */
.sw-bar { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.sw-btn { min-width: 40px; height: 40px; border-radius: 10px; border: 1px solid var(--line-strong); background: var(--card); font-size: 18px; line-height: 1; cursor: pointer; color: var(--ink); }
.sw-btn:disabled { opacity: .38; cursor: default; }
.sw-btn:not(:disabled):hover { background: var(--ink); color: var(--ink-on); border-color: var(--line-strong); }
.sw-btn:not(:disabled):active { transform: translateY(1px); }
.sw-count { font-size: 12px; color: var(--ink-dim); padding: 0 2px; font-variant-numeric: tabular-nums; }
.sw-count.sw-flash { color: var(--ink); font-weight: 700; }

/* ===== очередь собеседников комнаты: «▶ Ана говорит» =====
   Видна всегда (не hover-only), тап ≥40px: один тап = реплика этого NPC,
   это обычная генерация и списывается по прайсу модели. */
.queue-bar { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-top: 1px dashed var(--line-strong); background: var(--card-2); }
.queue-bar[hidden] { display: none; }
.queue-bar .q-btn { min-height: 40px; padding: 0 14px; font-size: 14px; }
.queue-bar .q-more { font-size: 12px; color: var(--ink-dim); }

/* ===== последствия скриптов + панель действий (вместо ввода) ===== */
.act-notes { padding: 6px 10px; border-top: 1px dashed var(--line); background: var(--card-2); font-size: 12px; line-height: 1.45; display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; }
.act-notes[hidden] { display: none; }
.act-chip { background: var(--card); border: 1px solid #e2d7b8; border-radius: 8px; padding: 2px 8px; }
.act-panel { border-top: 1px solid var(--line); background: var(--hover); padding: 10px; display: flex; flex-direction: column; gap: 8px; }
.act-panel[hidden] { display: none; }
.act-panel .row { align-items: center; }
.act-line { display: flex; justify-content: space-between; gap: 10px; font-size: 13px; padding: 4px 0; border-bottom: 1px dashed var(--line); flex-wrap: wrap; }
.act-sub { font-weight: 700; font-size: 12px; margin-top: 4px; }
.act-note { min-height: 16px; font-size: 13px; padding: 6px 8px; border-radius: 8px; }
.act-note.ok { background: rgba(74,222,128,.10); }
.act-note.bad { background: rgba(248,113,113,.10); }

/* меню «⋮» в композере: правый край — у кнопки, растёт ВЛЕВО и не шире экрана */
.composer .menu-drop { right: 0; left: auto; max-width: calc(100vw - 40px); }

/* ---- сцена внизу: место, объекты, действия ---- */
.scene-dock { border-top: 1px solid #e2d7b8; background: #1f1d18; padding: 6px 10px 8px; font-size: 12px; }
.scene-dock[hidden] { display: none; }
.sd-top { display: flex; align-items: center; gap: 8px; }
.sd-place { color: #a8a194; }
.sd-place b { color: var(--ink); }
/* миниатюра места: серверный place.background (за местом закреплён фон игры) */
.sd-pic { width: 44px; height: 30px; object-fit: cover; border-radius: 6px; border: 1px solid var(--line); flex: 0 0 auto; }
.sd-count { font-size: 11px; padding: 2px 8px; border: 1px solid #d9cba6; border-radius: 999px; background: var(--card); color: #a8a194; white-space: nowrap; }
.sd-count.part { border-color: #c9a94e; color: var(--warn); background: rgba(253,181,21,.12); }
.sd-count.full { border-color: var(--danger); color: var(--danger); background: rgba(233,33,61,.12); }
.sd-refresh { border: 1px solid #d9cba6; background: var(--card); border-radius: 8px; width: 26px; height: 24px; cursor: pointer; line-height: 1; }
.sd-refresh:hover { background: var(--hover); }
.sd-desc { color: #7a6f57; line-height: 1.35; margin-top: 3px; max-height: 34px; overflow: hidden; }
.sd-objs { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; max-height: 104px; overflow: auto; }
.sd-obj { display: inline-flex; align-items: center; gap: 5px; border: 1px solid var(--line); background: var(--card); border-radius: 9px; padding: 3px 8px; cursor: pointer; font-size: 12px; color: var(--ink); }
.sd-obj:hover { background: var(--hover); border-color: #c9b47a; }
.sd-obj b { font-weight: 600; }
.sd-obj i { font-style: normal; font-size: 10px; color: var(--ok); background: rgba(122,222,90,.10); border-radius: 6px; padding: 0 4px; }
.sd-obj.off { opacity: .45; }
/* выбранный объект: к нему примется набранный текст («подойти» → к нему) */
.sd-obj.sel { border-color: #c9b47a; box-shadow: inset 0 0 0 1px #c9b47a; background: var(--hover); }
/* «новое» этим ходом: объект появился или изменился (серверный sceneChanges) */
.sd-obj.fresh { border-color: #7ade5a; }
.sd-obj.fresh i { color: #2f6b2f; background: rgba(122,222,90,.22); font-weight: 600; }
.sd-new { color: var(--ok); }
.sd-verbs { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; margin-top: 6px; }
.sd-mini { border: 1px dashed #d9cba6; background: transparent; border-radius: 8px; padding: 2px 7px; font-size: 11px; cursor: pointer; color: #d9cba6; }
.sd-mini:hover { background: var(--hover); }
.sd-sep { display: inline-block; width: 1px; height: 12px; background: var(--line); vertical-align: middle; margin: 0 2px; }
.sd-mini.off { opacity: .45; }
.sd-note { font-size: 12px; margin-top: 8px; color: #a8a194; }
.sd-note.ok { color: #2f6b2f; }
.sd-note.bad { color: var(--danger); }
.sd-modal { position: absolute; inset: 0; z-index: 60; background: rgba(24, 21, 15, .38); display: flex; align-items: flex-end; justify-content: center; }
.sd-modal[hidden] { display: none; }
.sd-card { width: min(620px, 100%); max-height: 74%; overflow: auto; background: #1f1d18; border: 1px solid #d9cba6; border-bottom: 0; border-radius: 14px 14px 0 0; padding: 12px 12px 14px; box-shadow: 0 -10px 34px rgba(0, 0, 0, .2); }
.sd-card-head { display: flex; align-items: center; gap: 6px; font-size: 14px; }
.sd-card-head i { font-style: normal; font-size: 10px; color: var(--ok); background: rgba(122,222,90,.10); border-radius: 6px; padding: 1px 5px; }
.sd-card-desc { color: #5f5743; font-size: 12px; line-height: 1.45; margin-top: 6px; white-space: pre-wrap; }
.sd-acts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.sd-acts .btn.off { opacity: .45; }
.game-main { position: relative; }

/* ---- мобильный низ: три кнопки + попап сцены ---- */
.m-hud { display: none; }
@media (max-width: 900px) {
  .m-hud { display: flex; flex-wrap: wrap; gap: 6px; padding: 6px 8px 0; position: relative; background: #1f1d18; border-top: 1px solid #e2d7b8; }
  .scene-dock { display: none !important; }
  .hud-wrap { display: none; }   /* старая кнопка меню устава больше не нужна */
  .m-scene { position: absolute; left: 8px; right: 8px; bottom: calc(100% + 6px); max-height: 62vh; overflow: auto; background: #1f1d18; border: 1px solid #d9cba6; border-radius: 14px; box-shadow: 0 -10px 30px rgba(0, 0, 0, .18); padding: 10px; z-index: 50; }
  .m-scene[hidden] { display: none; }
  .m-scene-head { display: flex; align-items: center; gap: 6px; font-size: 14px; }
  .m-scene-head i { font-style: normal; font-size: 10px; color: var(--ok); background: rgba(122,222,90,.10); border-radius: 6px; padding: 1px 5px; }
  .m-place { font-size: 12px; color: #c7bfa8; margin-top: 4px; }
  .m-desc { font-size: 12px; color: #c7bfa8; line-height: 1.4; margin-top: 4px; max-height: 92px; overflow: auto; }
  .m-objs { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
  .m-acts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
  .m-own { display: flex; gap: 6px; margin-top: 10px; }
  .m-own input { flex: 1; min-width: 0; border: 1px solid #cfc3a4; border-radius: 8px; padding: 8px; font: inherit; background: var(--card); }
  .m-own .btn { white-space: nowrap; }
}

/* ─────────── скины чата: кадр/цвет/акцент на репликах, инвентарь ─────────── */
/* кадр скина поверх аватара реплики (та же техника, что у кадра сцены):
   прозрачный центр SVG не перекрывает фото, посадка с запасом на «шишку» */
/* кадр скина поверх аватара — общая техника (та же, что у кадра сцены):
   прозрачный центр SVG не перекрывает фото; элемент несёт --sk-fr */
.mav-fr { position: relative; display: inline-block; line-height: 0; }
.mav-fr::after {
  content: ""; position: absolute; inset: -9%;
  border-radius: 50%;
  background: var(--sk-fr) center / 100% 100% no-repeat;
  pointer-events: none;
}
/* мои аватарки персонажей/игроков: та же техника mav-fr, но кадр — МОЙ
   надетый (--skin-fr), как у #nickAv в шапке. Квадратный арт картинок
   (бывший body.has-imgfr img.char-ava) сюда не идёт — это аватарки */
body.has-fr .mav-fr.me { --sk-fr: var(--skin-fr); }
/* цвет текста и акцент ника из скина — видят все в комнате/ЛС */
.msg.skinned .mb .text { color: var(--sk-color, inherit); }
.msg.skinned .who-link { color: var(--sk-accent, inherit); }
/* панель скина — подложка реплики (видят все): 30% — тёмные панели
   остаются читаемыми с обычным текстом, светлые дают мягкий тон */
.msg.skinned { background-color: color-mix(in srgb, var(--sk-panel, transparent) 30%, transparent); }
.msg.skinned { border-left: 3px solid color-mix(in srgb, var(--sk-accent, transparent) 45%, transparent); }
.msg.skinned.mine { border-left: 0; border-right: 3px solid color-mix(in srgb, var(--sk-accent, transparent) 45%, transparent); }
/* профиль: надетый скин игрока — кадр вокруг аватара и цвет ника; кадр
   рисуется на обёртке .prof-av-fr (см. витрину профиля в конце файла) */
.prof-av-fr { position: relative; display: inline-block; line-height: 0; }
.prof-av-fr > .prof-av { display: block; }
.prof-av-fr::after {
  content: ""; position: absolute; inset: -9%;
  border-radius: 50%;
  /* только КРУГЛАЯ часть рамки: квадратный арт (imgframe) — для картинок,
     на аватарку он не ложится даже как запасной вариант */
  background: var(--sk-fr) center / 100% 100% no-repeat;
  pointer-events: none;
}
/* пати-чат: реплики в цветах скина автора (видят все в группе) */
.party-msgs .pm.skinned { color: var(--sk-color, inherit); background-color: color-mix(in srgb, var(--sk-panel, transparent) 30%, transparent); border-radius: 6px; padding: 1px 4px; }
.party-msgs .pm.skinned b { color: var(--sk-accent, inherit); }
/* Обводка текста, когда цвет скина не читается на подложке. Решает скрипт
   (ctrScan в app.js): он измеряет РЕАЛЬНЫЙ контраст выведенного текста и, если
   он ниже 4.5:1, вешает .ctr-fix и кладёт в --ctr-line цвет, обратный цвету
   текста по светлоте (тёмный текст → светлая обводка). Сам цвет текста и фон
   не меняются — скин остаётся авторским, но буквы видно. */
.ctr-fix {
  text-shadow:
    -1px -1px 0 var(--ctr-line, #000), 1px -1px 0 var(--ctr-line, #000),
    -1px  1px 0 var(--ctr-line, #000), 1px  1px 0 var(--ctr-line, #000),
     0   -1px 0 var(--ctr-line, #000), 0    1px 0 var(--ctr-line, #000),
    -1px   0  0 var(--ctr-line, #000), 1px   0  0 var(--ctr-line, #000);
}
/* бейдж количества предметов на вкладке «Инвентарь» */
.inv-badge { display: inline-block; min-width: 16px; padding: 0 4px; border-radius: 999px; background: #6c5ce7; color: #fff; font-size: 10px; line-height: 16px; text-align: center; vertical-align: 2px; }

/* — вкладка «Инвентарь» — */
.inv-tabs { display: flex; gap: 4px; flex-wrap: wrap; margin: 8px 0 12px; }
.inv-tabs button { border: 1px solid var(--line); background: var(--sunken); border-radius: 999px; padding: 5px 14px; font: inherit; cursor: pointer; }
.inv-tabs button.on { background: var(--ink); color: var(--ink-on); border-color: var(--line-strong); }
.inv-badge { display: inline-block; min-width: 16px; padding: 0 4px; border-radius: 999px; background: var(--warn); color: var(--acc-ink); font-size: 11px; font-weight: 700; text-align: center; }
.inv-tabs button.on .inv-badge { background: var(--card); color: var(--ink); }
.inv-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 10px; }
.inv-card { border: 1px solid var(--line); border-radius: 12px; padding: 10px; background: var(--card); display: flex; flex-direction: column; gap: 6px; }
.inv-art { width: 100%; aspect-ratio: 1; object-fit: contain; border-radius: 8px; background: var(--hover); }
.inv-art-ph { display: flex; align-items: center; justify-content: center; font-size: 34px; color: var(--ink-faint); }
.inv-name { font-weight: 600; font-size: 13px; line-height: 1.25; }
.inv-tag { position: static; align-self: flex-start; background: rgba(167,139,250,.12); border: 1px solid #8b5cf6; border-radius: 6px; padding: 1px 6px; font-size: 11px; }
.inv-card { position: relative; }
/* плашки-подписи внизу карточки (в потоке — не наезжают друг на друга) */
.inv-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }
.inv-tag.hold { background: rgba(251,191,36,.12); border-color: var(--warn); }
.inv-tag.owned { background: rgba(74,222,128,.12); border-color: var(--ok); color: var(--ok); }
.inv-tag.adm { background: rgba(248,113,113,.12); border-color: #dc2626; color: #fca5a5; }
.inv-card.owned { border-color: #86efac; box-shadow: 0 0 0 1px #bbf7d0; }
/* источник предмета и подсказки витрины — в потоке под редкостью */
.inv-src { align-self: flex-start; background: var(--card-2); border: 1px solid var(--line); border-radius: 6px; padding: 1px 6px; font-size: 10px; color: var(--ink-dim); }
.inv-hints { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }
.inv-hints span { background: var(--card-2); border: 1px dashed var(--line-strong); border-radius: 6px; padding: 1px 6px; font-size: 10px; color: var(--ink-faint); }
.inv-acts { display: flex; flex-wrap: wrap; gap: 4px; margin-top: auto; }
.inv-seller { font-size: 12px; }
.rar { display: inline-block; border: 1px solid color-mix(in srgb, var(--rar, #999) 55%, var(--card)); background: color-mix(in srgb, var(--rar, #999) 12%, var(--card)); color: color-mix(in srgb, var(--rar, #999) 80%, #000); border-radius: 999px; padding: 1px 8px; font-size: 11px; font-weight: 600; width: fit-content; }
/* четыре слота «надето» */
.inv-slots { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; margin-bottom: 14px; }
.inv-slot { border: 1px dashed var(--line); border-radius: 10px; padding: 8px; display: flex; flex-direction: column; gap: 6px; align-items: flex-start; background: var(--sunken); }
/* выбор из моих предметов: значения только из списка (сервер валиирует ещё раз) */
.inv-pick-row { display: flex; gap: 4px; width: 100%; align-items: center; }
.inv-pick { flex: 1; min-width: 0; font: inherit; font-size: 12px; padding: 3px 4px; border: 1px solid var(--line); border-radius: 6px; background: var(--card); color: inherit; }
/* фильтр по типу предмета / фильтр маркета по предмету */
.inv-filter { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; margin-bottom: 10px; }
.inv-filter button { font: inherit; font-size: 12px; padding: 2px 10px; border: 1px solid var(--line); border-radius: 999px; background: var(--card); color: inherit; cursor: pointer; }
.inv-filter button:hover { border-color: #a3a3a3; }
.inv-filter button.on { background: #171717; border-color: #171717; color: #fff; }
.inv-slot-lbl { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint); }
.inv-slot-val { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; }
.inv-swatch { width: 22px; height: 22px; border-radius: 6px; border: 1px solid rgba(0,0,0,.15); display: inline-block; }
/* превью слота «Рамка картинок» — мини-картинка, не аватарка: квадратный арт
   не показываем на круглом аватаре (маршрут артов: свой арт — на своей форме) */
.inv-picfr {
  flex: none; width: 44px; height: 30px; box-sizing: border-box;
  border: 4px solid transparent; border-image-slice: 14; border-image-repeat: stretch;
  background: var(--card-2); color: var(--ink-dim); font-size: 13px; font-weight: 600;
  display: inline-flex; align-items: center; justify-content: center;
}
/* лутбокс */
.box-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.reveal { border: 2px solid var(--rar, #999); border-radius: 14px; padding: 14px; margin: 6px 0 14px; background: color-mix(in srgb, var(--rar, #999) 7%, var(--card)); animation: pop .45s cubic-bezier(.2, 1.4, .4, 1); }
.reveal-in { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.reveal-art { width: 120px; height: 120px; object-fit: contain; }
.reveal-name { font-weight: 700; font-size: 16px; }
@keyframes pop { from { transform: scale(.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }
/* ЦЕРЕМОНИЯ ОТКРЫТИЯ ЛУТБОКСА: фаза 1 — тряска бокса (600мс), фаза 2 —
   вспышка в цвет редкости (200мс), фаза 3 — карта. Управляется из app.js
   (классы .box-open-pre → .box-open-flash → innerHTML карта). */
.box-open-pre { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 18px 0 8px; }
.box-shake {
  font-size: 64px; line-height: 1; display: inline-block;
  animation: boxShake .6s ease-in-out infinite;
  transform-origin: 50% 80%;
}
.box-open-hint { font-size: 13px; color: #6b6b6b; letter-spacing: .04em; }
@keyframes boxShake {
  0%, 100% { transform: rotate(0deg) translateX(0); }
  15% { transform: rotate(-9deg) translateX(-3px); }
  30% { transform: rotate(8deg) translateX(3px); }
  45% { transform: rotate(-7deg) translateX(-2px); }
  60% { transform: rotate(6deg) translateX(2px); }
  75% { transform: rotate(-4deg) translateX(-1px); }
  90% { transform: rotate(3deg) translateX(1px); }
}
/* фаза 2: вспышка — резкий всплеск яркости в цвет редкости, затем затухание */
.box-open-flash {
  display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 18px 0 8px;
  animation: boxFlash .2s ease-out forwards;
}
.box-open-flash .box-shake { animation: none; transform: scale(1.15); }
.box-open-flash .box-open-hint { opacity: 0; }
@keyframes boxFlash {
  0% { opacity: 1; filter: brightness(1); }
  40% { opacity: 1; filter: brightness(1.9) saturate(1.6); }
  100% { opacity: 0; filter: brightness(2.4) saturate(2); }
}
/* раскрытие шансов (правила/закон) */
/* петля лутбокса: полоса прогресса до следующего бесплатного бокса */
.box-prog { margin: 10px 0 14px; }
.box-prog-txt { font-size: 12px; margin-bottom: 5px; }
.box-prog-bar { height: 8px; border-radius: 99px; background: #2a2a31; border: 1px solid var(--line); overflow: hidden; }
.box-prog-fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #34d399, #059669); transition: width .4s; }

.odds { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 10px; }
.odds-tbl { border-collapse: collapse; font-size: 13px; }
.odds-tbl td { padding: 3px 12px 3px 0; }
.odds-tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
/* оферты */
.offer { border: 1px solid var(--line); border-radius: 10px; padding: 10px; margin-bottom: 8px; background: var(--card); }
.offer.in { border-left: 4px solid #3b82f6; }
.offer.out { border-left: 4px solid #a855f7; }
.offer-head { display: flex; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.offer-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 13px; margin: 3px 0; }
.tchip { border: 1px solid var(--line); border-radius: 999px; padding: 1px 8px; background: var(--hover); font-size: 12px; }
/* диалог оферты: две колонки вещей */
.toff-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
@media (max-width: 560px) { .toff-cols { grid-template-columns: 1fr; } }
.toff-list { border: 1px solid var(--line); border-radius: 10px; padding: 8px; max-height: 38vh; overflow: auto; display: flex; flex-direction: column; gap: 6px; }
.toff-item { display: flex; align-items: center; gap: 8px; border: 1px solid var(--line); border-radius: 8px; padding: 6px; cursor: pointer; background: var(--card); }
.toff-item.on { border-color: var(--line-strong); background: var(--hover); box-shadow: inset 0 0 0 1px var(--line-strong); }
.toff-art { width: 34px; height: 34px; object-fit: contain; border-radius: 6px; background: var(--hover); flex: none; }
.toff-art-ph { display: inline-block; }
.toff-name { font-size: 13px; font-weight: 600; flex: 1; min-width: 0; }

/* ───── полная перекраска интерфейса моей панелью + рамки везде ───── */
/* Панель скина красит ВЕСЬ мой интерфейс: фон страницы (10%), карточки (6%),
   верхняя панель (полная заливка, см. .topbar), акцент — на активной вкладке.
   Тёмные панели дают нейтральный серый, текст всегда читаем. */
body.skinned-me { background: color-mix(in srgb, var(--skin-panel, var(--card)) 10%, var(--card)); }
body.skinned-me .card { background: color-mix(in srgb, var(--skin-panel, var(--card)) 12%, var(--card)); border-color: color-mix(in srgb, var(--skin-accent, var(--ink)) 20%, var(--ink)); }
body.skinned-me #tabBar button.on { box-shadow: inset 0 -3px 0 var(--skin-accent, var(--ink)); }

/* ───── верхняя панель как тип предмета скина (п.10) ─────
   Значение слота topbar: ключ темы (toxic/matrix) либо hex-цвет (--skin-topbar).

   ПРЕДМЕТ НЕ КРАСИТ САМУ ШАПКУ. Шапка — стекло с логотипом, ником и балансом:
   перекраска фона ломала контраст кнопок (баланс, ✉, аватар) и выглядела как
   «шапка перекрасилась». Предмет заменяет ЦВЕТНУЮ ПОЛОСКУ ПОД ШАПКОЙ —
   неоновый шов .topbar::after (по умолчанию красно-янтарный градиент) —
   своим цветом, и роняет декор вниз, в полосу под шапкой (--tb-strip).
   Полоса висит ПОД шапкой, шапку не трогает. */
body.skin-topbar-toxic .topbar::after,
body.skin-topbar-matrix .topbar::after,
body.skin-topbar-solid .topbar::after { height: 2px; }
body.skin-topbar-toxic .topbar::after {
  background: linear-gradient(90deg, #2f8f22, #8bff5a 45%, #57c93a 75%, #2f8f22);
  box-shadow: 0 0 10px rgba(92, 201, 58, .55);
}
body.skin-topbar-matrix .topbar::after {
  background: linear-gradient(90deg, transparent 2%, #00ff41 26%, #00ff41 74%, transparent 98%);
  box-shadow: 0 0 10px rgba(0, 255, 65, .6);
}
body.skin-topbar-solid .topbar::after {
  background: var(--skin-topbar);
  box-shadow: 0 0 10px color-mix(in srgb, var(--skin-topbar) 65%, transparent);
}
/* сам декор — полоса под шапкой, а не заливка шапки */
body.skin-topbar-toxic .topbar-skin,
body.skin-topbar-matrix .topbar-skin {
  top: 100%; bottom: auto; height: var(--tb-strip, 24px);
}
/* токсик: слизь свисает из-под кромки и стекает вниз каплями */
body.skin-topbar-toxic .topbar-skin {
  background:
    radial-gradient(9px 15px at 34px 0, #8bff5a 0 62%, transparent 63%),
    radial-gradient(7px 24px at 122px 0, #57c93a 0 62%, transparent 63%),
    radial-gradient(11px 11px at 208px 0, #8bff5a 0 62%, transparent 63%),
    radial-gradient(8px 19px at 286px 0, #46a72c 0 62%, transparent 63%),
    radial-gradient(6px 9px at 372px 0, #8bff5a 0 62%, transparent 63%),
    radial-gradient(10px 22px at 452px 0, #57c93a 0 62%, transparent 63%),
    radial-gradient(7px 13px at 536px 0, #8bff5a 0 62%, transparent 63%),
    linear-gradient(180deg, #5cc93a, #2f8f22);
  background-repeat: no-repeat;
  background-size: 600px 100%, 600px 100%, 600px 100%, 600px 100%,
    600px 100%, 600px 100%, 600px 100%, 100% 3px;
  background-position: 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0;
  /* капли гаснут книзу — полоса не спорит с контентом под ней */
  -webkit-mask-image: linear-gradient(#000 0 46%, transparent 100%);
  mask-image: linear-gradient(#000 0 46%, transparent 100%);
  animation: wmSlime 5.5s ease-in-out infinite alternate;
}
@keyframes wmSlime { from { transform: translateY(-1px); } to { transform: translateY(2px); } }
/* матрица: цифры ПАДАЮТ ВНИЗ и уходят под шапку на пару десятков пикселей */
body.skin-topbar-matrix .topbar-skin {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='40'><g fill='%2300ff41' font-family='monospace' font-size='12'><text x='2' y='11'>01</text><text x='30' y='28'>10</text><text x='58' y='8'>11</text><text x='86' y='22'>01</text><text x='16' y='38'>10</text><text x='70' y='39'>00</text><text x='100' y='36'>10</text></g></svg>");
  background-size: 120px 40px;
  opacity: .85;
  /* верх — плотно, низ — тает: падающие цифры «втекают» из-под шапки */
  -webkit-mask-image: linear-gradient(#000 0 40%, transparent 100%);
  mask-image: linear-gradient(#000 0 40%, transparent 100%);
  animation: wmMatrix 2.6s linear infinite;
}
@keyframes wmMatrix { from { background-position: 0 0; } to { background-position: 0 40px; } }

/* ───── окно как тип предмета скина (п.9) ─────
   Блок живёт в КОНЦЕ style.css (раздел «окна»): раньше он стоял здесь, но
   ниже по файлу лежат плотные заливки .ov-body, профиля и .thread-head,
   которые перебивали шапку окон. Подробности — в самом блоке. */
/* рамка скина на моей аватарке в шапке (кадр = --skin-fr) */
body.has-fr #nickAv, body.has-fr .havatar-ph { position: relative; }
body.has-fr #nickAv::after, body.has-fr .havatar-ph::after {
  content: ""; position: absolute; inset: -14%;
  border-radius: 50%;
  background: var(--skin-fr) center / 100% 100% no-repeat;
  pointer-events: none;
}
/* список диалогов: рамка и акцент ника собеседника (переменные с кнопки) */
.conv.skinned .cav { position: relative; }
.conv.skinned .cav::after {
  content: ""; position: absolute; inset: -10%;
  border-radius: 50%;
  background: var(--sk-fr) center / 100% 100% no-repeat;
  pointer-events: none;
}
.conv.skinned .t { color: var(--sk-accent, inherit); }

/* временные предметы: плашки и обратный отсчёт */
.inv-src.temp { background: rgba(251,146,60,.12); border-color: var(--warn); color: var(--warn); }
.temp-left { color: var(--warn); font-size: 11px; white-space: nowrap; font-weight: 700; }
.reveal-temp { margin-top: 6px; font-size: 12px; color: var(--warn); font-weight: 600; }

/* таблица шансов: две колонки — постоянный и временный дроп */
.odds-tbl th { font-size: 11px; color: #8a8a8a; font-weight: 600; text-align: left; padding: 4px 12px 4px 0; }
.odds-tbl th.num { text-align: right; }

/* ───── рамка СГЕНЕРИРОВАННЫХ картинок (слот imgframe; рамка — один тип
   предметов на два слота) ─────
   Прорисовка — ПО КРАЮ, а не поверх картинки: border-image с 9-slice нарезает
   арт на 4 угла + 4 полосы, углы масштабируются равномерно, а толщина полосы
   одинакова по всему периметру (раньше art тянулся 100%/100% — на широкоформатных
   кадрах границы растягивало, а середина арта висела «в воздухе» поверх фото).
   --fr-slice (в % от арта) мерится под админскую рамку в applyFrame.
   repeat:stretch — полоса тянется ЦЕЛИКОМ вдоль края: единственный акцент
   арта (кружок «Змейки», штрих-погоня) рисуется ОДИН раз, а не тайлится.
   round давал повторы: кружок плодился по верхнему краю, один бегущий
   штрих превращался в одинаковые штрихи в каждом тайле — выглядело
   задвоенным и дешёвым. Углы при этом масштабируются равномерно. */
body.has-imgfr .gcover, body.has-imgfr .imgfr-w { position: relative; }
/* собственная 1px-рамка карточки гонится ПОД скиновой полосой — прячем,
   иначе вокруг полосы видна вторая тонкая контурная линия («задвоенная») */
body.has-imgfr .gcover { border-color: transparent; }
/* обложке сетки отдаём СТАТИЧНЫЙ вариант рамки (без SMIL <animate>):
   анимация внутри border-image перерисовывалась на каждый кадр по числу
   карточек, и hover «всплывал». Сцены (.imgfr-w) остаются анимированными */
body.has-imgfr .gcover::after, body.has-imgfr .imgfr-w::after {
  content: ""; position: absolute; inset: 0; z-index: 3;
  border: var(--fr-w, 9px) solid transparent;
  border-image-source: var(--skin-imgfr);
  border-image-slice: var(--fr-slice, 14);
  border-image-repeat: stretch;
  pointer-events: none;
}
body.has-imgfr .gcover::after { border-image-source: var(--skin-imgfr-st, var(--skin-imgfr)); }
/* под курсором конкретная карточка ОЖИВАЕТ: рамка переключается на анимированный
   арт — SMIL идёт только по одной наведённой карточке, а не по всей сетке каждый
   кадр (в этом и были лаги при «всплытии»). Уход курсора — снова статика */
.gcell:hover .gcover::after { border-image-source: var(--skin-imgfr); }
/* мелкие плитки (img без обёртки — псевдо на <img> не рисуется): рамка
   ложится ФОНОМ под картинку, видна кромкой в паддинге */
body.has-imgfr img.gmini-cover {
  padding: 4px;
  border: 3px solid transparent;
  border-image-source: var(--skin-imgfr-st, var(--skin-imgfr));
  border-image-slice: var(--fr-slice, 14);
  border-image-repeat: stretch;
  box-sizing: border-box;
}
/* Угловая рамка (frMode:"corner", витая лоза): SVG кропается viewBox'ом на
   два угла-орнамента (--fr-tl/--fr-br, квадрат — не растягивается) и ложится
   ЧЕТКО по реальным углам широкой картинки — никакого перекрытия середины. */
body.fr-corner.has-imgfr .gcover::after, body.fr-corner.has-imgfr .imgfr-w::after {
  border: none;
  background-image: var(--fr-tl), var(--fr-br);
  background-repeat: no-repeat, no-repeat;
  background-position: left top, right bottom;
  background-size: var(--fr-cs, 112px) var(--fr-cs, 112px);
}
body.fr-corner.has-imgfr img.gmini-cover {
  padding: 0; border: none;
  background-image: var(--fr-tl), var(--fr-br);
  background-repeat: no-repeat, no-repeat;
  background-position: left top, right bottom;
  background-size: var(--fr-cs, 64px) var(--fr-cs, 64px);
}
/* ───── дашборд (игровой HUD) в цветовой схеме моего скина ───── */
body.skinned-me .hud-note { background: color-mix(in srgb, var(--skin-panel, var(--hover)) var(--skin-panel-mix, 45%), var(--card)); }
body.skinned-me .hud-stat { border-bottom-color: color-mix(in srgb, var(--skin-accent, #2a2a31) 45%, transparent); }
body.skinned-me .hud-tabs .btn.primary { background: color-mix(in srgb, var(--skin-accent, var(--ink)) 82%, var(--ink)); }
body.skinned-me .party-av { border: 1px solid color-mix(in srgb, var(--skin-accent, var(--ink)) 55%, transparent); }
body.skinned-me .party-body { background: color-mix(in srgb, var(--skin-panel, var(--card)) 8%, var(--card)); }
/* ───── дашборд игры (dashboard.js): цветовая схема из моего скина ───── */
/* плотность тона — --skin-panel-mix (app.js: светлая панель 18%, тёмная 52%):
   иначе светлая панель при 55% давала фон, на котором ни светлый, ни тёмный
   текст не добирал 4.5:1 */
body.skinned-me .dash-left, body.skinned-me .dash-right {
  background: color-mix(in srgb, var(--skin-panel, var(--sunken)) var(--skin-panel-mix, 55%), var(--sunken));
}
body.skinned-me .dash-tabs button.on {
  background: color-mix(in srgb, var(--skin-panel, var(--card)) var(--skin-panel-mix, 65%), var(--card));
  border-color: color-mix(in srgb, var(--skin-accent, var(--ink)) 60%, var(--ink));
  color: var(--ink);
}
body.skinned-me .dash-row .bar i { background: color-mix(in srgb, var(--skin-accent, var(--ink)) 78%, var(--ink)); }
body.skinned-me .dash-person { border-color: color-mix(in srgb, var(--skin-accent, #26262c) 45%, #26262c); }

/* ═══ окрашивание пропусков: табы, сабтабы инвентаря, диалоги, нижняя
   панель, шапка комнаты/ЛС, кнопка ЛС, меню аккаунта ═══ */
body.skinned-me .tabs {
  background: color-mix(in srgb, var(--skin-panel, var(--sunken)) var(--skin-panel-mix, 55%), var(--sunken));
  /* текстура панели: мягкий шум поверх заливки, blend overlay — зерно
     видно и на светлой, и на тёмной панели, текстура не «пачкает» цвет */
  background-image: var(--noise-soft);
  background-blend-mode: overlay;
  border-bottom-color: color-mix(in srgb, var(--skin-accent, var(--ink)) 40%, var(--ink));
}
body.skinned-me .tabs button {
  /* цвет — обычный --ink: тон панели ослаблен для светлых панелей до 18%
     (--skin-panel-mix), поэтому фон вкладок тёмный при любой панели, а
     светлый текст даёт ≥4.5:1; inkOnOf(panel) тут наоборот давал тёмный
     текст на тёмном фоне. На телефоне это нижняя навигация. */
  color: var(--ink);
}
body.skinned-me .tabs button.on {
  /* чистый акцент без смеси + контрастный текст (skin-accent-ink): математика
     гарантирует ≥4.57:1 для ЛЮБОГО цвета (inkOnOf выбирает лучший из тёмного/
     светлого на точке равенства контрастов); старая смесь 82%+18% света
     давала худший случай 3.91:1 — не проходила AA */
  background: var(--skin-accent, var(--ink));
  border-bottom-color: var(--skin-accent, var(--ink));
  color: var(--skin-accent-ink, var(--ink-on));
  box-shadow: none;
}
body.skinned-me .inv-tabs button {
  background: color-mix(in srgb, var(--skin-panel, var(--sunken)) var(--skin-panel-mix, 45%), var(--sunken));
  background-image: var(--noise-soft);
  background-blend-mode: overlay;
  border-color: color-mix(in srgb, var(--skin-accent, #26262c) 30%, #26262c);
  color: var(--ink);
}
body.skinned-me .inv-tabs button.on {
  /* чистый акцент + контрастный текст — см. комментарий у .tabs button.on */
  background: var(--skin-accent, var(--ink));
  border-color: var(--skin-accent, var(--ink));
  color: var(--skin-accent-ink, var(--ink-on));
}
/* диалоги: рамка из акцента + мягкая подсветка из панели («рамки всплывающих окон») */
body.skinned-me .ov-card {
  border-color: color-mix(in srgb, var(--skin-accent, var(--ink)) 55%, var(--ink));
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--skin-panel, transparent) 60%, transparent), 0 18px 50px rgba(0, 0, 0, .25);
}
body.skinned-me .ov-head {
  background: color-mix(in srgb, var(--skin-panel, var(--hover)) var(--skin-panel-mix, 65%), var(--hover));
  border-bottom-color: color-mix(in srgb, var(--skin-accent, var(--ink)) 35%, var(--ink));
}
body.skinned-me .ov-body { background: color-mix(in srgb, var(--skin-panel, var(--card)) 8%, var(--card)); }
/* профиль: диалог в цветах владельца профиля (переменные ставит openProfile);
   id-селектор — выше body.skinned-me, чьи корневые переменные тут не при чём */
#overlay .ov-card.prof-ov {
  background: color-mix(in srgb, var(--sk-panel, var(--card)) 16%, var(--card));
  border-color: color-mix(in srgb, var(--sk-accent, var(--ink)) 55%, var(--ink));
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--sk-panel, transparent) 70%, transparent), 0 18px 50px rgba(0, 0, 0, .25);
}
#overlay .ov-card.prof-ov .ov-head {
  background: color-mix(in srgb, var(--sk-panel, var(--hover)) var(--sk-panel-mix, 75%), var(--hover));
  border-bottom-color: color-mix(in srgb, var(--sk-accent, var(--ink)) 40%, var(--ink));
}
#overlay .ov-card.prof-ov .ov-body { background: color-mix(in srgb, var(--sk-panel, var(--card)) 10%, var(--card)); }
#overlay .ov-card.prof-bare { background: var(--card); border-color: var(--line-strong); box-shadow: 0 18px 50px rgba(0, 0, 0, .25); }
#overlay .ov-card.prof-bare .ov-head { background: var(--hover); border-bottom-color: var(--ink); }
#overlay .ov-card.prof-bare .ov-body { background: var(--card); }
/* нижняя панель игры (моб.): статы/скиллы/сцена + сама сцена */
body.skinned-me .m-hud {
  background: color-mix(in srgb, var(--skin-panel, var(--card)) 15%, var(--card));
  border-top-color: color-mix(in srgb, var(--skin-accent, #26241f) 45%, #26241f);
}
body.skinned-me .m-hud .btn { border-color: color-mix(in srgb, var(--skin-accent, #26262c) 35%, #26262c); }
body.skinned-me .m-scene {
  background: color-mix(in srgb, var(--skin-panel, var(--card)) 15%, var(--card));
  border-color: color-mix(in srgb, var(--skin-accent, #26241f) 40%, #26241f);
}
/* шапка комнаты и шапка ЛС (один класс) */
body.skinned-me .thread-head {
  background: color-mix(in srgb, var(--skin-panel, var(--card)) 22%, var(--card));
  border-bottom-color: color-mix(in srgb, var(--skin-accent, var(--ink)) 25%, var(--ink));
}
/* строки-элементы: комнаты, персонажи, список ЛС */
body.skinned-me .item {
  background: color-mix(in srgb, var(--skin-panel, var(--card)) 10%, var(--card));
  border-color: color-mix(in srgb, var(--skin-accent, var(--ink)) 22%, var(--ink));
}
body.skinned-me .item.on { background: color-mix(in srgb, var(--skin-accent, var(--ink)) 82%, var(--ink)); }
body.skinned-me .item.conv.on {
  background: color-mix(in srgb, var(--skin-panel, var(--sunken)) var(--skin-panel-mix, 60%), var(--sunken));
  box-shadow: inset 3px 0 0 var(--skin-accent, var(--ink));
}
body.skinned-me .item.conv:hover { background: color-mix(in srgb, var(--skin-panel, var(--hover)) var(--skin-panel-mix, 55%), var(--hover)); }
/* кнопка ЛС и прочие кнопки шапки */
body.skinned-me .hbtn {
  background: color-mix(in srgb, var(--skin-panel, var(--card)) 10%, var(--card));
  border-color: color-mix(in srgb, var(--skin-accent, var(--ink)) 45%, var(--ink));
}
body.skinned-me .hbtn:hover {
  background: color-mix(in srgb, var(--skin-accent, var(--ink)) 85%, var(--ink));
  border-color: transparent; color: var(--ink-on);
}
/* меню аккаунта */
body.skinned-me .dropdown {
  background: color-mix(in srgb, var(--skin-panel, var(--card)) 14%, var(--card));
  border-color: color-mix(in srgb, var(--skin-accent, var(--ink)) 50%, var(--ink));
}
body.skinned-me .dropdown .card { background: transparent; border: 0; }
body.skinned-me .hud-tabs .btn { border-color: color-mix(in srgb, var(--skin-accent, #26262c) 30%, #26262c); }

/* ═══ событийные декорации сайта (body.ev-* + #siteDecor, рисует app.js) ═══ */
#siteDecor { position: fixed; inset: 0; pointer-events: none; z-index: 150; }
#siteDecor .sd-ring { position: absolute; inset: 0; }
.ev-ny #siteDecor .sd-ring {
  border: 2px solid rgba(147, 197, 253, .55);
  box-shadow: inset 0 0 26px rgba(147, 197, 253, .2);
}
.ev-halloween #siteDecor .sd-ring {
  border: 2px solid rgba(251, 146, 60, .5);
  box-shadow: inset 0 0 26px rgba(251, 146, 60, .16);
}
#siteDecor .sd-art { position: absolute; filter: drop-shadow(0 4px 8px rgba(0, 0, 0, .18)); }
#siteDecor .sd-bl { left: 8px; bottom: 6px; width: 74px; height: 84px; }
#siteDecor .sd-br { right: 10px; bottom: 8px; width: 78px; height: 78px; }
#siteDecor .sd-fall {
  position: absolute; top: -10px; border-radius: 50%;
  background: #cfe6ff; box-shadow: 0 0 4px rgba(120, 170, 230, .7);
  opacity: .85; animation-name: sdFall; animation-timing-function: linear; animation-iteration-count: infinite;
}
@keyframes sdFall {
  0% { transform: translate(0, -10px); }
  50% { transform: translate(16px, 52vh); }
  100% { transform: translate(-8px, 104vh); }
}
@media (max-width: 700px) {
  /* нижний бар (~41px): декор поднимаем над ним, иначе тыквa перекрывает табы */
  #siteDecor .sd-bl { width: 54px; height: 62px; left: 4px; bottom: 56px; }
  #siteDecor .sd-br { width: 56px; height: 56px; right: 6px; bottom: 56px; }
}
@media (prefers-reduced-motion: reduce) {
  /* без движения снежинки остаются на своём инлайн-top% — «застывшая метель»
     по всему экрану, а не строчка на одной высоте */
  #siteDecor .sd-fall { animation: none; opacity: .6; }
  /* лутбокс: церемония открытия выключается (JS тоже пропускает фазы) */
  .box-shake, .box-open-flash { animation: none !important; }
  /* предмет «верхняя панель»: слизь/цифры под шапкой замирают, но видны */
  body.skin-topbar-toxic .topbar-skin,
  body.skin-topbar-matrix .topbar-skin { animation: none !important; }
}

/* ═══ текстуры-стили панелей (админка → body.st-*): паттерн едва заметный,
   цвета по-прежнему даёт скин. Ставится ПОСЛЕ тинтов: только background-image,
   цвета тинтов не сбивает ═══ */
body.st-strict .m-hud, body.st-strict .m-scene, body.st-strict .card, body.st-strict .thread {
  background-image: repeating-linear-gradient(90deg, rgba(17, 17, 17, .035) 0 1px, transparent 1px 7px);
}
body.st-retro .m-hud, body.st-retro .m-scene, body.st-retro .card, body.st-retro .thread {
  background-image:
    repeating-linear-gradient(0deg, rgba(92, 58, 20, .05) 0 1px, transparent 1px 3px),
    radial-gradient(circle at 30% 20%, rgba(120, 80, 30, .06), transparent 60%);
}
body.st-futuristic .m-hud, body.st-futuristic .m-scene, body.st-futuristic .card, body.st-futuristic .thread {
  background-image:
    repeating-linear-gradient(0deg, rgba(34, 160, 220, .055) 0 1px, transparent 1px 16px),
    repeating-linear-gradient(90deg, rgba(34, 160, 220, .055) 0 1px, transparent 1px 16px);
}
body.st-gothic .m-hud, body.st-gothic .m-scene, body.st-gothic .card, body.st-gothic .thread {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Cpath d='M20 3 C26 10 30 14 37 20 C30 26 26 30 20 37 C14 30 10 26 3 20 C10 14 14 10 20 3 Z' fill='none' stroke='rgba(40,20,50,.07)' stroke-width='1.2'/%3E%3Ccircle cx='20' cy='20' r='2.5' fill='rgba(40,20,50,.06)'/%3E%3C/svg%3E");
}
body.st-fantasy .m-hud, body.st-fantasy .m-scene, body.st-fantasy .card, body.st-fantasy .thread {
  background-image:
    radial-gradient(rgba(120, 80, 40, .07) 1px, transparent 1.5px),
    radial-gradient(rgba(120, 80, 40, .05) 1px, transparent 1.5px);
  background-size: 23px 23px, 37px 37px;
  background-position: 0 0, 11px 17px;
}

/* ═══ конструктор косметики (вкладка «Инвентарь»): форма + живое превью ═══
   Блоки превью .ctor-b1…b4 — общая структура с админским разбором черновика:
   те же размеры (аватар Ø72, картинка160×96, панель160×28, свотчи32×32). */
.ctor-form textarea {
  border: 1px solid var(--line); border-radius: 6px; padding: 7px 9px;
  background: var(--card); outline: none; width: 100%; box-sizing: border-box; resize: vertical;
}
.ctor-filerow { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.ctor-tplrow { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 4px; }
.ctor-filerow input[type="file"] { font-size: 12px; max-width: 100%; }
.ctor-chip { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--line); border-radius: 8px; padding: 3px 6px; background: var(--sunken); }
.ctor-thumb { width: 34px; height: 34px; object-fit: contain; background: var(--card); border: 1px solid var(--line); border-radius: 4px; }
.ctor-colors { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }
.ctor-color { display: flex; flex-direction: column; gap: 4px; font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-dim); }
.ctor-color input[type="color"] { width: 68px; height: 38px; padding: 2px; border: 1px solid var(--line); border-radius: 6px; background: var(--card); cursor: pointer; }
.ctor-send { margin: 4px 0 14px; }
.ctor-h { font-weight: 700; margin-bottom: 8px; }
/* — превью — */
.ctor-prev {
  display: flex; flex-direction: column; gap: 12px; align-items: flex-start;
  border: 1px dashed var(--line, #26262c); border-radius: 10px;
  padding: 12px; background: var(--sunken); margin-bottom: 12px;
}
.ctor-b1 { display: flex; gap: 12px; align-items: center; }
.ctor-av {
  position: relative; flex: none; width: 72px; height: 72px;
  border-radius: 50%; background: var(--card-2); color: var(--ink-dim);
  display: flex; align-items: center; justify-content: center;
  font-size: 26px; font-weight: 700;
}
/* кольцо-кадр поверх аватарки: арт с прозрачным центром, посадка с запасом */
.ctor-ring {
  position: absolute; inset: -8%;
  border-radius: 50%;
  background: center / contain no-repeat;
  pointer-events: none;
}
.ctor-nick { font-size: 15px; font-weight: 700; }
.ctor-pic {
  width: 160px; height: 96px; box-sizing: border-box;
  border: 6px solid transparent; border-image-slice: 14; border-image-repeat: stretch;
  background: var(--hover); display: flex; align-items: center; justify-content: center;
  color: var(--ink-faint); font-size: 12px;
}
.ctor-panel {
  width: 160px; height: 28px; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; color: var(--ink);
}
.ctor-swrow { display: flex; gap: 10px; flex-wrap: wrap; }
.ctor-swi { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; color: var(--ink-dim); }
.ctor-sw { width: 32px; height: 32px; flex: none; border: 1px solid var(--line); border-radius: 6px; }
/* Block5: пример сообщения + кусок нижней панели — цвета «вживую» */
.ctor-msgdemo {
  display: flex; gap: 6px; align-items: baseline; flex-wrap: wrap;
  padding: 8px 10px; border-radius: 8px;
  background: color-mix(in srgb, var(--card-2) 70%, transparent);
  border-left: 3px solid currentColor; font-size: 13px;
}
.ctor-msgdemo b { font-weight: 700; }
.ctor-tabsdemo {
  display: flex; gap: 2px; padding: 0 6px;
  border-radius: 8px; font-size: 12px; overflow: hidden;
  background-image: var(--noise-soft);
  background-blend-mode: overlay;
}
.ctor-tabsdemo span, .ctor-tabsdemo b {
  padding: 7px 12px; font-weight: 400; white-space: nowrap;
}
.ctor-tabsdemo b { font-weight: 600; border-radius: 6px 6px 0 0; }
/* — мои черновики — */
.ctor-draft { border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; margin-bottom: 6px; background: var(--card); font-size: 13px; }
.ctor-draft-head { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.ctor-st { font-size: 11px; border-radius: 999px; padding: 1px 8px; border: 1px solid; }
.ctor-st.pend { color: var(--warn); border-color: var(--warn); background: rgba(251,146,60,.12); }
.ctor-st.ok { color: var(--ok); border-color: var(--ok); background: rgba(74,222,128,.10); }
.ctor-st.rej { color: var(--danger); border-color: #dc2626; background: rgba(248,113,113,.10); }
.ctor-draft-note, .ctor-draft-reply { font-size: 12px; color: var(--ink-dim); margin-top: 3px; }
.ctor-draft-paid { font-size: 12px; color: var(--ok); font-weight: 600; margin-top: 3px; }

/* ===== отзывы и рейтинг карточки (P1-7) ===== */
.rvsec { margin-top: 14px; border-top: 1px dashed var(--line); padding-top: 10px; }
.rvhead { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.rvagg { font-weight: 700; color: var(--ink); background: var(--hover); border: 1px solid var(--line); border-radius: 999px; padding: 3px 10px; font-size: 13px; }
.rvstars { display: flex; gap: 4px; margin-bottom: 6px; }
.rvstar { width: 44px; height: 44px; font-size: 22px; line-height: 1; border: 1px solid var(--line); border-radius: 8px; background: var(--card); color: var(--line-strong); cursor: pointer; padding: 0; }
.rvstar.on { color: var(--acc); border-color: var(--acc); background: color-mix(in srgb, var(--acc) 14%, transparent); }
.rvstar:focus-visible { outline: 2px solid var(--acc); outline-offset: 1px; }
.rvlist { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.rvitem { background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; }
.rvmeta { font-size: 13px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.rvmeta .rvs { font-weight: 700; }
.rvtxt { font-size: 14px; margin-top: 3px; word-break: break-word; }


/* --------- нижний индикатор фоновой загрузки (stale-while-revalidate) --------
   Крутится, пока в фоне идёт свежий запрос; интерфейс уже показан из кэша и
   кликабелен — просто ждём обновления. */
.pane-load {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
  display: flex; align-items: center; gap: 8px; padding: 8px 14px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--card); color: var(--ink);
  font-size: 13px; z-index: 60; box-shadow: 0 3px 12px rgba(0,0,0,.12);
}
.pane-load .spin {
  width: 15px; height: 15px; flex: none;
  border: 2px solid rgba(17,17,17,.2); border-top-color: var(--ink); border-radius: 50%;
  animation: wm-spin .7s linear infinite;
}
@keyframes wm-spin { to { transform: rotate(360deg); } }
.pane-load .spin { border-color: rgba(255, 255, 255, .2); border-top-color: var(--ink); }

/* ═══════════════════════════════════════════════════════════════════════
   ДИЗАЙН-СЛОЙ «КИНЕМАТОГРАФ» (по мотивам storyforge)
   Всё ниже перекрывает базу каскадом: дисплейная типографика, стеклянные
   панели, янтарь-CTA, киноварные акценты, свечение при наведении.
   ═══════════════════════════════════════════════════════════════════ */

/* ---------- типографика: заголовки — дисплейным Unbounded ---------- */
h1, h2, h3, h4, .brand, .gname, .pk-amt { font-family: "Unbounded", system-ui, sans-serif; }
h1, h2, h3 {
  letter-spacing: .01em; font-weight: 700;
  color: #fff;   /* дисплейный слой: чистый белый против тела --ink (#ece9e1) */
}
h4 {
  font-size: 13px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .09em; color: var(--ink);
}
/* подчёркивание секций: во всю ширину заголовка, как неоновая нить под шапкой.
   Если надет предмет «верхняя панель» — полоса берёт ЕГО цвет/тему (см. блок
   «полоса из инвентаря» в конце файла), иначе остаётся фирменный градиент. */
h4::after {
  content: ""; display: block; width: 100%; height: 3px; margin-top: 7px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--hot), var(--acc));
}
.gname { font-size: 13.5px; font-weight: 500; letter-spacing: .01em; }
/* крупные числа-метрики — из faint (3.84) в основной слой; цифры не прыгают */
.gph, .pill, .delta, .st-v, .dash-row .v, table.t td.num, .dp-item .num {
  font-variant-numeric: tabular-nums;
}
.gph { color: var(--ink); }

/* ---------- шапка: стекло + неоновая нить снизу ---------- */
.topbar {
  background: linear-gradient(180deg, rgba(26, 26, 31, .95), rgba(20, 20, 24, .9));
  backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  box-shadow: 0 8px 28px rgba(0, 0, 0, .45);
}
.topbar::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg, transparent 4%, rgba(233, 33, 61, .55) 40%, rgba(253, 181, 21, .45) 70%, transparent 96%);
  pointer-events: none;
}
/* логотип — inline SVG currentColor: в этой тёмной пресете наследует светлый
   --skin-panel-ink/--ink, отдельная инверсия не нужна */
.brand-mark svg { filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .5)); }
.brand { color: #fff; text-transform: uppercase; }
.b18 { background: rgba(233, 33, 61, .15); border-color: rgba(233, 33, 61, .6); color: var(--hot-ink); }

/* ---------- вкладки ---------- */
.tabs { background: rgba(255, 255, 255, .03); border-bottom-color: rgba(255, 255, 255, .08); }
.tabs button:hover { color: var(--ink); background: rgba(255, 255, 255, .05); }
.tabs button.on {
  background: var(--ink); color: var(--ink-on); border-radius: 9px 9px 0 0;
  box-shadow: 0 -6px 18px rgba(236, 233, 225, .12);
}

/* ---------- карточки: стекло и глубина ---------- */
.card {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .04), rgba(255, 255, 255, .012)),
    var(--card);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 14px;
  /* стеклянный край: тонкий хайлайн сверху — «плёнка» вместо плоской заливки */
  box-shadow: 0 12px 34px rgba(0, 0, 0, .35), inset 0 1px 0 rgba(255, 255, 255, .05);
}

/* ---------- каталог: геройские карточки ---------- */
.gcell {
  background: linear-gradient(180deg, #212129, var(--card));
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 14px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);
}
.gcell:hover {
  transform: translateY(-4px);
  box-shadow:
    0 20px 44px rgba(0, 0, 0, .55),
    0 0 0 1px rgba(233, 33, 61, .4),
    0 0 26px rgba(233, 33, 61, .18),
    inset 0 1px 0 rgba(255, 255, 255, .06);
}
.gcover { border-radius: 10px; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .07); }
.gplay {
  background: rgba(10, 10, 13, .72); border: 1px solid rgba(255, 255, 255, .28);
  backdrop-filter: blur(3px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .5);
}
.ginfo { background: rgba(19, 19, 23, .85); backdrop-filter: blur(4px); }
.ginfo:hover { background: var(--acc); color: var(--acc-ink); border-color: transparent; }
/* белые стикеры-теги поверх арта — readability first, но с тёплым тоном */
.gt { background: rgba(255, 253, 246, .94); color: #1c1a15; border-color: rgba(0, 0, 0, .15); }

/* ---------- поиск и чипы ---------- */
.all-q {
  background: rgba(0, 0, 0, .35); border-color: rgba(255, 255, 255, .16);
  padding: 11px 18px; font-size: 15px;
  transition: border-color .15s, box-shadow .15s;
}
.all-q:focus {
  outline: none; border-color: rgba(253, 181, 21, .7);
  box-shadow: 0 0 0 3px rgba(253, 181, 21, .18), 0 6px 18px rgba(0, 0, 0, .3);
}
.chip { background: rgba(255, 255, 255, .05); border-color: rgba(255, 255, 255, .14); transition: background .15s, border-color .15s, color .15s; }
.chip:hover { background: rgba(255, 255, 255, .1); }
.chip.on {
  background: var(--acc); color: var(--acc-ink); border-color: transparent;
  font-weight: 700; box-shadow: 0 4px 14px rgba(253, 181, 21, .3);
}

/* ---------- кнопки: янтарь-CTA ---------- */
.btn {
  background: rgba(255, 255, 255, .05); border-color: rgba(255, 255, 255, .16);
  color: var(--ink); border-radius: 10px;
  transition: background .15s, border-color .15s, transform .15s, box-shadow .15s;
}
.btn:hover { background: rgba(255, 255, 255, .1); border-color: rgba(255, 255, 255, .3); }
.btn.primary {
  background: linear-gradient(135deg, #fdb515, #f08a00);
  color: var(--acc-ink); border: 0; font-weight: 700;
  /* CTA-геометрия: главный янтарь — «плакатный», радиус 6px вместо 10px
     (дисконтный язык: мельче радиус = выше напор); hover тот же */
  border-radius: 6px;
  box-shadow: 0 6px 20px rgba(253, 181, 21, .28);
}
.btn.primary:hover {
  background: linear-gradient(135deg, #ffc23d, #fdb515);
  transform: translateY(-1px);
  box-shadow: 0 10px 26px rgba(253, 181, 21, .38);
}
.btn.primary:active { transform: translateY(0); }
.btn.danger { border-color: rgba(248, 113, 113, .5); color: var(--danger); }
.btn.danger:hover { background: rgba(248, 113, 113, .12); }
.btn:disabled { opacity: .35; transform: none; box-shadow: none; }

/* ---------- поля ввода ---------- */
input[type="text"], input[type="password"], input[type="email"], select, textarea {
  background: rgba(0, 0, 0, .35); border-color: rgba(255, 255, 255, .16);
  border-radius: 10px;
  transition: border-color .15s, box-shadow .15s;
}
input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus,
select:focus, textarea:focus {
  outline: none; border-color: rgba(253, 181, 21, .7);
  box-shadow: 0 0 0 3px rgba(253, 181, 21, .16);
}
input::placeholder, textarea::placeholder { color: var(--ink-faint); }

/* ---------- списки и пункты ---------- */
.item { border-color: rgba(255, 255, 255, .1); background: rgba(255, 255, 255, .03); transition: background .15s, border-color .15s; }
.item:hover { background: rgba(255, 255, 255, .07); }
.item.on {
  background: var(--ink); color: var(--ink-on); font-weight: 600;
  box-shadow: 0 6px 18px rgba(236, 233, 225, .14);
}

/* ---------- игровые реплики: стеклянные пузыри ---------- */
.game-main .msg {
  background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .02));
  border-color: rgba(255, 255, 255, .13);
  border-radius: 14px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .3);
}
.game-main .msg.user {
  background: linear-gradient(180deg, rgba(233, 33, 61, .14), rgba(233, 33, 61, .06));
  border-color: rgba(233, 33, 61, .35);
}
.game-main .mcard {
  background: rgba(20, 20, 25, .96);
  border-color: rgba(255, 255, 255, .16);
  border-radius: 10px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, .6);
}
.msg.room.user .mb, .msg.dm.user .mb {
  background: linear-gradient(135deg, rgba(233, 33, 61, .16), rgba(233, 33, 61, .07));
  border-color: rgba(233, 33, 61, .3); color: var(--ink);
}

/* ---------- вход: витрина ---------- */
.login-screen {
  background:
    radial-gradient(900px 500px at 50% -10%, rgba(233, 33, 61, .22), transparent 60%),
    radial-gradient(700px 420px at 85% 110%, rgba(253, 181, 21, .12), transparent 55%),
    linear-gradient(180deg, var(--bg), var(--bg-deep));
}
.login-card {
  background: linear-gradient(180deg, rgba(33, 33, 40, .92), rgba(24, 24, 29, .94));
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 16px;
  backdrop-filter: blur(12px);
  box-shadow: 0 34px 90px rgba(0, 0, 0, .6);
}
.login-card h2, .login-card .b18.big { text-align: center; }
.login-card .b18.big { background: rgba(233, 33, 61, .15); border-color: rgba(233, 33, 61, .6); color: var(--hot-ink); }

/* ---------- статусы и пустые состояния ---------- */
.empty {
  background: rgba(255, 255, 255, .03); border-color: rgba(255, 255, 255, .22);
  color: var(--ink-dim);
}
.err { background: rgba(248, 113, 113, .1); border-color: rgba(248, 113, 113, .55); color: #fca5a5; }
.ok-line { background: rgba(74, 222, 128, .08); border-color: rgba(74, 222, 128, .4); }

/* ---------- фокус для клавиатуры: янтарное кольцо ---------- */
:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }
button:focus-visible, .chip:focus-visible, .btn:focus-visible {
  outline: 2px solid var(--acc); outline-offset: 2px;
}

/* ---------- скроллбары ---------- */
* { scrollbar-color: #3d3d46 transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: #3d3d46; border-radius: 999px;
  border: 2px solid transparent; background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: #55555f; background-clip: content-box; }

/* ---------- маркдаун-подсветка выделения ---------- */
::selection { background: rgba(253, 181, 21, .35); color: #fff; }

/* ---------- нижний таббар (телефон): глубокое стекло ---------- */
@media (max-width: 700px) {
  .tabs {
    background: linear-gradient(180deg, rgba(17, 17, 21, .92), rgba(13, 13, 16, .97));
    backdrop-filter: blur(12px);
    border-top: 1px solid rgba(255, 255, 255, .1);
    box-shadow: 0 -10px 34px rgba(0, 0, 0, .55);
  }
  .tabs button.on {
    background: transparent; color: var(--acc); border-radius: 0;
    box-shadow: inset 0 -3px 0 var(--acc);
  }
  /* при скине заливку акцентом рисует skin-блок — текст контрастный к акценту */
  body.skinned-me .tabs button.on {
    background: var(--skin-accent, var(--ink));
    color: var(--skin-accent-ink, var(--ink-on)); border-radius: 0; box-shadow: none;
  }
}

/* ---------- текстуры st-* на тёмном ---------- */
body.st-strict .m-hud, body.st-strict .m-scene, body.st-strict .card, body.st-strict .thread {
  background-image: repeating-linear-gradient(90deg, rgba(255, 255, 255, .04) 0 1px, transparent 1px 7px);
}
body.st-gothic .m-hud, body.st-gothic .m-scene, body.st-gothic .card, body.st-gothic .thread {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Cpath d='M20 3 C26 10 30 14 37 20 C30 26 26 30 20 37 C14 30 10 26 3 20 C10 14 14 10 20 3 Z' fill='none' stroke='rgba(200,170,220,.08)' stroke-width='1.2'/%3E%3Ccircle cx='20' cy='20' r='2.5' fill='rgba(200,170,220,.07)'/%3E%3C/svg%3E");
}

/* ---------- дельты статов: белые стикеры (AA-цвета из :root — на белом) ---------- */
.delta {
  background: #fff;
  box-shadow: 0 3px 10px rgba(0, 0, 0, .45);
  border-color: var(--c, #111);
}

/* ---------- пресеты акцента темы (фаза 6) ---------- */
.acc-presets { display: flex; gap: 8px; flex-wrap: wrap; }
.acc-preset {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 40px; padding: 6px 12px;   /* тап ≥40px */
  background: var(--hover); border: 1px solid var(--line); border-radius: 999px;
  color: var(--ink); font: inherit; font-size: 13px; cursor: pointer;
  transition: border-color .15s, background .15s;
}
.acc-preset i { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto; }
.acc-preset:hover { border-color: var(--line-strong); }
.acc-preset.on { border-color: var(--acc); box-shadow: 0 0 0 2px color-mix(in srgb, var(--acc) 30%, transparent); font-weight: 700; }
.acc-preset:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }

/* ═══════════════ фаза 4 — зональные фоны и глубина ═══════════════
   У каждой зоны своя атмосфера: игра — тёплая и спокойная (янтарный
   боковой свет вместо киновари — киноварь остаётся каталогу/логину),
   статистика — холоднее (сине-фиолетовый подтон под графики).
   Виньетка ленты — слоем фона .game-main: края мягко темнеют,
   взгляд фокусируется на центре сцены (кинематограф). */

/* зона ИГРЫ: только полупрозрачные слои — скин-фон body.skinned-me
   (10% тинта) остаётся видимым, гасится лишь киноварь body;
   виньетка + тёплый боковой свет фиксированы к окну (не к скроллу) */
.game-main {
  background:
    radial-gradient(ellipse 78% 66% at 50% 44%, transparent 42%, rgba(0, 0, 0, .26) 100%),
    radial-gradient(1300px 700px at 100% 0%, rgba(253, 181, 21, .07), transparent 55%),
    radial-gradient(1100px 800px at 0% 100%, rgba(253, 181, 21, .05), transparent 60%);
  /* .game-main НЕ скроллится (скроллятся .msgs внутри), поэтому fixed ничего
     не менял по виду, но заставлял браузер перерисовывать фон при прокрутке
     ленты. См. body выше. */
}

/* зона СТАТИСТИКИ: холодный подтон (только слои — без непрозрачной базы,
   общий body-градиент виден сквозь; класс ставит stats.js, снимает app.js) */
#pane.zone-stats {
  background:
    radial-gradient(1200px 700px at 12% -8%, rgba(96, 165, 250, .08), transparent 60%),
    radial-gradient(1000px 600px at 92% 105%, rgba(167, 139, 250, .07), transparent 55%);
}

/* ═════════════════════════════════════════════════════════════════════════
   ПРИЧЁСКА 03.11 — одна палитра и один ритм там, где они сбивались.

   1) Устав и сцена были «пергаментными»: #1f1d18, #d9cba6, #7a6f57 — бежевое
      дерево поверх тёмного неона. Смотрится как чужая тема в чужом окне и
      не подчиняется скину. Переводим на токены сайта: тот же тёплый устав,
      но один набор цветов, контраст AA, и скин-панель работает как везде.
   2) Чипы «что изменил ход» (act-chip) рисовались светло-бежевой рамкой —
      на тёмном это самые контрастные линии на экране, хотя это подпись.
      Мягче: фон-впадина + линия темы, текст основного цвета.
   ═════════════════════════════════════════════════════════════════════════ */

/* ---- панели сцены/устава: палитра сайта вместо пергамента ---- */
.scene-dock, .m-hud, .m-scene, .sd-card { background: var(--card-2); border-color: var(--line); color: var(--ink); }
.scene-dock, .m-hud { border-top-color: var(--line); }
.sd-place, .sd-note { color: var(--ink-dim); }
.sd-place b { color: var(--ink); }
.sd-desc { color: var(--ink-dim); }
.sd-count { background: var(--sunken); border-color: var(--line); color: var(--ink-dim); }
.sd-count.part { border-color: rgba(251, 146, 60, .55); color: var(--warn); background: rgba(251, 146, 60, .12); }
.sd-count.full { border-color: rgba(248, 113, 113, .55); color: var(--danger); background: rgba(248, 113, 113, .12); }
.sd-refresh { background: var(--sunken); border-color: var(--line); color: var(--ink); }
.sd-refresh:hover { background: var(--hover); border-color: var(--line-strong); }
.sd-obj { background: var(--sunken); border-color: var(--line); }
.sd-obj:hover { background: var(--hover); border-color: var(--line-strong); }
.sd-obj.sel { border-color: var(--acc); box-shadow: inset 0 0 0 1px var(--acc); background: var(--hover); }
.sd-obj i { color: var(--ok); background: rgba(74, 222, 128, .12); }
.sd-mini { border-style: solid; border-color: var(--line-strong); color: var(--ink-dim); }
.sd-mini:hover { background: var(--hover); color: var(--ink); }
.sd-note.ok { color: var(--ok); }
.sd-modal { background: rgba(8, 8, 10, .55); }
.sd-card { border-color: var(--line-strong); box-shadow: 0 -12px 40px rgba(0, 0, 0, .55); }
.sd-card-desc { color: var(--ink-dim); }
.sd-card-head i { color: var(--ok); background: rgba(74, 222, 128, .12); }

/* ---- подпись последствий хода: тише, но читаемо ---- */
.act-note { border: 1px solid transparent; color: var(--ink); }
.act-note.ok { border-color: rgba(74, 222, 128, .4); }
.act-note.bad { border-color: rgba(248, 113, 113, .4); }
.act-chip {
  background: var(--sunken); border: 1px solid var(--line);
  border-radius: 8px; padding: 2px 8px; color: var(--ink);
}
/* «ФИНАЛ: …» — не просто чип, а состояние игры: тёплая плашка с иконкой.
   :first-of-type, потому что первым ребёнком теперь идёт кнопка «−/+». */
.act-chip:first-of-type { border-color: var(--line-strong); background: var(--hover); font-weight: 600; }
/* Список последствий длиннее самого чата: на телефоне 8 строк фактов съедали
   пол-экрана (265px против 262px реплики). Свой скролл с потолком — чат
   остаётся главным, факты доступны прокруткой. На ПК потолок выше. */
.act-notes { max-height: 32vh; overflow-y: auto; overscroll-behavior: contain; }
@media (min-width: 701px) { .act-notes { max-height: 220px; } }

/* ---- композер игры на телефоне: две строки вместо трёх ----
   Было: поле на всю ширину, ниже модель + меню + картинка, и отдельной
   третьей строкой «Отправить» во всю ширину. Кнопка съедала ~50px высоты
   чата ради одного слова. Теперь: поле целиком, под ним модель + меню +
   картинка + отправка в один ряд; отправка — компактная, но ≥44px. */
@media (max-width: 700px) {
  #gameComposer { gap: 6px; padding: 8px; }
  #gameComposer input[type="text"] { flex: 1 1 100%; }
  #gameComposer select { flex: 1 1 0; min-width: 0; }
  #gameComposer .btn.primary { flex: 0 0 auto; min-height: 44px; padding: 0 14px; }
  #gameComposer #imgSceneBtn, #gameComposer .menu-wrap .chip {
    min-width: 44px; min-height: 44px; padding: 0; font-size: 15px;
  }
}
/* ---- три кнопки устава: 48px были выше, чем нужно строке подписей ---- */
@media (max-width: 900px) {
  .m-hud { padding: 6px 8px; gap: 6px; }
  .m-hud .chip { min-height: 38px; padding: 4px 12px; }
}


/* ═════════ окна (предмет скина «окно») — ПОСЛЕДНЕЕ СЛОВО ═════════
   Слот window — это ТЕКСТУРА окна (картинка) или его тон (hex-цвет).
   Окна в этом интерфейсе: любая внешняя карточка .card (игры, персонажи,
   комнаты, личные сообщения, статистика, инвентарь…), переписка .thread
   (комната, ЛС, игра), диалог .ov-card (тарифы, профиль, друзья, настройки,
   память игры…) и шторка сцены .sd-card.

   ВАЖНО №1: раньше фон задавался шорткатом
     background: var(--skin-window-img, none) center/cover, color-mix(…)
   — такая запись невалидна, браузер выбрасывал ВСЮ декларацию, и текстура
   не показывалась нигде. Теперь слои разнесены на longhand: картинка —
   background-image, тон — background-color.

   ВАЖНО №2: блок стоит в конце файла намеренно. Ниже середины style.css
   объявлены плотные заливки (body.skinned-me .ov-body, #overlay .ov-card.prof-*),
   и на равной специфичности выигрывает тот, кто ниже.

   ВАЖНО №3: .card внутри .card/.thread/.ov-card/.sd-card — это НЕ окно, а
   строка списка или блок внутри окна; им текстуру не даём (иначе двойной
   рисунок и грязь). */
body.has-window .card:not(.card .card):not(.thread .card):not(.ov-card .card):not(.sd-card .card),
body.has-window .thread,
body.has-window .ov-card,
body.has-window .sd-card { position: relative; isolation: isolate; }

body.has-window .card:not(.card .card):not(.thread .card):not(.ov-card .card):not(.sd-card .card)::before,
body.has-window .thread::before,
body.has-window .ov-card::before,
body.has-window .sd-card::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  border-radius: inherit;
  /* текстура окна: тянется по окну, не плиткой — арты рисуют 320×400 под окно */
  background-image: var(--skin-window-img, none);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  /* тон окна (hex-предмет) — подложка под текстурой */
  background-color: color-mix(in srgb, var(--skin-window, transparent) 16%, transparent);
}
/* z-index: -1 + isolation: isolate на самом окне = текстура ложится НАД фоном
   окна, но ПОД всем содержимым. Детям ничего не назначаем специально: иначе
   ломается position: sticky у шапки игры и реек дашборда (у них свои z-index). */

/* поверх текстуры — ТОЛЬКО затемняющая плёнка, а не плотная заливка:
   иначе предмет видно лишь там, где нет содержимого. Плёнка одна на все
   поверхности окна, поэтому контраст текста одинаковый. */
body.has-window .ov-head,
body.has-window .thread > .thread-head {
  background:
    linear-gradient(rgba(10, 10, 13, .55), rgba(10, 10, 13, .55)),
    color-mix(in srgb, var(--skin-window, transparent) 22%, transparent);
  backdrop-filter: blur(3px);
}
body.has-window .thread > .composer {
  background:
    linear-gradient(rgba(10, 10, 13, .58), rgba(10, 10, 13, .58)),
    color-mix(in srgb, var(--skin-window, transparent) 18%, transparent);
  backdrop-filter: blur(3px);
}
body.has-window .ov-body { background: linear-gradient(rgba(10, 10, 13, .34), rgba(10, 10, 13, .34)); }
body.has-window .ov-body .card { background: color-mix(in srgb, var(--card) 48%, transparent); backdrop-filter: blur(2px); }
body.has-window .thread .msgs { background: color-mix(in srgb, var(--sunken) 82%, transparent); }
body.has-window .sd-card .sd-card-desc,
body.has-window .sd-card .sd-card-head { text-shadow: 0 1px 2px rgba(0, 0, 0, .55); }

/* профиль: у него id-селекторы (#overlay .ov-card.prof-*) и заливка цветами
   ВЛАДЕЛЬЦА профиля — их тоже переводим на плёнку, иначе текстура видна только
   в рамке вокруг тела окна. У .prof-ov своя витрина (шапка/тело/шов) — её не
   перебиваем, плёнка нужна только профилю без скина и прочим диалогам. */
body.has-window #overlay .ov-card.prof-bare .ov-head {
  background:
    linear-gradient(rgba(10, 10, 13, .55), rgba(10, 10, 13, .55)),
    color-mix(in srgb, var(--skin-window, var(--sk-panel, transparent)) 22%, transparent);
  backdrop-filter: blur(3px);
}
body.has-window #overlay .ov-card.prof-bare .ov-body { background: linear-gradient(rgba(10, 10, 13, .34), rgba(10, 10, 13, .34)); }
body.has-window #overlay .ov-card:not(.prof-ov) .ov-body { background: linear-gradient(rgba(10, 10, 13, .34), rgba(10, 10, 13, .34)); }

/* ═════════ полоса из инвентаря: предмет «верхняя панель» ═════════
   Полоса под заголовком секции (h4::after) была фирменным киноварно-янтарным
   градиентом. Надетый предмет верхней панели заменяет её своим цветом/темой —
   ровно так же, как неоновая нить .topbar::after в шапке. Без предмета —
   прежний градиент. */
body.skin-topbar-matrix h4::after {
  background: linear-gradient(90deg, transparent 2%, #00ff41 22%, #00ff41 78%, transparent 98%);
  box-shadow: 0 0 10px rgba(0, 255, 65, .55);
}
body.skin-topbar-toxic h4::after {
  background: linear-gradient(90deg, #2f8f22, #8bff5a 45%, #57c93a 75%, #2f8f22);
  box-shadow: 0 0 10px rgba(92, 201, 58, .5);
}
body.skin-topbar-solid h4::after {
  background: var(--skin-topbar);
  box-shadow: 0 0 10px color-mix(in srgb, var(--skin-topbar) 60%, transparent);
}
/* в диалоге «Тарифы и токены» полос не надо вовсе (просьба юзера) */
h4.plain::after, .plain h4::after { display: none; }

/* ═════════ #actNotes: кнопка «−/+» в правом верхнем углу ═════════ */
.act-notes { position: relative; padding-right: 38px; }
.act-toggle {
  position: absolute; top: 4px; right: 4px; width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  padding: 0; margin: 0; border: 1px solid var(--line-strong); border-radius: 7px;
  background: var(--card); color: var(--ink); font-size: 16px; line-height: 1;
  cursor: pointer; z-index: 2;
}
.act-toggle:hover { background: var(--hover); }
/* свёрнуто: одна строка — первый чип (обычно ФИНАЛ), остальное спрятано */
.act-notes.min { max-height: 36px; overflow: hidden; }
.act-notes.min .act-chip:not(:first-of-type),
.act-notes.min > b { display: none; }
@media (max-width: 700px) {
  .act-notes { padding-right: 44px; }
  .act-toggle { width: 34px; height: 34px; font-size: 18px; }
}

/* ═════════ ФОРМЫ ОКОН: силуэт задаёт сам предмет ═════════
   Текстура окна (слот window) — это материал, «чем окно обито». Форму окна
   задаёт предмет: у пергамента рваный край, у витрины стеклянная фаска, у
   терминала прямые углы с неоновой обводкой. Класс body.win-shape-* ставит
   applyMySkin по id надетого окна.
   Меняем только border-radius и outline: outline не участвует в расчёте
   размеров, поэтому ни один список не «прыгает» при смене окна. */
body[class*="win-shape-"] :is(
  .card:not(.card .card):not(.thread .card):not(.ov-card .card):not(.sd-card .card),
  .thread, .ov-card:not(.prof-ov), .sd-card
) { outline-offset: -1px; }

/* пергамент: неровный, «оборванный» край */
body.win-shape-deckle :is(.card:not(.card .card):not(.thread .card):not(.ov-card .card):not(.sd-card .card), .thread, .ov-card:not(.prof-ov), .sd-card) {
  border-radius: 12px 4px 10px 6px / 6px 10px 4px 12px;
  outline: 1px solid rgba(124, 92, 48, .5);
  box-shadow: inset 0 0 22px rgba(74, 50, 20, .28);
}
/* витрина: острая стеклянная фаска */
body.win-shape-glass :is(.card:not(.card .card):not(.thread .card):not(.ov-card .card):not(.sd-card .card), .thread, .ov-card:not(.prof-ov), .sd-card) {
  border-radius: 3px;
  outline: 1px solid rgba(214, 240, 255, .5);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .07), inset 0 1px 0 rgba(255, 255, 255, .16);
}
/* обсидиан с золотом: двойная обводка, крупный радиус */
body.win-shape-regal :is(.card:not(.card .card):not(.thread .card):not(.ov-card .card):not(.sd-card .card), .thread, .ov-card:not(.prof-ov), .sd-card) {
  border-radius: 11px;
  outline: 1px solid rgba(246, 214, 122, .55);
  box-shadow: inset 0 0 0 4px rgba(246, 214, 122, .12), inset 0 0 0 5px rgba(0, 0, 0, .45);
}
/* терминал: прямые углы и неоновая обводка */
body.win-shape-tech :is(.card:not(.card .card):not(.thread .card):not(.ov-card .card):not(.sd-card .card), .thread, .ov-card:not(.prof-ov), .sd-card) {
  border-radius: 0;
  outline: 1px solid rgba(0, 255, 204, .5);
  box-shadow: inset 0 0 0 3px rgba(0, 255, 204, .08), 0 0 14px rgba(0, 255, 204, .12);
}
/* изумруд: круглые углы, светлая кромка стекла */
body.win-shape-round :is(.card:not(.card .card):not(.thread .card):not(.ov-card .card):not(.sd-card .card), .thread, .ov-card:not(.prof-ov), .sd-card) {
  border-radius: 20px;
  outline: 1px solid rgba(140, 246, 190, .45);
  box-shadow: inset 0 0 0 1px rgba(200, 255, 225, .08);
}
/* аврора: мягкое свечение по контуру */
body.win-shape-soft :is(.card:not(.card .card):not(.thread .card):not(.ov-card .card):not(.sd-card .card), .thread, .ov-card:not(.prof-ov), .sd-card) {
  border-radius: 24px;
  outline: 1px solid rgba(196, 176, 255, .42);
  box-shadow: 0 0 20px rgba(120, 140, 255, .14), inset 0 0 26px rgba(90, 120, 220, .10);
}

/* ═════════ витрина профиля: весь надетый скин на самом окне ═════════
   Юзер хвалится не списком предметов, а ОБЛИКОМ своего профиля: текстура окна
   (window), тон панели в шапке и теле (panel), цвет ника (color), акцентная
   рамка окна (accent), кадр вокруг аватара (frame) и шов верхней панели под
   шапкой (topbar). Переменные --sk-* ставит openProfile через skinVarsCss,
   тему шва — атрибут data-tb. */
#overlay .ov-card.prof-ov { position: relative; isolation: isolate; overflow: hidden; }
/* текстура окна владельца — поверх моего «has-window», поэтому с id */
#overlay .ov-card.prof-ov::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  border-radius: inherit;
  background-image: var(--sk-window-img, none);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  background-color: color-mix(in srgb, var(--sk-window, transparent) 16%, transparent);
}
/* шапка: тон панели владельца + шов его верхней панели (как .topbar::after) */
#overlay .ov-card.prof-ov .ov-head {
  position: relative;
  background: color-mix(in srgb, var(--sk-panel, var(--hover)) var(--sk-panel-mix, 22%), var(--hover));
  border-bottom-color: color-mix(in srgb, var(--sk-accent, var(--line)) 45%, var(--line));
}
#overlay .ov-card.prof-ov[data-tb] .ov-head::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  pointer-events: none;
  background: var(--sk-topbar, transparent);
  box-shadow: 0 0 10px color-mix(in srgb, var(--sk-topbar, transparent) 60%, transparent);
}
#overlay .ov-card.prof-ov[data-tb="matrix"] .ov-head::after {
  background: linear-gradient(90deg, transparent 2%, #00ff41 26%, #00ff41 74%, transparent 98%);
  box-shadow: 0 0 10px rgba(0, 255, 65, .6);
}
#overlay .ov-card.prof-ov[data-tb="toxic"] .ov-head::after {
  background: linear-gradient(90deg, #2f8f22, #8bff5a 45%, #57c93a 75%, #2f8f22);
  box-shadow: 0 0 10px rgba(92, 201, 58, .55);
}
/* тело: плёнка плотнее общей (52%) — под ней может быть ЛЮБОЙ арт владельца,
   а текст профиля (био, статы) должен читаться; текстура остаётся видна в
   шапке и по краям окна */
#overlay .ov-card.prof-ov .ov-body {
  background:
    linear-gradient(rgba(10, 10, 13, .52), rgba(10, 10, 13, .52)),
    color-mix(in srgb, var(--sk-panel, transparent) 10%, transparent);
}
#overlay .ov-card.prof-ov .prof-nick { color: var(--sk-color, var(--ink)); }
/* кадр аватара: на обёртке, иначе ::after у <img> не рисуется */
#overlay .ov-card.prof-ov .prof-av-fr { flex: none; }

/* ═════════ «Тарифы и токены»: перелистывание тарифы ⇄ пакеты ═════════
   Не длинный скролл, а две страницы: свайп влево-вправо (на телефоне свайп
   вверх наверху страницы — это pull-to-refresh браузера), колесо мыши и
   кнопки-точки. Текстуры окна и полосы h4 тут нет (просьба юзера). */
body.has-window .ov-card.plain::before { content: none; }
.ov-card.plain .ov-head { background: var(--hover); backdrop-filter: none; }
.ov-card.plain .ov-body { background: none; }
.ov-card.plain .ov-body .card { background: var(--card); backdrop-filter: none; }
/* профильные правила окна идут с id (#overlay …) — их перебиваем отдельно */
body.has-window #overlay .ov-card.plain .ov-head { background: var(--hover); backdrop-filter: none; }
body.has-window #overlay .ov-card.plain .ov-body { background: none; }
/* touch-action: pan-y — вертикальный скролл остаётся браузеру, горизонтальный
   жест доходит до touchend (иначе свайп влево-вправо «глотается» скроллом) */
.showcase-flip { display: block; --flip-from: 26px; touch-action: pan-y; }
.flip-page { display: none; }
.showcase-flip[data-show="plans"] .flip-page[data-page="plans"],
.showcase-flip[data-show="packs"] .flip-page[data-page="packs"] { display: block; animation: wmFlipIn .26s ease-out; }
@keyframes wmFlipIn {
  from { opacity: 0; transform: translateX(var(--flip-from, 26px)); }
  to { opacity: 1; transform: none; }
}
.flip-dots {
  position: sticky; bottom: 0; display: flex; gap: 8px; justify-content: center;
  padding: 10px 0 2px; background: linear-gradient(transparent, var(--card) 55%);
}
.flip-dot {
  min-height: 34px; padding: 0 14px; border-radius: 999px;
  border: 1px solid var(--line-strong); background: var(--card);
  color: var(--ink-dim); font-size: 12px; letter-spacing: .04em; cursor: pointer;
}
.flip-dot.on { background: var(--ink); border-color: var(--ink); color: var(--ink-on); font-weight: 600; }
@media (max-width: 700px) { .flip-dot { min-height: 40px; } }
@media (prefers-reduced-motion: reduce) {
  .showcase-flip[data-show="plans"] .flip-page[data-page="plans"],
  .showcase-flip[data-show="packs"] .flip-page[data-page="packs"] { animation: none; }
}


/* ---------- «Чейнджлоги»: комната только для чтения ----------
   Сюда пишет SYSTEM (посты из папки data/changelog), игроки только читают.
   Кнопка «копировать» у админа — для переноса записи в соцсети: показываем
   её сразу, а не по ховеру, иначе на телефоне до неё не добраться. */
.who-sys { color: var(--ink); letter-spacing: .05em; font-weight: 800; }
.role-tag.sys {
  color: var(--ink-dim); border: 1px solid currentColor; border-radius: 6px;
  padding: 0 4px; font-size: 9px; letter-spacing: .06em; text-transform: uppercase;
}
.msg.role-system .mavatar-ph { color: var(--ink-dim); }
.msg.role-system .msg-acts {
  position: static; opacity: 1; pointer-events: auto; transform: none;
  background: transparent; border: 0; box-shadow: none; padding: 0; margin-top: 6px;
}
.msg.role-system .text { white-space: pre-wrap; }
.mini.ok { color: var(--ok); }
.composer.ro-only {
  justify-content: center; align-items: center; min-height: 44px;
  font-size: 12px; padding: 10px 14px; text-align: center;
}
.composer.ro-only .dim { white-space: normal; line-height: 1.35; }

/* ---------- фактура по умолчанию: серые панели без текстуры --------------
   Жалоба: «много серых панелей, которым не хватает текстур». Пока игрок не
   надел окно-скин, панели — плоская заливка. Добавляем тонкую «бумажную»
   фактуру: почти невидимые точки + мягкий вертикальный градиент. Это
   background-image, поэтому цвет от --card остаётся, а текстура окна-предмета
   (body.has-window ::before) лежит поверх и ничего не ломает. */
.card:not(.card .card),
.item,
.pane,
.pk,
.gcell,
.gm,
.login-card,
.dash-left,
.dash-right,
.ov-card,
.thread,
.sd-card {
  background-image:
    radial-gradient(rgba(255, 255, 255, .05) 1px, transparent 1.2px),
    linear-gradient(180deg, rgba(255, 255, 255, .035), rgba(0, 0, 0, .05));
  background-size: 14px 14px, 100% 100%;
  background-repeat: repeat, no-repeat;
}
@media (prefers-reduced-motion: no-preference) {
  .card, .item, .gcell, .gm { transition: box-shadow .16s, transform .16s; }
}
/* глубже — плотнее фактура: вложенные блоки внутри окна не «светятся» */
.card .card, .ov-body .card, .thread .card { background-image: none; }

/* ---------- 🎁 выбор получателя подарка: друзья списком ---------- */
.gp-list { margin-top: 8px; max-height: 250px; overflow-y: auto; overscroll-behavior: contain; }
.gp-row {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 6px 8px; border: 1px solid transparent; border-radius: 8px;
  background: transparent; color: inherit; font: inherit; cursor: pointer; text-align: left;
}
.gp-row:hover, .gp-row:focus-visible { background: var(--hover); border-color: var(--line); }
.gp-av {
  width: 26px; height: 26px; border-radius: 50%; object-fit: cover; flex: none;
  background: var(--sunken); display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; color: var(--ink-dim);
}
.gp-nick { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gp-st { font-size: 11px; color: var(--ink-dim); flex: none; }
.gp-dot { width: 7px; height: 7px; border-radius: 50%; background: #9ca3af; flex: none; opacity: .6; }
.gp-dot.on { background: #22c55e; opacity: 1; box-shadow: 0 0 0 2px rgba(34, 197, 94, .22); }

.fr-chip { display: inline-flex; align-items: center; gap: 6px; }

/* ---------- HUD как кнопка: в игре раскрывает дашборд, в списке — игру ----- */
#ghHud { cursor: pointer; }
#ghHud:hover { filter: brightness(1.07); }
#ghHud:focus-visible { outline: 2px solid var(--accent, #f59e0b); outline-offset: -2px; }
/* раскрытая панель дашборда показывает всё подробно — плашка HUD убирается */
#ghHud.hud-off { display: none; }
/* пункт «Моих игр» — карточка игры с HUD, а не строка с именем */
.mine-game { display: block; padding: 10px 12px; }
.item-wrap .mine-game { padding-right: 46px; }   /* ✕ не наезжает на чип мира */
.mine-game .mg-head { display: flex; align-items: center; gap: 8px; min-width: 0; }
.mine-game .mg-head .t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mine-game .mg-head .gworld { flex: none; font-size: 11px; }
.mine-game .mg-hudwrap { margin-top: 7px; }
.mine-game .gh-hud.mg-hud {
  background: transparent; border: 0; border-top: 1px dashed var(--line);
  padding: 7px 0 0; gap: 10px;
}
.mine-game .ghu-av { width: 32px; height: 32px; }
.mine-game .ghu-id b { font-size: 12.5px; }
.mine-game .ghu-clock { font-size: 12.5px; }
.mine-game .ghu-penta svg.penta { width: 64px; height: 64px; }
.mine-game .mg-nohud { font-size: 11.5px; padding-top: 5px; }
@media (max-width: 900px) {
  /* в списке HUD остаётся одной компактной строкой: подпись под пентагоном
     не нужна — имя персонажа сцены видно по наведению */
  .mine-game .gh-hud.mg-hud { flex-wrap: nowrap; align-items: center; }
  .mine-game .ghu-penta { width: auto; justify-content: flex-end; border-top: 0; padding-top: 0; }
  .mine-game .ghu-penta svg.penta { width: 52px; height: 52px; }
  .mine-game .ghu-penta-cap { display: none; }
  .mine-game .ghu-av { width: 28px; height: 28px; }
}
.mine-hud { padding: 0; overflow: hidden; cursor: pointer; margin-bottom: 12px; flex: none; }
.mine-hud-top { display: flex; align-items: center; gap: 8px; padding: 9px 12px 2px; font-size: 13px; }
.mine-hud-top .mini { color: var(--ink-dim); font-size: 12px; white-space: nowrap; }
.mine-hud .gh-hud { background: transparent; border-bottom: 0; }
.mine-hud:hover { border-color: var(--line-strong); }
.mine-hud:focus-visible { outline: 2px solid var(--accent, #f59e0b); outline-offset: 2px; }
@media (max-width: 900px) {
  .mine-hud-top { padding: 8px 10px 0; font-size: 12.5px; }
}

/* ---------- «продолжить игру»: ОДНА строка ------------------------------
   Раньше это был баннер на 2–3 строки и отъедал высоту у сетки игр. Теперь
   компактная полоса: название игры слева, картинка персонажа и пентагон
   отношений справа. Панель HUD внутри полосы уже не нужна (герой/часы есть
   в самой игре), поэтому из неё показываем ТОЛЬКО пентагон. */
.hud-strip {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; margin-bottom: 12px; cursor: pointer; min-width: 0;
}
.hud-strip:hover { border-color: var(--line-strong); }
.hud-strip:focus-visible { outline: 2px solid var(--accent, #f59e0b); outline-offset: 2px; }
.hud-strip-go { flex: none; color: var(--acc); font-size: 13px; line-height: 1; }
.hud-strip-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13.5px; }
.hud-strip-note { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hud-strip .gh-hud {
  background: transparent; border: 0; padding: 0; gap: 6px;
  flex: none; min-width: 0; flex-wrap: nowrap;
}
.hud-strip .ghu-hero, .hud-strip .ghu-state { display: none; }
.hud-strip .ghu-penta { flex: none; gap: 6px; }
.hud-strip .ghu-penta svg.penta { width: 56px; height: 56px; }
.hud-strip .ghu-penta-cap { display: none; }
.hud-strip-ch {
  flex: none; width: 40px; height: 40px; border-radius: 8px; object-fit: cover;
  border: 1px solid var(--line-strong); background: var(--sunken);
}
@media (max-width: 900px) {
  .hud-strip { gap: 8px; padding: 7px 10px; }
  .hud-strip-note { display: none; }
  .hud-strip .ghu-penta svg.penta { width: 46px; height: 46px; }
  .hud-strip-ch { width: 34px; height: 34px; }
}
