/* ============================================================
   DM Workspace — «карты на сукне»
   Тёмное сукно игрового стола, панели — листы, разложенные на нём.
   Палитра:  сукно #17201A · пергамент #EFE7D3 · чернила #2B2620
             сургуч #9E3B2F · латунь #B08D4F · линия #CDBFA4
   Шрифты:   Old Standard TT (заголовки) · Alegreya Sans (текст)
             IBM Plex Mono (время, числа)
   ============================================================ */

/* --- шрифты: self-host (шаг 5 ребилда 3.1) --------------------------
   Три голоса §4.1 со своего домена (woff2, latin+cyrillic+ext) — внешних
   хостов у страницы больше нет, CSP default-src 'self' разблокирована.
   +Alegreya Sans 400 italic: «курсив = ремарка мастера» перестал быть
   синтетическим наклоном. unicode-range — как отдавал Google CSS API. */
@font-face {
  font-family: 'Alegreya Sans';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-400i-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-400i-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-400i-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-400-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-400-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-500-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-500-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-500-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-700-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-700-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Alegreya Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/alegreyasans-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/ibmplexmono-400-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/ibmplexmono-400-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/ibmplexmono-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/static/fonts/ibmplexmono-600-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/static/fonts/ibmplexmono-600-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/static/fonts/ibmplexmono-600-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Old Standard TT';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/oldstandardtt-400-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Old Standard TT';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/oldstandardtt-400-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Old Standard TT';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/oldstandardtt-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Old Standard TT';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/oldstandardtt-700-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Old Standard TT';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/oldstandardtt-700-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Old Standard TT';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/oldstandardtt-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Alegreya (СЕРИФ, не Sans) — голос ЧТЕНИЯ: лонгформ вики (Фаза 3.2
   шаг 3, решение PM концепт-сессии). Статические инстансы на вес, как у
   остальных трёх: css2 отдаёт вариативный файл, если попросить сразу
   несколько весов, — тогда 700 был бы тем же файлом, что 400 (жирный
   осью, а не своим рисунком). Токен — --font-read. */
@font-face {
  font-family: 'Alegreya';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreya-400i-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Alegreya';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreya-400i-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Alegreya';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreya-400i-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Alegreya';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreya-400-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Alegreya';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreya-400-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Alegreya';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/alegreya-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Alegreya';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/alegreya-700-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Alegreya';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/alegreya-700-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Alegreya';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/static/fonts/alegreya-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Гравюрные глифы реестра §6.8 (шаг 4 рефаба): сабсет DejaVu Sans
   (свободная лицензия), 7 КБ. До него глифы жили на милости системного
   fallback — «＋» U+FF0B молчал вовсе (в сабсете замаплен на глиф плюса).
   Стоит ПОСЛЕ основных семей в стеках: текст рисуют они, глифы — он. */
@font-face {
  font-family: 'DMWS Glyphs';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/static/fonts/dmws-glyphs.woff2) format('woff2');
  unicode-range: U+00B7, U+00D7, U+2039, U+203A, U+2190-2193, U+2212, U+221E, U+2684, U+2694, U+2699, U+26A0, U+2713, U+2715, U+2726-2727, U+270E, U+271F, U+FF0B;
}

:root {
  --felt: #17201a;
  --felt-deep: #101711;
  --paper: #efe7d3;
  --paper-shade: #e4d9bf;
  /* крещение бродячих hex — шаг 6 рефаба (мораторий §2.3) */
  --paper-card: #f7f0df;  /* лист карточки героя: светлее панели, темнее полей */
  --paper-mute: #efe6cf;  /* тихая плашка на бумаге: блок листа, «выдано», победа */
  --paper-err: #f6e7de;   /* лист беды: фон плашек ошибок (второй розовый схлопнут) */
  --brass-hi: #c6a15f;    /* светлая ступень латуни: блик монограммы (§2.4) */
  --brass-lo: #8a6c3a;    /* тёмная ступень латуни: тень монограммы (§2.4) */
  --ink: #2b2620;
  --ink-soft: #5c5346;
  --wax: #9e3b2f;
  --brass: #b08d4f;
  --brass-ink: #7a5c2a; /* латунь ЧЕРНИЛАМИ на пергаменте (d_design_bible
                           §2.2: латунь заливкой текстом — FAIL 2.5:1,
                           brass-ink — AA 5.0:1); заведён шагом 17 */
  --line: #cdbfa4;

  /* Геометрия контролов (правка PM 18.08): тач держит канон 44/40 (§3.3),
     fine-указка (мышь) компактнее — переключение медиа-блоком в конце файла */
  --ctl-h: 40px;   /* высота поля форм (стандарт PM 25.07) */
  --tap-h: 44px;   /* тач-дожим кнопок наружки/ЛК */
  /* «Мягкая латунь» (выбор PM 18.08, пробник v4): скругления контролов
     и листа поповера; панели/карточки держат прежние радиусы */
  --r-ctl: 9px;    /* кнопки, поля, селекты, сегменты */
  --r-sheet: 12px; /* лист поповера */

  /* Крещение шага 1 ребилда 3.1 (d_design_bible §2.2/§2.4, приёмка PM).
     Светлые листы: */
  --paper-bright: #fbf6e9; /* свежий лист: поля ввода, CTA */
  --paper-tile: #ede4cd;   /* истёртый лист: плитки, плотные ряды */
  --paper-hover: #f4ecd8;  /* лист под пальцем: hover светлых поверхностей */
  --paper-lit: #f3e6d0;    /* лист под верхним светом: титулы на сукне */
  --wax-deep: #863227;     /* сургуч в тени: hover залитых сургучных */
  --brass-deep: #a07f43;   /* латунь в тени: hover залитых латунных */
  /* Сургучная печать (триада градиента): */
  --seal-hi: #b45540; --seal-mid: #8c3226; --seal-lo: #6f2318;
  --seal-quiet: #6f6758;   /* тихая печать: нейтральный статус-пилюля
                              (затемнён с 8b8271: пергамент по нему был
                              3.1:1, стал 4.5:1 AA — шаг 2) */
  /* Жизнь (зелень хитов — один токен на бой и ЛК, §11 п.16): */
  --vital: #5c7a4a;        /* заливка хитов, «в строю» */
  --vital-deep: #4a6741;   /* тёмная жизнь: стабилен, импорт-ok, win-пипы */
  --vital-hi: #6f8f5a;     /* верх градиента полосы ЛК */
  --hp-track: #d9cca9;     /* жёлоб полос (хиты, бюджет, встречная шкала) */
  --ember: #b0762a;        /* тлеющий уголь: низкие хиты, предупреждение */
  /* Мел (текст на сукне — тёмные поверхности кабинета/сетапа/ЛК): */
  --chalk: #cbc2a6;        /* тихий текст на сукне */
  --chalk-dim: #b8ad8f;    /* приглушённый текст/рамки на сукне */
  --chalk-mute: #8f8472;   /* самый тихий: подписи-мета кабинета
                              (осветлён с 6d6350 2.8:1 до 4.5:1 AA — шаг 2;
                              атмосфера не стоит зрения, §10.3) */

  --font-display: "Old Standard TT", "DMWS Glyphs", serif;
  --font-body: "Alegreya Sans", "DMWS Glyphs", sans-serif;
  --font-mono: "IBM Plex Mono", "DMWS Glyphs", monospace;
  /* четвёртый голос — ЧТЕНИЕ (Фаза 3.2 шаг 3): серифная Alegreya для
     лонгформа вики. Интерфейс остаётся на Sans; сериф включается только
     там, где читают подряд (лист статьи), — решение PM концепт-сессии */
  --font-read: "Alegreya", "DMWS Glyphs", Georgia, serif;

  /* Движение (§7.3): тишина по умолчанию, драма по событию */
  --t-tap: 140ms;
  --t-swap: 180ms;
  --t-drama: 400ms;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  /* зерно сукна: виньетка + SVG-шум (склейка двух body-правил, шаг 1 ребилда;
     слои — из позднего правила фазы 1.6, итоговый вид прода не менялся) */
  background:
    radial-gradient(ellipse at 50% -10%, #22301f 0%, transparent 60%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E")
    var(--felt);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
}

/* --- шапка стола ------------------------------------------- */

.table-header {
  max-width: 1360px;
  margin: 0 auto;
  padding: 28px 24px 20px;
  border-bottom: 1px solid var(--brass);
}

.eyebrow {
  margin: 0 0 2px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brass);
}

.campaign-name {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(28px, 4vw, 44px);
  color: var(--paper);
}

/* --- сукно и листы ------------------------------------------ */

.table {
  max-width: 1360px;
  margin: 0 auto;
  padding: 34px 24px 48px;
  display: grid;
  /* правой колонке — минимум 280px (просьба PM 18.08): пара кнопок меню
     («Импорт из LSS» + «＋ Руками») обязана вставать в один ряд */
  grid-template-columns: 1.2fr 1.3fr minmax(280px, 0.55fr);
  gap: 28px;
  align-items: start;
}
/* полный лист героя просит ширины: пока слот формы занят, колонка игроков
   получает больше стола (прецедент :has — крит-селектор сбора боя);
   узкое окно и так одноколоночное */
@media (min-width: 981px) {
  .table:has(#player-form-slot:not(:empty)) {
    grid-template-columns: 1.9fr 1fr minmax(280px, 0.55fr);
  }
  /* раскрытые «Настройки» стола: формы кампании не живут в колонке-спичке —
     правая колонка получает треть стола (переработка PM 15.08) */
  .table:has(.menu__item--settings[open]) {
    grid-template-columns: 1.1fr 1fr minmax(280px, 0.9fr);
  }
  /* обе просьбы разом (форма героя + настройки) — делим пополам края */
  .table:has(#player-form-slot:not(:empty)):has(.menu__item--settings[open]) {
    grid-template-columns: 1.5fr 0.8fr minmax(280px, 0.9fr);
  }
}

.panel {
  position: relative;
  background: linear-gradient(175deg, var(--paper) 0%, var(--paper-shade) 100%);
  border-radius: 3px;
  box-shadow:
    0 1px 0 #ffffff30 inset,
    0 10px 24px -10px var(--felt-deep);
  padding: 34px 22px 22px;
}
/* равный рост листов — свойство СТОЛА (три листа бок о бок), не бумаги:
   вне стола лист живёт в размер содержимого — иначе однострочные панели
   лавки/сделок/летописи тянулись пустым пергаментом (аудит 15.08) */
.table .panel { min-height: 320px; }

/* фирменная деталь: латунный корешок-вкладка у каждого листа */
.panel__tab {
  position: absolute;
  top: -13px;
  left: 18px;
  margin: 0;
  padding: 3px 14px 2px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-top: 2px solid var(--brass);
  border-radius: 2px 2px 0 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
}

/* --- хроника кампании: витрина фактов (2.0.1 шаг 2a) --------- */
.chronicle__jewel {              /* жемчужина: «время в мирах» */
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 15px;
  color: var(--brass-ink);
  margin: 0 0 14px;
}
.chronicle__add {                /* кнопка-свиток «добавить событие» у даты */
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;   /* тап-зона: иконка 20px — цель была вдвое меньше канона */
  min-height: 40px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--brass-ink);
  cursor: pointer;
}
.chronicle__add:hover { color: var(--wax); }
.chronicle__add-icon {
  display: block;                /* без inline-baseline-зазора */
  transform: translateY(-2px);  /* к оптическому центру: у даты есть нижние выносные */
}
.chronicle__empty {              /* пустое состояние — ремарка мастера */
  color: var(--ink-soft);
  margin: 0;
}
.chronicle__cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 14px;
}
.chr-card {
  background: var(--paper-bright);           /* свежий лист (стиль новых окон) */
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 12px 14px;
}
.chr-card__num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 22px;
  line-height: 1.1;
  color: var(--ink);
}
.chr-card__num--drama { color: var(--wax); }        /* беда — сургуч */
.chr-card__num--luck  { color: var(--brass-ink); }  /* подарок — латунь */
.chr-card__label {
  font-size: 12.5px;
  color: var(--ink-soft);
  margin: 4px 0 0;
}
.chronicle__reroll { margin-top: 14px; }

/* форма-заметка (переиспользует .settings под поля) + летопись */
.chronicle-note-form { margin: 0 0 16px; }
.chronicle-note-form__error { color: var(--wax); font-size: 13px; margin: 0 0 8px; }
.chronicle-note-form__actions { display: flex; gap: 10px; margin-top: 4px; }

.chronicle__notes { list-style: none; margin: 16px 0 0; padding: 0; }
.chronicle-note { padding: 10px 0; border-top: 1px solid var(--line); }
.chronicle-note__when {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--brass-ink);
  margin: 0 0 2px;
}
.chronicle-note__title {
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--ink);
  margin: 0;
}
.chronicle-note__body {
  font-size: 13.5px;
  color: var(--ink-soft);
  margin: 3px 0 0;
  white-space: pre-wrap;
}

/* завершённые бои в летописи (2.4 шаг 4) — сестра ленты заметок */
.chronicle__combats { margin: 16px 0 0; }
.chronicle__section {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-size: 15px;
  color: var(--brass-ink);
}
.chronicle-combats { list-style: none; margin: 0; padding: 0; }
.chronicle-combat { padding: 8px 0; border-top: 1px solid var(--line); }
.chronicle-combat__when {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--brass-ink);
  margin: 0 0 2px;
}
.chronicle-combat__name {
  font-family: var(--font-display);
  font-size: 15px;
  color: var(--ink);
  margin: 0;
}
.chronicle-combat__meta {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--ink-soft);
  margin: 2px 0 0;
}

/* --- печати хроники (2.0.1 шаг 2b): пилюля материалом --------
   Материал несёт смысл (d_design_bible §2.1): сургуч — драма, латунь —
   подарок судьбы, тихая пергаментная — верность столу. Новых hex нет:
   заливки существующими токенами (мораторий §2.3). На витрине хроники
   незаработанных не бывает (секции просто нет); на служебном листе
   «Печати» (шаг 2c) они есть — тускло, состоянием .seal--locked. */
.seals {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 14px;
}
.seal__pill {
  display: inline-block;
  padding: 3px 12px 4px;
  border-radius: 999px;
  border: 1px solid transparent;
  font-family: var(--font-display);
  font-size: 14px;
  line-height: 1.25;
}
.seal__pill--wax {                        /* сургуч: драма и необратимость */
  background: var(--wax);
  color: var(--paper);
}
.seal__pill--brass {                      /* латунь: подарок судьбы */
  background: var(--brass);
  color: var(--ink);
}
.seal__pill--quiet {                      /* тихая: верность столу */
  background: var(--paper-shade);
  border-color: var(--line);
  color: var(--ink-soft);
}
.seal__caption {
  font-size: 12.5px;
  color: var(--ink-soft);
  margin: 6px 0 0;
}
/* моно-строки печати одной породы (дата, прогресс, счёт листа) — один
   набор свойств, различия модификаторами: близнецов не плодим */
.seal__when, .seal__progress, .seals__score {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  margin: 2px 0 0;
  color: var(--ink-soft);
}
.seal__when { color: var(--brass-ink); }      /* дата — латунью, она награда */
.seals__score { margin: 0 0 12px; }

/* лист-реестр (шаг 2c): невзятая печать — ПУСТОЙ ОТТИСК: контур материала
   пунктиром по пергаменту, имя чернилами в полную силу. Гасить пилюлю
   прозрачностью нельзя — имя уходит в нечитаемое, а лист именно для того,
   чтобы DM прочёл весь реестр. */
.seal--locked .seal__pill {
  background: none;
  border-style: dashed;
  color: var(--ink-soft);
}
.seal--locked .seal__pill--wax { border-color: var(--wax); }
.seal--locked .seal__pill--brass { border-color: var(--brass-ink); } /* пунктир — UI-рамка: латунь 2.5:1 слепла */
.seal--locked .seal__pill--quiet { border-color: var(--line); }

/* --- игровые часы ------------------------------------------- */

.game-clock {
  text-align: center;
  padding: 18px 0 22px;
  border-bottom: 1px solid var(--line);
}

.game-clock__time {
  margin: 0;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 56px;
  line-height: 1;
  color: var(--brass-ink); /* прибор, не беда: сургуч на мирной панели — решение PM 15.08 */
}

.game-clock__dateline {          /* дата + кнопка-свиток в одну ось */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 10px 0 0;
}
.game-clock__date {
  margin: 0;
  font-family: var(--font-display);
  font-size: 21px;
  line-height: 1;                /* box жмётся к глифам → центр совпадает с иконкой */
}

.game-clock__weekday {
  margin: 2px 0 0;
  color: var(--ink-soft);
  font-size: 14px;
}

/* --- пустые состояния и меню -------------------------------- */

.empty { padding: 18px 4px 0; }
.empty p { margin: 0 0 8px; }
.empty__hint { color: var(--ink-soft); font-size: 14px; }

/* --- меню кампании: список пунктов-аккордеонов --------------
   details/summary — нативный аккордеон без JS; латунный маркер
   вращается на open. Тап-мишень summary — min 44px. ----------- */

.menu { margin: 6px 0 16px; }

.menu__item { border-bottom: 1px solid var(--line); }

.menu__summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 10px 4px;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
}

.menu__summary::-webkit-details-marker { display: none; }

.menu__summary::before {
  content: "";
  width: 0;
  height: 0;
  border-left: 7px solid var(--brass);
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  transition: transform var(--t-tap) ease;
  flex: none;
}

.menu__item[open] > .menu__summary::before { transform: rotate(90deg); }

.menu__summary:hover { background: #00000008; }

.menu__body { padding: 2px 4px 14px 21px; }

/* пункт-ссылка в меню (шаг 13.1): ведёт на свою страницу */
.menu__item--link {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 10px 4px;
  font-weight: 500;
  color: inherit;
  text-decoration: none;
}
.menu__item--link::before {
  content: "";
  width: 0;
  height: 0;
  border-left: 7px solid var(--brass);
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  flex: none;
}
.menu__item--link::after { content: "\203A"; margin-left: auto; color: var(--ink-soft); }
.menu__item--link:hover { background: #00000008; }

/* примитив «подсказка/пустое состояние» (шаг 2 ребилда): .menu__hint жил
   в 8+ местах вне меню — роль получила своё имя .dm-hint; курсив ремарки
   мастера остаётся за <i> внутри (голос §8) */
.dm-hint,
.menu__hint {
  margin: 0 0 10px;
  font-size: 13px;
  color: var(--ink-soft);
}

/* Пресет NPC/мобов в Меню (шаг 13) */
.npcs__list { list-style: none; margin: 0 0 12px; padding: 0; }
.npcs__row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  padding: 6px 0;
  border-bottom: 1px dashed var(--line);
}
.npcs__name { font-weight: 600; }
.npcs__meta {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--ink-soft);
}
.npcs__del { margin-left: auto; min-width: 34px; }
/* ✎ пресета боя прижат вправо к ✕, а не к хвосту состава */
.npcs__edit { margin-left: auto; min-width: 34px; }
.npcs__edit + .npcs__del { margin-left: 0; }
.npcs__note {
  flex-basis: 100%;
  margin: 0;
  font-size: 13px;
  color: var(--ink-soft);
  white-space: pre-line;   /* заметка пресета боя многострочная — как набрана */
}

/* узкая колонка меню: текст кнопки НЕ переносим («Импорт / из LSS» —
   находка PM 18.08), тесно — переносится сама кнопка и растёт во всю
   ширину строкой меню; паддинг ужат под колонку 0.55fr */
.menu__actions { display: flex; flex-wrap: wrap; gap: 8px; }
.menu__actions .btn {
  flex: 1 1 auto;
  white-space: nowrap;
  padding-left: 10px;
  padding-right: 10px;
}

/* «Продавцы» — малый лист на столе (решение PM 12.08: отдельный блок, не
   жилец Меню): список галочек is_open, сами галочки набраны общими
   примитивами .gold-flag/.wax-check. Интервал строк задаёт ОДИН
   источник — gap сетки: одиночный margin примитива .gold-flag (отбивка
   флага от соседнего контента) в стопке гасится, иначе шаг строк
   управлялся бы из двух мест (находка ревью шага) */
.merchants__list {
  margin: 0 0 10px;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 8px;
}
.merchants__list .gold-flag { margin: 0; }
/* правая колонка стола — стопка листов «Продавцы» + «Меню»: обёртка
   занимает грид-ячейку, зазор тот же, что у сетки стола */
.table__col { display: flex; flex-direction: column; gap: 28px; min-width: 0; }
/* малый лист живёт в размер содержимого, а не в рост соседей */
.panel--merchants { min-height: 0; }

/* --- доступность и мобильные -------------------------------- */

/* Канон фокуса (шаг 1 ребилда, §3.3): механика — только outline (high-contrast
   режимы срезают box-shadow — урок 1.6); на сукне — латунное кольцо, на бумаге —
   чернильное; offset 2px, у плотных вложенных сегментов — узаконенный -2px. */
:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 2px;
}

@media (max-width: 980px) {
  .table { grid-template-columns: 1fr; }
  .table .panel { min-height: auto; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
/* --- шаг 2: карточки героев ---------------------------------- */

.btn {
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.01em;
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  background: var(--paper-card);
  color: var(--ink);
  padding: 6px 14px;
  min-height: var(--ctl-h); /* тач-канон пульта: кнопки ~33px усыпали DM-экраны
                               (аудит 15.08); рост — в ногу с полем (18.08) */
  cursor: pointer;
  /* «мягкая латунь» (v4): тень-подъём, hover приподнимает на 1px;
     reduced-motion глушится глобальным правилом доступности */
  box-shadow: 0 1px 2px #10171124, 0 2px 6px #10171114;
  transition: transform 120ms ease, box-shadow 120ms ease,
              background-color 120ms ease, border-color 120ms ease,
              filter 120ms ease;
  /* кнопкой бывает и ссылка (<a class="btn">: «отмена» в бою и луте,
     «+ статья» в вики) — браузерное подчёркивание на залитой кнопке
     читается как дефект. Кнопки-элементы не подчёркиваются и так */
  text-decoration: none;
}
.btn:hover {
  transform: translateY(-1px);
  background: var(--paper-hover);
  border-color: var(--brass-lo);
  box-shadow: 0 2px 4px #10171129, 0 5px 12px #1017111f;
}
.btn:active { transform: translateY(0); box-shadow: 0 1px 2px #10171129; }
/* на бумаге глобальная латунь кольца слепнет — латунь чернилами (AA 5.0);
   механика — outline (урок 1.6), латунное свечение — декор поверх */
.btn:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: 2px;
}

.btn--tap {
  font-family: var(--font-mono);
  font-weight: 600;
  min-width: var(--tap-h);  /* пальце-дружелюбный размер */
  min-height: var(--tap-h); /* боевые тапы дожаты до 44 (решение PM, §3.3) */
  padding: 4px 6px;
}
/* наружка и ЛК живут пальцем: канон 44 (§3.3); мышь — компакт 40 */
.auth .btn,
.lk .btn { min-height: var(--tap-h); }

/* «Мягкая латунь» (выбор PM 18.08, пробник v4): залитые кнопки — материал
   градиентом (прецедент — сургучная печать), hover — свет фильтром,
   подъём наследуется от .btn */
.btn--wax {
  background: linear-gradient(180deg, var(--seal-hi), var(--wax) 45%, var(--wax-deep));
  border-color: var(--wax-deep);
  color: var(--paper-bright); /* пергамент на сургуче — пара §3.1 */
}
.btn--wax:hover {
  background: linear-gradient(180deg, var(--seal-hi), var(--wax) 45%, var(--wax-deep));
  border-color: var(--wax-deep);
  filter: brightness(1.06);
}

/* Латунная CTA-«монета» (шаг 1 ребилда: «Дальше ›» — рутина, не беда;
   схема «чернила на латуни» — AA 4.8:1 по §3.1, светлый верх градиента
   контраст только поднимает) */
.btn--brass {
  background: linear-gradient(180deg, var(--brass-hi), var(--brass));
  border-color: var(--brass-lo);
  color: var(--ink);
  font-weight: 700;
  box-shadow: inset 0 1px 0 #fbf6e93d, 0 1px 2px #1017112e, 0 2px 6px #1017111a;
}
.btn--brass:hover {
  background: linear-gradient(180deg, var(--brass-hi), var(--brass));
  border-color: var(--brass-lo);
  filter: brightness(1.05) saturate(1.03);
  box-shadow: inset 0 1px 0 #fbf6e955, 0 2px 4px #1017112e, 0 5px 12px #10171124;
}
.btn--brass:active { filter: none; }

.btn--ghost {
  border: none;
  padding: 4px 8px;
  color: var(--ink-soft);
  font-size: 13px;
  background: transparent;
  box-shadow: none;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.btn--ghost:hover {
  background: transparent;
  color: var(--ink);
  transform: none;
  box-shadow: none;
}
/* опасная-призрак: беда видна ДО наведения (аудит 15.08), при наведении
   наливается сургучом; wax на бумаге 5.5:1 AA */
.btn--danger {
  color: var(--wax);
  background: transparent;
  border-color: #9e3b2f3d; /* альфа токена --wax */
  box-shadow: none;
}
.btn--danger:hover {
  color: var(--wax-deep);
  background: #9e3b2f12;
  border-color: var(--wax);
  box-shadow: 0 2px 6px #9e3b2f26;
}
.btn--danger:active { box-shadow: none; }
/* призрак-крестики и прочие ghost+danger: ghost раздевает, danger красит —
   рамку тоже гасим, иначе призрак получает пилюлю */
.btn--ghost.btn--danger { border: none; }

.player-card {
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 14px 14px 10px;
  margin-bottom: 14px;
}

.player-card__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
}
.player-card__name {
  margin: 0;
  font-family: var(--font-display);
  font-size: 21px;
  line-height: 1.15;
}
.player-card__meta {
  margin: 2px 0 0;
  color: var(--ink-soft);
  font-size: 13px;
}
.player-card__gold {           /* кошелёк героя (Фаза 2.3): латунь = ресурс, моно */
  margin: 3px 0 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--brass-ink);
}

.ac {
  flex: none;
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  border: 2px solid var(--brass);
  border-radius: 50%;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 17px;
}

/* --- шапка карточки: вдохновение + AC ------------------------ */

.player-card__badges {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
}

.insp {
  flex: none;
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  border: 2px solid var(--ink-soft); /* линия давала 1.6:1 — интерактив невидим */
  border-radius: 50%;
  background: transparent;
  color: var(--ink-soft);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
}

.insp:hover { border-color: var(--brass); color: var(--brass-ink); }

.insp--on {
  border-color: var(--brass);
  background: var(--brass);
  color: var(--paper);
}

.hp { margin-top: 12px; }
.hp__bar {
  height: 10px;
  background: var(--hp-track);
  border-radius: 999px; /* капсула полосы */
  overflow: hidden;
}
.hp__fill {
  height: 100%;
  background: var(--vital);
  transition: width var(--t-swap) ease;
}
.hp__fill--low  { background: var(--ember); }
.hp__fill--crit { background: var(--wax); }

.hp__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 6px;
  gap: 8px;
}
.hp__label {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--ink-soft);
  flex: none;
  white-space: nowrap; /* «38 / 38» не разваливается на мобиле (аудит 15.08) */
}
.hp__num { font-size: 19px; font-weight: 600; color: var(--ink); }
.hp__controls { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
/* два режима ряда HP (переработка PM 27.07): обычный — фикс-кнопки + [±N],
   компакт своего значения скрыт; .hp--custom (вешает app.js) меняет их
   местами. Оба — flex той же геометрии, чтобы ряд не прыгал. */
.hp__fixed, .hp__customrow { display: flex; gap: 6px; align-items: center; }
.hp__customrow { display: none; }
.hp--custom .hp__fixed { display: none; }
.hp--custom .hp__customrow { display: flex; }
/* поле «своё значение хитов» (2.4) — скин от примитива полей (шаг 2), тут
   геометрия боевого ряда. Селектор двойной НАМЕРЕННО: адаптер примитива ниже
   по файлу при одиночном классе перебивал высоту 44→40 и паддинг — поле
   выпадало из ряда тапов (правило «соседей равнять ЯВНО»). Цифры — в размер
   и вес подписей .btn--tap: у поля и кнопок один боевой ряд. */
.hp__controls .hp__custom {
  width: var(--tap-h);
  text-align: center;
  height: var(--tap-h); /* боевой тап — дожат до 44 (решение PM, §3.3);
                           на мыши садится в 38 вместе с рядом ±N (аудит 18.08) */
  padding: 4px 6px;
  font-size: 16px;
  font-weight: 600;
  -moz-appearance: textfield;   /* спиннеры number — дефолт браузера, прячем */
  appearance: textfield;
}
.hp__custom::-webkit-inner-spin-button,
.hp__custom::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.hp__custom:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: 2px;
  border-color: var(--brass);
}

.exhaustion {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
}
.exhaustion__label { font-size: 13px; color: var(--ink-soft); margin-right: auto; }
.exhaustion__pips { display: flex; gap: 5px; }
.pip {
  width: 11px;
  height: 11px;
  border: 1px solid var(--ink-soft);
  border-radius: 50%;
}
.pip--on { background: var(--wax); border-color: var(--wax); }

/* --- спасброски смерти: трекер при 0 хитов --------------------
   Меню win/lose: успехи зелёными пипами, провалы сургучом; тапы ±
   с клэмпом на сервере. Вердикты — три успеха / три провала. */

.death {
  margin-top: 10px;
  padding: 8px 10px;
  border: 1px solid var(--wax);
  border-radius: 3px;
  background: #9e3b2f14;
}

.death--stable { border-color: var(--vital-deep); background: #4a674114; }
.death--dead { background: #9e3b2f2e; }

.death__title,
.death__verdict {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 700;
  color: var(--wax);
}

.death--stable .death__verdict { color: var(--vital-deep); }
.death--dead .death__verdict {
  font-size: 15px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.death__row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 3px 0;
}

.death__label {
  font-size: 13px;
  color: var(--ink-soft);
  margin-right: auto;
}

.death__pips { display: flex; gap: 5px; }

.death__pips--win .pip--on {
  background: var(--vital-deep);
  border-color: var(--vital-deep);
}

/* --- состояния героя: чипы + палитра -------------------------- */

.conds {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 38px;
  padding: 4px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--ink-soft);
  font-family: var(--font-body);
  font-size: 13px;
  cursor: pointer;
}

.chip:hover { background: #00000010; }

.chip--on {
  border-color: var(--ink);
  color: var(--ink);
  background: #2b262012;
  font-weight: 600;
}

.chip--conc.chip--on {
  border-color: var(--brass);
  color: var(--brass-ink);
  background: #b08d4f1f;
}

.chip__x { font-style: normal; font-size: 11px; opacity: 0.6; }

.chip--add { color: var(--ink-soft); border-style: dashed; }

.conds__palette { display: inline-flex; flex-direction: column; }
.conds__palette[open] { flex-basis: 100%; }
.conds__palette > summary { list-style: none; align-self: flex-start; }
.conds__palette > summary::-webkit-details-marker { display: none; }
.conds__palette[open] > summary { border-style: solid; color: var(--ink); }

.conds__list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--line);
}
.btn--pip { min-width: 34px; }


.player-card__actions {
  display: flex;
  justify-content: flex-end;
  gap: 4px;
  margin-top: 8px;
}

/* стрелки порядка: группа слева, править/убрать остаются справа */
.card-order {
  display: flex;
  gap: 4px;
  margin-right: auto;
}

.player-form {
  margin-top: 14px;
  padding: 14px;
  border: 1px dashed var(--brass);
  border-radius: 3px;
}
.player-form__title { margin: 0 0 10px; font-family: var(--font-display); font-size: 18px; }
.player-form label { display: block; font-size: 13px; color: var(--ink-soft); margin-bottom: 10px; }
/* Рисованный чекбокс и радио — ИСКЛЮЧЕНЫ (правило проекта, калька
   .settings input ниже): без исключения display:block + width:100%
   растягивали .wax-check владений в сургучную полосу и ломали ряд
   .prof-check — поймано PM на форме «править» героя (12.08). */
.player-form input:not([type="checkbox"]):not([type="radio"]),
.player-form textarea {
  display: block;   /* скин — примитив полей (шаг 2); тут геометрия */
  width: 100%;
  margin-top: 3px;
}
.player-form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.player-form__actions { display: flex; gap: 8px; margin-top: 4px; }
/* --- шаг 2.5: полный лист и импорт ---------------------------- */


.hp__temp {
  color: var(--brass-ink); /* §3.2: текст на бумаге */
  font-weight: 600;
  margin-left: 2px;
}

.player-form__hint { margin: 0 0 10px; font-size: 13px; color: var(--ink-soft); }
.player-form__error { margin: 0 0 10px; font-size: 13px; color: var(--wax); font-weight: 600; }
.player-form__row--4 { grid-template-columns: repeat(4, 1fr); }

.player-form__abilities {
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 8px 10px 10px;
  margin: 0 0 12px;
}
.player-form__abilities legend {
  font-size: 12px;
  color: var(--ink-soft);
  padding: 0 6px;
}
/* ячейки заклинаний в редакторе героя (шаг 7 «Стола игроков»): девять
   уровней одной линейкой, подпись-цифра над полем — скин fieldset общий
   с характеристиками */
.player-form__slots {
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 8px 10px 10px;
  margin: 0 0 12px;
}
.player-form__slots legend {
  font-size: 12px;
  color: var(--ink-soft);
  padding: 0 6px;
}
.player-form__slots-grid {
  display: grid;
  grid-template-columns: repeat(9, minmax(0, 1fr));
  gap: 6px;
}
.player-form__slots-grid label {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  font-size: 12px;
  color: var(--ink-soft);
}
.player-form__slots-grid input { width: 100%; text-align: center; }

.ab-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: 6px;
  align-items: center;
  margin-bottom: 6px;
}
.ab-grid--head {
  font-size: 11px;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 2px;
}
.ab-grid__name { font-weight: 500; font-size: 14px; }
.ab-grid input { margin-top: 0; text-align: center; font-family: var(--font-mono); }

.skill-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px 12px;
}
.skill-grid__item {
  display: flex !important;
  align-items: center;
  gap: 6px;
  margin-bottom: 2px !important;
  font-size: 13px;
  color: var(--ink);
}
.skill-grid__item input {
  width: 52px;
  margin-top: 0;
  text-align: center;
  font-family: var(--font-mono);
}

.prof-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  align-items: center;
  font-size: 14px;
  margin: 4px 0;
}
.prof-row > span { color: var(--ink-soft); font-size: 13px; min-width: 64px; }
.prof-check {
  display: flex !important;
  align-items: center;
  gap: 5px;
  margin: 0 !important;
  font-size: 14px;
  color: var(--ink);
}
/* прежде тут был accent-color нативного бокса; теперь вид даёт .wax-check
   (17.9) — .prof-check остаётся раскладкой ярлыка (не задаём width) */
.prof-check input { margin: 0; }

/* разворот «Полный лист» */
.sheet { margin-top: 12px; font-size: 14px; }
.sheet > summary {
  cursor: pointer;
  color: var(--brass-ink); /* латунь второй пробы: текст на бумаге, §3.2 */
  font-weight: 500;
}
.sheet__strip {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  padding: 10px 0 6px;
  font-size: 13px;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--line);
}
.sheet__strip b { color: var(--ink); font-family: var(--font-mono); }
.sheet__bg { margin: 8px 0 0; font-size: 13px; color: var(--ink-soft); }

.sheet__stats {
  width: 100%;
  border-collapse: collapse;
  margin-top: 8px;
}
.sheet__stats td { padding: 3px 6px 3px 0; }
.sheet__ability td:first-child { font-weight: 700; font-family: var(--font-display); }
.sheet__ability { border-top: 1px solid var(--line); }
.sheet__skill td { font-size: 13px; }
.sheet__skill-name { padding-left: 18px !important; color: var(--ink-soft); }
.sheet__stats .num { font-family: var(--font-mono); }
.sheet__stats .dim { color: var(--ink-soft); font-size: 12px; }

.sheet__profs { margin: 10px 0 0; font-size: 13px; }
.sheet__block {
  margin-top: 8px;
  padding: 8px 10px;
  background: var(--paper-mute);
  border-radius: 2px;
  white-space: pre-line;
  font-size: 13px;
}
.sheet__block--notes { border-left: 3px solid var(--brass); }

@media (max-width: 980px) {
  .player-form__row--4 { grid-template-columns: 1fr 1fr; }
  .skill-grid { grid-template-columns: 1fr; }
  /* ячейки заклинаний (шаг 7): девять колонок на узком дают поля ~30px —
     складываем линейку в три (находка ревью, паттерн соседних рядов) */
  .player-form__slots-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* --- шаг 2.6: импорт файлом — скин у примитива .dm-file --------------- */
.import-alt { margin-bottom: 10px; }
.import-alt summary {
  cursor: pointer;
  font-size: 13px;
  color: var(--ink-soft);
  margin-bottom: 8px;
}
/* --- шаг 3: календарь ------------------------------------------ */

.skips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  margin-top: 12px;
}
.skips--custom { margin-top: 8px; align-items: center; }
.skips--custom input[type="number"],
.skips--custom select {
  /* скин и высота 40 — примитив полей (шаг 2); был локальный 34 */
  padding: 0 8px;
}
.skips--custom input[type="number"] { width: 64px; text-align: center; }

.month { margin-top: 16px; }
.month__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.month__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 18px;
}

.month__grid {
  width: 100%;
  margin-top: 8px;
  border-collapse: collapse;
  table-layout: fixed;
}
.month__grid th {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  color: var(--ink-soft);
  text-transform: uppercase;
  padding-bottom: 4px;
}
.month__grid td { padding: 1px; text-align: center; }

/* --- подсказка полного имени (хвост 1.7): месяц >15 симв в шапке грида
   сжат до 3 букв капсом, дни недели всегда до 3 букв — полное имя живёт
   в пузыре. Один механизм на все входы без JS: мышь наводит (:hover),
   палец тапает (:focus через tabindex), клавиатура фокусирует. */
.tip {
  position: relative;
  cursor: help;
  border-bottom: 1px dotted var(--ink-soft);
  outline: none;
}
.tip::after {
  content: attr(data-tip);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 6px);
  transform: translateX(-50%);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  line-height: 1.3;
  padding: 5px 9px;
  border-radius: 2px;
  box-shadow: 0 3px 10px #0006;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-tap);
  z-index: 30;
}
.tip:hover::after,
.tip:focus::after { opacity: 1; }
/* краевые дни недели: пузырь прижимается к краю, а не вылетает за панель */
.month__grid th:first-child .tip::after { left: 0; transform: none; }
.month__grid th:last-child .tip::after { left: auto; right: 0; transform: none; }

.day {
  width: 100%;
  max-width: 48px;      /* потолок: при неделе из 2-3 дней ячейки широченные,
                           без потолка квадратная кнопка раздувает ряды */
  margin: 0 auto;
  display: block;
  aspect-ratio: 1;
  border: 1px solid transparent;
  border-radius: 2px;
  background: transparent;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--ink);
  cursor: pointer;
  position: relative;
}
.day:hover { background: #00000010; }
.day--today {
  border-color: var(--wax);
  font-weight: 600;
  color: var(--wax);
}
.day--event::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 3px;
  transform: translateX(-50%);
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--brass);
}
.day--selected { background: #b08d4f33; }

/* Призрак межмесячья: 0-дневный месяц в обычный год — пунктирная приглушённая
   карточка «не в этом году», события ждут високосного года (канон §1.5). */
.month__ghost {
  margin-top: 6px;
  padding: 16px 12px;
  border: 1px dashed var(--line);
  border-radius: 3px;
  text-align: center;
  opacity: .72;
}
.month__ghost-lede {
  margin: 0;
  font-style: italic;
  letter-spacing: .04em;
  color: var(--ink-soft);
}
.month__ghost-ev {
  margin: 8px 0 0;
  font-style: italic;
  font-size: 14px;
  color: var(--ink-soft);
}
.month__ghost-wait { color: var(--brass-ink); white-space: nowrap; }
.month__ghost-hint {
  margin: 8px 0 0;
  font-style: italic;
  font-size: 13px;
  color: var(--ink-soft);
}

.day-detail, .today-events {
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}
.day-detail__title {
  margin: 0 0 8px;
  font-family: var(--font-display);
  font-size: 17px;
}

.event {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 5px 0;
  font-size: 14px;
}
.event__time {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
  flex: none;
  width: 62px;
}
.event__title { flex: 1; }
.event__note { color: var(--ink-soft); font-style: normal; font-size: 13px; }
/* Плавающее (високосное) событие — read-only, из календаря: латунная метка ✦
   в колонке часов (выравнена с обычными событиями), без чипов и удаления. */
.event__float-mark {
  flex: none;
  width: 62px;
  text-align: center;
  color: var(--brass-ink);
  font-size: 13px;
  cursor: default;
}

/* Календарные чипы (таймер часов, тумблер видимости события, статик-плашка
   «сегодня») — свой класс. Раньше это был второй глобальный .chip: он делил
   базу с чипами состояний героя/моба и подавлял их задуманную пилюлю. Дедуп
   17.9: состояния вернулись к пилюле (.chip выше), календарь остался
   компактным моно (self-contained — прежний вид пиксель-в-пиксель). */
.cal-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
  min-height: 38px;
  padding: 2px 9px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: transparent;
  color: var(--ink-soft);
  font-family: var(--font-mono);
  font-size: 11px;
  cursor: pointer;
}
.cal-chip:hover { background: #00000010; }
.cal-chip--players { border-color: var(--vital-deep); color: var(--vital-deep); } /* 11px: vital 3.9:1 не тянул */
.cal-chip--dm { border-color: var(--brass-ink); color: var(--brass-ink); } /* §3.2 */
.cal-chip--static { cursor: default; }

.event-form { margin-top: 10px; }
/* скин полей — примитив (шаг 2); здесь только геометрия рядов */
.event-form input[name="title"], .event-form input[name="note"] {
  width: 100%;
  margin-bottom: 6px;
}
.event-form input[type="time"] { margin-bottom: 6px; }
.event-form__row { display: flex; gap: 6px; }
.event-form__row input[name="title"] { flex: 1; }
/* повтор события: селект — скин из примитива полей (шаг 2) */
.event-form__recur {
  width: 100%;
  margin-bottom: 6px;
}
/* ряд «повтор + длительность»: число и единицы живут только при
   выбранном повторе, единица следует за селектом — всё на :has, без JS */
.event-form__row--recur { align-items: center; }
.event-form__row--recur .event-form__recur { flex: 1; margin-bottom: 6px; }
.recur-len {
  display: none;
  align-items: center;
  gap: 5px;
  margin-bottom: 6px;
}
.recur-len input { width: 64px; } /* скин — примитив полей (шаг 2) */
.recur-len__unit {
  display: none;
  font-size: 12px;
  color: var(--ink-soft);
}
.event-form__row--recur:has(option[value="weekly"]:checked) .recur-len,
.event-form__row--recur:has(option[value="monthly"]:checked) .recur-len,
.event-form__row--recur:has(option[value="yearly"]:checked) .recur-len {
  display: flex;
}
.event-form__row--recur:has(option[value="weekly"]:checked) .recur-len__unit--weekly,
.event-form__row--recur:has(option[value="monthly"]:checked) .recur-len__unit--monthly,
.event-form__row--recur:has(option[value="yearly"]:checked) .recur-len__unit--yearly {
  display: inline;
}
.event-form__recur-hint { display: none; margin: -2px 0 6px; }
.event-form:has(option[value="weekly"]:checked) .event-form__recur-hint,
.event-form:has(option[value="monthly"]:checked) .event-form__recur-hint,
.event-form:has(option[value="yearly"]:checked) .event-form__recur-hint {
  display: block;
}
/* значок серии ↻: подсказка через .tip, но без пунктира — сам символ и
   есть сигнал; латунь отличает от текста, не крича */
.event__recur {
  border-bottom: none;
  color: var(--brass-ink); /* хвост §3.2: латунь ТЕКСТОМ на бумаге — вторая проба */
  font-weight: 700;
}
.event-form__row--actions {
  justify-content: space-between;
  align-items: center;
}

.today-events__item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 4px 0;
  font-size: 14px;
}

.game-clock__timer { margin-top: 10px; padding: 4px 14px; font-size: 12px; }

/* Свёртка календаря: вкладка-тумблер в углу карточки (как «В бой!», но латунная,
   не сургучная), прячет ТОЛЬКО грид и деталь дня — часы, перемотки и «Сегодня»
   остаются видны. Класс cal-compact на <html> ставит скрипт base.html из
   localStorage (сервер не знает; переживает свопы #calendar-panel и F5). */
.panel__tab--fold {
  left: auto;
  right: 18px;
  border-top-color: var(--brass);
  color: var(--brass-ink);
  line-height: inherit;   /* как у <h2>/<a>-вкладок (body 1.5); иначе button-normal ниже */
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}
.panel__tab--fold::before { content: "\25B2"; }               /* ▲ календарь развёрнут — свернуть */
.cal-compact .panel__tab--fold::before { content: "\25BC"; }  /* ▼ свёрнут — развернуть */
.panel__tab--fold:hover { background: var(--paper-hover); }
.cal-compact .panel--calendar .month,
.cal-compact .panel--calendar .day-detail { display: none; }

/* --- шаг 5: настройки ------------------------------------------ */
.settings label { display: block; margin-bottom: 12px; font-size: 14px; }
/* /settings — пересборка PM 16.08: стопка листов-документов аккаунта
   (панельный канон); секции делят сами листы, линейки auth-простыни сняты */
.settings-page { max-width: 640px; }
.settings-panel { margin-top: 26px; }
.settings-panel .settings { max-width: 460px; }
.settings-panel .settings + .settings { margin-top: 14px; }
.settings-panel .settings + .settings--joined { margin-top: 6px; }
/* «‹ Назад» лежит на сукне: латунь первой пробы (brass-ink тут слепнет) */
.settings-page__back a { color: var(--brass); }
.settings-page__back a:hover { color: var(--paper); }
/* скин полей — примитив (шаг 2); здесь геометрия колонки.
   Рисованный чекбокс и радио — ИСКЛЮЧЕНЫ (правило проекта, как у
   .setup__form input и адаптеров примитива): без исключения width:100%
   растягивал .wax-check в широкую сургучную полосу — поймано
   скриншот-приёмкой шага 3 на форме статьи вики. Сегодня чекбокс в
   settings-форме только там, у календаря и сетапа свои формы. */
.settings input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.settings select, .settings textarea {
  display: block;
  width: 100%;
  margin-top: 4px;
}
.settings input:focus-visible,
.settings select:focus-visible,
.settings textarea:focus-visible {
  outline: 2px solid var(--brass-ink); /* фокус «мягкой латуни»: латунь чернилами (AA 5.0) */
  outline-offset: 2px;
}
.settings__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(88px, 1fr));
  gap: 8px;
}
.settings__row label { margin-bottom: 4px; min-width: 0; }
/* input и select рендерятся с разной внутренней геометрией — в ряду
   равняем height явно (урок библии), иначе «Сложность»-селект выше полей */
.settings__row input, .settings__row select {
  min-width: 0;
  height: var(--ctl-h);
  padding: 8px 6px;
}
.settings__hint { font-size: 12px; color: var(--ink-soft); margin: 4px 0 8px; }
span.settings__hint { display: block; }
/* ошибка формы настроек (запрет увода мира, шаг 2 вики) — семья
   ошибок форм: сургуч, как .player-form__error */
.settings__error { margin: 0 0 10px; font-size: 13px; color: var(--wax); font-weight: 600; }

/* --- фаза 1.6: кабинет мастера --------------------------------
   Дизайн-язык: сдержанный скевоморфизм. Текстура и глубина — только там,
   где несут смысл: сукно с зерном, карточки-листы с верхним светом,
   углубление в столе под новый лист. Рамки на интерактиве — всегда
   (режимы высокой контрастности срезают тени). */

.cabinet { max-width: 920px; margin: 0 auto; padding: 40px 16px 60px; }

.cabinet__eyebrow,
.page-head__eyebrow { /* примитив page-head (шаг 3 ребилда): шапка внутренних страниц */
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--brass);
  margin: 0 0 6px;
}
.cabinet__topbar {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}
.cabinet__session { display: flex; align-items: baseline; gap: 12px; }
.cabinet__user {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--brass);
}
.cabinet__logout {           /* светлая ссылка: кабинет на тёмном сукне */
  font-family: var(--font-body);
  font-size: 13px;
  background: none;
  border: none;
  color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  padding: 2px 4px;
}
.cabinet__logout:hover { color: var(--brass); }
.cabinet__title {
  font-family: var(--font-display);
  color: var(--paper);
  font-size: 34px;
  margin: 0;
  text-shadow: 0 2px 8px #000c;
  letter-spacing: 0.02em;
}
.cabinet__rule,
.page-head__rule {
  border: none;
  height: 1px;
  margin: 14px 0 26px;
  background: linear-gradient(90deg, var(--brass), transparent 70%);
}
.cabinet__empty {
  color: var(--chalk);
  font-style: italic;
  margin: 0 0 18px;
}

.cabinet__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 22px;
}

/* карточка = запечатанный конверт: клапан с верхним светом,
   сургучная печать с инициалом кампании, стопка теней на сукне */
.campaign-card {
  position: relative;
  display: block;
  background: linear-gradient(178deg, #f4edda 0%, #ece2ca 70%, #e5dabd 100%);
  border: 1px solid #c6b68c;
  border-radius: 2px;
  padding: 84px 22px 20px;
  text-decoration: none;
  color: var(--ink);
  box-shadow:
    inset 0 1px 0 #fffdf5cc,
    0 1px 2px #0008,
    0 6px 16px #0007;
  transition: transform var(--t-tap) ease, box-shadow var(--t-tap) ease;
}
.campaign-card::before {           /* клапан конверта */
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 62px;
  background: linear-gradient(180deg, #eee3c8, #ddcfab);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  filter: drop-shadow(0 1px 1px #00000038);
}
.campaign-card::after {            /* сургуч с инициалом на острие клапана */
  content: attr(data-initial);
  position: absolute;
  top: 42px;
  left: 50%;
  transform: translateX(-50%);
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--seal-hi), var(--seal-mid) 65%, var(--seal-lo));
  box-shadow: 0 2px 5px #000a, inset 0 1px 2px #ffffff40, inset 0 -2px 4px #00000060;
  color: var(--paper-lit);
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 38px;
  text-align: center;
  text-shadow: 0 1px 1px #0008;
}
.cabinet__grid > .campaign-card:nth-child(3n+1) { rotate: -0.4deg; }
.cabinet__grid > .campaign-card:nth-child(3n+2) { rotate: 0.3deg; }
a.campaign-card:hover, a.campaign-card:focus-visible {
  transform: translateY(-3px);
  box-shadow:
    inset 0 1px 0 #fffdf5cc,
    0 2px 3px #0008,
    0 14px 28px #000a;
}
.campaign-card:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }

.campaign-card__name {
  font-family: var(--font-display);
  font-size: 22px;
  margin: 0 0 8px;
  color: #2b2620;
  text-shadow: 0 1px 0 #fffdf590;   /* letterpress: вдавлено в бумагу */
}
.campaign-card__date {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--ink-soft); /* chalk-mute на конверте — 3.1:1 при 12.5px (аудит 15.08) */
  margin: 0;
}
.campaign-card__meta {
  font-size: 13px;
  color: var(--ink-soft);
  margin: 10px 0 0;
  padding-top: 8px;
  border-top: 1px solid #d8cba533;
}

/* конверт создания = углубление в сукне: без клапана, печать-плюс
   внутри, письмо-форма под ней */
.campaign-card--new {
  display: flex;
  flex-direction: column;
  gap: 12px;
  justify-content: center;
  align-items: stretch;
  padding: 26px 22px 24px;
  background: #00000024;
  border: 1px dashed #b08d4f66;
  box-shadow: inset 0 2px 8px #000a, inset 0 -1px 0 #ffffff10;
  rotate: none !important;
}
.campaign-card--new::before { content: none; }
.campaign-card--new::after { content: none; }
.campaign-card--new:focus-within {
  border-color: var(--brass);
  background: #00000033;
}
.campaign-card__seal {
  position: static;
  transform: none;
  align-self: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--seal-hi), var(--seal-mid) 65%, var(--seal-lo));
  box-shadow: 0 2px 6px #000a, inset 0 1px 2px #ffffff40, inset 0 -2px 4px #00000060;
  color: var(--paper-lit);
  font-size: 24px;
  line-height: 46px;
  text-align: center;
  text-shadow: 0 1px 1px #0008;
  margin-bottom: 2px;
}
.campaign-card--new input {
  padding: 12px 11px;
  font: inherit;
  font-size: 15px;
  color: var(--paper-lit);
  caret-color: var(--brass);
  background: #ffffff12;
  border: 1px solid #b08d4f88;
  border-radius: var(--r-ctl); /* контекст перебивал примитив квадратом 2px (аудит 18.08) */
}
.campaign-card--new input::placeholder { color: #cbc2a6aa; }
.campaign-card--new input:focus {
  outline: none;
  border-color: var(--brass);
  background: #ffffff1e;
}
.campaign-card--new .btn { align-self: center; padding: 10px 30px; }
/* нажатие кабинета — общий .btn:active «мягкой латуни» (локальный дубль снят 18.08) */

/* архив: читаемый, тихий */
.cabinet__archive { margin-top: 30px; }
.cabinet__archive summary {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--chalk-dim);
}
.cabinet__archive summary:hover { color: var(--brass); }
.cabinet__archived-row {
  display: flex;
  gap: 14px;
  align-items: baseline;
  margin: 10px 0 0 18px;
  font-size: 14px;
}
.cabinet__archived-row a { color: var(--paper-shade); }
.cabinet__archived-row a:hover { color: var(--brass); }
.cabinet__archived-row span {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--chalk-dim);
}
/* снос из архива: тихая текст-кнопка у правого края ряда (родня .bst-row__del,
   но на сукне — пары chalk-dim/chalk и hover-латунь уже живут в этом блоке).
   Тот же крестик — у пустого мира (один логический контрол одинаков везде:
   общая селекторная группа, не близнец) */
.cabinet__archived-del { margin-left: auto; }
.cabinet__archived-del button,
.cabinet__world-del button {
  background: none;
  border: 0;
  padding: 2px 6px;
  font-size: 12px;
  color: var(--chalk-dim);
  cursor: pointer;
  border-radius: var(--r-ctl);
}
.cabinet__archived-del button:hover,
.cabinet__world-del button:hover { color: var(--brass); }
.cabinet__archived-del button:focus-visible,
.cabinet__world-del button:focus-visible {
  outline: 2px solid var(--chalk-dim);
  outline-offset: 2px;
}
/* снос пачкой: рамочная тихая кнопка под списком архива (те же пары
   chalk-dim/латунь на сукне, что у соседей по блоку) */
.cabinet__bulk-del {
  margin: 14px 0 2px 18px;
  background: none;
  border: 1px solid var(--chalk-dim);
  padding: 9px 14px;
  font-size: 12px;
  color: var(--chalk-dim);
  cursor: pointer;
  border-radius: var(--r-ctl);
}
.cabinet__bulk-del:hover { color: var(--brass); border-color: var(--brass); }
.cabinet__bulk-del:focus-visible {
  outline: 2px solid var(--chalk-dim);
  outline-offset: 2px;
}
/* [x] сноса черновика — поверх карточки-ссылки (обёртка держит позицию;
   пергамент карточки → пара ink-soft/сургуч, как у .bst-row__del) */
.cabinet__draftwrap { position: relative; }
.cabinet__draft-del {
  position: absolute;
  top: 8px;
  right: 8px;
}
.cabinet__draft-del button {
  background: none;
  border: 0;
  padding: 4px 8px;
  font-size: 14px;
  color: var(--ink-soft);
  cursor: pointer;
  border-radius: var(--r-ctl);
}
.cabinet__draft-del button:hover { color: var(--wax); }
.cabinet__draft-del button:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: 2px;
}
/* чекбокс выбора в ряду архива: меньше примитива и по центру ряда (baseline
   флекс-ряда ронял его ниже строки) — только геометрия, рисованная галочка
   пересчитана под 16px */
.cabinet__archived-row .wax-check {
  width: 16px;
  height: 16px;
  align-self: center;
}
.cabinet__archived-row .wax-check:checked::after {
  left: 5px;
  top: 1px;
  width: 4px;
  height: 9px;
}
/* редактор миров (Фаза 3.2): спойлер-семья архива — тот же моно-summary
   на сукне; ряд равняется по центру с ЯВНОЙ высотой соседей (правило
   ряда шага 17: input 40px из примитива, кнопке высоту задаём сами) */
.cabinet__worlds { margin-top: 30px; }
.cabinet__worlds summary {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--chalk-dim);
}
.cabinet__worlds summary:hover { color: var(--brass); }
.cabinet__worlds-hint {
  margin: 10px 0 0 18px;
  font-size: 13px;
  color: var(--chalk-dim);
}
.cabinet__world-row {
  display: flex;
  gap: 14px;
  align-items: center;
  margin: 10px 0 0 18px;
}
.cabinet__world-rename {
  display: flex;
  gap: 8px;
  align-items: center;
}
.cabinet__world-rename .dm-input { width: 240px; }
/* кнопка на СУКНЕ — семья .cabinet__bulk-del (chalk-dim/латунь), не .btn:
   чернильный .btn на сукне слеп (1.11:1 — находка ревью); высота 40 —
   явное выравнивание с примитивом поля */
.cabinet__world-rename button {
  height: var(--ctl-h);
  background: none;
  border: 1px solid var(--chalk-dim);
  padding: 6px 14px;
  font-size: 12px;
  color: var(--chalk-dim);
  cursor: pointer;
  border-radius: var(--r-ctl);
}
.cabinet__world-rename button:hover { color: var(--brass); border-color: var(--brass); }
.cabinet__world-rename button:focus-visible {
  outline: 2px solid var(--chalk-dim);
  outline-offset: 2px;
}
.cabinet__world-meta {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--chalk-dim);
  white-space: nowrap;
}
/* ✕ пустого мира стилизуется общей группой с .cabinet__archived-del */

.masthead__back {
  display: inline-flex;
  align-items: center;
  min-height: 44px; /* «‹ назад» — тап-цель, не строка петита */
  color: var(--brass);
  text-decoration: none;
  font-size: 13px;
  letter-spacing: 0.06em;
}
.masthead__back:hover { color: var(--paper); } /* чинён шагом 1: ссылался на несуществующий токен parchment */

/* --- фаза 1.7: страница подготовки кампании --------------------
   Черновик = развёрнутое письмо на сукне: один пергаментный лист
   с формой, внизу — сургучная печать, закрывающая черновик навсегда.
   Черновики в кабинете — конверты без печати (не запечатаны). */

.setup { max-width: 680px; margin: 0 auto; padding: 40px 16px 60px; }

/* сироты .setup__title/.setup__status вычеркнуты (шаг 6 рефаба):
   шаблоны давно на page-head-семье, grep по templates/ пуст */
.page-head__title {
  font-family: var(--font-display);
  color: var(--paper);
  font-size: 34px;
  margin: 0;
  text-shadow: 0 2px 8px #000c;
  letter-spacing: 0.02em;
}
.page-head__status {
  color: var(--chalk);
  font-style: italic;
  margin: 6px 0 0;
  font-size: 14px;
}
/* тот же статус ВНУТРИ листа (касса лавки): мел — цвет сукна,
   на пергаменте 1.4:1 → выцветшие чернила (аудит 15.08) */
.panel .page-head__status { color: var(--ink-soft); }

.setup__error {
  background: var(--paper-err);
  border: 1px solid var(--wax);
  border-left: 4px solid var(--wax);
  border-radius: 2px;
  color: var(--seal-lo);
  padding: 10px 12px;
  font-size: 14px;
  margin: 0 0 16px;
}

/* лист рисует .panel (панельный канон, шаг 3 ребилда) — свой скин формы снят */
.setup__panel { margin-top: 22px; }
.setup__form label { display: block; margin-bottom: 12px; font-size: 14px; }
/* скин полей — примитив (шаг 2); здесь геометрия колонки.
   Радио и файл исключены (правило проекта): width:100% растягивал
   рисованное радио .wax-radio в эллипс на всю панель — поймано
   скриншот-приёмкой шага 1 рефаба */
.setup__form input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.setup__form select, .setup__form textarea {
  display: block;
  width: 100%;
  margin-top: 4px;
}
/* input и select рендерятся с разной внутренней геометрией — равняем
   высоту явно, иначе селект месяца выпирает из ряда. Радио, файл и рисованный
   чекбокс (.wax-check) живут своей жизнью — их не трогаем. */
/* высота — стандарт 40 из примитива (шаг 2, решение PM); локальный 42 снят */
/* файл-поля сетапа — примитив .dm-file (раздевавшее правило снято шагом 1 рефаба) */
.setup__form .btn { margin-top: 6px; padding: 10px 26px; }

.setup__slug {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
  margin: -6px 0 14px;
}
.setup__slug b { color: var(--brass-ink); font-weight: 600; }

.setup__group {
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 8px 10px 2px;
  margin: 0 0 14px;
}
.setup__group legend { font-size: 12px; color: var(--ink-soft); padding: 0 6px; }

/* вертикальный стек «радио слева — подпись справа», подписи переносятся */
.setup__cal > input[type="radio"] {
  display: block;
  float: left;
  clear: left;
  margin: 10px 10px 0 2px; /* вид даёт .wax-radio; тут — только раскладка */
}
.setup__cal > label {
  display: block;
  overflow: hidden;
  padding: 9px 0 0;
  margin-bottom: 0;
  font-size: 14px;
}

/* точка отсчёта живёт в трёх экземплярах — по одному на календарь;
   виден блок выбранного радио. Мгновенно, без сервера и без JS. */
.setup__epoch { display: none; clear: both; margin-top: 12px; padding-top: 4px; border-top: 1px dashed var(--line); }
#cal-gregorian:checked ~ .setup__epoch--g,
#cal-harptos:checked ~ .setup__epoch--h,
#cal-custom:checked ~ .setup__epoch--c { display: block; }
.setup__epoch-title { font-size: 12px; color: var(--ink-soft); margin: 6px 0 8px; }
.setup__epoch input[type="file"] { margin-top: 6px; }
/* время точки отсчёта — прибор: моно-цифры (§4.1); нативную иконку пикера
   не выпиливаем (без неё тач теряет вход в пикер) — только приглушаем */
.setup__form input[type="time"] {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.setup__form input[type="time"]::-webkit-calendar-picker-indicator {
  opacity: 0.55;
  cursor: pointer;
}

/* --- свой календарь: конструктор ИЛИ файл (шаг 8.5) -------------------
   вложенные радио выбирают СПОСОБ ВВОДА одного и того же calendar_json;
   переключение — тем же CSS-трюком, что и блоки эпох. */
.custom__mode-radio {
  display: inline-block;
  margin: 2px 6px 0 2px; /* вид даёт .wax-radio; тут — только раскладка */
}
.setup__form label.custom__mode-label {
  display: inline-block;
  margin: 0 18px 6px 0;
  font-size: 14px;
}
.custom__pane { display: none; padding-top: 2px; }
#mode-builder:checked ~ .custom__pane--builder,
#mode-file:checked ~ .custom__pane--file { display: block; }

.builder__subtitle {
  font-size: 12px;
  color: var(--ink-soft);
  margin: 10px 0 6px;
}
.builder__row {
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--paper-bright);
  margin-bottom: 8px;
}
.builder__main {
  display: grid;
  grid-template-columns: 1fr 96px auto 44px;
  gap: 8px;
  align-items: center;         /* весь ряд по вертикали центрируется — и чекбокс */
  padding: 6px 8px;
}
/* сброс margin-top полей (иначе .setup__form input сдвигает их вниз на 4px,
   и чекбокс кажется выше центра ряда) — специфичность выше базового правила */
.setup__form .builder__main input { margin-top: 0; }
/* чекбокс «високосный» — сургучная печать-триггер (.wax-check); раскрывает
   этаж за латунной каймой (латунь = подарок, канон §2.1). Обводка пустого — как
   у полей ввода (--line), не темнее. По вертикали центрирован в ряду. */
.setup__form .builder__leapchk {   /* .setup__form: перебить глобальное .setup__form label{display:block} */
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-soft);
  white-space: nowrap;
  cursor: pointer;
  margin-bottom: 0;                /* гасим наследуемый label margin-bottom:12px */
}
.builder__leapchk .wax-check { border-color: var(--line); }
/* Високосный этаж: раскрывается по чекбоксу, латунная кайма слева — редкий
   подарок календаря; appear 180ms с тихой reduced-motion-версией. Одна строка:
   «Дней в високосный год: [N]  |  Период: [N] лет» (период у месяца — свой). */
.builder__leap {
  display: none;
  align-items: center;         /* вся строка по центральной оси */
  flex-wrap: wrap;
  gap: 8px 14px;
  margin: 0 8px 8px;
  padding: 8px 0 8px 12px;
  border-top: 1px dashed var(--line);
  border-left: 3px solid var(--brass);
}
.builder__row.is-leap .builder__leap {
  display: flex;
  animation: builder-leap-in var(--t-swap) ease;
}
@keyframes builder-leap-in { from { opacity: 0; transform: translateY(-2px); } }
@media (prefers-reduced-motion: reduce) {
  .builder__row.is-leap .builder__leap { animation: none; }
}
.setup__form .builder__leap-field {   /* .setup__form: перебить .setup__form label{display:block} */
  display: flex;
  flex-direction: row;               /* «Подпись: [поле]» в одну строку (выбор PM) */
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--ink-soft);
  margin-bottom: 0;                  /* гасим наследуемый label margin-bottom:12px */
}
.builder__leap-cap, .builder__leap-unit { white-space: nowrap; }
/* поля этажа — короткое число, компактная одинаковая ширина обоих полей */
.setup__form .builder__leap-field input {   /* (0,2,1): своя ширина поверх глобального input width:100% */
  width: 76px;
  margin-top: 0;
  font-family: var(--font-mono);
  text-align: center;
}
.builder__leap-field--days { flex: 0 0 auto; }
.builder__leap-field--period { flex: 0 0 auto; }
/* Разделитель двух полей — тонкий вертикальный хайрлайн (чисто CSS, одинаков
   на всех устройствах; повторяет рисунок «||» из ТЗ). */
.builder__leap-sep {
  flex: none;
  align-self: center;
  width: 1px;
  height: 22px;
  background: var(--line);
}
/* узко (телефон): строка не влезает — прячем разделитель, поля в столбик */
@media (max-width: 560px) {
  .builder__leap-sep { display: none; }
  .setup__form .builder__leap-field { flex-basis: 100%; }
}
/* Реестр «Событие(я) на плавающий день»: строка [дата (МОНО, brass-ink —
   «сказал движок»)][название][описание], генерится JS из високосных дней. */
.builder__floating { display: flex; flex-direction: column; gap: 6px; margin: 4px 0 10px; }
.builder__frow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--paper-bright);
}
/* скрытые month/day: глобальное .setup__form input{display:block} иначе
   показало бы их пустыми блоками — гасим точечно (специфичнее глобалки) */
.setup__form .builder__frow input[type="hidden"] { display: none; }
.setup__form .builder__frow input { margin-top: 0; }
.builder__frow-date {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--brass-ink);
  white-space: nowrap;
}
.builder__frow-title { flex: 1 1 150px; }
.builder__frow-note { flex: 2 1 210px; }
.builder__floating-empty {
  font-size: 13px;
  color: var(--ink-soft);
  font-style: italic;
  padding: 2px 2px 4px;
}
.setup__form .builder__del {
  height: 44px;
  min-width: 44px;
  margin-top: 0;
  padding: 0;
  font-size: 15px;
  line-height: 1;
}
.setup__form .builder__add {
  margin: 2px 0 14px;
  padding: 8px 18px;
  font-size: 13px;
}
.builder__week { margin-top: 4px; }

.setup__divider { margin: 22px 0 16px; }

.setup__seal { text-align: center; padding: 6px 0 0; }
.setup__seal-hint {
  color: var(--ink-soft); /* был мел — цвет сукна, на бумаге 1.3:1 (аудит 15.08) */
  font-size: 13px;
  font-style: italic;
  margin: 0 0 14px;
}
.setup__seal .btn--wax {
  padding: 12px 34px;
  font-size: 15px;
  box-shadow: 0 2px 6px #000a, inset 0 1px 2px #ffffff30;
}

/* --- партия на сетапе: второй лист под формой ----------------
   Список заведённых героев + пакетный импорт LSS (HTMX-остров). */

.setup__players {
  /* лист рисует .panel (шаг 3 ребилда); здесь только отступ */
  margin-top: 26px;
}

.setup__players-hint {
  margin: 0 0 14px;
  font-size: 13px;
  color: var(--ink-soft);
}

.setup__party {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
}

.setup__party-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 2px;
  border-bottom: 1px solid var(--line);
}

.setup__party-name { font-weight: 600; }

.setup__party-meta {
  flex: 1;
  font-size: 13px;
  color: var(--ink-soft);
}

.setup__party-del {
  min-width: 34px;
  min-height: 34px;
  padding: 4px 8px;
}
.setup__party-del:hover { color: var(--wax); }

.setup__import label {
  display: block;
  font-size: 14px;
  margin-bottom: 12px;
}

.setup__import input[type="file"] { margin-top: 6px; } /* геометрия; скин — .dm-file */
/* «Импортировать партию» — близнец «Сохранить черновик»: одна геометрия */
.setup__import .btn { padding: 10px 26px; }

.setup__import-report { margin: 0 0 14px; }

.setup__import-ok {
  margin: 0 0 6px;
  font-size: 13px;
  color: var(--vital-deep);
  font-weight: 600;
}

.setup__import-err {
  margin: 0 0 6px;
  font-size: 13px;
  color: var(--wax);
}

/* черновики в кабинете: конверты, ещё не тронутые печатью */
.cabinet__drafts-title {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  margin: 30px 0 14px;
}
.campaign-card--draft::after { content: none; }   /* печати нет — черновик */
.campaign-card--draft { padding-top: 72px; }
.campaign-card--draft .campaign-card__name { opacity: 0.85; }
.campaign-card__annotation {
  font-size: 13px;
  font-style: italic;
  color: var(--ink-soft);
  margin: 6px 0 0;
}

.combat-init {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 700;
  color: var(--brass-ink); /* §3.2: на бумаге карточек; плитка ленты уже так */
  white-space: nowrap;
}
/* значок крита инициативы (15c): очередь объясняет сама себя —
   нат.20 стоит выше большего броска, нат.1 падает в самый низ */
.combat-init__crit {
  margin-left: 2px;
  font-style: normal;
}

.is-turn {
  outline: 2px solid var(--brass);
  outline-offset: 1px;
  box-shadow: 0 0 0 5px #b08d4f22;
}

.mob-card {
  background: var(--paper-tile);
  border: 1px dashed var(--line);
  border-radius: 3px;
  padding: 10px 12px 8px;
  margin-bottom: 14px;
}
.mob-card__head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 6px;
}
.mob-card__name {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}
.mob-card__badges {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}
.mob-card__x { min-width: 34px; }
.mob-card__note {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--ink-soft);
}

/* три кнопки подкрепления: пресет / бестиарий (заглушка) / подмога.
   Отступ от ленты — у РЯДА: margin на самом details (наследство шага
   14) толкал первую кнопку вниз — align-items центрирует марджин-бокс */
.combat-call {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
}
.combat-call .combat-add { margin: 0; }
/* ЕДИНАЯ геометрия кнопок боя — шапка и нижний ряд: одна высота, один
   шрифт, одни паддинги. summary и button рендерятся с разной внутренней
   геометрией — равняем явно, иначе ряд гуляет по вертикали */
.combat-head__controls .btn,
.combat-call .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--tap-h); /* кнопки шапки боя дожаты 40→44 (решение PM, §3.3) */
  box-sizing: border-box;
  padding: 0 14px;
  margin: 0;
  font-size: 14px;
  cursor: pointer;
}
.combat-call .btn[disabled] {
  opacity: 0.45;
  cursor: default;
}
.combat-add > summary { list-style: none; }
.combat-add > summary::-webkit-details-marker { display: none; }
/* раскрытая форма пресета занимает свою строку, кнопки съезжают вниз */
.combat-call .combat-add[open] { flex-basis: 100%; }
.combat-call__reserve { color: var(--wax); border-color: var(--wax); }

.combat-add__form {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}
/* поля подкрепления — в тон пергаменту, как поля сбора боя
   (дефолтные белые контролы выбивались из доски) */
form.combat-add__form select,
form.combat-add__form input:not([type="checkbox"]) {
  /* скин — примитив (шаг 2); подкрепление — боевой тап, дожат до 44 (PM).
     Тег form в селекторе — специфичность выше адаптеров примитива: одиночный
     класс проигрывал им, и дожим молча не работал (аудит 18.08) */
  height: var(--tap-h);
}
.combat-add__form select { flex: 1; min-width: 0; }
.combat-add__form input {
  width: 72px;
  text-align: center;
  font-family: var(--font-mono);
}

.combat-setup__hint {
  margin: 12px 0 6px;
  font-size: 13px;
  color: var(--ink-soft);
}
.combat-setup__actions {
  display: flex;
  gap: 8px;
  margin-top: 14px;
}

/* --- бой v2 (шаг 15): корешок, баннер, сбор, страница ------------------ */
.panel__tab--fight {
  left: auto;
  right: 18px;
  border-top-color: var(--wax);
  color: var(--wax);
  text-decoration: none;
  cursor: pointer;
}
.panel__tab--fight:hover { background: var(--paper-hover); }

.combat-banner {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 14px;
  padding: 10px 12px;
  background: #9e3b2f14;
  border: 1px solid var(--wax);
  border-radius: 3px;
  color: var(--ink);
  text-decoration: none;
}
.combat-banner:hover { background: #9e3b2f22; }
.combat-banner__mark { color: var(--wax); }
.combat-banner__text { flex: 1; }
.combat-banner__go {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--wax);
  white-space: nowrap;
}

/* полоса «Стол» (Фаза 3 шаг 3): открыть/закрыть игровую сессию */
.table-strip { margin: 0 0 14px; }
.table-strip__live {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: #b08d4f14;
  border: 1px solid var(--brass);
  border-radius: 3px;
}
.table-strip__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--wax);          /* live-точка сургучом (паритет с ЛК шага 4) */
  flex: none;
}
.table-strip__text { flex: 1; color: var(--ink); }
.table-strip__closed > summary {
  list-style: none;
  cursor: pointer;
  padding: 6px 12px;
  border: 1px dashed var(--line);
  border-radius: 3px;
  color: var(--ink-soft);
  font-size: 14px;
}
.table-strip__closed > summary::-webkit-details-marker { display: none; }
.table-strip__closed > summary::before { content: "＋ "; color: var(--brass-ink); }
.table-strip__closed[open] > summary { color: var(--ink); border-style: solid; }
.table-strip__form {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-top: none;
  border-radius: 0 0 3px 3px;
}
.table-strip__hint { margin: 0 0 8px; color: var(--ink-soft); font-size: 13px; }
.table-strip__who-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin: 0 0 10px;
}
.table-strip__who {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
}

/* сбор боя: страница-развилка */
.fight-new__panel,
.fight-page__panel {
  max-width: 720px;
  margin: 26px auto 0;
  padding-top: 22px;
}

/* поля сбора — в тон сетапу: раньше тут жили браузерные дефолты
   (белые поля, синие галочки), форма выглядела недоработанной */
/* скин и высота 40 — примитив полей (шаг 2) */
.fightform input[type="number"] {
  font-family: var(--font-mono);
  text-align: center;
}
.fightform input[type="text"]:focus-visible,
.fightform input[type="number"]:focus-visible,
.wax-check:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: 2px;
}

/* Галочка-«печать»: рисованная, сургуч по пергаменту — ОБЩИЙ ПРИМИТИВ
   (17.9): класс на самом input, не скоуп-предок .fightform. Единый контрол
   везде — сбор боя (криты, участие), владения листа героя, видимость
   события, «именные NPC» поисков. Настоящий input остаётся: :has-трюки
   формы сбора (тускнение рядов, показ crit-сегментов) живут как жили. */
.wax-check {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 22px;
  height: 22px;
  margin: 0;
  position: relative;
  background: var(--paper-bright);
  border: 1px solid var(--ink-soft);
  border-radius: 2px;
  cursor: pointer;
  vertical-align: middle;
}
.wax-check:hover { border-color: var(--wax); }
.wax-check:checked {
  background: var(--wax);
  border-color: var(--wax);
}
/* галочка рисуется рамкой, не глифом — шрифтовые ✓ гуляют по платформам */
.wax-check:checked::after {
  content: "";
  position: absolute;
  left: 7px;
  top: 3px;
  width: 6px;
  height: 11px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* Радио-«печать» — родня .wax-check: тот же свежий лист и рамка, но круг
   (круглое — за печатями, §5.3), выбранное — сургучная точка триадой печати.
   Класс на самом input: соседские :checked ~ трюки сетапа живут как жили. */
.wax-radio {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 22px;
  height: 22px;
  margin: 0;
  position: relative;
  background: var(--paper-bright);
  border: 1px solid var(--ink-soft);
  border-radius: 50%;
  cursor: pointer;
  vertical-align: middle;
}
.wax-radio:hover { border-color: var(--wax); }
.wax-radio:checked { border-color: var(--wax); }
.wax-radio:checked::after {
  content: "";
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--seal-hi), var(--seal-mid) 60%, var(--seal-lo));
}
.wax-radio:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: 2px;
}

/* строка «сургуч-галочка + подпись» опциональных фильтров (именные NPC) */
.named-check {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  font-size: 13px;
  color: var(--ink-soft);
  cursor: pointer;
}

.fightform__name {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 4px 0 12px;
}
.fightform__name span { white-space: nowrap; }
.fightform__name input { flex: 1; min-width: 0; }

.fightform__crits {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin: 0 0 6px;
}
.fightform__crits-hint {
  flex-basis: 100%;
  margin: 2px 0 0 30px;   /* под текст подписи: 22px галочка + 8px зазор */
  font-style: normal;
  font-size: 12px;
  color: var(--ink-soft);
}

.fightform__row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0;
}
.fightform__who {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.fightform__who span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fightform__init { width: 96px; }
/* без галочки участия ряд тускнеет (сервер его и так игнорирует) */
.fightform__row:not(:has(.fightform__check:checked)) .crit-seg,
.fightform__row:not(:has(.fightform__check:checked)) .fightform__init {
  opacity: 0.35;
}

/* сегмент критов: [нат.1][—][нат.20]; виден при включённом чекбоксе */
.crit-seg {
  display: none;
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  overflow: hidden;
}
.fightform:has(#crit-rules:checked) .crit-seg { display: inline-flex; }
.crit-seg__opt input { position: absolute; opacity: 0; pointer-events: none; }
.crit-seg__opt span {
  display: inline-flex;
  align-items: center;
  /* в рост поля броска МИНУС рамка контейнера: у поля border входит в
     height, у сегмента добавлялся сверху — торчал на 2px (аудит 18.08) */
  min-height: calc(var(--ctl-h) - 2px);
  padding: 6px 12px;
  font-family: var(--font-mono);
  font-size: 12px;
  cursor: pointer;
  border-left: 1px solid var(--line);
}
.crit-seg__opt:first-child span { border-left: 0; }
.crit-seg__opt input:checked + span {
  background: var(--brass);
  color: var(--ink); /* пара канона «чернила на латуни» 4.8:1; #fff давал 3.1:1 */
}
.crit-seg__opt input:focus-visible + span {
  outline: 2px solid var(--brass-ink);
  outline-offset: -2px;
}

/* развилка «В бой!»: карточки пресетов боёв (шаг 16) */
.enc-pick { margin: 4px 0 14px; }
.enc-pick__card {
  display: block;
  margin: 6px 0;
  padding: 8px 12px;
  background: var(--paper-bright);
  border: 1px solid var(--line);
  border-radius: 3px;
  text-decoration: none;
  color: inherit;
}
.enc-pick__card:hover { border-color: var(--brass); }
.enc-pick__card--active {
  border-color: var(--wax);
  box-shadow: 0 0 0 1px var(--wax) inset;
}
.enc-pick__name { margin-right: 8px; }
.enc-pick__mix {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
}
/* конструктор состава пресета боя: ряды [имя NPC][кол-во] + [+ NPC].
   Специфичность с запасом: .settings input красит все поля формы в
   width:100% и margin-top — ряду нужны СВОИ ширины (без запаса имя
   схлопывалось в ноль, а счётчик разъезжался на всю строку) */
.enc-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 6px 0;
}
.settings .enc-row input[name="enc_name"] {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
  margin: 0;
}
.settings .enc-row input[name="enc_count"] {
  flex: 0 0 76px;
  width: 76px;
  margin: 0;
  text-align: center;
  font-family: var(--font-mono);
}
.settings .enc-row select[name="enc_when"] {
  flex: 0 0 auto;
  width: auto;
  margin: 0;
  font-size: 13px;
}
/* input и select рендерятся с разной геометрией — равняем явно; margin-top 4
   адаптера .settings (специфичность :not-хвостов) перекашивал инпуты ряда
   на 2px против селекта — глушим тем же хвостом (аудит 18.08) */
.settings .enc-row input, .settings .enc-row select { height: 38px; }
.settings .enc-row input:not([type="checkbox"]):not([type="radio"]):not([type="file"]) { margin: 0; }
.enc-row__del { flex: none; }
.enc-add { margin: 2px 0 10px; }

/* заметка боя в шапке доски: свёрнутый пергамент-пузырь */
.combat-note {
  margin: 0 0 14px;
  padding: 6px 12px;
  background: var(--paper-bright);
  border: 1px solid var(--line);
  border-radius: 3px;
}
.combat-note__summary {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
}
.combat-note__text {
  margin: 8px 0 4px;
  font-size: 14px;
  white-space: pre-line;   /* переносы заметки DM — как набраны */
}

/* значок «проведён» — на развилке и на странице пресетов */
.encounters__played {
  margin-left: 6px;
  padding: 1px 7px;
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--brass-ink);          /* §3.2: 11px на бумаге — тем более */
  border: 1px solid var(--brass-ink);
  border-radius: 999px;
  white-space: nowrap;
}

/* страница боя: шапка, активный, лента */
.combat-head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 14px;
  padding: 10px 12px;
  background: #00000012;
  border: 1px solid var(--line);
  border-radius: 3px;
}
.combat-head__titles { flex: 1; min-width: 200px; }
.combat-head__name { margin: 0; font-size: 18px; }
.combat-head__meta {
  margin: 2px 0 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--ink-soft);
}
.combat-head__controls {
  display: flex;
  gap: 6px;
  align-items: center;
}

.combat-active { margin: 0 0 14px; }
.combat-active__label {
  margin: 0 0 6px;
  font-size: 13px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--brass-ink); /* §3.2: подпись на бумаге карты */
}

/* плашки активного (15c): объясняют ход до того, как DM спросит.
   Нат.20 — латунь (подарок), нат.1 и смерть — сургуч (беда).
   Кнопка внутри — обычный уход хода, просто с подписью по делу. */
.combat-plates {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0 0 14px;
}
.combat-plate {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  background: #0000000a;
  border: 1px solid var(--line);
  border-radius: 3px;
}
.combat-plate__mark {
  color: var(--ink-soft);
  font-size: 15px;
}
.combat-plate__text {
  flex: 1 1 200px;
  min-width: 0;
  margin: 0;
  font-size: 14px;
}
.combat-plate .btn { flex: none; }
.combat-plate--crit20 {
  background: #b08d4f1c;
  border-color: var(--brass);
}
.combat-plate--crit20 .combat-plate__mark { color: var(--brass); }
.combat-plate--crit1,
.combat-plate--death {
  background: #9e3b2f14;
  border-color: var(--wax);
}
.combat-plate--crit1 .combat-plate__mark,
.combat-plate--death .combat-plate__mark { color: var(--wax); }

.combat-strip__label {
  margin: 12px 0 6px;
  font-size: 13px;
  color: var(--ink-soft);
}

/* --- фича «павшие мобы»: череп, лента павших, экран победы --- */
.combat-strip__label--fallen { color: var(--wax); }
.mob-card__skull { color: var(--wax); }
/* павший — НЕ затемняем (правило PM): приглушение opacity гасило бы и форму
   обыска (дочерний элемент ярче родителя быть не может). «Мёртвость» несёт
   череп ☠ и латунное имя, а не тёмная карта */
.mob-card--dead .mob-card__name { color: var(--wax); }
.combat-fallen { display: flex; flex-direction: column; gap: 8px; }
.combat-victory {
  margin: 14px 0;
  padding: 16px 18px;
  text-align: center;
  border: 1px solid var(--brass);
  border-radius: 3px;
  background: var(--paper-mute);   /* пергамент-акцент, как give-status--ok */
}
.combat-victory__title {
  margin: 0 0 4px;
  font-family: var(--font-display);
  font-size: 22px;
  color: var(--brass-ink);       /* латунь = триумф/ресурс */
}
.combat-victory__text {
  margin: 0 0 12px;
  color: var(--ink-soft);
  font-size: 14px;
}

/* --- живая лента боя (шаг 4): урон/лечение/вердикты текущего боя --- */
.combat-log {
  margin: 14px 0 0;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--paper-shade);
}
.combat-log__label {
  margin: 0 0 8px;
  font-family: var(--font-display);
  font-size: 15px;
  color: var(--brass-ink);
}
.combat-log__list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 200px;
  overflow-y: auto;
}
.combat-log__line {
  padding: 4px 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--ink-soft);
  border-top: 1px solid var(--line);
}
.combat-log__line:first-child { border-top: 0; }
.combat-log__line--drama { color: var(--wax); }        /* урон герою — сургуч */
.combat-log__line--luck  { color: var(--brass-ink); }  /* лечение героя — латунь */
/* лента вертикальная: миниатюра = строка во всю ширину (решение PM:
   так в неё влезает больше — полоска хитов сейчас, чипы состояний в 15c) */
.combat-strip {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* плитка ленты — native details: summary = строка-миниатюра (тап
   раскрывает карточку в теле НА МЕСТЕ, повторный тап сворачивает) */
.combat-tile { width: 100%; }
.combat-tile__row {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  align-items: baseline;
  column-gap: 12px;
  row-gap: 6px;
  min-height: 44px;
  padding: 8px 12px;
  background: var(--paper-tile);
  border: 1px solid var(--line);
  border-radius: 3px;
  cursor: pointer;
  list-style: none;   /* маркер рисуем сами шевроном у имени */
}
.combat-tile__row::-webkit-details-marker { display: none; }
.combat-tile--mob > .combat-tile__row { border-style: dashed; }
.combat-tile > .combat-tile__row:hover { border-color: var(--brass); }
.combat-tile[open] > .combat-tile__row {
  border-color: var(--brass);
  border-radius: 3px 3px 0 0;
}
.combat-tile__body {
  border: 1px solid var(--brass);
  border-top: 0;
  border-radius: 0 0 3px 3px;
  padding: 6px 10px 8px;
  background: var(--paper);
}
.combat-tile__name {
  font-weight: 600;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* шеврон-маркер у имени (грид не сдвигается — ::before внутри ячейки) */
.combat-tile__name::before {
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  margin-right: 6px;
  border: 4px solid transparent;
  border-left-color: var(--brass);
  vertical-align: middle;
  transition: transform var(--t-tap) ease;
}
.combat-tile[open] .combat-tile__name::before { transform: rotate(90deg); }
.combat-tile__init {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; /* колонка чисел ленты — разряды столбиком (§4.1) */
  font-size: 12px;
  color: var(--brass-ink); /* хвост §3.2: ⚔ N на плитке — 2.4:1 латунью, 5.0:1 второй пробой */
  white-space: nowrap;
}
.combat-tile__crit {
  margin-left: 2px;
  font-style: normal;
}
.combat-tile__ac {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
  white-space: nowrap;
}
.combat-tile__hp {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
  white-space: nowrap;
}
.combat-tile__bar {
  grid-column: 1 / -1;
  display: block;
  height: 5px;
  background: #00000014;
  border-radius: 2px;
  overflow: hidden;
}
.combat-tile__bar .hp__fill { display: block; height: 100%; }

/* Бестиарий reference.db (шаг 16.5): режим «Справочник» — плотные ряды,
   моно-числа, разворот статблока на месте. Живёт и панелью на странице
   пресета NPC, и details'ом на доске боя. Поле — в тон пергаменту, как
   поля сбора/подкрепления (var(--paper-bright) уже в файле). */
.bestiary__input {
  /* скин — примитив полей (шаг 2) */
  box-sizing: border-box;
  width: 100%;
  margin: 0 0 10px;
}
.bestiary__list { list-style: none; margin: 0; padding: 0; }
.bestiary__row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px dashed var(--line);
}
.bestiary__card { flex: 1; min-width: 0; }
.bestiary__head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
  cursor: pointer;
}
.bestiary__head::marker { color: var(--brass-ink); } /* §3.2; -webkit-вендор был мёртв */
.bestiary__name { font-weight: 600; }
.bestiary__meta,
.bestiary__stats {
  font-family: var(--font-mono);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}
.bestiary__block { margin: 6px 0 2px; }
.bestiary__line,
.bestiary__stats,
.bestiary__kv { margin: 0 0 4px; font-size: 13px; }
.bestiary__en { font-style: italic; color: var(--ink-soft); }
.bestiary__kv { color: var(--ink-soft); }
.bestiary__statblock {
  margin-top: 6px;
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-line;   /* статблок парсера — с переносами, как набран */
}
.bestiary__act { flex: none; }
.bestiary__count {
  /* скин, моно и высота 40 — примитив полей (шаг 2); был локальный 38 */
  width: 56px;
  margin-right: 6px;
  text-align: center;
}
/* раскрытый поиск бестиария на доске боя занимает свою строку — геометрию
   уже задаёт .combat-add[open] (§ выше), .combat-add--bestiary её наследует */
.combat-add__bestiary { margin-top: 8px; }

/* страница пресета: два листа на столе не слипаются (приёмка 16.5) */
.presets__panel + .presets__panel { margin-top: 32px; }

/* фильтры поиска (16.5b → адаптив 1.8, подчистка PM). Шапка [поиск][☐ Именные
   NPC] — флекс; галочка вынесена сюда из сетки. Широко: сетка
   [КД от/до][Хиты от/до][Сложность] / [Размер][Биом] (КД над Размером, Хиты
   над Биомом; подписи display:contents — колонки строго по вертикалям). */
.bestiary__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  margin: 0 0 10px;
}
/* поиск как флекс-элемент только в шапке — .bestiary__input отдельно живёт
   лёгкой формой доски боя (width:100%), её не трогаем */
.bestiary__top .bestiary__input { flex: 1 1 240px; width: auto; margin: 0; }
.bestiary__named {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  cursor: pointer;
  font-size: 13px;
  color: var(--ink-soft);
}
/* чекбокс «мой» в ячейке трио (каталог игрока, шаг 6 «Стола игроков»):
   ростом с соседние селекты — линия ряда цела (правило выравнивания PM) */
.bestiary__named--cell { min-height: var(--ctl-h); }
.bestiary__filter-row {
  display: grid;
  grid-template-columns: auto 64px 64px auto 64px 64px auto minmax(88px, 1fr);
  gap: 12px 8px;
  align-items: center;
  margin: 0 0 10px;
  font-size: 13px;
  color: var(--ink-soft);
}
.bestiary__filter-row label { display: contents; }
.bestiary__filter-row label > span { padding-right: 4px; white-space: nowrap; }
/* широкие селекты второго ряда занимают обе колонки своей пары «от/до» */
.bestiary__fsel--wide { grid-column: span 2; }
/* Ряд из ТРЁХ селектов без пар «от/до» (каталог предметов, 2.1 шаг 2):
   восьмиколоночная сетка бестиария скроена под числовые пары, и селект в
   136px РЕЖЕТ длинные значения («Чудесный предмет» — 530 позиций каталога,
   «Волшебная палочка»). Здесь подпись встаёт НАД полем: три равные трети
   листа дают селектам ~196px — режется нечему, и контролы одного смысла
   одинаковы (правило выравнивания PM, ступень «смысл»). */
.bestiary__filter-row--trio {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.bestiary__filter-row--trio label {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.bestiary__filter-row--trio label > span { padding-right: 0; }
/* одиночный фильтр во всю ширину листа — та же раскладка «подпись над
   полем», одна доля (селект «Доступные герою», шаг «Заклинания героя») */
.bestiary__filter-row--solo {
  grid-template-columns: minmax(0, 1fr);
}
.bestiary__filter-row--solo label {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.bestiary__filter-row--solo label > span { padding-right: 0; }
/* пара фильтров снаряжения — та же раскладка «подпись над полем», две доли */
.bestiary__filter-row--pair {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.bestiary__filter-row--pair label {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.bestiary__filter-row--pair label > span { padding-right: 0; }
/* пары «от/до» — строго одна ширина (борьба с разнобоем приёмки 16.5b);
   скин и высота — примитив полей (сирота-селектор с запятой прятал их от
   списка адаптеров до шага 1 рефаба — поля стояли UA-голыми);
   селекты тянутся до своей колонки, чтобы ряд не гулял от длины опции */
.bestiary__filter-row input:not([type="checkbox"]) {
  width: 64px;
  font-family: var(--font-mono);
  text-align: center;
}
.bestiary__filter-row select { width: 100%; min-width: 0; }
/* Узкое окно «Из бестиария» (≤640px): галочка уходит под поиск, а фильтры
   встают друг под другом. Сетка [подпись | от | до] — подписи в общей колонке
   max-content, от/до выровнены; селекты тянутся на всю ширину (span 2). */
@media (max-width: 640px) {
  .bestiary__named { flex-basis: 100%; }
  .bestiary__filter-row { grid-template-columns: max-content 1fr 1fr; }
  .bestiary__filter-row input:not([type="checkbox"]) { width: 100%; }
  .bestiary__filter-row select { grid-column: span 2; }
  /* трио каталога на узком экране — по одному фильтру в строку (подпись
     уже над полем, тянуть три селекта в ряд на телефоне нечем) */
  .bestiary__filter-row--trio,
  .bestiary__filter-row--pair { grid-template-columns: 1fr; }
}
.bestiary__total {
  margin: 0 0 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
}

/* статблок пресета: разворот в строке списка и аккордеон формы (16.5b) */
.npcs__statblock { flex-basis: 100%; margin: 2px 0 0; }
.npcs__statblock > summary,
.npcs__form-statblock > summary {
  font-size: 13px;
  color: var(--ink-soft);
  cursor: pointer;
}
.npcs__form-statblock { margin-bottom: 12px; }
.npcs__form-statblock label { margin-top: 10px; }

/* участник состава пресета боя (шаг 17): каждый моб — свой выделенный
   разворачиваемый контейнер, а не стена текста */
.enc-member {
  flex-basis: 100%;
  margin: 6px 0 0;
  padding: 5px 10px;
  background: var(--paper-bright);
  border: 1px solid var(--line);
  border-radius: 3px;
}
.enc-member > summary {
  cursor: pointer;
  display: flex;
  flex-wrap: wrap;
  gap: 2px 10px;
  align-items: baseline;
  list-style: none;   /* display:flex гасит нативный треугольник — рисуем свой */
}
.enc-member > summary::-webkit-details-marker { display: none; }
/* шеврон-маркер по конвенции .menu__summary (латунь, поворот на [open]) */
.enc-member > summary::before {
  content: "";
  flex: none;
  width: 0;
  height: 0;
  margin-right: 2px;
  border: 4px solid transparent;
  border-left-color: var(--brass);
  transition: transform var(--t-tap) ease;
}
.enc-member[open] > summary::before { transform: rotate(90deg); }
.enc-member__name { font-weight: 600; }
.enc-member__stat {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
}
.enc-member[open] { padding-bottom: 8px; }

/* --- случайный бой (шаг 17): развилка сбора, ряды бестиария, полосы ----
   Вёрстка по референсу docs/prototypes/encounter_random_prototype.html —
   референс, не донор: цвета переведены на токены, новых hex нет
   (жёлоб var(--hp-track) и поле var(--paper-bright) уже живут в файле, риски — альфа
   чернил #2b2620). ------------------------------------------------------ */

/* развилка «не из пресета»: корешки-табы. «Свои параметры» — активный
   ярлык (панель всегда под ним), «Автогенерация» — прямая ССЫЛКА на
   критерии (решение PM: тап сразу ведёт на ⚔ Критерии). */
.gather-fork { margin-top: 14px; }
.gather-fork__tabs {
  display: flex;
  gap: 8px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 12px;
}
.gather-fork__tab {
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: 3px 3px 0 0;
  color: var(--ink-soft);
  text-decoration: none;
}
.gather-fork__tab--active {
  background: var(--paper-bright);
  color: var(--brass-ink);
  font-weight: 700;
  border-color: var(--brass);
}
.gather-fork__tab--link { cursor: pointer; }
.gather-fork__tab--link:hover { background: var(--paper-hover); color: var(--brass-ink); }
.gather-fork__tab--link:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: -2px;
}
.gather-fork__tab--off { opacity: 0.5; cursor: not-allowed; }
.gather-pane--own { display: block; }

/* строка добавления из пресета: [селект NPC][счётчик][добавить] */
.presetline {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.presetline .dm-select { flex: 1; min-width: 140px; }
/* кнопка «добавить» — той же высоты, что поле количества и селект (40),
   а не короче по контенту (единый ряд, урок про смешанные геометрии) */
.presetline .btn { height: var(--ctl-h); display: inline-flex; align-items: center; }
/* поле количества — в стиль проекта (пергамент/моно/центр), высотой
   в ряд с селектом и кнопкой (40); не дефолт браузера */
.presetline input[type="number"] {
  /* скин, моно и фокус — класс .dm-input.dm-num (адаптер вычеркнут шагом 6);
     здесь — только геометрия */
  width: 72px;
  text-align: center;
}

/* --- примитивы полей (шаг 2 ребилда 3.1) ---------------------------
   Правило PM шага 17: один логический контрол одинаков ВЕЗДЕ.
   .dm-input — текст/число/поиск; .dm-select — селект; .dm-num —
   модификатор моно-числа (вешается ВМЕСТЕ с .dm-input).
   Скин «мягкой латуни» (выбор PM 18.08, пробник v4): свежий лист, тихая
   граница --line + внутренняя тень — «здесь вводят» несут светлый лист и
   углубление, не тёмная рамка (пересмотр §11 п.6 решением PM); радиус
   --r-ctl, высота --ctl-h — тач 40 (стандарт PM 25.07), мышь 38 (единая
   контрольная линия). Геометрия (width/flex) — у
   контекстных классов; чернильный фокус — канон шага 1. */
.dm-input,
.dm-select,
/* адаптеры примитива: исторические контекстные селекторы полей.
   Скин ТОЛЬКО здесь; контекстные блоки держат геометрию (width/flex/
   отступы). Перевод разметки на класс .dm-input — по ходу шагов 3+,
   адаптер тогда вычёркивается из списка. */
.randform__field select,
.player-form input:not([type="checkbox"]):not([type="file"]),
.player-form textarea,
.skips--custom select,
.skips--custom input[type="number"],
.event-form input,
.event-form select,
.recur-len input,
.settings input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.settings select,
.settings textarea,
.setup__form input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.setup__form select,
.setup__form textarea,
.builder__row input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.builder__frow input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
.combat-add__form input:not([type="checkbox"]),
.combat-add__form select,
.fightform input[type="text"],
.fightform input[type="number"],
.bestiary__count,
.bestiary__filter-row select,
.bestiary__filter-row input:not([type="checkbox"]),
.player-form select,

.give-custom input:not([type="checkbox"]),
.gold-form__num,
.gold-form__reason input,
.lootform__num,
.hp__custom,
.lk-adddm input {
  height: var(--ctl-h);
  padding: 6px 12px;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  background-color: var(--paper-bright);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  box-shadow: inset 0 1px 2px #2b26200d;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
/* рука над полем — рамка теплеет заранее (v4); один список на примитив
   и адаптеры, как у плейсхолдеров */
.dm-input:hover,
.dm-select:hover,
.randform__field select:hover,
.player-form input:not([type="checkbox"]):not([type="file"]):hover,
.player-form textarea:hover,
.player-form select:hover,
.skips--custom select:hover,
.skips--custom input[type="number"]:hover,
.event-form input:hover,
.event-form select:hover,
.recur-len input:hover,
.settings input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):hover,
.settings select:hover,
.settings textarea:hover,
.setup__form input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):hover,
.setup__form select:hover,
.setup__form textarea:hover,
.builder__row input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):hover,
.builder__frow input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):hover,
.combat-add__form input:not([type="checkbox"]):hover,
.combat-add__form select:hover,
.fightform input[type="text"]:hover,
.fightform input[type="number"]:hover,
.bestiary__count:hover,
.bestiary__filter-row select:hover,
.bestiary__filter-row input:not([type="checkbox"]):hover,
.give-custom input:not([type="checkbox"]):hover,
.gold-form__num:hover,
.gold-form__reason input:hover,
.lootform__num:hover,
.hp__custom:hover,
.lk-adddm input:hover { border-color: var(--brass-lo); }
textarea.dm-input,
.player-form textarea,
.settings textarea,
.setup__form textarea { height: auto; min-height: 72px; resize: vertical; }
.dm-num,
.hp__custom,
.bestiary__count,

.give-custom input[type="number"],
.gold-form__num,
.lootform__num,
.fightform input[type="number"] {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
/* чернила 55 — закон форм §6.6; один список на примитив и адаптеры
   (дефолтный серый UA у плейсхолдеров items/gear/gold — находка аудита 15.08) */
.dm-input::placeholder,

.bestiary__count::placeholder,
.bestiary__filter-row input::placeholder,
.player-form input::placeholder,
.player-form textarea::placeholder,
.settings input::placeholder,
.settings textarea::placeholder,
.setup__form input::placeholder,
.setup__form textarea::placeholder,
.event-form input::placeholder,
.combat-add__form input::placeholder,
.fightform input::placeholder,
.give-custom input::placeholder,
.gold-form__reason input::placeholder,
.gold-form__num::placeholder,
.lootform__num::placeholder,
.lk-adddm input::placeholder,
.builder__row input::placeholder,
.builder__frow input::placeholder,
.recur-len input::placeholder,

.skips--custom input::placeholder,
.hp__custom::placeholder { color: #2b262055; }
/* фокус «мягкой латуни»: мышь — латунное свечение (декор box-shadow),
   клавиатура — кольцо латуни чернилами (механика outline, урок 1.6;
   brass-ink на бумаге AA 5.0 — чистая латунь слепла 2.5). Один список на
   примитив и адаптеры (аудит 18.08: свечение только у классов примитива
   раскалывало «один контрол — один вид»); outline здесь НЕ гасим — рулит
   :focus-visible, иначе специфичность :not-хвостов убьёт кольца */
.dm-input:focus,
.dm-select:focus,
.randform__field select:focus,
.player-form input:not([type="checkbox"]):not([type="file"]):focus,
.player-form textarea:focus,
.player-form select:focus,
.skips--custom select:focus,
.skips--custom input[type="number"]:focus,
.event-form input:focus,
.event-form select:focus,
.recur-len input:focus,
.settings input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus,
.settings select:focus,
.settings textarea:focus,
.setup__form input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus,
.setup__form select:focus,
.setup__form textarea:focus,
.builder__row input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus,
.builder__frow input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus,
.combat-add__form input:not([type="checkbox"]):focus,
.combat-add__form select:focus,
.fightform input[type="text"]:focus,
.fightform input[type="number"]:focus,
.bestiary__count:focus,
.bestiary__filter-row select:focus,
.bestiary__filter-row input:not([type="checkbox"]):focus,
.give-custom input:not([type="checkbox"]):focus,
.gold-form__num:focus,
.gold-form__reason input:focus,
.lootform__num:focus,
.hp__custom:focus,
.lk-adddm input:focus {
  border-color: var(--brass);
  box-shadow: inset 0 1px 2px #2b26200a, 0 0 0 3px #b08d4f4d; /* альфа --brass */
}
.dm-input:focus-visible,
.dm-select:focus-visible,
.randform__field select:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: 2px;
  border-color: var(--brass);
}

/* нативная стрелка UA у селектов — вне канона значков: карандашный шеврон
   (в data-URI живёт только литерал — %235c5346 = значение токена --ink-soft) */
.dm-select,
.randform__field select,
.skips--custom select,
.event-form select,
.settings select,
.setup__form select,
.player-form select,
.combat-add__form select,
.bestiary__filter-row select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 30px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%235c5346' stroke-width='1.6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
}

/* .dm-file — файл-поле: латунный пунктир приглашения (рисунок добыт импортом
   героя 2.6, примитивом стал шагом 1 рефаба). Кнопка выбора — лист примитива,
   подпись выбранного — выцветшие чернила; текст кнопки даёт локаль браузера. */
.dm-file {
  display: block;
  width: 100%;
  padding: 12px 9px;
  font: inherit;
  font-size: 13px;
  color: var(--ink-soft);
  background: var(--paper-bright);
  border: 1px dashed var(--brass);
  border-radius: var(--r-ctl);
  cursor: pointer;
}
.dm-file::file-selector-button {
  margin-right: 10px;
  padding: 6px 12px;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line); /* тихая рамка «мягкой латуни» */
  border-radius: var(--r-ctl);
  cursor: pointer;
}
.dm-file:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: 2px;
}

/* ряды мобов сбора: пресетные и бестиарные — одна геометрия */
.bst-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0;
}
.bst-row__name {
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;         /* «Взрослый зелёный дракон» не распирает ряд */
  text-overflow: ellipsis;
  min-width: 0;
  flex-shrink: 1;
}
.bst-row__meta {
  flex: 1;
  min-width: 0;
  font-size: 12px;
  font-family: var(--font-mono);
  color: var(--ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bst-row__count { width: 96px; }
.bst-row__del {
  width: 40px;
  min-height: var(--ctl-h);
  border: 0;
  background: none;
  color: var(--ink-soft);
  font-size: 15px;
  cursor: pointer;
  border-radius: var(--r-ctl);
}
.bst-row__del:hover { color: var(--wax); }
.bst-row__del:focus-visible { outline: 2px solid var(--brass-ink); outline-offset: 2px; }

/* сегмент сложности: клон .crit-seg, всегда видимый; выбранная ступень —
   латунью, выбранный «смертельный» (последний) — сургучом (референс 17) */
.diff-seg {
  display: inline-flex;
  flex-wrap: wrap;        /* четыре ступени на узком телефоне — в два ряда */
  max-width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  overflow: hidden;
}
.diff-seg__opt input { position: absolute; opacity: 0; pointer-events: none; }
.diff-seg__opt span {
  display: inline-flex;
  align-items: center;
  min-height: var(--ctl-h);
  padding: 0 14px;
  cursor: pointer;
  border-left: 1px solid var(--line);
}
.diff-seg__opt:first-child span { border-left: 0; }
.diff-seg__opt input:checked + span {
  background: var(--brass);
  color: var(--ink); /* пара канона «чернила на латуни» 4.8:1 */
  font-weight: 700;
}
.diff-seg__opt:last-child input:checked + span {
  background: var(--wax);
  color: var(--paper-bright); /* на сургуче — светлый лист, 6.2:1 */
}
.diff-seg__opt input:focus-visible + span {
  outline: 2px solid var(--brass-ink);
  outline-offset: -2px;
}

/* страница критериев: поля и сводка партии */
.randform__filters {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 12px;
}
.randform__field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 13px;
  color: var(--ink-soft);
}
.randform__field select { min-width: 150px; }
.randform__party {
  background: var(--paper-bright);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 10px 12px;
  margin: 6px 0;
  font-size: 14px;
}
.randform__party b { font-family: var(--font-mono); font-weight: 500; }
/* бюджет виден только у выбранной ступени (:has по радио — ноль JS) */
.randform__budget { display: none; color: var(--brass-ink); }
.randform:has(input[value="easy"]:checked)   .randform__budget--easy,
.randform:has(input[value="medium"]:checked) .randform__budget--medium,
.randform:has(input[value="hard"]:checked)   .randform__budget--hard,
.randform:has(input[value="deadly"]:checked) .randform__budget--deadly {
  display: inline;
}

/* полоса XP-бюджета: масштаб потолка +10% — риски 70% и 100% видны,
   перебор занимает честный хвост справа */
.budget { margin: 14px 0 4px; }
.budget__cap {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  color: var(--ink-soft);
}
.budget__cap b {
  font-family: var(--font-mono);
  font-weight: 500;
  color: var(--ink);
}
.budget__tier { font-style: italic; }
.budget__track {
  position: relative;
  height: 10px;
  border-radius: 999px; /* капсула полосы */
  background: var(--hp-track);   /* жёлоб полосок хитов — тот же материал */
  overflow: hidden;
  margin-top: 5px;
}
.budget__goal,
.budget__cap100 {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  background: #2b262059;
  z-index: 1;
}
.budget__cap100 { background: #2b262080; }
.budget__fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 0%;
  background: var(--brass);
  transition: width var(--t-swap) ease;
}
.budget__fill--low { background: var(--ink-soft); opacity: 0.45; }
.budget__fill--over { background: var(--wax); }
.budget__verdict {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--ink-soft);
}
.budget__word--ok { color: var(--brass-ink); }
.budget__word--over { color: var(--wax); }

/* встречная шкала хитов: руки от риски паритета — латунь влево (запас
   партии), сургуч вправо (перевес мобов); пороги вердикта — в encgen */
.hpline { margin-top: 10px; }
.hpvs {
  position: relative;
  height: 10px;
  border-radius: 999px; /* капсула полосы */
  background: var(--hp-track);
  overflow: hidden;
  margin-top: 5px;
}
.hpvs__mid {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  background: #2b262080;
  z-index: 1;
}
.hpvs__arm {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 0%;
  transition: width var(--t-swap) ease;
}
.hpvs__arm--party { right: 50%; background: var(--brass); }
.hpvs__arm--mobs { left: 50%; background: var(--wax); }

/* добавлялка из бестиария: details-панель под формой (остров вне формы —
   вложенных форм HTML не знает); кнопки добавления — btn высотой 40 */
.adder {
  margin-top: 14px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--paper-bright);
}
.adder summary {
  list-style: none;
  cursor: pointer;
  min-height: 44px;
  display: flex;
  align-items: center;
  padding: 0 12px;
  font-weight: 700;
  color: var(--brass-ink);
}
.adder summary::-webkit-details-marker { display: none; }
.adder summary::before { content: "+"; margin-right: 8px; font-size: 17px; }
.adder summary:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: -2px;
}
.adder__inner { padding: 2px 12px 12px; }

/* ============================================================================
   Инвентарь и выдача (Фаза 2.2 шаг 2)
   Ряд выдачи в каталоге [герой][кол-во][＋ герою], строка статуса, форма
   кастома и блок инвентаря на «Полном листе». Элементы — в стиле проекта
   (пергамент var(--paper-bright), латунный фокус, моно у чисел), соседей ряда равняем
   по высоте ЯВНО (правило PM: input/select/button — разная геометрия).
   ========================================================================= */

/* --- ряд выдачи в результатах каталога --- */
.give {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.give__hero { min-width: 120px; max-width: 190px; }
/* три соседа ряда — одной высоты (38), явно: селект по умолчанию 40, кнопка
   короче по контенту — иначе ступеньками */
.give .dm-select,
.give .bestiary__count,
.give .btn { height: 38px; }
.give .btn { display: inline-flex; align-items: center; }
.give .bestiary__count { margin-right: 0; }

/* --- строка статуса выдачи (свой слот вне острова поиска) --- */
.give-status-slot:empty { margin: 0; }
.give-status {
  margin: 8px 0;
  padding: 7px 11px;
  border-radius: 3px;
  font-size: 13px;
}
.give-status--ok {
  color: var(--brass-ink);
  background: var(--paper-mute);
  border-left: 3px solid var(--brass);
}
.give-status--err {
  color: var(--wax);
  background: var(--paper-err); /* был второй розовый #f3e2dd — схлопнут (§2.3) */
  border-left: 3px solid var(--wax);
}

/* --- форма кастомного предмета --- */
.give-custom { display: flex; flex-direction: column; gap: 10px; }
.give-custom__row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: flex-end;
}
/* кнопка равняется по НИЗУ поля: center против полей с лейблами-колонками
   давал ступеньку 11px (аудит 18.08, ловушка «align-items центрирует») */
.give-custom__row--foot { align-items: flex-end; }
.give-custom label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--ink-soft);
}
/* скин и высота 40 — примитив полей (шаг 2); был локальный 38 */
.give-custom input[type="number"] {
  width: 90px;
  text-align: center;
}
.give-custom input:focus-visible,
.give-custom .dm-select:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: 2px;
  border-color: var(--brass);
}
/* .dm-select — высота 40 из примитива; локальный 38 снят (шаг 2) */
.give-custom__hero .dm-select,
.give-custom__hero { min-width: 150px; }
.give-custom__name,
.give-custom__type,
.give-custom__note { flex: 1; min-width: 170px; }
.give-custom__name input,
.give-custom__type input,
.give-custom__note input { width: 100%; }
/* чекбокс настройки — латунным акцентом, ряд не колонкой */
.give-custom__att {
  display: flex; /* без явного display flex-direction был мёртв — чекбокс падал в столбик */
  flex-direction: row;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ink);
}
/* чекбокс «требует настройки» — общий примитив .wax-check (шаг 1 ребилда);
   локальный native-скин (16px + accent-color) снят */
.give-custom__row--foot .btn--brass { height: var(--ctl-h); margin-left: auto; }

/* --- пульт «Казна» (Фаза 2.3): баланс латунью, форма проводки, лента ------- */
.gold__balance {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 16px;
}
.gold__balance-label { font-size: 13px; color: var(--ink-soft); }
.gold__balance-sum {
  font-family: var(--font-mono);
  font-size: 26px;
  color: var(--brass-ink);           /* латунь = ресурс */
}
.gold-form { display: flex; flex-direction: column; gap: 12px; margin-bottom: 20px; }
.gold-form__row { display: flex; gap: 14px; flex-wrap: wrap; align-items: flex-end; }
/* низ формы: кнопка равняется по ПОЛЮ причины, не по всей колонке (подпись+поле).
   flex-end — низы поля и кнопки на одной линии (обе 40px), align-items:center
   всплывал бы кнопкой к подписи (ловушка «разная геометрия» из правила PM) */
.gold-form__row--foot { align-items: flex-end; }
.gold-form__coins { display: flex; gap: 8px; }
/* подпись номинала над узким моно-полем; ряд равняем по высоте ЯВНО (правило
   PM: сегмент 40 и поля 40 — иначе ступеньками) */
.gold-form__coin,
.gold-form__reason {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--ink-soft);
}
.gold-form__reason { flex: 1; min-width: 200px; }
/* скин казны/лута — теперь общий примитив полей (шаг 2), локальный блок снят */
.gold-form__num {
  width: 84px;
  text-align: center;
}
/* монетное трио зм/см/мм везде одной ширины с эталоном казны (правило
   близнецов, шаг 17): касса и ценник полки были 56px */
.shop-wallet .bestiary__count,
.shop-rows__price .bestiary__count { width: 84px; }
.gold-form__reason input { width: 100%; }
.gold-form__num:focus-visible,
.gold-form__reason input:focus-visible,
.lootform__num:focus-visible {
  outline: 2px solid var(--brass-ink);
  outline-offset: 2px;
  border-color: var(--brass);
}
.gold-form__row--foot .btn--brass { height: var(--ctl-h); margin-left: auto; }

/* лента проводок — плотность справочника, суммы моно, знак материалом */
.gold-ledger { list-style: none; margin: 0; padding: 0; }
.gold-row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 8px 0;
  border-top: 1px solid var(--line);
}
.gold-row__sum {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; /* колонка сумм леджера (§4.1) */
  font-size: 14px;
  white-space: nowrap;
  min-width: 116px;
}
.gold-row__sum--in { color: var(--brass-ink); }   /* приход — латунь */
.gold-row__sum--out { color: var(--wax); }         /* расход — сургуч */
.gold-row__reason { flex: 1; min-width: 0; color: var(--ink); font-size: 14px; }
.gold-row__who { font-weight: 600; color: var(--ink); }   /* имя героя-контрагента */
.gold-row__when {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
  white-space: nowrap;
}
.gold__empty { color: var(--ink-soft); font-size: 14px; }

/* кошельки героев: подзаголовок-разделитель, стаб-флаг, список балансов,
   форма перевода (реюз .gold-form + .dm-select + .wax-check) */
.gold-heroes {
  margin: 22px 0;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.gold__subhead {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--brass-ink);
}
/* строка-капабилити «что можно героям»: галочка + пояснение. Имя
   историческое (родилась в казне), но примитив общий — им же набран
   тумблер обмена в Настройках (Фаза 4 шаг 6a). Второй такой же класс
   ради другого имени был бы близнецом, а не порядком. */
.gold-flag {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-bottom: 14px;
  font-size: 13px;
  color: var(--ink);
}
.gold-flag i { color: var(--ink-soft); }
.gold-wallets { list-style: none; margin: 0 0 18px; padding: 0; }
.gold-wallet {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  border-top: 1px solid var(--line);
}
.gold-wallet__name { color: var(--ink); font-size: 14px; }
.gold-wallet__sum {
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--brass-ink);           /* кошелёк героя — тоже ресурс, латунь */
  white-space: nowrap;
}
.gold-transfer__hero {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--ink-soft);
  min-width: 150px;
}
.gold-transfer__hero .dm-select { height: var(--ctl-h); }

/* --- инвентарь: свой спойлер (.sheet--inv), отдельно от «Полного листа» --- */
/* счётчик у summary — латунью-моно, чуть отодвинут от слова «Инвентарь» */
.inv__count {
  font-family: var(--font-mono);
  color: var(--brass-ink);
  font-size: 13px;
  margin-left: 2px;
}
/* итог веса у summary — тише счётчика (справочная величина, не акцент) */
.inv__weight {
  font-family: var(--font-mono);
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 400;
}
.inv__empty { margin: 6px 0 0; font-size: 13px; color: var(--ink-soft); font-style: italic; }
/* сортировка инвентаря (фаза «Стол игроков» шаг 1): тихий компакт-ряд —
   литерал 32 как самосогласованный петит (мельче полей форм сознательно:
   служебный контрол, не ввод данных) */
.inv__sort { display: flex; align-items: center; gap: 8px; margin: 8px 0 0; }
.inv__sort label { font-size: 13px; color: var(--ink-soft); }
.inv__sort .dm-select { height: 32px; width: auto; font-size: 13px; padding: 2px 26px 2px 8px; }
/* Подзаголовок внутри списка — ОДИН примитив на подгруппы инвентаря
   (заказ PM 24.08 «не стена текста») и разделы обмена: .trade__head жил
   в разметке БЕЗ правила (сирота), теперь у обоих один голос — тихая
   строчная линия, отбивающая полку от полки. Латунная нить сверху
   работает как шов ящика; у первой полки её нет — заголовок и так
   первый после summary. */
.list__head,
.trade__head {
  margin: 14px 0 2px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--brass-ink);
  font-weight: 600;
}
.inv__list + .list__head,
.inv__list + .trade__head { margin-top: 10px; }
/* ПЕРВОЙ полке шва не нужно: она и так первая после шапки блока. Три
   входа, и все три обязаны попасть в правило (находки ревью 24.08):
   после summary спойлера, после селекта порядка и просто первым ребёнком
   карточки — так рождается первая полка в карманах соседа */
.inv__sort + .list__head,
summary + .list__head,
summary + .trade__head,
.list__head:first-child,
.trade__head:first-child { margin-top: 8px; border-top: none; padding-top: 0; }
.list__head .inv__count { text-transform: none; letter-spacing: 0; }

.inv__list { list-style: none; margin: 6px 0 0; padding: 0; }
/* Ряд списка — ГРИД «содержимое | действия» (правка PM 22.08 «сделаем
   ровно»). Флекс с wrap ставил действия куда придётся: у длинного имени
   блок кнопок переносился под строку, у короткого — липнул к имени, а
   колонка .inv__flags добавляла лесенку. Грид держит вторую колонку по
   правому краю ВСЕГДА, при любой длине имени; align-items:center равняет
   имя и кнопки по общей средней линии. */
.inv__row {
  display: grid;
  /* минимум колонке имени — иначе широкий блок тапов DM (± qty, надет,
     настроен, убрать) в узкой карточке пульта дожимает название до
     трёх строк. При нехватке места переносятся ДЕЙСТВИЯ внутри своей
     колонки (у обоих блоков flex-wrap), а не разваливается имя */
  grid-template-columns: minmax(9rem, 1fr) auto;
  align-items: center;
  column-gap: 10px;
  row-gap: 6px;
  padding: 7px 0;
  border-top: 1px solid var(--line);
}
/* Ряды в проекте двух форм: обёрнутая (.inv__more/.inv__main + действия —
   инвентарь, книга, полка лавки) и плоская (имя и мета прямыми детьми —
   обмен, журналы лавки). Раскладку задаём ОБЕИМ, чтобы «ровно» было
   везде, а не только там, где разметку переписали: текст ряда — левая
   колонка стопкой, блок действий — правая, по центру всей стопки. */
.inv__row > .inv__name,
.inv__row > .inv__meta,
.inv__row > .inv__note { grid-column: 1; }
.inv__row > .inv__flags,
.inv__row > .inv__acts {
  grid-column: 2;
  /* span вместо 1 / -1: явной сетки по строкам у ряда нет, а «-1» без неё
     схлопывается в первую строку — блок липнул к имени, оставляя пустой
     угол против меты (находка ревью). span 2 покрывает обе строки плоского
     ряда (имя + мета), у обёрнутого ряда строка одна и лишний трек не
     рождается */
  grid-row: 1 / span 2;
  align-self: center;
  justify-self: end;
}
/* CTA во всю ширину (приём/отказ/отзыв в обмене) — своей строкой под
   текстом: это не иконка ряда, а главное действие карточки */
.inv__row > form,
.inv__row > .lk-cta { grid-column: 1 / -1; }
.inv__row:first-child { border-top: none; }
.inv__row--worn {
  border-left: 3px solid var(--brass);
  padding-left: 8px;
  margin-left: -8px;   /* акцент не сдвигает содержимое ряда */
}
.inv__main { flex: 1; min-width: 0; }
.inv__name { margin: 0; font-size: 14px; font-weight: 600; }
.inv__qty { font-family: var(--font-mono); color: var(--brass-ink); font-size: 13px; }
.inv__meta { margin: 2px 0 0; font-size: 12px; color: var(--ink-soft); }
.inv__note { margin: 2px 0 0; font-size: 12px; color: var(--ink-soft); font-style: italic; }
/* действия ряда (сторона DM) — одной линией по правому краю; переносятся
   внутри своей колонки, не разваливая ряд (правка PM 22.08) */
.inv__acts {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  flex-wrap: wrap;
}
.inv__qtybox { display: inline-flex; gap: 2px; }
/* строка-спойлер предмета (шаг «витрина героя»): summary — прежняя шапка
   строки, латунный треугольник вращается на open (приём меню §13.2);
   подробности приезжают лениво в .inv__cardbody (intersect once) */
.inv__more { flex: 1; min-width: 0; }
.inv__more > .inv__main {
  cursor: pointer;
  list-style: none;
  position: relative;
  padding-left: 15px;
}
.inv__more > .inv__main::-webkit-details-marker { display: none; }
.inv__more > .inv__main::before {
  content: "";
  position: absolute;
  left: 0;
  top: 5px;
  width: 0;
  height: 0;
  border-left: 7px solid var(--brass);
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  transition: transform var(--t-tap) ease;
}
.inv__more[open] > .inv__main::before { transform: rotate(90deg); }
.inv__cardbody { padding: 6px 0 2px 15px; }
.inv__props {
  margin: 0;
  font-size: 12px;
  color: var(--ink-soft);
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
}
.inv__prop b { color: var(--ink); font-weight: 600; }
.inv__text { margin: 6px 0 0; font-size: 13px; white-space: pre-line; }
.inv__nothing { margin: 4px 0 0; font-size: 12px; color: var(--ink-soft); font-style: italic; }
/* активный тумблер (надет/настроен) — латунью, жирным, без подчёркивания */
.inv__toggle.is-on { color: var(--brass-ink); font-weight: 700; text-decoration: none; }

/* Генератор лута (2.4): ряд оценки бюджета + выдача клада. Числовое поле —
   ОБЩИЙ примитив с .gold-form__num (базовый скин там, здесь лишь ширина+моно);
   ряды равняем по высоте ЯВНО (правило PM: select/input/button 40 — иначе
   ступеньками). Полоса бюджета и встречная шкала — общие .budget/.hpvs
   (шаг 17); ряды клада — общий .bst-row без счётчика (qty всегда 1). */
.lootform__budget {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  margin: 14px 0 4px;
}
.lootform__budget .randform__field { margin: 0; }
.lootform__num { width: 150px; font-family: var(--font-mono); }
.lootform__budget .btn { height: var(--ctl-h); }

/* --- ИИ-режим генераторов (тест, заказ PM 09.09) --------------------
   Галочка «✦ ИИ сочиняет» + поле пожелания одним рядом под критериями
   (клад и бой — один компонент .ai-opt, правило PM «один контрол везде»).
   «Сцена»/«Находка» от модели — записка на пергаменте над полосой
   бюджета: затенённый лист поверх листа, карандашная рамка. Цвета —
   токенами, новых hex нет; ярлык «тест» — латунь чернилами (AA 5.0). */
.ai-opt {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin-top: 8px;
}
.ai-opt .named-check { margin-top: 0; }
.ai-opt__tag {
  font-style: normal;
  font-size: 11px;
  font-family: var(--font-mono);
  color: var(--brass-ink);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0 6px;
  margin-left: 4px;
}
.ai-opt__theme { flex: 1 1 260px; }
.ai-opt__theme input { width: 100%; }
.ai-story {
  margin: 12px 0 10px;
  padding: 10px 12px;
  background: var(--paper-shade);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
}
.ai-story__title { display: block; font-size: 14px; }
.ai-story__text {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--ink-soft);
  font-style: italic;
}
/* ряд клада от ИИ несёт механику предмета второй строкой ВНУТРИ ряда:
   ✕ уносит её вместе с рядом (JS снимает .loot-row целиком) */
.loot-row--ai { flex-wrap: wrap; }
.loot-row__note {
  flex-basis: 100%;
  margin: -2px 0 4px;
  font-size: 12px;
  color: var(--ink-soft);
  font-style: normal;
}
/* панель «ИИ» настроек: «проверить связь» и «убрать ключ» одним рядом */
.settings__ai-actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* окошко статуса генерации ИИ (просьба PM 09.09): узкая строка моно под
   галочкой — ожидание тикает секундами, итог показывает модель/время/
   токены; провал — сургучный акцент и спойлер с обрывком ответа */
.ai-status {
  margin: 8px 0 0;
  padding: 6px 10px;
  font-size: 12px;
  font-family: var(--font-mono);
  color: var(--ink-soft);
  background: var(--paper-bright);
  border: 1px dashed var(--line);
  border-radius: var(--r-ctl);
}
/* ожидание — единственное «долгое» состояние проекта (10–40 с), потому
   живое: искра пульсирует, точки бегут, латунная полоса скользит. Всё
   гаснет при reduced-motion (остаётся текст и счётчик секунд). */
.ai-status--pending[hidden] { display: none; }   /* display:flex ниже не должен перебивать hidden */
.ai-status--pending {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--ink);
  border: 1px solid var(--brass);
}
.ai-status--pending .ai-status__line { font-family: var(--font-body); }
.ai-status--pending .ai-status__tick { font-family: var(--font-mono); font-weight: 400; }
.ai-status--pending .ai-status__hint { flex-basis: 100%; margin: 0; }
.ai-status__spark {
  display: inline-block;
  color: var(--brass-ink);
  font-size: 18px;
  line-height: 1;
  animation: ai-spark 1.4s ease-in-out infinite;
}
.ai-status__dots::after {
  display: inline-block;
  width: 1.2em;
  text-align: left;
  content: "…";
  animation: ai-dots 1.2s steps(4, end) infinite;
}
.ai-status__bar {
  display: block;
  flex-basis: 100%;
  height: 4px;
  border-radius: 999px;
  background: #cdbfa480;               /* --line с альфой */
  overflow: hidden;
  position: relative;
}
.ai-status__bar::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 38%;
  border-radius: 999px;
  background: var(--brass);
  animation: ai-slide 1.3s ease-in-out infinite;
}
@keyframes ai-spark { 50% { opacity: 0.3; transform: scale(0.8) rotate(45deg); } }
@keyframes ai-dots { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "…"; } }
@keyframes ai-slide { from { left: -40%; } to { left: 100%; } }
@media (prefers-reduced-motion: reduce) {
  .ai-status__spark, .ai-status__bar::after, .ai-status__dots::after { animation: none; }
  .ai-status__bar::after { left: 0; width: 100%; opacity: 0.5; }
}
/* обыск павшего: индикатор внутри HTMX-формы, виден только на время
   запроса (класс htmx-request ставит HTMX); кнопка на это время глохнет */
.ai-working { display: none; }
.mob-search__form.htmx-request .ai-working {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
  flex-basis: 100%;
  font-size: 14px;
  color: var(--ink);
}
.mob-search__form.htmx-request .mob-search__go { opacity: 0.5; pointer-events: none; }
/* ИИ-автор вики (просьба PM 09.09): ряд «пожелание + ✦ Сочинить» внутри
   формы статьи; поле — примитив, кнопка ростом с поле (равнялка ряда) */
.wiki-form__ai { margin: 6px 0 14px; align-items: flex-end; }
.wiki-form__ai .ai-opt__theme { margin-bottom: 0; }
.wiki-form__ai .btn { height: var(--ctl-h); margin-bottom: 0; }
.wiki-form__ai .settings__hint { flex-basis: 100%; margin-top: 0; }
.ai-status--failed { border-style: solid; border-color: var(--wax); }
.ai-status--failed b { color: var(--wax); }
.ai-status__hint { display: block; font-family: var(--font-body); font-style: italic; }
.ai-status__raw { margin-top: 4px; }
.ai-status__raw summary { cursor: pointer; color: var(--brass-ink); }
.ai-status__raw pre {
  margin: 4px 0 0;
  max-height: 220px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 11px;
}
.loot-give__foot,
.loot-treasury {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 14px;
}
.loot-give__foot .dm-select { min-width: 150px; }
.loot-give__foot .btn,
.loot-treasury .btn { height: var(--ctl-h); margin-left: auto; }
.loot-treasury {
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.loot-treasury__field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--ink-soft);
}
.loot-row .bst-row__name { flex: none; }
.loot-row .bst-row__meta { flex: 1; }

/* Обыск павшего моба (2.4 шаг 3): «Проверка:» + ряд [Анализ:][бросок][крит]
   [Обыскать] — форма развёрнута явно (не свёрнута), всё в один ряд ВЫСОТОЙ 40,
   выровнено по оси (align-items:center; правило PM). Крит-сегмент — общий
   .crit-seg (вне fightform скрыт: показываем и дотягиваем до 40); поле — общий
   примитив .lootform__num. */
.mob-search { margin: 10px 0 2px; }
.mob-search__label {
  margin: 0 0 6px;
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.mob-search__form {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.mob-search__skill { font-size: 14px; color: var(--ink); }
.mob-search__num { width: 92px; text-align: center; }
.mob-search__crit {           /* вне fightform .crit-seg скрыт — показываем в рост ряда */
  display: inline-flex;
  height: var(--ctl-h);
  box-sizing: border-box;
}
.mob-search__crit .crit-seg__opt span {
  display: flex;
  align-items: center;
  height: 100%;
  padding: 0 12px;
}
.mob-search__go { height: var(--ctl-h); }
.mob-search__err { margin: 6px 0; }
.mob-search__done { margin: 8px 0 2px; font-size: 13px; color: var(--ink-soft); }
.mob-search__magic { color: var(--brass-ink); }
.mob-search__coins { font-family: var(--font-mono); color: var(--brass-ink); }
/* ИИ-обыск (тест, 09.09): галочка в ряду формы, фраза-история и статус под
   сводкой; откат к таблице — сургучом */
.mob-search__ai { margin-top: 0; }
.mob-search__story { margin: 4px 0 2px; font-size: 13px; font-style: italic; color: var(--ink-soft); }
.mob-search__ai-meta { margin: 2px 0; font-size: 11px; font-family: var(--font-mono); color: var(--ink-soft); }
.mob-search__ai-meta--err { color: var(--wax); }

/* --- Фаза 3 шаг 1: вход / регистрация ---------------------------------------
   Свежий лист по центру сукна. Поля — общий примитив .settings (пергамент
   var(--paper-bright), рамка --line, сургучный :focus-visible); здесь только layout-обёртка
   карточки, дублей полей нет. Инвайт-блок — в теле Меню, тем же материалом. */
.auth { max-width: 380px; margin: 8vh auto; padding: 0 20px; }
.auth__card {
  background: var(--paper-bright);
  border: 1px solid var(--line);
  border-top: 2px solid var(--brass);
  border-radius: 2px;
  padding: 22px 22px 26px;
}
.auth__eyebrow {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brass-ink);
  margin: 0 0 4px;
}
.auth__title {
  font-family: var(--font-display);
  font-size: 24px;
  margin: 0 0 16px;
}
.auth__error { color: var(--wax); font-size: 14px; margin: 0 0 14px; }
.auth__hint { color: var(--ink-soft); font-size: 13px; margin: 8px 0 0; }
.auth__note { display: block; margin-top: 4px; color: var(--ink-soft); font-size: 13px; }
.auth__switch {
  margin: 16px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  font-size: 14px;
}
.auth__switch a {
  display: inline-flex;
  align-items: center;
  min-height: 44px; /* «Сменить пароль» / «‹ Назад» — тап-цели, не петит (скрин PM 16.08) */
  color: var(--brass-ink);
  text-decoration: none;
}
.auth__switch a:hover { text-decoration: underline; }

/* «Оттиск ошибки» (шаг 4 ребилда, §6.13): печать с номером статуса */
.oops { text-align: center; }
.oops__seal {
  display: grid;
  place-items: center;
  width: 76px;
  height: 76px;
  margin: 6px auto 14px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%,
    var(--seal-hi) 0%, var(--seal-mid) 55%, var(--seal-lo) 100%);
  box-shadow: 0 2px 6px #0006, inset 0 1px 0 #ffffff30;
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: 0.04em;
}
.oops__title {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-size: 24px;
}
.oops__text { margin: 0 0 10px; font-size: 14px; color: var(--ink-soft); }

.invite-issued {
  margin-top: 12px;
  border-top: 1px solid var(--line);
  padding-top: 12px;
}
.invite-issued__label { font-size: 13px; color: var(--ink-soft); margin: 0 0 4px; }
.invite-issued__link { font-size: 13px; color: var(--ink-soft); margin: 10px 0 4px; }
.invite-issued__code {
  display: block;
  font-family: var(--font-mono);
  font-size: 15px;
  color: var(--brass-ink);
  word-break: break-all;
}

/* ── ЛК игрока /me (Фаза 3 шаг 4, канон §6.9; финальный вид — ребилд 3.1) ──
   mobile-first, одна колонка 430; карты на сукне; live-точка сургучом =
   осознанное исключение из «сургуч = беда» (лампа «запись идёт», §6.9) */
.lk {
  max-width: 430px;
  margin: 0 auto;
  padding: 14px 14px 40px;
  color: var(--paper);
}
.lk-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 6px 2px 16px;
}
.lk-nick {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 400;  /* h1-семантика (шаг 5) не меняет вид: гасим UA-стили */
  margin: 0;
  line-height: 1.1;
}
.lk-nick small {
  display: block;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--brass);
  letter-spacing: 0.04em;
}
/* .lk-bio снят вместе с «о себе» (решение PM 16.08) */

/* Аватарка (ЛК 2.0 шаг 2) — личная печать аккаунта. <img> — загруженная,
   <span data-initial> — фолбэк: сургуч с инициалом на триаде печати
   (пара paper-lit/seal-* канонизирована сургучом campaign-card). */
.avatar {
  display: inline-block;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  object-fit: cover;               /* для <img>; span не задевает */
  box-shadow: 0 1px 3px #0007, inset 0 1px 2px #ffffff30;
  vertical-align: middle;
  flex: none;
}
span.avatar {
  background: radial-gradient(circle at 35% 30%, var(--seal-hi), var(--seal-mid) 65%, var(--seal-lo));
  color: var(--paper-lit);
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 38px;
  text-align: center;
}
span.avatar::after { content: attr(data-initial); }
.avatar--lg { width: 72px; height: 72px; }
span.avatar--lg { font-size: 32px; line-height: 72px; }
.avatar--sm { width: 24px; height: 24px; }
span.avatar--sm { font-size: 12px; line-height: 24px; }
.pool-list__nick { font-size: 12px; }   /* @ник при имени: цвет наследуется */
.settings__avatar-row {            /* ряд «печать + поле файла» в /settings */
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 8px;
}
.settings__session {               /* строка устройства (шаг 4): даты — прибор */
  margin: 2px 0;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12.5px;
}
.lk-gear { margin-left: auto; position: relative; }
.lk-gear > summary {
  list-style: none;
  cursor: pointer;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  font-size: 20px;
  opacity: 0.75;
  border: 1px solid transparent;
  border-radius: var(--r-ctl);
}
.lk-gear > summary::-webkit-details-marker { display: none; }
.lk-gear > summary:hover { opacity: 1; border-color: var(--brass); }
.lk-gear > summary:focus-visible {
  opacity: 1;
  border-color: var(--brass);
  outline: 2px solid var(--brass);
  outline-offset: 2px;
}
.lk-gear__menu {
  position: absolute;
  top: calc(100% + 6px); /* отлип листа от шестерёнки: лист «поднят», не приклеен (§5.3) */
  right: 0;
  z-index: 5;
  width: min(260px, calc(100vw - 32px)); /* сверхузкие вьюпорты (Fold 280) — лист в кадре */
  /* длинный список мастеров скроллится ВНУТРИ листа: тач-скролл страницы
     начинается с pointerdown мимо details — data-close-outside схлопнул бы меню */
  max-height: calc(100dvh - 90px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 14px;
  /* «мягкая латунь»: лист с верхним светом, мягкая глубокая тень */
  background: linear-gradient(180deg, var(--paper-card), var(--paper));
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r-sheet);
  box-shadow: 0 1px 2px #1017112e, 0 12px 32px #10171159;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* фокус листа: латунь чернилами (глобальная латунь на пергаменте слепнет
   2.5:1, чистые чернила ушли с «мягкой латунью») — адаптер на интерактивы */
.lk-gear__menu :focus-visible { outline-color: var(--brass-ink); }
.lk-adddm label { display: block; font-size: 14px; color: var(--ink-soft); }
.lk-gear__menu .lk-adddm input {
  /* скин — примитив полей (шаг 2); ЛК — тач, высота 44 (канон §6.9);
     специфичность выше адаптера примитива — победа не порядком в файле.
     16px — порог автозума iOS при фокусе: меньше — Safari увозит лист */
  display: block;
  width: 100%;
  margin-top: 4px;
  height: 44px;
  font-size: 16px;
}
.lk-adddm input:focus-visible { border-color: var(--brass); } /* кольцо — адаптер листа выше */
/* CTA листа — во всю ширину (жест «мягкой латуни», пробник v4) */
.lk-adddm button { margin-top: 8px; width: 100%; }
.lk-adddm__error { margin: 6px 0 0; font-size: 13px; color: var(--wax); }
.lk-gear__hint { margin: 0; font-size: 14px; color: var(--ink-soft); } /* подпись зоны — кегль label */
/* «Твои мастера» с ✕ (шаг 6): ряд имя+кнопка, кнопка компактная */
.lk-dms { display: flex; flex-direction: column; gap: 2px; }
/* ряд мастера — тихая пилюля, оживает под рукой (v4) */
.lk-dms__row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  padding: 2px 8px;
  border-radius: calc(var(--r-ctl) + 1px);
  transition: background-color 120ms ease;
}
.lk-dms__row:hover { background: var(--paper-hover); }
/* ник без пробелов до 32 знаков шире листа: ужимается многоточием,
   ✕ остаётся на листе (идиома .lk-hero__meta) */
.lk-dms__row b {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lk-dms__row form { margin-left: auto; display: flex; }
.lk-dms__x {
  min-width: var(--tap-h);  /* тач-канон 44×44 (§3.3); высота явно, не наследством .lk .btn */
  min-height: var(--tap-h);
  padding: 0 6px;
  border-radius: var(--r-ctl);
  text-decoration: none; /* глиф — не строка, ghost-подчёркивание тут дефект */
}
.lk-dms__x:hover { background: #9e3b2f14; } /* альфа --wax: сургучный налив под рукой */
/* пункты меню одного роста: «Настройки» (ссылка) и «Выйти» (кнопка POST) —
   один скин, единая геометрия ряда (§6.2); скин element-agnostic */
.lk-gear__link {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: var(--tap-h); /* пункт меню — тап-цель, не строка петита */
  padding: 0;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 500;
  color: var(--brass-ink);
  /* «мягкая латунь»: подчёркивание только под рукой */
  text-decoration: none;
  background: none;
  border: 0;
  cursor: pointer;
  transition: color 120ms ease;
}
.lk-gear__link:hover { text-decoration: underline; text-underline-offset: 3px; }
/* «Выйти» — тихий выход: чернила-софт, под рукой тёмный сургуч (v4) */
button.lk-gear__link { color: var(--ink-soft); }
button.lk-gear__link:hover { color: var(--wax-deep); }
/* шов зон: навигация аккаунта отделяется линейкой от хозяйства мастеров —
   как листы пересборки /settings; внутри зоны швов нет */
.lk-gear__menu > a.lk-gear__link {
  border-top: 1px solid var(--line);
  padding-top: 12px;
  margin-top: 2px;
}
/* ряды одной зоны стоят вплотную: высоту воздуха даёт сама тап-цель 44,
   flex-gap листа между ними гасится */
.lk-gear__menu > a.lk-gear__link + form { margin-top: -10px; }

.lk-card {
  background: var(--paper);
  color: var(--ink);
  border-radius: 3px;
  padding: 14px 16px;
  box-shadow: 0 1px 0 #00000059, 0 6px 14px #00000040;
}
.lk-card + .lk-card { margin-top: 12px; }
.lk-sect {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--paper);
  opacity: 0.65;
  margin: 26px 2px 10px;
}

/* hero-карта «сейчас за столом» — сигнатура страницы */
.lk-now__top { display: flex; align-items: baseline; gap: 10px; }
.lk-now__top h1 {
  font-family: var(--font-display);
  font-size: 24px;
  margin: 0;
  line-height: 1.15;
}
.lk-live {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--brass-ink);
  white-space: nowrap;
}
.lk-live i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--wax);
  animation: lk-pulse 1.6s ease-in-out infinite;
}
@keyframes lk-pulse { 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .lk-live i { animation: none; } }
.lk-gametime {
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--brass-ink);
  margin: 2px 0 12px;
}
.lk-hero { display: flex; gap: 12px; align-items: center; }
.lk-crest {
  width: 52px;
  height: 52px;
  flex: none;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--brass-hi), var(--brass) 55%, var(--brass-lo));
  display: grid;
  place-items: center;
  color: var(--ink); /* был #241d12 — сведён к чернилам (§2.4) */
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 700;
  box-shadow: inset 0 1px 2px #ffffff80, 0 1px 2px #0000004d;
}
.lk-hero__meta { min-width: 0; }
.lk-hero__name { font-weight: 700; font-size: 18px; }
.lk-hero__sub { font-size: 14px; color: var(--ink-soft); }
.lk-hp { margin-top: 12px; }
.lk-hp__lbl {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  color: var(--ink-soft);
}
.lk-hp__lbl b {
  font-family: var(--font-mono);
  font-weight: 500;
  color: var(--ink);
}
.lk-hp__bar {
  height: 8px;
  border-radius: 999px;
  background: var(--hp-track);
  margin-top: 4px;
  box-shadow: inset 0 1px 1px #00000026;
  overflow: hidden;
}
.lk-hp__bar i {
  display: block;
  height: 100%;
  background: linear-gradient(180deg, var(--vital-hi), var(--vital));
}
.lk-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  margin-top: 14px;
  min-height: var(--tap-h);
  border: 1.5px solid var(--brass);
  border-radius: var(--r-ctl);
  color: var(--brass-ink);
  font: inherit;
  font-weight: 700;
  letter-spacing: 0.02em;
  background: var(--paper-bright);
  cursor: pointer;
}
.lk-cta:hover,
.lk-cta:focus-visible { background: var(--paper-hover); }
.lk-cta:focus-visible {
  outline: 2px solid var(--brass-ink); /* канон §3.3: на бумаге — чернильное кольцо */
  outline-offset: 2px;
}

/* стопка карточек-участий */
.lk-camp { border-left: 3px solid var(--brass); }
.lk-camp__name { font-family: var(--font-display); font-size: 19px; }
.lk-camp__sub {
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-size: 14px;
  color: var(--ink-soft);
  margin-top: 2px;
  flex-wrap: wrap;
}
.lk-camp__sub b { color: var(--ink); font-weight: 500; }
.lk-camp__date {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 12.5px;
}
.lk-camp--done {
  border-left-color: var(--chalk-dim);
  filter: saturate(0.75);
  opacity: 0.82;
}
.lk-pill {
  display: inline-block;
  font-size: 12px;
  color: #fff;
  background: var(--wax);
  border-radius: 999px;
  padding: 2px 9px;
  letter-spacing: 0.03em;
}
.lk-pill--quiet { background: var(--seal-quiet); }

/* витрина */
.lk-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  /* нативный ul вместо role-хака (шаг 5) — гасим дефолт списка */
  list-style: none;
  margin: 0;
  padding: 0;
}
.lk-stat {
  background: var(--paper);
  color: var(--ink);
  border-radius: 3px;
  padding: 12px 8px;
  text-align: center;
  box-shadow: 0 1px 0 #00000059, 0 4px 10px #00000033;
}
.lk-stat b {
  display: block;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 22px;
}
.lk-stat span { font-size: 12.5px; color: var(--ink-soft); }

/* пустое состояние — приглашение (§6.9) */
.lk-invite { margin-top: 12px; }
.lk-invite h2 {
  font-family: var(--font-display);
  font-size: 20px;
  margin: 0 0 8px;
}
.lk-invite p { margin: 0; color: var(--ink-soft); }
.lk-camp__top { display: flex; align-items: baseline; gap: 10px; }
.lk-camp__top .lk-live { margin-left: auto; }
.lk-cta--row { margin-top: 10px; min-height: var(--tap-h); } /* тач 44, мышь 38 */

/* Контур игрока — тач-цели 44px (§12.2; решение PM 06.08 по вопросу 1
   Фазы 4): примитив .dm-input держит 40px для пульта DM, где мышь и
   трекпад, а в ЛК игрок тычет пальцем в телефон за столом. Это не
   исключение в каноне, а СВОЙ размер контура — поэтому отдельный класс, а
   не пополнение списка исторических адаптеров полей выше. Идёт ПОСЛЕ
   .dm-input по файлу: специфичность та же, побеждает порядок. */
.lk-input { height: var(--tap-h); } /* тач 44, мышь — единая линия 38 (аудит 18.08) */
/* «Купить» строкой витрины: высоту НЕ ужимаем, в отличие от .lk-cta--row
   (38px на уже принятых экранах) — это вход в трату денег */
.lk-cta--buy { margin-top: 10px; }

/* подтверждение покупки (шаг 5) */
.lk-buy__item { margin: 0; font-weight: 700; }
.lk-buy__meta { margin: 2px 0 10px; color: var(--ink-soft); font-size: 13px; }
/* заметка лавочника под титулом: лежит на СУКНЕ (ink-soft давал 2.2:1) —
   мел + курсив, ремарка мастера (§4.1) */
.lk-shop-note {
  margin: 2px 0 10px;
  color: var(--chalk);
  font-size: 13px;
  font-style: italic;
}
.lk-buy__price, .lk-buy__total, .lk-buy__wallet { margin: 10px 0 0; }
/* деньги сравнивают глазами — моно с ровными разрядами (§4.1) */
.lk-buy__price strong,
.lk-buy__total strong {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.lk-buy__field { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
/* 92px — только числовым полям; селекты «Что»/«Кому» резало до «Длинны»
   (аудит 18.08) — им полная ширина листа */
.lk-buy__field .dm-num { width: 92px; }
.lk-buy__field .dm-select { width: 100%; }
/* торг у прилавка (0050): контекстному классу — только геометрия (канон);
   цвета и скин полей/кнопок — от примитивов .dm-input/.btn */
.lk-haggle { margin-top: 12px; }
.lk-haggle__acts { display: flex; gap: 8px; margin-top: 8px; }
.lk-haggle__acts .btn { min-height: var(--tap-h); }   /* тап-мишень §6.9 */
.lk-buy__pay { margin: 12px 0 0; border: 1px solid var(--line); border-radius: 3px; padding: 8px 10px; }
.lk-buy__pay legend { padding: 0 6px; color: var(--ink-soft); font-size: 13px; }
.lk-buy__pay label { display: flex; align-items: center; gap: 8px; min-height: 44px; }

/* печати стола на публичной карточке-участии (шаг 7): узкая колонка ЛК —
   сетка печатей мельче, чем на пергаменте хроники */
.lk-camp__seals {
  margin-top: 12px;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
}

/* «Добавить игрока по нику» (Меню → Пригласить игрока, доб. PM 24.07) */
.menu__hint--pool { margin-top: 14px; border-top: 1px dashed var(--line); padding-top: 12px; }
/* статус пула — общий примитив .give-status (шаг 2 ребилда); локальный
   близнец .pool-added снят */
/* список пула с ✕ (шаг 6): ряд имя+кнопка, зеркало .lk-dms игрока */
.pool-list { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
.pool-list__row { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.pool-list__row form { margin-left: auto; display: flex; }
.pool-list__x { min-width: 30px; min-height: 26px; padding: 0 6px; }

/* смена пароля (Фаза 3 шаг 4.5): ссылки-точки входа */
.cabinet__pwlink {           /* близнец .cabinet__logout, но <a> */
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.cabinet__pwlink:hover { color: var(--brass); }

/* витрина героя /me/hero (Фаза 3 шаг 5): read-only лист + инвентарь + золото */
/* титул страниц ЛК (лавки, покупка, обмен): печатный станок на сукне —
   класс жил в шаблонах с Фазы 4, скина не имел (аудит 15.08) */
.lk-title {
  margin: 2px 0 14px;
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--paper-lit);
}

.lk-back { margin: 0 2px 12px; font-size: 14px; }
.lk-back a {
  color: var(--brass);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.lk-back a:hover { color: var(--paper); }
.lk-back a:focus-visible { color: var(--paper); outline: 2px solid var(--brass); outline-offset: 2px; }
.lk-hero--link {                 /* ряд героя в hero-карте = ссылка на лист */
  text-decoration: none;
  color: inherit;
  border-radius: 3px;
  min-height: 44px;              /* тап-мишень §6.9 */
}
.lk-hero--link:hover .lk-hero__name,
.lk-hero--link:focus-visible .lk-hero__name { color: var(--brass-ink); }
.lk-hero--link:focus-visible { outline: 2px solid var(--brass-ink); outline-offset: 2px; } /* §3.3: бумага */
.lk-hero__go { margin-left: auto; font-size: 24px; color: var(--brass-ink); }
.lk-camp__hero {                 /* имя героя в стопке — вход на лист */
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--brass);
  text-underline-offset: 3px;
}
.lk-camp__hero:hover b, .lk-camp__hero:focus-visible b { color: var(--brass-ink); }
/* «Посетить торговца» (лист героя) — ряд-карточка в ГОЛОСЕ спойлеров
   листа (.sheet > summary: латунь, 500), но ссылкой: раскрывать нечего,
   выбор лавки — отдельная страница. Шеврон — как .lk-hero__go */
.lk-visit {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;              /* тап-мишень §6.9 */
  text-decoration: none;
  color: var(--brass-ink); /* §3.2: ряд на бумаге */
  font-weight: 500;
}
.lk-visit:hover, .lk-visit:focus-visible { color: var(--brass-ink); }
.lk-visit:focus-visible { outline: 2px solid var(--brass-ink); outline-offset: 2px; } /* §3.3: бумага */
.lk-visit__go { font-size: 24px; color: var(--brass-ink); }
/* карточка-ссылка торговца (страница «Торговцы», вход «Посетить
   торговца»): вся карточка — тап-мишень, калька .lk-hero--link. Цвет —
   ЯВНО чернилами, не inherit: у образца ссылка живёт ВНУТРИ карточки
   (inherit приносит ink с .lk-card), а торговец — САМА карточка, и
   inherit тянул --paper с контура .lk: имя сливалось с бумажным фоном */
.lk-merchant { display: block; text-decoration: none; color: var(--ink); }
.lk-merchant:hover .inv__name,
.lk-merchant:focus-visible .inv__name { color: var(--brass-ink); }
.lk-merchant:focus-visible { outline: 2px solid var(--brass-ink); outline-offset: 2px; } /* §3.3: бумага */
h1.lk-hero__name { margin: 0; font-size: 20px; font-weight: 700; }
.lk-herocamp {
  margin: 10px 0 0;
  font-size: 14px;
  color: var(--ink-soft);
  display: flex;
  gap: 8px;
  align-items: baseline;
  flex-wrap: wrap;
}
.lk-state { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 6px; }
.lk-state .chip { cursor: default; }        /* чипы состояния — не кнопки */
.lk .sheet + .sheet,
.lk .lk-card + .sheet { margin-top: 12px; }
.lk-card > summary { cursor: pointer; }
.inv__flags {           /* readonly-бейджи и действия игрока — ОДНОЙ ЛИНИЕЙ
                           по правому краю (правка PM 22.08 «сделаем ровно»:
                           колонка ставила «попросить»/«украсть» лесенкой и
                           роняла имя ряда на середину высоты) */
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 4px 8px;
}
/* ссылка-действие ряда: ростом с соседей по линии, не жмётся текстом */
.inv__pass { white-space: nowrap; }
.inv__flag {
  font-size: 11.5px;
  letter-spacing: 0.04em;
  color: var(--brass-ink);
  border: 1px solid var(--brass);
  border-radius: 999px;
  padding: 1px 8px;
  white-space: nowrap;
}
/* лента золота на 430: дата уходит вниз строки, суммы моно */
.lk .gold-row { flex-wrap: wrap; row-gap: 2px; }
.lk .gold-row__when { flex-basis: 100%; text-align: right; }

/* бой глазами игрока (фаза «Стол игроков» шаг 5): баннер + очередь хода.
   Только существующие токены; подсветка хода — общий .is-turn, полосы —
   .lk-hp__bar (у чужих ширина квантована сервером четвертями) */
.lk-combat { margin-top: 12px; }   /* отступ на секции, не на слоте: пустой
                                      узел ресинка зазора не оставляет */
.lk-combat__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.lk-combat__name {              /* имя боя — ввод DM до 120 знаков: переносим,
                                   не режем (min-width:0 — иначе flex не даст
                                   ужаться, слитная строка распёрла бы ряд) */
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  min-width: 0;
  overflow-wrap: anywhere;
}
.lk-combat__round { font-size: 13px; color: var(--ink-soft); white-space: nowrap; }
.lk-combat__plate {
  margin-top: 10px;
  padding: 8px 10px;
  background: var(--paper-mute);
  border-radius: 6px;
  font-size: 14px;
}
.lk-combat__plate p { margin: 0; }
.lk-combat__plate p + p { margin-top: 4px; }
.lk-combat__order {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: grid;
  gap: 8px;
}
.lk-combat__row {
  padding: 8px 10px;
  background: var(--paper-card);
  border: 1px solid var(--line);
  border-radius: 6px;
}
.lk-combat__row--mob {                    /* враг: истёртый лист, шов пунктиром
                                             — голос mob-card DM-доски */
  background: var(--paper-tile);
  border-style: dashed;
}
.lk-combat__line {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 4px;
}
.lk-combat__who {
  font-weight: 600;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lk-combat__hp {
  margin-left: auto;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 14px;
  white-space: nowrap;
}
.lk-combat__death { margin: 6px 0 0; font-size: 13px; color: var(--wax); }
.lk-combat__fallen { margin: 10px 0 0; font-size: 13px; color: var(--ink-soft); }

/* подарок золотом в «Карманах» (добавка 22.08): подводка формы — голосом
   вторичных подписей листа, не дефолтом браузера (правило CLAUDE.md) */
.purse-give { margin-top: 12px; }
.purse-give__head {
  margin: 0 0 8px;
  font-size: 14px;
  font-weight: 600;
}
.purse-give__mine { font-weight: 400; color: var(--ink-soft); }

/* каталог заклинаний игрока (фаза «Стол игроков» шаг 6): остров поиска
   бестиария живёт на листе ЛК как есть, свои только подводка и отступ */
.lk-catalog { margin-top: 12px; }
.lk-catalog__hint { margin: 0 0 10px; font-size: 14px; color: var(--ink-soft); }

/* мир кампании: время + события «доступно игрокам» */
#hero-world-slot { margin-top: 12px; }
.lk-world .lk-gametime { margin-top: 0; margin-bottom: 0; display: inline; }
.lk-world__wd { margin: 2px 0 0; font-size: 13px; color: var(--ink-soft); }
/* календарь из даты (решение PM 27.07): строка даты — summary, латунный
   треугольник вращается на open (приём меню §13.2); сетка — та же .month,
   что у DM-панели */
.lk-world__toggle {
  cursor: pointer;
  list-style: none;
  position: relative;
  padding-left: 15px;
  margin-bottom: 12px;
}
.lk-world__toggle::-webkit-details-marker { display: none; }
.lk-world__toggle::before {
  content: "";
  position: absolute;
  left: 0;
  top: 5px;
  width: 0;
  height: 0;
  border-left: 7px solid var(--brass);
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  transition: transform var(--t-tap) ease;
}
.lk-world__cal[open] > .lk-world__toggle::before { transform: rotate(90deg); }
.lk-world__cal .month { margin-top: 4px; }
.lk-world__cal .day-detail { margin-top: 8px; }
.lk-events { list-style: none; margin: 8px 0 0; padding: 0; }
.lk-event {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 7px 0;
  border-top: 1px solid var(--line);
}
.lk-event:first-child { border-top: none; }
.lk-event__when {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--brass-ink);
}
.lk-event__title { font-size: 14px; font-weight: 600; }
.lk-event__note { font-size: 13px; color: var(--ink-soft); }

/* --- книга заклинаний героя (шаг «Заклинания героя») ------------------------
   вкладки «Снаряженные | Известные»: радио на общем примитиве .diff-seg,
   панели переключает :has — ноль JS, как панели сетапа; выбранное радио
   переживает свапы сохранялкой app.js (data-preserve-details на блоке).
   Строки книги — общие классы .inv__*: одна плотность со строками
   инвентаря, своего здесь — только геометрия вкладок. */
/* ячейки заклинаний в книге (шаг 7 «Стола игроков»): ряд на уровень,
   закрашенный пип = свободная; латунь, не сургуч — ресурс, не беда.
   Кнопки — общий примитив btn--pip спасбросков */
.slotrows { margin: 10px 0 4px; display: grid; gap: 6px; }
.slotrow { display: flex; align-items: center; gap: 8px; }
.slotrow__lvl {
  min-width: 44px;
  font-size: 13px;
  color: var(--ink-soft);
  white-space: nowrap;
}
.slotrow__pips { display: flex; flex-wrap: wrap; gap: 4px; }
.slotrow .pip--on { background: var(--brass); border-color: var(--brass); }
.slotrows__rest { justify-self: start; }

.spelltab__seg { margin: 10px 0; }
/* обе вкладки равноправны: «смертельный» сургуч последней ступени примитива
   здесь не семантичен — вариант --tabs глушит его латунью */
.diff-seg--tabs .diff-seg__opt:last-child input:checked + span {
  background: var(--brass);
}
.spelltab__pane { display: none; }
.spelltab:has(.spelltab__radio--prep:checked) .spelltab__pane--prep,
.spelltab:has(.spelltab__radio--known:checked) .spelltab__pane--known {
  display: block;
}

/* --- вики мира (Фаза 3.2 шаг 3) -------------------------------------
   Лист статьи по канону §6.10: мера чтения, сериф --font-read, латунь
   чернилами на ссылках, тип-пилюля, подвал с тегами и бэклинками.
   Новых цветов НЕТ: всё существующими токенами (пилюля — brass-ink,
   как крещён шагом 17; фон секрета приедет шагом 4 вместе с ширмой). */
.wiki { max-width: 720px; margin: 0 auto; padding: 14px 16px 64px; }

/* лист статьи — та же поверхность, что .panel (градиент пергамента,
   радиус 3, тень с felt-deep): прототип рисовал плоский paper и radius 4,
   но канон 3.1 поверхностей один — близнеца не плодим */
.wiki-sheet {
  position: relative;
  background: linear-gradient(175deg, var(--paper) 0%, var(--paper-shade) 100%);
  color: var(--ink);
  border-radius: 3px;
  box-shadow:
    0 1px 0 #ffffff30 inset,
    0 10px 24px -10px var(--felt-deep);
  padding: 26px 26px 20px;
}
.wiki-sheet__kind {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .05em;
  color: var(--paper-bright);
  background: var(--brass-ink);
  border-radius: 999px;
  padding: 2px 10px;
}
.wiki-sheet__title {
  font-family: var(--font-display);
  font-size: 34px;
  line-height: 1.12;
  margin: 10px 0 2px;
}
.wiki-sheet__meta {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--ink-soft);
  margin: 0 0 18px;
}
/* тумблер видимости — тихая текст-кнопка в мета-строке (не вторая
   кнопка-соперник заголовку); состояние приходит с сервера */
.wiki-sheet__eye {
  font: inherit;
  background: none;
  border: 0;
  border-bottom: 1px dashed var(--line);
  padding: 0;
  color: var(--ink-soft);
  cursor: pointer;
}
.wiki-sheet__eye[aria-pressed="true"] { color: var(--brass-ink); }
.wiki-sheet__eye:hover { color: var(--brass-ink); }
.wiki-sheet__eye:focus-visible { outline: 2px solid var(--brass-ink); outline-offset: 2px; } /* §3.3: бумага */

/* лонгформ: сериф, мера 66ch, воздух абзацам (§6.10 «читают подряд») */
.wiki-sheet__body {
  font-family: var(--font-read);
  font-size: 18px;
  line-height: 1.55;
  max-width: 66ch;
}
.wiki-sheet__body p,
.wiki-sheet__body ul,
.wiki-sheet__body blockquote { margin: 0 0 14px; }
.wiki-sheet__body h2,
.wiki-sheet__body h3 {
  font-family: var(--font-display);
  line-height: 1.2;
  margin: 22px 0 8px;
}
.wiki-sheet__body h2 { font-size: 23px; }
.wiki-sheet__body h3 { font-size: 19px; }
.wiki-sheet__body ul { padding-left: 22px; }
.wiki-sheet__body blockquote {
  border-left: 3px solid var(--line);
  padding-left: 14px;
  color: var(--ink-soft);
  font-style: italic;
}

/* вики-ссылка: латунь чернилами + тонкое подчёркивание (§6.10) */
.wikilink {
  color: var(--brass-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
/* hover не перекрашивает подарок в беду (семантика §2.1) — жирнеет черта */
.wikilink:hover { text-decoration-thickness: 2px; }
.wikilink:focus-visible { outline: 2px solid var(--brass-ink); outline-offset: 2px; border-radius: 2px; } /* §3.3 */
/* битая — пунктир с «+»: приглашение дописать мир, ТОЛЬКО глазами DM
   (игрокская половина — плоский текст, приедет шагом 5) */
.wikilink--broken { text-decoration-style: dashed; }
.wikilink--broken::after { content: " +"; font-weight: 700; }

/* подвал листа: теги-пилюли и «Упоминается в» */
.wiki-pill {
  display: inline-block;
  font-size: 12.5px;
  color: var(--ink-soft);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 2px 10px;
}
.wiki-pill--kind {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--paper-bright);
  background: var(--brass-ink);
  border-color: var(--brass-ink);
}
.wiki-sheet__tags {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin: 18px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.wiki-sheet__back { margin-top: 14px; }
.wiki-sheet__back h2 {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 6px;
}
.wiki-sheet__back ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  gap: 8px 16px;
  flex-wrap: wrap;
}

/* ✎ — плавающая кнопка правки (§6.10): свежий лист в латунной кайме */
.wiki-fab {
  position: fixed;
  right: 18px;
  bottom: 18px;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--paper-bright);
  color: var(--brass-ink);
  display: grid;
  place-items: center;
  font-size: 20px;
  text-decoration: none;
  border: 1.5px solid var(--brass);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .35);
}
.wiki-fab:hover { background: var(--paper-hover); }
.wiki-fab:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }

/* индекс: список статей плотными рядами (§5.2 «Справочник») */
.wiki-index__new { margin: 0 0 12px; }
.wiki-list { margin: 0; padding: 0; list-style: none; }
.wiki-list__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 0; /* ряд ≥44 на таче (аудит: шаг сетки был ~41px) */
  border-bottom: 1px solid var(--line);
}
.wiki-list__link { color: var(--ink); font-size: 16px; }
.wiki-list__link:hover { color: var(--brass-ink); }
.wiki-list__hidden {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--ink-soft);
  white-space: nowrap;
}
/* секции индекса по типу статьи («тип = папка»): спойлер с честным
   счётчиком. summary остаётся list-item (flex снял бы маркер details) —
   счётчик инлайном, маркер латунью */
.wiki-section { margin: 0 0 2px; }
.wiki-section > summary {
  cursor: pointer;
  padding: 10px 0 4px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
}
.wiki-section > summary::marker { color: var(--brass-ink); } /* §3.2: маркер на бумаге */
.wiki-section__count {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 400;
  color: var(--ink-soft);
  margin-left: 4px;
}
.wiki-section > .wiki-list { margin-left: 18px; } /* створ под маркером */

/* форма статьи: тело — главный элемент экрана, ему и место */
.wiki-form__body {
  width: 100%;
  min-height: 340px;
  font-family: var(--font-read);
  font-size: 16px;
  line-height: 1.5;
  resize: vertical;
}
/* ряд «галочка + подпись»: .settings label ставит display:block со
   специфичностью 0-1-1 — своему классу нужен вес выше, иначе подпись
   уезжает под чекбокс (поймано скриншот-приёмкой). Форма импорта —
   семья .setup__import с тем же конфликтом: один логический контрол
   одинаков везде (правило PM) */
.settings label.wiki-form__check,
.setup__import label.wiki-form__check {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* --- за ширмой и созревание (Фаза 3.2 шаг 4) -------------------------
   Секрет — сургучная кайма 3px + пилюля-ярлык + фон на ступень темнее
   пергамента (§6.10). Новых цветов НЕТ: «ступень темнее» — уже крещёный
   --paper-tile («истёртый лист»), сургуч и латунь — свои токены.
   Глазами игрока этих блоков в HTML не существует: их вырезает рендер,
   а не эти правила (спрятанное стилем читается «просмотром кода»). */
.wiki-secret {
  position: relative;
  border-left: 3px solid var(--wax);
  background: var(--paper-tile);
  border-radius: 0 3px 3px 0;
  margin: 18px 0;
  padding: 16px 16px 4px;
}
/* созревание — латунная кайма: раскрытие это подарок, а не тайна (§2.1) */
.wiki-secret--ripen { border-left-color: var(--brass); }
/* звонок прозвенел — блок ЖДЁТ раскрытия (шаг 2 фазы 3.3: «созрело»
   больше не значит «открыто»). Отличие ГЕОМЕТРИЕЙ (пунктир), не новым
   цветом: пара «текст на фоне» у блока одна на все состояния */
.wiki-secret--open { border-left-style: dashed; }

/* полоса будильника на индексе: спойлер, открытый по умолчанию — если
   созревшее есть, мастер должен увидеть его, не раскрывая ничего */
.wiki-alarm { margin: 0 0 12px; }
.wiki-alarm > summary {
  cursor: pointer;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  color: var(--brass-ink);
}
.wiki-alarm__list { margin: 6px 0 0; padding: 0 0 0 18px; }
.wiki-alarm__list li { margin: 0 0 4px; }
.wiki-alarm__when,
.wiki-alarm__peek {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-left: 6px;
}
.wiki-secret__tag {
  position: absolute;
  top: -9px;
  left: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .05em;
  color: var(--paper-bright);
  background: var(--wax);
  border-radius: 999px;
  padding: 1px 8px;
}
.wiki-secret--ripen > .wiki-secret__tag { background: var(--brass-ink); }
/* моно-строка «откроется игрокам · дата» и маркер битой даты */
.wiki-secret__when {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--ink-soft);
  margin: 0 0 10px;
}

/* РАСКРЫТЫЙ блок глазами игрока (Фаза 3.3, решение PM 01.08): своё
   пространство имён .wiki-known — слова мастера («за ширмой», «созреет»)
   в периметр игрока не попадают ни при какой политике. Кайма латунная и
   тоньше сургучной: это не тайна, а узнанное за столом */
.wiki-known {
  position: relative;
  border-left: 2px solid var(--brass);
  background: var(--paper-tile);
  border-radius: 0 3px 3px 0;
  margin: 18px 0;
  padding: 16px 16px 4px;
}
.wiki-known__tag {
  position: absolute;
  top: -9px;
  left: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .05em;
  color: var(--paper-bright);
  background: var(--brass-ink);
  border-radius: 999px;
  padding: 1px 8px;
}
.wiki-known__when {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--ink-soft);
  margin: 0 0 10px;
}
/* «рассказать» — тихая ссылка ВНУТРИ раскрытого блока (шаг 3): передавать
   можно ровно то, что знаешь, и только там понятно, о чём речь */
.wiki-known__acts { margin: 6px 0 10px; }
.wiki-known__act {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--brass-ink);
}
.wiki-known__act:hover { color: var(--ink); }
/* страница передачи: блок цитатой — игрок видит, что подтверждает */
.wiki-tell__block {
  margin: 12px 0 16px;
  padding: 10px 14px;
  border-left: 2px solid var(--brass);
  background: var(--paper-tile);
  font-family: var(--font-read);
  white-space: pre-line;
}
/* блок, раскрытый за столом, глазами МАСТЕРА: сургучная кайма сплошная,
   но помечена — «эту тайну партия уже знает» */
.wiki-secret--told { border-left-color: var(--brass); }

/* панель «Протокол тайн» — хром мастера под телом статьи */
.wiki-proto { margin: 18px 0 0; padding-top: 14px;
  border-top: 1px solid var(--line); }
.wiki-proto__tab {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 8px;
}
.wiki-proto__list { margin: 0; padding: 0; list-style: none; }
.wiki-proto__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  border-bottom: 1px solid var(--line);
}
.wiki-proto__anchor {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--brass-ink);
}
.wiki-proto__peek {
  flex: 1 1 220px;
  color: var(--ink-soft);
  font-size: 14px;
}
.wiki-proto__state {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--ink-soft);
  white-space: nowrap;
}
.wiki-proto__acts,
.wiki-proto__catch { display: flex; flex-wrap: wrap; gap: 6px; }
.wiki-proto__catch { flex-basis: 100%; }

/* переключатель взгляда: сегмент в латунной кайме (прототип §6.10) */
.wiki-eyes {
  display: inline-flex;
  border: 1px solid var(--brass);
  border-radius: 999px;
  overflow: hidden;
  margin: 0 0 16px;
}
.wiki-eyes__btn {
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 7px 16px;
  min-height: 44px;           /* канон тап-цели §12.2: лист читают с планшета */
  display: inline-flex;
  align-items: center;
  cursor: pointer;
}
.wiki-eyes__btn:hover { color: var(--brass-ink); }
.wiki-eyes__btn[aria-current] {
  background: var(--brass);
  color: var(--ink);          /* пара «ink на brass» — крещёная (§Б) */
  font-weight: 700;
}
/* крайние сегменты держат форму пилюли — по ним же ложится кольцо фокуса */
.wiki-eyes__btn:first-child { border-radius: 999px 0 0 999px; }
.wiki-eyes__btn:last-child { border-radius: 0 999px 999px 0; }
/* фокус ЧЕРНИЛЬНЫЙ: канон §3.3 «на бумаге — чернильное кольцо». Полные
   чернила, а не ink-soft: кольцо ложится и на залитый ЛАТУНЬЮ активный
   сегмент, где soft даёт 2.4:1 (ниже порога UI 3:1), а ink — 4.8:1;
   латунное кольцо на латуни было бы 1:1, то есть невидимо. */
.wiki-eyes__btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: -3px;
}

/* ПЛАШКА ВИКИ — один примитив на все её экраны (сервер сообщает мастеру
   факт про эту страницу): «скрытой статьи игрок не видит вовсе» на листе,
   «статья ещё не добавлена» на форме рождения. Близнеца под каждый экран
   не заводим — канон общих примитивов */
.wiki-notice {
  border-left: 3px solid var(--wax);
  background: var(--paper-tile);
  color: var(--ink-soft);
  font-size: 14px;
  margin: 0 0 16px;
  padding: 8px 12px;
}

/* карта Watabou (шаг 6): тихая кнопка над телом + моно-подпись источника.
   Кнопка — общий .btn (кнопкой бывает и ссылка), здесь только геометрия ряда.
   На узком экране переносится ПОДПИСЬ, а не слова кнопки */
.wiki-sheet__map {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin: 0 0 16px;
}
.wiki-sheet__map .btn { white-space: nowrap; }
.wiki-sheet__map-credit {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--ink-soft);
}

/* ряд «сгенерировать» формы статьи: тихие ссылки шести генераторов Arcana */
.wiki-form__gens a {
  color: var(--brass-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  margin-right: 8px;
}

/* импорт .md (хвост 3.2): спойлер .import-alt + файл-семья .setup__import;
   здесь только геометрия страницы вики */
.wiki-import { margin: 0 0 12px; }
.wiki-import .setup__import { margin-top: 8px; }
.wiki-import__tpl {
  color: var(--brass-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.wiki-import__report { margin: 0 0 12px; }
.wiki-import__report:empty { margin: 0; }
/* «проверь» — не беда и не успех: латунные чернила (пара paper/brass-ink
   жива с шага 3, contrast_check её уже держит) */
.wiki-import__warn {
  margin: 0 0 6px;
  font-size: 13px;
  color: var(--brass-ink);
}
.wiki-import__warn a { color: inherit; }
.wiki-import__list {
  margin: 6px 0 0;
  padding-left: 20px;
  font-size: 14px;
}
.wiki-import__list a { color: var(--ink); }
.wiki-import__list a:hover { color: var(--brass-ink); }

/* снос статьи: тихая опасная кнопка под формой правки, отделена воздухом */
.wiki-form__del {
  margin-top: 18px;
  display: flex;
  justify-content: flex-end;
}

/* вход в вики с витрины героя (шаг 5): приглушённая строка под датой —
   чтение вдолгую не соперничает с «сейчас за столом» (§6.9) */
.lk-world__wiki { margin: 8px 0 0; }
.lk-world__wiki a {
  font-family: var(--font-read);
  font-size: 15px;
  color: var(--brass-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.lk-world__wiki-n {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--ink-soft);
  text-decoration: none;
  margin-left: 4px;
}
/* вики игроку — каркас ЛК (.lk), внутри карточек те же плотные строки,
   что у справочника DM; последняя строка списка без разделителя */
.wiki-player .wiki-list__row:last-child { border-bottom: 0; padding-bottom: 0; }
.wiki-player .wiki-list__row:first-child { padding-top: 0; }

/* смена взгляда — appear 180ms (§6.10); класс ставит СЕРВЕР только свапу
   взгляда, поэтому первая загрузка и тумблер видимости молчат (§7.3).
   reduced-motion глушит глобальным правилом «* { animation: none }» —
   своего дубля здесь не держим (канон: CSS без точечных вставок). */
.wiki-sheet__body--appear { animation: wiki-eyes-in var(--t-swap) ease; }
@keyframes wiki-eyes-in { from { opacity: 0; } }

/* --- лавка: список и торговый зал (Фаза 4 шаг 2) ---------------------------
   Скин — общие примитивы (.npcs, .give, .btn); здесь ТОЛЬКО геометрия
   инструментов строки и цвет ссылки-входа существующими токенами
   (правило «новый цвет — только токеном»: новых значений нет). */
.shops__link { color: var(--ink); }
.shops__link:hover { color: var(--brass-ink); }
.shop-rows__tools {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  white-space: normal; /* pre-line от .npcs__note ломал ряд переносами разметки */
}
.shop-rows__stock {
  display: flex;
  align-items: center;
  gap: 4px;
}
.shop-rows__label { color: var(--ink-soft); }
/* счётчик запаса − / + / ∞: были призрачные подчёркнутые глифы ~26px —
   тап-кнопки одной породы с ±хитов (аудит 15.08) */
.shop-rows__stock .btn--ghost {
  min-width: 40px;
  padding: 4px 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: 15px;
}
.shop-rows__price summary {
  cursor: pointer;
  color: var(--ink-soft);
}
/* маркеры раскрывашек полки — латунь-чернильная, как у всего пульта
   (чёрные UA-треугольники — «зоопарк», аудит 15.08) */
.shop-rows__price summary::marker,
.shop-rows__sell summary::marker { color: var(--brass-ink); }
.shop-rows__price form {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 6px;
}
/* white-space: normal переехал в основной блок .shop-rows__tools (дубль снят шагом 6) */

/* --- десктоп-компакт (правка PM 18.08) ------------------------------
   Тач-канон 44/40 (§3.3) — про палец; у fine-указки цели точнее:
   единая контрольная линия 38 — поле и кнопка одного роста («мягкая
   латунь», пробник v4). Тач (coarse/no-hover) в медиа не попадает и
   держит канон. Явные равнялки рядов сидят на тех же токенах
   (--ctl-h/--tap-h) — ряд ужимается целиком; литералы 38 (enc-row, .give)
   — самосогласованные компакт-ряды, их не трогаем. Блок стоит в конце
   файла сознательно — переопределения обязаны побеждать порядком. */
@media (hover: hover) and (pointer: fine) {
  /* «мягкая латунь»: единая контрольная линия 38 — поле и кнопка одного
     роста, ряды сходятся без подгонок (геометрия пробника v4) */
  :root { --ctl-h: 38px; --tap-h: 38px; }
  /* поле поповера ЛК: 44/16px — тач и порог автозума iOS Safari;
     мыши хватает стандарта поля */
  .lk-gear__menu .lk-adddm input { height: var(--ctl-h); font-size: 14px; }
  /* кнопки страницы аккаунта — дожим как у .lk (базовая строка — WIP
     password→settings, здесь только медиа-ступень) */
  .settings-page .btn { min-height: var(--tap-h); }
}
