/* Оформление по пакету Claude design (папка «Интерфейс», бриф 03.11.2026) и брендбуку:
   серая страница и белые панели, графитовое боковое меню с оранжевой отметкой текущего
   пункта, оранжевая главная кнопка с чёрным текстом (белый на оранжевом — 3,2:1, нельзя),
   логотип из брендбука, вход — графит с шестиугольниками. Решение «со всем согласен,
   продолжай» заменило решение 28.10.2026 о графитовом акценте RAL 7024 (docs/ui-reference.md
   §7). Классы — наши (на них стоят тесты), пакетные (.btn, .tbl, .steps…) не подключаются:
   облик им дают эти правила. Плотность таблиц — строка около 36 px, как в пакете. Оранжевый —
   действие и текущая позиция; срочность — красный и янтарный, готово — зелёный.
   Цвет пишется только здесь, в :root (tests/core/test_brand.py): правила берут переменные. */

:root {
  /* Бренд — брендбук EG, стр. 4 и 6, не менять (`Интерфейс/tokens.json`, brand). */
  --eg-orange-600: #F75C10;
  --eg-black: #000000;
  --eg-orange-500: #FF7835;
  --eg-graphite-700: #45494E;
  --eg-graphite-900: #292D32;
  --eg-slate-600: #525F7A;
  --eg-slate-400: #8D99B3;     /* только графика и маркеры, не текст: 2,9:1 */
  --eg-slate-200: #D7DDEA;
  --eg-slate-100: #ECEEF3;

  /* Веб-адаптация пакета (tokens.json, color): поверхности, текст, оболочка, действие, фокус. */
  --eg-bg: #ECEEF3;
  --eg-surface: #FFFFFF;
  --eg-surface-2: #F5F6F9;
  --eg-surface-hover: #F7F8FA;
  --eg-border: #D7DDEA;
  --eg-border-soft: #E6E9F0;
  --eg-border-input: #7A869F;  /* 3,7:1 к белому — граница полей */
  --eg-text: #292D32;
  --eg-text-2: #525F7A;        /* 6,4:1 на белом, 5,5:1 на фоне страницы */
  --eg-placeholder: #6B7690;   /* 4,55:1 — только на белом */
  --eg-shell: #45494E;
  --eg-shell-active: #292D32;
  --eg-on-shell: #FFFFFF;
  --eg-on-shell-2: #D7DDEA;
  --eg-action: #F75C10;
  --eg-action-hover: #FF7835;
  --eg-action-press: #E5520C;
  --eg-on-action: #000000;     /* 6,5:1 */
  --eg-accent-on-dark: #FF7835;
  --eg-focus: #292D32;
  --eg-focus-on-dark: #FFFFFF;
  /* Семантика — всегда со словом: просрочено, сегодня или завтра (янтарный), готово, нейтрально. */
  --eg-danger-fg: #B42318;
  --eg-danger-bg: #FDECEA;
  --eg-danger-dot: #D92D20;
  --eg-warn-fg: #8A4B00;
  --eg-warn-bg: #FFF1D6;
  --eg-warn-dot: #E0A000;
  --eg-ok-fg: #1E6B3A;
  --eg-ok-bg: #E5F3EA;
  --eg-ok-dot: #2E9150;
  --eg-neutral-fg: #525F7A;
  --eg-neutral-bg: #EEF0F5;
  --eg-info-fg: #292D32;
  --eg-info-bg: #EEF0F5;
  /* Из правил eg-ui.css, без имени в tokens.json: рамки сообщений, трек полоски, наведение на графите. */
  --eg-ok-line: #B7DEC3;
  --eg-danger-line: #F5C2BC;
  --eg-warn-line: #F2D9A6;
  --eg-bar-track: #E3E7EF;
  --eg-on-shell-hover: rgba(255, 255, 255, .06);

  /* Шрифт — системный стек пакета: файлов шрифтов и веб-лицензии бренд-бука нет. */
  --eg-font-ui: "Segoe UI", system-ui, -apple-system, "Roboto", "Helvetica Neue", Arial, sans-serif;
  --eg-fs-12: 12px; --eg-lh-12: 16px;
  --eg-fs-13: 13px; --eg-lh-13: 18px;
  --eg-fs-14: 14px; --eg-lh-14: 20px;
  --eg-fs-16: 16px; --eg-lh-16: 22px;
  --eg-fs-20: 20px; --eg-lh-20: 26px;
  --eg-fs-24: 24px; --eg-lh-24: 30px;
  --eg-fs-28: 28px; --eg-lh-28: 34px;
  /* Сетка: шаг 4, радиусы, высоты строки и полей, ширина меню и бокового столбца, тени. */
  --eg-sp-1: 4px; --eg-sp-2: 8px; --eg-sp-3: 12px; --eg-sp-4: 16px;
  --eg-sp-5: 20px; --eg-sp-6: 24px; --eg-sp-8: 32px;
  --eg-r-sm: 4px; --eg-r-md: 6px; --eg-r-lg: 8px;
  --eg-h-row: 36px; --eg-h-ctl: 36px; --eg-h-ctl-sm: 28px; --eg-h-touch: 44px; --eg-h-touch-lg: 48px;
  --eg-side-w: 216px; --eg-aside-w: 320px;
  --eg-shadow-1: 0 1px 2px rgba(41,45,50,.06);
  --eg-shadow-2: 0 4px 16px rgba(41,45,50,.10);
  --eg-shadow-lift: 0 14px 40px rgba(0, 0, 0, .28);   /* белая карточка входа на графите */

  /* Прежние имена — их берут правила ниже — указывают на токены пакета. Акцент теперь — цвет
     действия (оранжевый): `--accent-dark` — его наведение (светлее), `--accent-press` — нажатие. */
  --bg: var(--eg-bg);
  --panel: var(--eg-surface-hover);
  --soft: var(--eg-surface-2);
  --card: var(--eg-surface);
  --text: var(--eg-text);
  --muted: var(--eg-text-2);
  --faint: var(--eg-placeholder);
  --line: var(--eg-border);
  --line-strong: var(--eg-border-input);
  --accent: var(--eg-action);
  --accent-dark: var(--eg-action-hover);
  --accent-press: var(--eg-action-press);
  --on-accent-muted: var(--eg-on-shell-2);
  --late: var(--eg-danger-fg);
  --soon: var(--eg-warn-fg);
  --done: var(--eg-ok-fg);

  /* Рисунки — SVG в адресе data: (внешних файлов нет); цвет в них — здесь же, в :root.
     Шестиугольники входа («соты» брендбука): заливка — графит оболочки, мягкие тени — чёрная
     и белая полупрозрачные копии. */
  /* Значки пунктов меню — контурные 24×24, линия 1,8, как в пакете; рисует их маска цветом текста
     пункта, поэтому цвет линии в рисунке не важен. */
  --eg-icon-home: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 10 12 3l9 7v10a1 1 0 0 1-1 1h-5v-6H9v6H4a1 1 0 0 1-1-1Z'/%3E%3C/svg%3E");
  --eg-icon-grid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='7' height='7' rx='1'/%3E%3Crect x='14' y='3' width='7' height='7' rx='1'/%3E%3Crect x='14' y='14' width='7' height='7' rx='1'/%3E%3Crect x='3' y='14' width='7' height='7' rx='1'/%3E%3C/svg%3E");
  --eg-icon-list: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='8' y='2' width='8' height='4' rx='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2M12 11h4M12 16h4M8 11h.01M8 16h.01'/%3E%3C/svg%3E");
  --eg-icon-receipt: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 2h14v20l-3.5-2-3.5 2-3.5-2L5 22ZM9 7h6M9 11h6M9 15h4'/%3E%3C/svg%3E");
  --eg-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='18' height='18' rx='2'/%3E%3Cpath d='m9 12 2 2 4-4'/%3E%3C/svg%3E");
  --eg-icon-settings: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3Cpath d='M12 2v3M12 19v3M2 12h3M19 12h3M4.9 4.9 7 7M17 17l2.1 2.1M4.9 19.1 7 17M17 7l2.1-2.1'/%3E%3C/svg%3E");
  --eg-icon-wallet: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='6' width='20' height='12' rx='2'/%3E%3Ccircle cx='12' cy='12' r='2'/%3E%3Cpath d='M6 12h.01M18 12h.01'/%3E%3C/svg%3E");
  --eg-icon-files: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8ZM14 2v6h6M16 13H8M16 17H8M10 9H8'/%3E%3C/svg%3E");
  /* Галочка пройденной ступени полосы этапов — белая линия на зелёном кружке. */
  --eg-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5 9-10'/%3E%3C/svg%3E");
  --eg-icon-exit: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9'/%3E%3C/svg%3E");
  --eg-hexagons: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 900'%3E%3Cdefs%3E%3Cpath id='h' d='M100 0 50 86.6-50 86.6-100 0-50-86.6 50-86.6z'/%3E%3Cfilter id='b' x='-.05' y='-.05' width='1.1' height='1.1'%3E%3CfeGaussianBlur stdDeviation='10'/%3E%3C/filter%3E%3Cg id='c'%3E%3Cuse href='%23h' transform='translate(1250 110) scale(.9)'/%3E%3Cuse href='%23h' transform='translate(1106 193) scale(.9)'/%3E%3Cuse href='%23h' transform='translate(1394 193) scale(.52)'/%3E%3Cuse href='%23h' transform='translate(1250 276) scale(.9)'/%3E%3Cuse href='%23h' transform='translate(1394 359) scale(.9)'/%3E%3Cuse href='%23h' transform='translate(140 790) scale(.9)'/%3E%3Cuse href='%23h' transform='translate(284 873) scale(.55)'/%3E%3Cuse href='%23h' transform='translate(250 330) scale(.42)'/%3E%3Cuse href='%23h' transform='translate(760 842) scale(.34)'/%3E%3Cuse href='%23h' transform='translate(1330 770) scale(.62)'/%3E%3Cuse href='%23h' transform='translate(1186 850) scale(.4)'/%3E%3C/g%3E%3C/defs%3E%3Cuse href='%23c' fill='%23000' opacity='.32' filter='url(%23b)' transform='translate(8 10)'/%3E%3Cuse href='%23c' fill='%23fff' opacity='.06' filter='url(%23b)' transform='translate(-6 -7)'/%3E%3Cuse href='%23c' fill='%2345494e'/%3E%3C/svg%3E");

  /* Оболочка и компоненты по макетам пакета (бриф 08.11.2026): значки — контурные 24×24, линия 1,8,
     маской цветом текста. Поиск, меню пользователя, кнопки со значком (`data-icon`), счётчики пульта
     (справа, как в эталоне `02_ui-dashboard.png`), плитка файла. */
  --eg-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-4-4'/%3E%3C/svg%3E");
  --eg-icon-bell: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9M10.3 21a1.94 1.94 0 0 0 3.4 0'/%3E%3C/svg%3E");
  --eg-icon-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E");
  --eg-icon-refresh: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 11a8 8 0 1 0-2.3 5.7M20 4v7h-7'/%3E%3C/svg%3E");
  --eg-icon-download: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4v11m-5-5 5 5 5-5M5 20h14'/%3E%3C/svg%3E");
  --eg-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='16' rx='2'/%3E%3Cpath d='M3 10h18M8 3v4M16 3v4'/%3E%3C/svg%3E");
  --eg-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  --eg-icon-next: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 6 6 6-6 6'/%3E%3C/svg%3E");
  --eg-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5l3 2'/%3E%3C/svg%3E");
  --eg-icon-card: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='5' width='20' height='14' rx='2'/%3E%3Cpath d='M2 10h20'/%3E%3C/svg%3E");
  --eg-icon-truck: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 17V6H2v11h3M14 9h4l3 4v4h-2M9 17h6'/%3E%3Ccircle cx='7' cy='17' r='2'/%3E%3Ccircle cx='17' cy='17' r='2'/%3E%3C/svg%3E");
  /* Уголок списка выбора в фильтрах-пилюлях: фон, а не маска, — у списка выбора нет псевдоэлементов;
     линия — цвета вторичного текста. */
  --eg-select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23525F7A' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  /* Соты брендбука (слайд 06, палитры светлая и тёмная): связка внизу меню — как в макете пакета
     (контуры белым на графите, одна серо-голубая и одна оранжевая); бледная — у заголовка страницы
     и в пустом состоянии, на светлом фоне; выпуклая на графите — обложка страниц ошибок вошедшего,
     тем же приёмом, что фон входа. */
  --eg-hex-menu: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 168 120'%3E%3Cdefs%3E%3Cpath id='h' d='M0-20 17.3-10 17.3 10 0 20-17.3 10-17.3-10z'/%3E%3C/defs%3E%3Cg fill='none' stroke='%23fff' stroke-opacity='.14' stroke-width='1.5'%3E%3Cuse href='%23h' transform='translate(30 30)'/%3E%3Cuse href='%23h' transform='translate(64.6 30)'/%3E%3Cuse href='%23h' transform='translate(116.5 90)'/%3E%3C/g%3E%3Cuse href='%23h' transform='translate(47.3 60)' fill='%238D99B3' fill-opacity='.4'/%3E%3Cuse href='%23h' transform='translate(81.9 60)' fill='%23FF7835'/%3E%3C/svg%3E");
  --eg-hex-pale: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 176 84'%3E%3Cdefs%3E%3Cpath id='h' d='M0-20 17.3-10 17.3 10 0 20-17.3 10-17.3-10z'/%3E%3C/defs%3E%3Cg stroke='%23D7DDEA' stroke-width='1.5'%3E%3Cuse href='%23h' transform='translate(30 26)' fill='none'/%3E%3Cuse href='%23h' transform='translate(64.6 26)' fill='none'/%3E%3Cuse href='%23h' transform='translate(47.3 56)' fill='%23fff'/%3E%3Cuse href='%23h' transform='translate(81.9 56)' fill='%23D7DDEA' fill-opacity='.6'/%3E%3Cuse href='%23h' transform='translate(138 60)' fill='none'/%3E%3C/g%3E%3C/svg%3E");
  --eg-hex-cover: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 440 330'%3E%3Cdefs%3E%3Cpath id='h' d='M100 0 50 86.6-50 86.6-100 0-50-86.6 50-86.6z'/%3E%3Cfilter id='b' x='-.05' y='-.05' width='1.1' height='1.1'%3E%3CfeGaussianBlur stdDeviation='7'/%3E%3C/filter%3E%3Cg id='c'%3E%3Cuse href='%23h' transform='translate(150 80) scale(.55)'/%3E%3Cuse href='%23h' transform='translate(242.4 133.3) scale(.55)'/%3E%3Cuse href='%23h' transform='translate(150 186.7) scale(.55)'/%3E%3Cuse href='%23h' transform='translate(334.8 80) scale(.55)'/%3E%3Cuse href='%23h' transform='translate(242.4 240) scale(.55)'/%3E%3Cuse href='%23h' transform='translate(372 262) scale(.3)'/%3E%3Cuse href='%23h' transform='translate(62 262) scale(.24)'/%3E%3C/g%3E%3C/defs%3E%3Cuse href='%23c' fill='%23000' opacity='.32' filter='url(%23b)' transform='translate(6 8)'/%3E%3Cuse href='%23c' fill='%23fff' opacity='.07' filter='url(%23b)' transform='translate(-5 -6)'/%3E%3Cuse href='%23c' fill='%2345494e'/%3E%3C/svg%3E");
}

* { box-sizing: border-box; }

/* Атрибут hidden слабее любого правила с display: без этой строки кнопка,
   спрятанная сценарием, оставалась бы на виду. */
[hidden] { display: none !important; }

/* Оболочка: графитовое меню слева на всю высоту, справа — белая шапка (имя, роль, колокольчик)
   и страница. Сетка, а не ряд: шапка стоит в разметке раньше меню (`templates/base.html`),
   а на экране — над страницей справа от него. */
body {
  margin: 0;
  font: var(--eg-fs-14)/var(--eg-lh-14) var(--eg-font-ui);
  color: var(--text);
  background: var(--bg);
  display: grid;
  grid-template-columns: var(--eg-side-w) minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  min-height: 100vh;
}

/* Ссылка — цвета текста и подчёркнута линией цвета границы поля, как `.link` пакета: в таблице
   её видно среди текста (вопрос 28 брифа); при наведении линия темнеет. */
a {
  color: var(--text);
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
}
a:hover { text-decoration-color: currentColor; }

/* Фокус виден везде: графитовая рамка, на графите — белая. */
:focus-visible { outline: 2px solid var(--eg-focus); outline-offset: 2px; }

/* Меню слева остаётся на виду, когда список длинный: логотип, пункты, в пустом низу — связка сот,
   как в макете пакета (рисунок `--eg-hex-menu`; псевдоэлемент — в разметку меню ничего не
   добавлено). «Выйти» — в меню пользователя в шапке. */
.menu {
  grid-column: 1;
  grid-row: 1 / 3;
  display: flex;
  flex-direction: column;
  gap: 2px;
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  padding: 20px 12px 16px;
  background: var(--eg-shell);
  color: var(--eg-on-shell);
  overflow-y: auto;
}
.menu :focus-visible { outline-color: var(--eg-focus-on-dark); }
.menu::after {
  content: "";
  flex: none;
  width: 168px;
  height: 120px;
  margin-top: auto;
  margin-left: 8px;
  background: var(--eg-hex-menu) left bottom / contain no-repeat;
}
/* Невысокое окно: пунктам место нужнее сот. */
@media (max-height: 600px) {
  .menu::after { display: none; }
}

/* Над пунктами — логотип со светлым текстом шириной 168 px, с полем вокруг (охранное поле
   брендбука). */
.menu-head { display: flex; align-items: center; margin: 0 0 20px; padding: 4px 8px; }

/* Логотип — картинка в ссылке на главную (templates/core/_brand.html); размер задаёт место. */
.brand { display: inline-block; flex: none; line-height: 0; }
.brand-logo { display: block; width: auto; height: auto; }
.menu-head .brand-logo { width: 168px; }

/* Пункты — прямые потомки меню: логотип и колокольчик в `.menu-head` их правил не берут. */
.menu > a,
.menu-soon {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 40px;
  padding: 8px 12px;
  border-radius: var(--eg-r-md);
  color: var(--eg-on-shell-2);
  font-size: 15px;
  line-height: 20px;
  text-decoration: none;
  white-space: nowrap;
}
.menu > a:hover { background: var(--eg-on-shell-hover); color: var(--eg-on-shell); }
.menu > a.current { background: var(--eg-shell-active); color: var(--eg-on-shell); font-weight: 600; }
/* Значок перед подписью — по адресу пункта (разметка пункта — ссылка с текстом, её сверяют
   тесты); «/» — стартовый экран роли. Маска красит значок цветом текста пункта, у текущего —
   оранжевым, как в макете. */
.menu > a::after {
  content: "";
  order: -1;
  flex: none;
  width: 18px;
  height: 18px;
  margin-right: 12px;
  background: currentColor;
  -webkit-mask: var(--eg-icon) center / contain no-repeat;
  mask: var(--eg-icon) center / contain no-repeat;
}
.menu > a { --eg-icon: var(--eg-icon-files); }
.menu > a[href="/"] { --eg-icon: var(--eg-icon-home); }
.menu > a[href="/pult/"] { --eg-icon: var(--eg-icon-grid); }
.menu > a[href="/requisitions/"] { --eg-icon: var(--eg-icon-list); }
.menu > a[href="/invoices/"] { --eg-icon: var(--eg-icon-receipt); }
.menu > a[href="/review/"] { --eg-icon: var(--eg-icon-check); }
.menu > a[href="/admin/"] { --eg-icon: var(--eg-icon-settings); }
.menu > a[href="/to-pay/"] { --eg-icon: var(--eg-icon-wallet); }
.menu > a.current::after { background: var(--eg-accent-on-dark); }
/* Текущий пункт отмечен оранжевой полосой слева, как в пакете. */
.menu > a.current::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  bottom: 8px;
  width: 3px;
  border-radius: 2px;
  background: var(--eg-accent-on-dark);
}
.menu-soon { color: var(--eg-slate-400); }

/* Форма выхода — последней в меню, без кнопки: её отправляет «Выйти» из меню пользователя
   (`form="logout-form"`); скрытая форма отправляется так же. */
.menu form.logout { display: none; }

/* Шапка над страницей, как в макете пакета: слева поле поиска (когда поиск есть), справа колокольчик
   и кнопка меню пользователя — круг с инициалами, имя и роль. Логотип и роль слева — только на
   телефоне: на компьютере логотип в меню, роль — в кнопке меню. */
.topbar {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 60px;
  padding: 10px 24px;
  background: var(--card);
  border-bottom: 1px solid var(--line);
}
.topbar .brand,
.topbar-role { display: none; }
.topbar .brand-logo { height: 28px; }
.topbar a.bell { margin-left: auto; }

/* Поле поиска (адрес — `{% url 'search' %}`): рамка — у формы, лупа — маской слева, подсказка
   «Ctrl K» — справа; фокус — рамкой всей формы. */
form.search {
  display: flex;
  flex: 1 1 260px;
  align-items: center;
  gap: 8px;
  max-width: 560px;
  height: var(--eg-h-ctl);
  padding: 0 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--eg-r-md);
  background: var(--card);
  color: var(--muted);
}
form.search::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  background: currentColor;
  -webkit-mask: var(--eg-icon-search) center / contain no-repeat;
  mask: var(--eg-icon-search) center / contain no-repeat;
}
form.search:focus-within { outline: 2px solid var(--eg-focus); outline-offset: 1px; }
form.search input { flex: 1 1 auto; min-width: 0; padding: 0; border: 0; background: none; color: var(--text); }
form.search input:focus { outline: none; }
form.search kbd {
  flex: none;
  padding: 0 5px;
  border: 1px solid var(--line);
  border-radius: var(--eg-r-sm);
  font: inherit;
  font-size: var(--eg-fs-12);
  line-height: 18px;
  color: var(--muted);
}

/* Колокольчик (блок 10): ссылка на «Уведомления»; число непрочитанных — графитовым кружком в углу
   значка, а не красным: красный значит «просрочено». */
a.bell {
  position: relative;
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--eg-r-md);
  color: var(--text);
  text-decoration: none;
  line-height: 1;
}
a.bell:hover { background: var(--soft); }
a.bell svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.bell-count {
  position: absolute;
  top: 0;
  left: 50%;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border: 2px solid var(--card);
  border-radius: 9px;
  background: var(--eg-shell-active);
  color: var(--eg-on-shell);
  font-size: 10px;
  font-weight: 700;
  line-height: 14px;
  text-align: center;
}

/* Меню пользователя (`details`): кнопка — круг с инициалами, имя и роль, уголок; под ней —
   «Уведомления» и «Выйти» белой панелью поверх страницы. Открывается мышью и Enter без сценария,
   Esc и нажатие мимо закрывают его (static/js/shell.js). */
.user-menu { position: relative; flex: none; }
.user-menu > summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 8px;
  border-radius: var(--eg-r-md);
  list-style: none;
  cursor: pointer;
}
.user-menu > summary::-webkit-details-marker { display: none; }
.user-menu > summary:hover,
.user-menu[open] > summary { background: var(--soft); }
.user-menu > summary::after {
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  background: var(--muted);
  -webkit-mask: var(--eg-icon-chevron) center / contain no-repeat;
  mask: var(--eg-icon-chevron) center / contain no-repeat;
}
.avatar {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--eg-shell);
  color: var(--eg-on-shell);
  font-size: var(--eg-fs-13);
  font-weight: 600;
  line-height: 1;
}
.who { display: flex; flex-direction: column; min-width: 0; line-height: 18px; }
.who-name { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.who-role { font-size: var(--eg-fs-12); line-height: var(--eg-lh-12); color: var(--muted); }
.user-menu ul {
  position: absolute;
  z-index: 20;
  top: calc(100% + 6px);
  right: 0;
  min-width: 200px;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  box-shadow: var(--eg-shadow-2);
}
.user-menu li > a,
.user-menu li > button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 36px;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--eg-r-md);
  background: none;
  font-weight: 400;
  color: var(--text);
  text-align: left;
  text-decoration: none;
}
.user-menu li > a:hover,
.user-menu li > button:hover { background: var(--soft); }
.user-menu li > a::before,
.user-menu li > button::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  background: var(--muted);
  -webkit-mask: var(--eg-icon) center / contain no-repeat;
  mask: var(--eg-icon) center / contain no-repeat;
}
.user-menu li > a { --eg-icon: var(--eg-icon-bell); }
.user-menu li > button { --eg-icon: var(--eg-icon-exit); }

main {
  grid-column: 2;
  grid-row: 2;
  min-width: 0;
  padding: 20px 24px 40px;
  max-width: 1720px;
}

/* Страница без меню — вход, приглашение, 500, «Страница устарела»: графит оболочки
   с шестиугольниками («соты» брендбука, рисунок — `--eg-hexagons` в :root), над узкой белой
   карточкой — логотип со светлым текстом в ссылке на главную (`div.guest-brand`). Фон «cover»
   от правого верхнего угла: куст шестиугольников на виду на любом окне. */
body.guest {
  display: flex;
  flex-direction: column;
  align-items: center;
  background-color: var(--eg-shell);
  background-image: var(--eg-hexagons);
  background-repeat: no-repeat;
  background-position: right top;
  background-size: cover;
}
.guest-brand { margin: 10vh 16px 0; }
.guest-brand .brand-logo { width: 200px; }
.guest-brand :focus-visible { outline-color: var(--eg-focus-on-dark); }
.guest main {
  flex: none;
  width: calc(100% - 32px);
  max-width: 400px;
  margin: 24px 0 40px;
  padding: 24px 28px 28px;
  background: var(--card);
  border-radius: var(--eg-r-lg);
  box-shadow: var(--eg-shadow-lift);
}
.guest form p { margin: 0 0 14px; }
.guest form label { display: block; margin-bottom: 4px; font-size: 13px; font-weight: 600; color: var(--muted); }
.guest form input { width: 100%; }
.guest form .helptext { display: block; margin-top: 4px; font-size: 12px; color: var(--faint); }
.guest form button.primary { width: 100%; }

/* Шапка страницы, как в макетах пакета: слева хлебные крошки (у карточек), заголовок и подпись,
   справа действия; между ними — бледные соты, как в эталоне пульта. Пустое место между заголовком и
   действиями — `span.page-hex`: он забирает только свободное место строки, и соты (его псевдоэлемент)
   рисуются, лишь когда места не меньше 220 px (запрос контейнера), — под заголовок и кнопки рисунок
   не попадает, обрезка шестиугольника у заголовка нет. Разметка — `templates/base.html`, блоки
   crumbs, heading, subtitle, actions. */
.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px 16px;
  margin-bottom: 20px;
}
.page-title { display: flex; flex-direction: column; gap: 4px; min-width: 0; max-width: 100%; }
.page-title > p { margin: 0; font-size: 14px; color: var(--muted); overflow-wrap: anywhere; }
.crumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 2px;
  font-size: var(--eg-fs-13);
  line-height: var(--eg-lh-13);
  color: var(--muted);
}
.crumbs a { color: var(--muted); }
.page-hex {
  display: flex;
  flex: 1 1 0;
  align-self: stretch;
  align-items: center;
  min-width: 0;
  margin-top: -20px;
  container-type: inline-size;
}
.page-hex::before {
  content: "";
  width: 100%;
  height: 56px;
  background: var(--eg-hex-pale) left 16px center / auto 100% no-repeat;
}
@container (max-width: 219px) {
  .page-hex::before { display: none; }
}
.page-head > .actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-left: auto; }

/* Длинный номер или адрес без пробелов (письмо, ссылка, «ЭГ/2026/…») переносится по знакам,
   а не раздвигает страницу: заголовок — элемент строки шапки, и без этого он не сжимался. */
h1 { margin: 0; font-size: var(--eg-fs-24); line-height: var(--eg-lh-24); font-weight: 700; overflow-wrap: anywhere; }
h2 { margin: 24px 0 10px; font-size: var(--eg-fs-16); line-height: var(--eg-lh-16); font-weight: 700; }

/* Кнопка по умолчанию тихая: белая с рамкой цвета поля. Главная кнопка экрана — primary —
   оранжевая с чёрным текстом; на экране она одна. Высота 36 px, как контрол пакета. */
button,
a.button {
  display: inline-block;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  line-height: 20px;
  padding: 7px 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--eg-r-md);
  background: var(--card);
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
}

button:hover,
a.button:hover { background: var(--soft); }

button.primary,
a.button.primary { background: var(--accent); border-color: var(--accent); color: var(--eg-on-action); }

button.primary:hover,
a.button.primary:hover { background: var(--accent-dark); border-color: var(--accent-dark); }

button.primary:active,
a.button.primary:active { background: var(--accent-press); border-color: var(--accent-press); }

/* Тихая кнопка — без рамки и заливки (второстепенное действие рядом с главной, как ghost пакета);
   малая — 28 px, как малый контрол пакета. Значок перед подписью — `data-icon="plus|refresh|
   download|search|calendar|next"`: маска цветом текста кнопки (на оранжевой — чёрная). */
button.quiet,
a.button.quiet { border-color: transparent; background: none; }
button.quiet:hover,
a.button.quiet:hover { background: var(--soft); }
button.small,
a.button.small { padding: 3px 10px; font-size: var(--eg-fs-13); }
[data-icon],
a.button[data-icon] { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
[data-icon]::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  background: currentColor;
  -webkit-mask: var(--eg-icon) center / contain no-repeat;
  mask: var(--eg-icon) center / contain no-repeat;
}
.small[data-icon]::before { width: 14px; height: 14px; }
[data-icon="plus"] { --eg-icon: var(--eg-icon-plus); }
[data-icon="refresh"] { --eg-icon: var(--eg-icon-refresh); }
[data-icon="download"] { --eg-icon: var(--eg-icon-download); }
[data-icon="search"] { --eg-icon: var(--eg-icon-search); }
[data-icon="calendar"] { --eg-icon: var(--eg-icon-calendar); }
[data-icon="next"] { --eg-icon: var(--eg-icon-next); }

input[type="text"],
input[type="password"],
input[type="email"],
input[type="number"],
input[type="search"],
input[type="date"],
select,
textarea {
  font: inherit;
  font-size: 14px;
  line-height: 20px;
  padding: 7px 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--eg-r-md);
  background: var(--card);
  color: var(--text);
}
::placeholder { color: var(--faint); }

input:focus,
select:focus,
textarea:focus { outline: 2px solid var(--eg-focus); outline-offset: 1px; }

/* Сообщение после перехода (`.messages li`) и рядом с действием (`.msg` — `p` или `div`), по пакету:
   успех зелёный, предупреждение янтарное, отказ красный, обычное — серое; цвет со словом. Классы
   те же, что у сообщений Django: success, warning, error. */
.messages { list-style: none; padding: 0; margin: 0 0 16px; }
.messages li,
.msg {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--eg-r-md);
  background: var(--soft);
  color: var(--text);
  margin-bottom: 8px;
  font-size: 14px;
  word-break: break-word;
}
.msg { margin-top: 0; }

/* Предупреждение и отказ отличаются от обычного сообщения: их нужно заметить. */
.messages li.success,
.msg.success { background: var(--eg-ok-bg); border-color: var(--eg-ok-line); color: var(--eg-ok-fg); }
.messages li.warning,
.msg.warning { background: var(--eg-warn-bg); border-color: var(--eg-warn-line); color: var(--eg-warn-fg); }
.messages li.error,
.msg.error { background: var(--eg-danger-bg); border-color: var(--eg-danger-line); color: var(--eg-danger-fg); }

/* Подсказки первого входа: три короткие строки над стартовым экраном и «Понятно». */
.hints {
  max-width: 760px;
  margin: 0 0 20px;
  padding: 14px 18px 16px;
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--eg-shell);
  border-radius: var(--eg-r-lg);
}
.hints ol { margin: 0 0 12px; padding-left: 20px; }
.hints li { padding: 2px 0; }
.hints form { margin: 0; }

.errorlist { color: var(--late); padding-left: 18px; font-size: 13px; }

.late { color: var(--late); }
.soon { color: var(--soon); }
.done { color: var(--done); }

/* Компоненты пакета для экранов (бриф 08.11.2026, `Интерфейс/eg-ui.css`): вид — как в макетах,
   имена — наши; что есть что — `.claude/skills/ui-screens/base.md`. */

/* Панель: белая, с рамкой и тенью; в шапке — заголовок (`h2`), под ним подпись (`p`), справа
   ссылка («Все 12»); внутри — таблица без своей рамки, текст или лента; внизу — строка пояснения. */
.panel {
  min-width: 0;
  margin: 0 0 16px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  box-shadow: var(--eg-shadow-1);
}
.panel-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
}
.panel-head > h2 { margin: 0; font-size: var(--eg-fs-16); line-height: var(--eg-lh-16); font-weight: 600; }
.panel-head > p { grid-column: 1; margin: 2px 0 0; font-size: var(--eg-fs-13); line-height: var(--eg-lh-13); color: var(--muted); }
.panel-head > a { grid-column: 2; grid-row: 1 / span 2; font-size: var(--eg-fs-13); font-weight: 600; white-space: nowrap; }
.panel-body { padding: 12px 16px; }
.panel-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  padding: 8px 16px;
  border-top: 1px solid var(--eg-border-soft);
  font-size: var(--eg-fs-13);
  color: var(--muted);
}
.panel > table.data { border: 0; }
.panel > .panel-head ~ table.data th { border-radius: 0; }

/* Плитка файла: значок с расширением, имя и подпись (размер, дата), справа — стрелка «скачать»;
   ссылка целиком ведёт на файл: `<a class="file-tile" href="…"><span class="file-ext">PDF</span>
   <span><strong>Счёт.pdf</strong><small>240 КБ · 28.10.2026</small></span></a>`. Плитка с двумя
   ссылками (`mail/_file_links.html`: имя — просмотр, «Скачать») — `div.file-tile`, без стрелки. */
a.file-tile, div.file-tile {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--eg-r-md);
  background: var(--card);
  color: var(--text);
  text-decoration: none;
  overflow-wrap: anywhere;
}
a.file-tile:hover, div.file-tile:hover { border-color: var(--line-strong); }
a.file-tile::after {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  margin-left: auto;
  background: var(--muted);
  -webkit-mask: var(--eg-icon-download) center / contain no-repeat;
  mask: var(--eg-icon-download) center / contain no-repeat;
}
a.file-tile small, div.file-tile small { display: block; font-size: var(--eg-fs-12); color: var(--muted); }
/* «Скачать» рядом с именем файла (`mail/_file_links.html`): тише имени, и в плитке тоже. */
.file-download { margin-left: 4px; font-size: var(--eg-fs-12); font-weight: 400; white-space: nowrap; }
.file-ext {
  display: inline-flex;
  flex: none;
  align-items: flex-end;
  justify-content: center;
  width: 32px;
  height: 36px;
  padding-bottom: 4px;
  border: 1px solid var(--line-strong);
  border-radius: var(--eg-r-sm);
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  color: var(--muted);
}

/* Пустое состояние: по центру — бледные соты, строка «что здесь будет» (`strong`) и следующий шаг
   (`p`, кнопка); соты — над текстом, не под ним. */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 32px 16px;
  color: var(--muted);
  text-align: center;
}
.empty::before {
  content: "";
  width: 132px;
  height: 63px;
  margin-bottom: 4px;
  background: var(--eg-hex-pale) center / contain no-repeat;
}
.empty strong { font-size: 15px; color: var(--text); }
.empty p { margin: 0; }

/* Компактная полоска этапов в строке заявки (`{% stage_mini stage %}`): восемь делений одного
   элемента — пройденные зелёные, текущее оранжевое (текущая позиция), будущие серые. Номер ступени —
   переменная `--step` в разметке; деления — маской с прозрачным промежутком 2 px. */
.stage-mini {
  --done: calc((var(--step) - 1) * 12.5%);
  --now: calc(var(--step) * 12.5%);
  display: inline-block;
  flex: none;
  width: 64px;
  height: 6px;
  vertical-align: middle;
  background: linear-gradient(90deg, var(--eg-ok-dot) 0 var(--done), var(--eg-action) var(--done) var(--now), var(--eg-slate-200) var(--now));
  -webkit-mask: repeating-linear-gradient(90deg, var(--eg-text) 0 calc(12.5% - 2px), transparent calc(12.5% - 2px) 12.5%);
  mask: repeating-linear-gradient(90deg, var(--eg-text) 0 calc(12.5% - 2px), transparent calc(12.5% - 2px) 12.5%);
}

/* Страницы ошибок вошедшего (404, 403): графит с выпуклыми сотами, как обложка брендбука. Соты —
   справа, текст — слева и не доходит до них; на телефоне соты над текстом: под текстом рисунка нет. */
.cover {
  min-height: 280px;
  padding: 32px 380px 32px 32px;
  border-radius: var(--eg-r-lg);
  background: var(--eg-shell) var(--eg-hex-cover) right 24px center / auto 250px no-repeat;
  color: var(--eg-on-shell);
}
.cover p { max-width: 520px; margin: 0 0 16px; font-size: 16px; line-height: 24px; }
.cover p:last-child { margin-bottom: 0; }
.cover :focus-visible { outline-color: var(--eg-focus-on-dark); }
/* Гостю те же страницы — белой карточкой на графите с сотами (вход): обложка там лишняя. */
.guest .cover { min-height: 0; padding: 0; background: none; color: inherit; }

/* Класс, а не сам тег: страница состояния почты из блока 02 обходилась
   без оформления таблиц, и менять её вид эта задача не просила.
   Таблица — белая панель на сером фоне. Текст 14 px при высоте строки 20 px и полях ячейки
   8 px дают строку 36 px, как в пакете; шапка — 13 px на светло-сером. Рамки ячеек раздельные —
   иначе у таблицы не скругляются углы. */
table.data {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  font-size: 14px;
  line-height: 20px;
}

table.data th,
table.data td {
  padding: 8px 12px;
  text-align: left;
  border-bottom: 1px solid var(--eg-border-soft);
  vertical-align: top;
}

/* Шапка остаётся на виду при прокрутке. */
table.data th {
  position: sticky;
  top: 0;
  z-index: 1;
  font-size: var(--eg-fs-13);
  line-height: var(--eg-lh-13);
  font-weight: 600;
  color: var(--muted);
  background: var(--soft);
  border-bottom-color: var(--line);
  white-space: nowrap;
}

table.data th:first-child { border-top-left-radius: 7px; }
table.data th:last-child { border-top-right-radius: 7px; }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data tbody tr:hover td { background: var(--panel); }
/* Строка с адресом (data-row-href, static/js/row-href.js) — нажимается вся: рука над ней, как над ссылкой
   названия; на телефоне та же строка — карточка целиком. */
table.data tbody tr[data-row-href] { cursor: pointer; }
table.data tbody tr:last-child td:first-child { border-bottom-left-radius: 7px; }
table.data tbody tr:last-child td:last-child { border-bottom-right-radius: 7px; }

/* Первая колонка называет запись — она заметнее остальных, как в макетах. Ссылки в ячейках —
   подчёркнутые, по общему правилу `a` выше. */
table.data td:first-child { font-weight: 600; }
table.data td small { color: var(--muted); font-weight: 400; }
table.data td input { padding: 3px 8px; width: 120px; }

/* Действие в строке таблицы плотнее обычного (28 px, как малый контрол пакета): строка
   с кнопкой или списком выбора не выше строки с полем ввода. Форма в ячейке — в одну линию. */
table.data td button,
table.data td a.button,
table.data td select { padding: 3px 10px; }
table.data td a.button:hover { text-decoration: none; }
table.data td form.in-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
/* В таблице (от 1280 px) кнопка, список и поле в ячейке (28 px) не раздвигают строку: она остаётся
   36 px, как строка без них, — до этого строки с кнопкой были 45 px. Отрицательные поля съедают
   лишнюю высоту; на карточках (ниже 1280 px) строки не одной высоты, там правило не нужно. */
@media (min-width: 1280px) {
  table.data td button,
  table.data td a.button,
  table.data td select,
  table.data td input:not([type="checkbox"]):not([type="radio"]) { margin-top: -4px; margin-bottom: -4px; }
}
/* Длинное имя не раздвигает таблицу: в закрытом списке оно обрезано, в раскрытом — целиком. */
table.data td select { max-width: 190px; }

/* Числа вправо и цифрами одной ширины: разряды стоят друг под другом. */
table.data th.num,
table.data td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Длинное значение обрезается многоточием; целиком оно стоит в title ячейки.
   Нулевой предел ширины с долей в процентах — приём для таблиц: обрезаемая
   колонка занимает до пятой части таблицы, а когда остальным колонкам места
   не хватает, сжимается первой, так что таблица не вылезает за страницу. */
table.data td.cut {
  width: 20%;
  max-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Номер в колонке без `cut` (номер счёта, документа, прораба) — ссылка или метка с пределом ширины:
   длинный обрезается многоточием, полный стоит в title. Без этого одна запись, в которой разбор
   вместо номера оставил длинную строку, растягивала весь список за страницу. Обычные номера
   («0007031-0000Z1/4290», «0210005531-МСК») в предел помещаются целиком. */
table.data td .ref {
  display: inline-block;
  max-width: 14em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: top;
}
/* «Без документов»: в ячейке номер счёта с датой («№ 0007031-0000Z1/4290 от 22.01.2026») —
   читается целиком, пока не длиннее 22 em. */
table.data.no-docs td .ref { max-width: 22em; }

/* Список: на запись ровно одна строка. Таблицы позиций — в карточке и на экране
   остатков — тоже списки, на телефоне это карточки; но наименование позиции
   обрезать нельзя, и под ним стоит артикул, поэтому класс wrap возвращает перенос. */
table.data.list td { white-space: nowrap; }
table.data.list.wrap td { white-space: normal; }

/* Блок, который HTMX запрашивает заново: на время запроса прежние строки
   бледнеют, а не исчезают, рядом появляется «загрузка…». */
.live.htmx-request table { opacity: .5; }
.live .loading { display: none; }
.live.htmx-request .loading { display: inline; }

/* Строка над списком: счётчик, «загрузка…» и место для сообщения об ошибке. Стоит на сером
   фоне страницы — вторичным текстом (5,5:1), а не подсказкой поля (там меньше 4,5:1). */
.list-status {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin: 0 0 8px;
  font-size: 13px;
  color: var(--muted);
}

/* Сортировка и поиск больших списков (сборка 12.11.2026, `core.listing`, `{% sort_th %}`).
   Заголовок сортируемого столбца — ссылка цвета заголовка без подчёркивания (подчёркнуты ссылки
   значений, заголовок — кнопка порядка); у текущего столбца — стрелка ▲/▼ и тёмный текст. Ячейка
   одна: ручка ширины столбца (`table-columns.js`) стоит в ней же, справа, — ссылке оставлен отступ. */
table.data th a.sort {
  display: inline-block;
  padding-right: 6px;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}
table.data th a.sort:hover,
table.data th[aria-sort] a.sort { color: var(--text); }
.sort-arrow { margin-left: 4px; font-size: 11px; color: var(--text); }
/* Выбор «Сортировка» — вместо заголовков, которых у списка-карточек нет (ниже 1280 px); на
   широком окне прячется. Стоит в строке фильтров или своей формой над списком. */
.sort-select { display: inline-flex; margin: 0 0 8px; }
form.filters.sort-select { margin-bottom: 8px; }
@media (min-width: 1280px) {
  .sort-select,
  form.filters.sort-select { display: none; }
}
/* Поле «Поиск» над списком: в строке фильтров — ещё одно поле, самостоятельное — своей формой. */
.filters input[type="search"] {
  min-width: 220px;
  max-width: 420px;
  flex: 1 1 320px;
  height: 32px;
  border: 1px solid var(--line-strong);
  border-radius: var(--eg-r-md);
  background: var(--card);
  font-size: var(--eg-fs-13);
}
form.filters.search-box { margin-bottom: 12px; }
/* Строка архива над списком: вторичным текстом, как строка со счётчиком. */
.archive-note { margin: 0 0 8px; font-size: 13px; color: var(--muted); }
/* Пустой итог поиска: текст и «Сбросить поиск» — одной строкой, соты — над ней. */
p.empty.search-empty { display: block; margin: 12px 0; }
p.empty.search-empty::before { display: block; margin: 0 auto 8px; }
@media (max-width: 720px) {
  .filters input[type="search"] { flex: 1 1 100%; min-width: 0; }
}

/* Текст рядом с действием: «сохранено» либо причина отказа. */
.note { font-size: 14px; color: var(--muted); }
.note.refusal { color: var(--late); }
.note.soon { color: var(--soon); }

/* Отказ и прежнее «сохранено» вместе не стоят: пока виден отказ, заметка
   и прежняя ошибка ввода после него спрятаны. */
[data-note]:not([hidden]) ~ .note,
[data-note]:not([hidden]) ~ .errorlist { display: none; }

/* Правка на месте: строка бледнеет, пока её поле сохраняется. */
tr.htmx-request,
dd.htmx-request { opacity: .5; }
table.data td input ~ .note { margin-left: 8px; }

/* Кнопка, недоступная из-за состояния записи, стоит неактивной, рядом причина. */
button:disabled,
button:disabled:hover { color: var(--faint); background: var(--eg-neutral-bg); border-color: var(--line); cursor: not-allowed; }
.why { margin-left: 8px; color: var(--muted); }

/* Фильтры — поля по 32 px в ряд, как в пакете; значение живёт в адресе. */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-bottom: 16px;
  font-size: 14px;
}

/* Список шириной в самое длинное название раздвигал страницу на телефоне. */
.filters select { max-width: min(100%, 260px); }
.filters select,
.filters input[type="text"],
.filters input[type="search"],
.filters input[type="date"],
.filters button { padding-top: 5px; padding-bottom: 5px; }
.filters label { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); }
/* Фильтры-пилюли, как в пакете («Объект: все ⌄»): список выбора без рамки браузера, значение жирным,
   уголок справа; подпись со списком в одном `label` — одна пилюля, подпись серым. */
form.filters select {
  height: 32px;
  padding: 0 28px 0 10px;
  border-radius: var(--eg-r-md);
  background: var(--card) var(--eg-select-arrow) right 8px center / 14px no-repeat;
  -webkit-appearance: none;
  appearance: none;
  font-size: var(--eg-fs-13);
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
}
form.filters label:has(> select) {
  height: 32px;
  padding-left: 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--eg-r-md);
  background: var(--card);
  font-size: var(--eg-fs-13);
}
form.filters label:has(> select):focus-within { outline: 2px solid var(--eg-focus); outline-offset: 1px; }
form.filters label > select { height: 30px; padding-left: 0; border: 0; }
form.filters label > select:focus { outline: none; }

/* Поиск в списке выбора (static/js/select-search.js): поле над списком, под ним — «Нет поставщика с „…“».
   В пилюле фильтра поле стоит между подписью и списком, а подпись «ничего нет» — под пилюлей. */
.select-search { display: block; width: 100%; box-sizing: border-box; margin: 0 0 6px; }
.select-search-empty { display: block; margin: 4px 0 0; font-size: var(--eg-fs-13); color: var(--muted); }
form.filters label:has(> .select-search) { position: relative; }
form.filters .select-search { display: inline-block; width: 150px; height: 24px; margin: 0; padding: 0 8px; font-size: var(--eg-fs-13); }
form.filters .select-search:focus { outline: none; border-color: var(--eg-focus); }
form.filters .select-search-empty { position: absolute; left: 0; top: 100%; z-index: 2; margin-top: 4px; padding: 4px 8px; white-space: nowrap; border: 1px solid var(--line-strong); border-radius: var(--eg-r-md); background: var(--card); }

/* Карточка: шапка парами «подпись — значение» — белая панель, как «Реквизиты» пакета;
   полоса этапов, боковой столбец. Подпись и значение стоят на одной линии текста: строка
   с полем срока выше остальных, и без этого подпись «Срок» висела бы над датой в поле. */
.card-head {
  display: grid;
  grid-template-columns: max-content 1fr;
  align-items: baseline;
  gap: 6px 20px;
  margin: 0 0 20px;
  padding: 14px 18px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  font-size: 14px;
}

.card-head dt { color: var(--muted); }
/* Значение шапки — адрес, имя, телефон — бывает длинным и без пробелов: переносится по знакам,
   иначе вторая колонка сетки растягивалась за страницу. */
.card-head dd { margin: 0; overflow-wrap: anywhere; }

/* Срок правится на месте: поле, запасная кнопка и заметка стоят в одну линию.
   Поле плотное, как в строке таблицы, и берёт цвет срока. */
.card-head form.in-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.card-head form.in-head input[type="date"] { padding: 5px 10px; color: inherit; }
.card-head form.in-head button { padding: 5px 10px; }
.card-head form.in-head .errorlist { margin: 0; padding: 0; list-style: none; }

/* Отгрузка в карточке счёта (блок 07): поля «Отметить» в строке плотные, количество
   узкое; «Принято всё» — своя строка формы под таблицей. */
.card-body table.receiving td { vertical-align: middle; }
.card-body table.receiving td.num { white-space: nowrap; }
.card-body table.receiving td form.in-row input[name="qty"] { width: 72px; }
.card-body table.receiving td form.in-row input[type="date"] { width: auto; }
/* В таблице (от 1280 px) поля и «Отметить» стоят в одну линию: переносится наименование. */
@media (min-width: 1280px) {
  .card-body table.receiving td form.in-row { flex-wrap: nowrap; }
}
form.ship-all,
p.ship-all { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 12px 0 0; }
form.ship-all input[type="date"],
form.ship-all select,
form.ship-all button { padding: 5px 10px; }
p.ship-all .why { margin-left: 0; }
.list-status.shipped-count { margin-top: 20px; }
.card-body table.shipments td { vertical-align: middle; }

/* Закрывающие документы (блок 07): «Передать в бухгалтерию» над списком — номер реестра,
   дата и кнопка в одну линию; галочки у документов, которые можно передать. */
form.registry { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin: 0 0 12px; }
form.registry label { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); }
form.registry input[type="text"] { width: 72px; }
form.registry input[type="date"],
form.registry button { padding: 5px 10px; }
table.closing-docs td input[type="checkbox"] { width: 18px; height: 18px; margin: 0; }
/* Карточка документа на проверке: список выбора позиции счёта не шире своей колонки. */
form.doc-form table.doc-items td { vertical-align: middle; }
form.doc-form table.doc-items td select { width: 100%; max-width: 360px; font-weight: 400; }
form.doc-form { max-width: none; }
form.doc-form .fields { margin-bottom: 8px; }
ul.doc-queries { margin: 0; padding-left: 18px; }

/* Полоса этапов, как в эталоне заказчика (spec №122): ступени кружками, соединёнными линией,
   подпись под кружком — в две строки, если длинная. Пройденная — зелёный круг с белой галочкой и
   зелёная линия до него, текущая — оранжевое кольцо (текущая позиция) и жирная подпись, будущие —
   серый контур. Кружок, линия и галочка — псевдоэлементы: в разметке только подписи (`li` без
   вложенных тегов — их разбирают тесты). Полоса согласования счёта — в том же виде; у шага, на
   котором счёт заблокирован, под подписью — красное «заблокирован». Ступени — столбцы равной
   ширины: линия идёт от середины прошлого кружка к середине своего. */
.stage-strip,
.approval-strip {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  list-style: none;
  margin: 0;
  padding: 0;
}

.stage-strip li,
.approval-strip li {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 0 4px;
  color: var(--muted);
  font-size: var(--eg-fs-13);
  line-height: var(--eg-lh-13);
  text-align: center;
}

.stage-strip li::before,
.approval-strip li::before {
  content: "";
  position: relative;
  z-index: 1;
  flex: none;
  width: 18px;
  height: 18px;
  box-sizing: border-box;
  border: 2px solid var(--eg-slate-400);
  border-radius: 50%;
  background: var(--card);
}

.stage-strip li::after,
.approval-strip li::after {
  content: "";
  position: absolute;
  top: 8px;
  left: -50%;
  right: 50%;
  height: 2px;
  background: var(--line);
}
.stage-strip li:first-child::after,
.approval-strip li:first-child::after { content: none; }

.stage-strip li.past,
.approval-strip li.past { color: var(--text); }
.stage-strip li.past::before,
.approval-strip li.past::before {
  border-color: var(--eg-ok-dot);
  background: var(--eg-ok-dot) var(--eg-check) center / 10px no-repeat;
}
.stage-strip li.past::after,
.stage-strip li.current::after,
.approval-strip li.past::after,
.approval-strip li.current::after { background: var(--eg-ok-dot); }
.stage-strip li.current,
.approval-strip li.current { color: var(--text); font-weight: 700; }
.stage-strip li.current::before,
.approval-strip li.current::before { border: 5px solid var(--eg-action); }

/* Блок этапа карточки заявки — белая панель, как в эталоне: полоса, под ней «Отгружено N из M
   позиций» жирным и полоска доли отгруженного (заливка зелёная). Полоска стоит в разметке раньше
   слов — стили ставят её под ними. У отменённой заявки вместо полосы — «Заявка отменена …». */
#card-stage {
  margin: 0 0 20px;
  padding: 16px 16px 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
}
#card-stage > p.late { margin: 0 0 10px; font-weight: 600; }
#card-stage > .stage-strip + p.shipped { margin-top: 14px; }
p.shipped {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-width: 420px;
  margin: 0;
  font-weight: 600;
}
p.shipped progress {
  order: 1;
  width: 100%;
  height: 6px;
  appearance: none;
  border: 0;
  border-radius: 3px;
  background: var(--eg-bar-track);
  overflow: hidden;
}
p.shipped progress::-webkit-progress-bar { background: var(--eg-bar-track); }
p.shipped progress::-webkit-progress-value { background: var(--eg-ok-dot); }
p.shipped progress::-moz-progress-bar { background: var(--eg-ok-dot); }

/* Блок согласования в карточке счёта: полоса шагов на белой панели, «У кого», кнопки, история
   решений. */
.approval { margin: 0 0 24px; }
.approval-strip {
  margin-bottom: 12px;
  padding: 16px 8px 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
}
.approval-strip li small { font-weight: 400; color: var(--late); }
.approval .holder { margin: 0 0 12px; }
.approval .muted { margin: 0 0 8px; color: var(--muted); }
.approval-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 12px; }
.approval-actions form { margin: 0; }
.approval-actions .why { margin-left: 4px; }
/* «Заблокировать» — контурная красная, как на макете руководителя. */
.danger a.button,
.danger button:not(:disabled) { border-color: var(--late); color: var(--late); background: var(--card); }
.approval-history { list-style: none; padding: 0; margin: 0; font-size: 14px; }
.approval-history li { padding: 0 0 8px; }
.approval-history q { color: var(--muted); }
form.comment-form { max-width: 640px; }
form.comment-form textarea { display: block; width: 100%; }

/* Позиции слева, письмо, файлы и история справа — так требует ТЗ. На окне
   меньше 1500 px боковая колонка уходит под таблицу: правило ниже, перед телефоном. */
.card-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 28px;
  align-items: start;
}

/* Одиннадцать колонок позиций заявки с номером счёта на окне 1280 px помещаются
   только с полями ячеек поуже: с обычными страница выходила за окно. */
.card-body table.data th,
.card-body table.data td { padding-left: 10px; padding-right: 10px; }
/* Карточка заявки у администратора (класс wide): с колонкой «Документы» (блок 07),
   списком снабженца и «Отменить» таблица на окне 1280 px выходила за окно на 55 px,
   а с позицией на двух счетах и этапом «Согласование» — ещё на 75 px. Помещается
   с полями ячеек 5 px, списком снабженца не шире 112 px и шапкой, которая переносится
   по словам («На / складе»). Ниже 1280 px список — карточки со своими полями, правило
   к ним не относится. */
@media (min-width: 1280px) {
  .card-body.wide #positions > table.data th,
  .card-body.wide #positions > table.data td { padding-left: 5px; padding-right: 5px; }
  .card-body.wide #positions > table.data th { white-space: normal; }
  .card-body.wide #positions > table.data td select { max-width: 104px; }
  .card-body.wide #positions > table.data .invoice-ref a { max-width: 6em; }
  /* Два длинных номера Диадока («№ 0210005531-МСК; № 0210005532-МСК») по 5em раздвигали
     таблицу администратора на 1280 px за её блок на 19–26 px: здесь номеру — 4em, а список
     снабженца — уже на 8 px, чтобы запас был и при этапе «Согласование». */
  .card-body.wide #positions > table.data .invoice-refs .invoice-ref a { max-width: 4em; }
}
/* Счёт позиции в карточке заявки (блок 07): номер одной строкой, состояние
   согласования второй — не шире номера, обрезка многоточием, целиком в title.
   Нулевая ширина с наименьшей во всю обёртку: строка состояния не раздвигает колонку.
   Номер длиннее 7em («№ 0210005530-МСК» Диадока) обрезается тоже: иначе таблица
   администратора на окне 1280 px выходила за окно. */
.invoice-ref { display: inline-block; vertical-align: top; }
.invoice-ref a {
  display: inline-block;
  max-width: 7em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: top;
}
/* Несколько счетов позиции — рядом через «; » одной строкой, у каждого номер со своей
   обрезкой и согласование под ним: ячейка не выше двух строк. Номер уже одиночного:
   иначе два номера раздвинули бы таблицу за окно. */
.invoice-refs { white-space: nowrap; }
.invoice-refs .invoice-ref a { max-width: 5em; }
.invoice-ref small {
  display: block;
  width: 0;
  min-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Оплаты счёта: в строке кнопка «Отменить» — дата и сумма стоят по её середине. */
.card-body table.payments td { vertical-align: middle; }

/* Боковой столбец — белая панель: файл, письмо, версии, история. */
.card-side {
  padding: 16px 18px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  font-size: 14px;
}
.card-side h2:first-child { margin-top: 0; }
.card-side ul { list-style: none; padding: 0; margin: 0; }
.card-side li { position: relative; padding: 0 0 12px 16px; }

/* Точка перед строкой списка бокового столбца (файл, версии). */
.card-side li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 7px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--eg-slate-400);
}

/* Лента истории, как в макете пакета (`.tl`): записи на вертикальной линии с кружком, свежая
   (`li.now`) — залитым. В записи — когда (`time` или `small`), что (`strong`), кто и подробности
   (`small`). Где бы ни стояла (боковой столбец, вкладка, панель), вид один. */
ul.history,
ol.history { margin: 0; padding: 0 0 0 4px; list-style: none; }
ul.history > li,
ol.history > li {
  position: relative;
  padding: 0 0 14px 18px;
  border-left: 1px solid var(--line);
  overflow-wrap: anywhere;
}
ul.history > li:last-child,
ol.history > li:last-child { padding-bottom: 0; border-left-color: transparent; }
ul.history > li::before,
ol.history > li::before {
  content: "";
  position: absolute;
  top: 5px;
  left: -5px;
  width: 9px;
  height: 9px;
  box-sizing: border-box;
  border: 2px solid var(--eg-slate-400);
  border-radius: 50%;
  background: var(--card);
}
ul.history > li.now::before,
ol.history > li.now::before { border-color: var(--text); background: var(--text); }
.history time,
.history small { color: var(--muted); font-size: var(--eg-fs-12); font-variant-numeric: tabular-nums; }

/* Вкладки карточек (spec №116а, static/js/tabs.js), как в пакете: подписи над разделом, число —
   в серой капсуле, открытая вкладка отмечена оранжевой чертой снизу — текущая позиция, как отметка
   пункта меню. Вкладки-кнопки бухгалтерии и срезов (`nav.filters.tabs`) — свои. */
.card-main { min-width: 0; }
/* Нижняя линия — тенью внутри полосы, под ней отметка вкладки 2 px: рамка с отметкой на поле −1 px
   выступала за полосу, и на 1280 и 1440 px у вкладок карточек появлялась лишняя полоса прокрутки
   (остаток слепой приёмки). По горизонтали полоса прокручивается, только когда вкладки не влезают. */
nav.tabs:not(.filters) {
  display: flex;
  gap: 4px;
  margin: 0 0 14px;
  box-shadow: inset 0 -1px 0 var(--line);
  overflow-x: auto;
  overflow-y: hidden;
}
nav.tabs:not(.filters) a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 40px;
  padding: 0 12px;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
nav.tabs:not(.filters) a:hover { color: var(--text); }
nav.tabs:not(.filters) a[aria-current] { color: var(--text); border-bottom-color: var(--eg-action); }
nav.tabs .cnt {
  padding: 1px 7px;
  border-radius: 10px;
  background: var(--eg-neutral-bg);
  color: var(--muted);
  font-size: var(--eg-fs-12);
  line-height: var(--eg-lh-12);
  font-variant-numeric: tabular-nums;
}
/* Под вкладками заголовок раздела повторял бы подпись вкладки: со сценарием (вкладка отмечена) он
   уходит из вида, а экранный чтец его читает. Без сценария разделы идут подряд с заголовками. */
nav.tabs:has(a[aria-current]) ~ .tab-panel h2:first-of-type {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
/* Списки разделов («Счета», «Файлы», история счёта) — белой панелью, как таблица позиций. */
.card-main .tab-panel > ul {
  list-style: none;
  margin: 0 0 20px;
  padding: 10px 16px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  overflow-wrap: anywhere;
}
.card-main .tab-panel > ul:not(.history) > li { padding: 8px 0; border-bottom: 1px solid var(--eg-border-soft); }
.card-main .tab-panel > ul:not(.history) > li:last-child { border-bottom: 0; }
.card-main .tab-panel > ul.history { padding: 14px 16px 14px 20px; }

.card-side small { color: var(--muted); }

/* Письмо прораба: текст чужой, и длинное слово или адрес в нём не должны
   раздвигать столбец. */
.letter { overflow-wrap: anywhere; }
.letter p { margin: 0 0 8px; }
.letter summary { margin-bottom: 8px; color: var(--text); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; cursor: pointer; }

tr.cancelled td { color: var(--faint); text-decoration: line-through; }

/* Кнопки шапки карточки стоят в ряд: формы «Беру всё» и «Вернуть в работу» —
   рядом с кнопками-ссылками, отступы одинаковые. Причина после неактивных
   кнопок — одна на группу. */
#card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
#card-actions .why { margin-left: 0; }

/* «Назначить свободные» — строка над таблицей позиций: список и кнопка в ряд.
   Класс стоит только у администратора: у остальных обёртка пустая и места
   не занимает. */
.assign-all,
.assign-all form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.assign-all { margin-bottom: 14px; }
.assign-all .why { margin-left: 0; }

/* Страница отмены: комментарий во всю ширину формы. */
form.cancel, form.upload { max-width: 560px; }
form.cancel .field, form.upload .field { margin-bottom: 14px; }
form.cancel label, form.upload label { display: block; margin-bottom: 4px; font-size: 13px; color: var(--muted); }
form.cancel textarea { display: block; width: 100%; }
form.cancel button, form.upload button { margin-right: 8px; }

/* Остатки: кнопки «сразу всё» над таблицей, «Сохранить» под ней. */
.stock-all { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }

/* Пометка «на проверке» рядом с номером заявки в списке — красная, как причина
   в карточке: общее правило для мелкого текста в ячейке сделало бы её серой. */
table.data td small.late { color: var(--late); }

/* Правка заявки и «Новая заявка»: шапка — сетка подписанных полей, как в макете
   проверки счёта; на узком окне колонок становится меньше, на телефоне — одна.
   Кнопки внизу справа: тихая «Сохранить», за ней главная «Готово». */
form.edit { max-width: 1100px; }

form.edit .fields {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px 20px;
  margin-bottom: 16px;
}

form.edit .field label { display: block; margin-bottom: 4px; font-size: 13px; color: var(--muted); }
form.edit .field input:not([type="file"]),
form.edit .field select { width: 100%; }
form.edit .field small { display: block; margin-top: 4px; font-size: 13px; color: var(--muted); }
form.edit .field small.soon { color: var(--soon); }
form.edit .errorlist { margin: 4px 0 0; padding: 0; list-style: none; }
form.edit ul.files { margin: 0 0 16px; padding-left: 18px; font-size: 14px; }
form.edit .buttons { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin: 16px 0 0; }
/* Значение длиннее поля обрезается многоточием, а не краем поля: видно, что оно не всё. */
form.edit input[type="text"] { text-overflow: ellipsis; }
/* Выбор из двух-трёх вариантов («Как оплачено» в окне наличных): варианты в ряд,
   подпись группы — как у поля; общее правило растянуло бы переключатель на всю ширину. */
form.edit fieldset.choices { margin: 0; padding: 0; border: 0; min-width: 0; }
form.edit fieldset.choices legend { padding: 0; margin-bottom: 4px; font-size: 13px; color: var(--muted); }
form.edit fieldset.choices label { display: inline-flex; align-items: center; gap: 6px; margin: 6px 16px 0 0; font-size: inherit; color: inherit; }
form.edit .field.choices input[type="radio"] { width: auto; margin: 0; }

/* Проверка счёта, как в макете: файл слева, поля справа. Файл прилипает к верху
   окна — длинный список позиций сверяется с ним без прокрутки назад. Позиции —
   карточками: в половину экрана восемь полей строки таблицей не помещаются. */
.review {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 32px;
  align-items: start;
}
.review-file { position: sticky; top: 16px; }
.review-file-head { display: flex; justify-content: space-between; gap: 12px; margin: 0 0 10px; font-size: 14px; }
.review-file iframe {
  display: block;
  width: 100%;
  height: calc(100vh - 140px);
  min-height: 480px;
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  background: var(--soft);
}
form.review-form { max-width: none; }
form.review-form .hint { margin: 0 0 12px; font-size: 14px; color: var(--muted); }
form.review-form .fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.check { display: flex; align-items: center; font-weight: 600; }
.check.done .dot { background: var(--eg-ok-dot); }
.check.late .dot { background: var(--eg-danger-dot); }
form.review-form fieldset.line {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px 12px;
  margin: 0 0 12px;
  padding: 10px 14px 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
}
form.review-form fieldset.line legend { padding: 0 6px; font-size: 13px; color: var(--muted); }
form.review-form .line-name { grid-column: 1 / 4; }
form.review-form .line-remove { grid-column: 4; align-self: end; }
form.review-form .line-site,
form.review-form .line-link,
form.review-form .line-section,
form.review-form .line-split { grid-column: span 2; }
/* Позиция, разделённая по объектам (бриф 03.11.2026): своего объекта у неё нет — на месте поля
   «Объект» подпись и что делать, в той же ячейке сетки. */
form.review-form .line-split p { margin: 6px 0 0; color: var(--muted); }
form.review-form .line-split .label { display: block; margin-bottom: 4px; font-size: 13px; color: var(--muted); }
/* Счёт из таблицы истории без файла: найденные в письмах файлы — карточками под просмотром, у
   каждого «Открыть» и «Это файл счёта»; длинное имя файла переносится по знакам. */
ul.file-candidates { display: grid; gap: 8px; margin: 0 0 16px; padding: 0; list-style: none; }
ul.file-candidates > li {
  padding: 12px 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  overflow-wrap: anywhere;
}
ul.file-candidates small { color: var(--muted); }
ul.file-candidates form { margin: 8px 0 0; }
form.review-form .field input[type="checkbox"] { width: auto; margin: 0 6px 0 0; }
form.review-form .field.checkbox label,
form.review-form .line-remove label { display: flex; align-items: center; font-size: 14px; color: var(--text); }

@media (max-width: 1099px) {
  .review { grid-template-columns: minmax(0, 1fr); }
  .review-file { position: static; }
  .review-file iframe { height: 60vh; }
}

/* На телефоне встроенный просмотр PDF не работает: файл открывается ссылкой. */
@media (max-width: 720px) {
  .review-file iframe { display: none; }
  form.review-form .fields,
  form.review-form fieldset.line { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  form.review-form .fields .field,
  form.review-form .line-name,
  form.review-form .line-remove,
  form.review-form .line-site,
  form.review-form .line-link { grid-column: 1 / -1; }
}

/* Поля позиций занимают ячейку целиком. Почти половина таблицы — наименованию;
   количеству места с запасом: обрезанное число читается как другое число. */
table.data.items-edit th:first-child { width: 46%; }
table.data.items-edit th:nth-child(2) { width: 22%; }
table.data.items-edit th:nth-child(3) { width: 13%; }
table.data.items-edit td input { width: 100%; min-width: 64px; font-weight: 400; }
table.data.items-edit td:first-child input { min-width: 200px; }

/* Пульт, как в пакете: первой строкой — заголовок и справа «Создать заявку», второй — фильтры и
   «Срезы»; ниже четыре счётчика карточками-ссылками, под ними две колонки — «Требует внимания» и
   «По объектам»; цветом окрашена только точка строки. Шапка — сетка, обёртка действий в ней не
   участвует (`display: contents`): кнопка и фильтры — её ячейки. */
.page-head:has(.head-tools) { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
.page-head:has(.head-tools) > .actions { display: contents; }
.page-head:has(.head-tools) .head-tools { grid-column: 1 / -1; }
/* В сетке шапки свободного места между заголовком и кнопкой нет — бледные соты не ставятся. */
.page-head:has(.head-tools) > .page-hex { display: none; }
.head-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.head-tools .filters { margin-bottom: 0; }
/* В шапке ширину формы задаёт самый длинный пункт списка: предел в процентах
   здесь не от чего считать, и длинное название объекта раздвигало страницу. */
.head-tools .filters select { max-width: 240px; }

.counters {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

/* Счётчик — белая карточка-ссылка, как KpiCard пакета: подпись, крупное число, сумма. Слева —
   цветная полоса, справа — значок, как в эталоне `02_ui-dashboard.png`: просрочено — красная и часы,
   ждут согласования — янтарная и документ, ждут оплаты — янтарная и карта (оранжевый — только
   действие и текущая позиция, spec, история 10), оплачено, не привезено — зелёная и машина.
   Счётчик узнаётся по адресу списка, который он открывает (разметку счётчика сверяют тесты). */
.counter {
  position: relative;
  padding: 14px 48px 16px 20px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  box-shadow: var(--eg-shadow-1);
}
.counter::before {
  content: "";
  position: absolute;
  left: 0;
  top: 12px;
  bottom: 12px;
  width: 4px;
  border-radius: 0 2px 2px 0;
  background: var(--eg-slate-400);
}
a.counter[href*="due=overdue"]::before { background: var(--eg-danger-dot); }
a.counter[href*="approval=waiting"]::before { background: var(--eg-warn-dot); }
a.counter[href*="approval=to_pay"]::before { background: var(--eg-warn-dot); }
a.counter[href*="payment=paid"]::before { background: var(--eg-ok-dot); }
a.counter::after {
  content: "";
  position: absolute;
  top: 14px;
  right: 16px;
  width: 22px;
  height: 22px;
  background: var(--muted);
  -webkit-mask: var(--eg-icon) center / contain no-repeat;
  mask: var(--eg-icon) center / contain no-repeat;
}
a.counter { --eg-icon: var(--eg-icon-next); }
a.counter[href*="due=overdue"] { --eg-icon: var(--eg-icon-clock); }
a.counter[href*="approval=waiting"] { --eg-icon: var(--eg-icon-files); }
a.counter[href*="approval=to_pay"] { --eg-icon: var(--eg-icon-card); }
a.counter[href*="payment=paid"] { --eg-icon: var(--eg-icon-truck); }
.counter > span { display: block; font-size: 14px; font-weight: 600; color: var(--text); }
.counter strong { display: block; margin-top: 8px; font-size: var(--eg-fs-28); line-height: var(--eg-lh-28); font-weight: 700; font-variant-numeric: tabular-nums; }
/* Счётчик открывает список, который посчитал. Сумма «Ждут оплаты» — мельче, на одной
   линии с числом; точная — в подсказке. */
a.counter { display: block; color: inherit; text-decoration: none; }
a.counter:hover { border-color: var(--line-strong); }
.counter strong small { font-size: 15px; font-weight: 600; white-space: nowrap; }
.live.htmx-request .counters { opacity: .5; }
/* В окне уже 1100 px четыре карточки в ряд узки: подпись «Ждут согласования» не помещалась в
   карточку. Два в ряд; на телефоне — свои поля (ниже, в правилах телефона). */
@media (max-width: 1099px) {
  .counters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Обложке страницы ошибки рядом с сотами тексту места мало: соты — над текстом. */
  .cover { padding: 196px 24px 24px; background-position: center top 20px; background-size: auto 160px; }
}

/* Строка ссылок администратора над счётчиками. */
.pult-links { display: flex; flex-wrap: wrap; gap: 4px 24px; margin: 0 0 16px; font-size: 14px; }

/* Под счётчиками — «Требует внимания» и «По объектам». Рядом, как в макете (около 60 и 40 %),
   они стоят с окна 1700 px: пяти колонкам списка нужно не меньше 720 px, а «По объектам» с
   полоской объекта — не меньше 560 px (на 1440 px в 444 px объект обрезался до трёх букв). Уже —
   блоки друг под другом, и короткое «По объектам» — первым: длинный список горящих порциями по 50
   не отодвигает его на несколько экранов вниз. */
.pult { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 32px; align-items: start; }
.pult > section { min-width: 0; }
.pult-sites { order: -1; max-width: 760px; }
@media (min-width: 1700px) {
  .pult { grid-template-columns: minmax(720px, 3fr) minmax(560px, 2fr); }
  .pult-sites { order: 0; max-width: none; }
}
/* «Требует внимания»: поля ячеек поуже, как в списке счетов; документ — главное в строке,
   ему места больше; «По объектам»: главное — объект. Ширины — только на широком окне
   (от 1280 px, пока список — таблица): правило весомее `td.cut { width: auto }` карточки
   и сжало бы её строку. */
table.data.attention th,
table.data.attention td,
table.data.sites th,
table.data.sites td { padding-left: 8px; padding-right: 8px; }
/* Как в макете: документ — главное в строке, «у кого лежит» и срок — серым; цветом окрашена
   только точка объекта. */
table.data.attention td.cut:nth-child(2) a { font-weight: 600; }
table.data.attention td:nth-child(n+4) { color: var(--muted); }
@media (min-width: 1280px) {
  table.data.attention td.cut:nth-child(1) { width: 28%; }
  table.data.attention td.cut:nth-child(2) { width: 30%; }
  table.data.attention td.cut:nth-child(4) { width: 16%; }
  table.data.sites td.cut { width: 30%; }
  table.data.sites td.share { width: 34%; }
}
/* Длинные заголовки чисел «По объектам» — в две строки, как в макете. */
table.data.sites th { white-space: normal; }
table.data.sites td { vertical-align: middle; }

/* Точка срока — цвет точки пакета: красная — просрочено, янтарная — сегодня или завтра, серая —
   в срок; слово рядом всегда. */
.dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--eg-slate-400);
  vertical-align: 1px;
}
.dot.late { background: var(--eg-danger-dot); }
.dot.soon { background: var(--eg-warn-dot); }
/* Срок, как в пакете: точка, дата и слово (`<span class="due"><span class="dot late"></span>29.10
   <span class="late">Просрочено 5 дн.</span></span>`): цветом — только точка и слово, строку не
   заливаем. */
.due { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.due > .dot { margin: 0; }
.due > .late,
.due > .soon { font-size: var(--eg-fs-13); font-weight: 600; }

/* «Что мне сделать»: номер с объектом — главное в строке, остальные колонки
   короткие, и пятой части таблицы ему мало. Пояснение к счёту обрезается, как заголовок:
   в нём бывает комментарий согласующего. */
table.data.tasks td.cut { width: 40%; }
.tasks-lead { margin: -10px 0 18px; color: var(--muted); }
/* «Всего: N» раздела — вплотную под подзаголовком: это число раздела, а не строка над таблицей. */
.tasks-section > h2 + .list-status { margin-top: -6px; }
/* Только в таблице (от 1280 px): правило весомее `td.cut { width: auto }` карточки и сжало бы
   её строку до узкой колонки. */
@media (min-width: 1280px) {
  table.data.tasks td.cut:nth-child(2) { width: 30%; }
}
/* Причина неактивной кнопки в таблице (от 1280 px) стоит рядом с кнопкой и обрезана многоточием,
   целиком — в подсказке (title): запись — одна строка. Под кнопкой она переносилась в ширине
   240 px, и строка «Приход товара» занимала две-три линии; без предела ширины растягивала колонку
   кнопки и сжимала номер документа. На карточках (ниже 1280 px) причина — полностью, под кнопкой. */
table.data.tasks:not(.questions) td .why {
  display: inline-block;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}

/* «Подтверждения»: статус словами — главное в строке («принято 15.10, склад, объект,
   Сторчак И., Петров П.»), пятой части таблицы ему мало: на 1280 px он обрезался, а сумма
   стояла в полупустой колонке. Длинный комментарий «не получено» по-прежнему обрезается.
   Только в таблице (от 1280 px): правило весомее `td.cut { width: auto }` карточки и сжало бы
   её строку. */
@media (min-width: 1280px) {
  table.data.queries td.cut:last-child { width: 45%; }
}

/* «Без документов»: наименование позиции — главное в строке и читается целиком: оно
   переносится внутри ячейки, а не обрезается; номер счёта читается целиком, пока не длиннее
   22 em (правило `.ref` выше). На широком окне наименованию — больше места, иначе короткое
   переносилось в три строки. */
table.data.no-docs td.item { white-space: normal; }
@media (min-width: 1280px) {
  table.data.no-docs td.item { width: 40%; }
}

/* Список счетов: десять колонок на окне 1280 px помещаются только с полями
   ячеек поуже, иначе поставщику и объекту оставалось по полслова. Номер — до 9 em (полный — в
   подсказке), две пометки рядом с ним («новая версия», «проверить») — мелко: с ними и плашками
   отметок список на копии стенда выходил за окно 1280 px (1378 px). Ответственный обрезается
   многоточием, как поставщик и объект. */
table.data.invoices th,
table.data.invoices td { padding-left: 6px; padding-right: 6px; }
table.data.invoices td .ref { max-width: 9em; }
table.data.invoices td small { font-size: var(--eg-fs-12); }
@media (min-width: 1280px) {
  table.data.invoices td.cut:last-child { width: 12%; }
}
/* Список заявок: девять колонок с плашкой этапа и мини-полоской на окне 1280 px помещаются с
   полями ячеек поуже и номером прораба до 7 em (полный — в подсказке); пометка «на проверке» —
   мелко. Инициатор и «Взял» обрезаются, объекту — больше места. */
table.data.requisitions th,
table.data.requisitions td { padding-left: 8px; padding-right: 8px; }
table.data.requisitions td .ref { max-width: 7em; }
table.data.requisitions td small { font-size: var(--eg-fs-12); }
@media (min-width: 1280px) {
  table.data.requisitions td.cut { width: 14%; }
  table.data.requisitions td.cut:nth-child(3) { width: 22%; }
}

/* Десять колонок позиций помещаются рядом с боковым столбцом только на широком
   окне: на 1280 и 1366 px таблица наезжала на письмо и историю, а ширина страницы
   при этом оставалась в пределах окна. До 1500 px боковой столбец стоит под
   таблицей. */
@media (max-width: 1499px) {
  .card-body { grid-template-columns: minmax(0, 1fr); }
}

/* У администратора в таблице ещё список выбора снабженца и колонка «Отменить»:
   её наименьшая ширина — 988 px, и рядом с боковым столбцом ей нужно окно шире.
   На 1700 px колонке наименования остаётся 202 px, на 1800 — 294: почти
   столько же, сколько у таблицы во всю ширину на 1500 (320). Класс wide держит
   боковой столбец под таблицей до 1800 px. */
@media (max-width: 1799px) {
  .card-body.wide { grid-template-columns: minmax(0, 1fr); }
}

/* Телефон: сверху белая шапка с горизонтальным логотипом, ролью и колокольчиком, как в пакете;
   меню уходит вниз белой полосой вкладок; записи — белые карточки на сером. Медиазапрос стоит
   после основных правил: выше он был бы перебит ими — одинаковая весомость, побеждает последнее. */
@media (max-width: 720px) {
  body { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr auto; font-size: 15px; line-height: 22px; }

  .menu {
    grid-column: 1;
    grid-row: 3;
    flex-direction: row;
    gap: 0;
    top: auto;
    bottom: 0;
    height: auto;
    padding: 0;
    background: var(--card);
    color: var(--text);
    border-top: 1px solid var(--line);
    overflow-x: auto;
    overflow-y: hidden;
    z-index: 5;
  }
  .menu :focus-visible { outline-color: var(--eg-focus); outline-offset: -2px; }
  .menu::after { display: none; }

  .menu-head { display: none; }

  /* Шапка телефона, как в макетах пакета на 390 px: горизонтальный логотип и роль слева, колокольчик
     и круг с инициалами справа, касание — 44 px; поле поиска — строкой под ними. */
  .topbar {
    grid-column: 1;
    grid-row: 1;
    flex-wrap: wrap;
    gap: 4px 8px;
    min-height: 56px;
    padding: 6px 8px 6px 16px;
  }
  .topbar .brand { display: inline-block; }
  .topbar-role {
    display: block;
    min-width: 0;
    margin-left: 4px;
    padding-left: 12px;
    border-left: 1px solid var(--line);
    overflow: hidden;
    font-size: 14px;
    line-height: 20px;
    color: var(--muted);
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  form.search { order: 1; flex: 1 1 100%; max-width: none; margin: 2px 8px 6px 0; height: var(--eg-h-touch); }
  form.search kbd { display: none; }
  .topbar a.bell { width: var(--eg-h-touch); height: var(--eg-h-touch); }
  .user-menu > summary { justify-content: center; width: var(--eg-h-touch); height: var(--eg-h-touch); padding: 0; }
  .user-menu > summary::after,
  .user-menu .who { display: none; }
  .user-menu li > a,
  .user-menu li > button { min-height: var(--eg-h-touch); }

  /* Поле не меньше 16 px: иначе телефон увеличивает страницу, когда в поле ставят курсор. */
  input[type="text"],
  input[type="password"],
  input[type="email"],
  input[type="number"],
  input[type="search"],
  input[type="date"],
  select,
  textarea { font-size: 16px; }

  /* Кнопки и фильтры шапки — на всю ширину под заголовком: списки выбора друг под другом,
     а не лесенкой разной ширины. */
  .actions:has(.head-tools) { flex: 1 1 100%; min-width: 0; }
  .head-tools,
  .head-tools .filters { width: 100%; min-width: 0; }
  /* min-width: 0 — иначе список растёт до самого длинного названия объекта и раздвигает страницу. */
  .head-tools .filters select { flex: 1 1 100%; min-width: 0; max-width: 100%; }
  /* Фильтры-пилюли — под палец, текст 16 px (иначе телефон увеличивает страницу). */
  form.filters select { height: var(--eg-h-touch); font-size: 16px; }
  form.filters label:has(> select) { height: var(--eg-h-touch); }
  form.filters label > select { height: 42px; }
  form.filters input[type="search"] { height: var(--eg-h-touch); font-size: 16px; }

  /* Шапка страницы: действия — строкой под заголовком, слева; бледным сотам здесь места нет. */
  .page-hex { display: none; }
  .page-head > .actions { margin-left: 0; }

  /* Меню роли — полоса внизу, значок над подписью, как нижняя навигация пакета: пунктов не больше
     пяти, «Выйти» — в меню пользователя в шапке; у текущей вкладки — оранжевая черта сверху. */
  .menu > a,
  .menu-soon {
    flex: 1 1 0;
    flex-direction: column;
    justify-content: center;
    gap: 2px;
    min-width: 0;
    min-height: 56px;
    margin: 0;
    padding: 6px 2px;
    border-radius: 0;
    overflow: hidden;
    font-size: var(--eg-fs-12);
    font-weight: 600;
    line-height: 16px;
    text-align: center;
    color: var(--muted);
  }

  .menu > a:hover { background: none; color: var(--text); }
  .menu > a::after { width: 22px; height: 22px; margin-right: 0; }
  .menu > a.current { background: none; color: var(--text); }
  .menu > a.current::after { background: currentColor; }
  .menu > a.current::before {
    top: 0;
    bottom: auto;
    left: 30%;
    right: 30%;
    width: auto;
    height: 3px;
    border-radius: 0 0 2px 2px;
    background: var(--eg-action);
  }

  main { grid-column: 1; grid-row: 2; padding: 16px 16px 24px; }
  /* Восемь ступеней в 343 px подписей не вмещают: на телефоне — кружки с линией и подпись только
     у текущей ступени (как «этап 3 из 8» пакета); подписи остальных — в разметке, их читает
     экранный чтец, на экране их нет. */
  .stage-strip li { gap: 0; font-size: 0; line-height: 0; }
  .stage-strip li.current { gap: 6px; font-size: var(--eg-fs-13); line-height: var(--eg-lh-13); white-space: nowrap; }
  .guest-brand { margin-top: 7vh; }
  .guest-brand .brand-logo { width: 168px; }
  /* Куст сот — внизу справа, под карточкой: на узком окне «cover» ставил его за логотип. */
  body.guest { background-size: 640px auto; background-position: right bottom; }
  .guest main { margin-top: 18px; padding: 22px 20px 26px; }
  h1 { font-size: var(--eg-fs-20); line-height: var(--eg-lh-20); }

  /* Обложка страниц ошибок: соты сверху, текст под ними. */
  .cover { min-height: 0; padding: 196px 20px 24px; background-position: center top 20px; background-size: auto 160px; }

  /* Счётчики пульта на телефоне — по два в ряд. */
  .counters { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .counter { padding: 12px 36px 12px 14px; }
  a.counter::after { top: 12px; right: 12px; width: 18px; height: 18px; }
  .counter strong { margin-top: 6px; font-size: var(--eg-fs-24); line-height: var(--eg-lh-24); }
  /* Сумма на телефоне — под числом: точка-разделитель там лишняя. */
  .counter strong small { display: block; margin-top: 6px; font-size: 15px; }
  .counter strong small .sep { display: none; }
}

/* Список — карточки ниже 1280 px: на телефоне, на планшете и в узком окне ноутбука. Таблицы
   заявок и счетов (десять колонок), позиций карточки и других списков в окне уже 1280 px выходили
   за страницу: на 800 px — на 400 px вправо, на 1024 — на 160. Шапки у карточки нет, подпись
   значения берётся из data-label ячейки. Правила таблицы, которым карточка мешает (ширины колонок,
   поля ячеек), включаются только от 1280 px — выше в файле. На планшете карточка не шире 760 px:
   подпись и значение в строке шире читаются плохо. Стоит после правил телефона и до правил
   экрана «Что мне сделать»: у них одинаковая весомость, побеждает последнее. */
@media (max-width: 1279px) {
  table.data.list,
  table.data.list tbody,
  table.data.list tr { display: block; }

  table.data.list { max-width: 760px; border: 0; background: none; }
  table.data.list thead { display: none; }

  table.data.list tr {
    margin-bottom: 10px;
    padding: 10px 14px;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--eg-r-lg);
    box-shadow: var(--eg-shadow-1);
  }

  table.data.list td,
  table.data.list td.cut {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    width: auto;
    max-width: none;
    padding: 3px 0;
    border: 0;
    border-radius: 0;
    background: none;
    overflow: visible;
    overflow-wrap: anywhere;
    white-space: normal;
    text-align: right;
  }

  table.data.list td::before {
    content: attr(data-label);
    flex-shrink: 0;
    font-weight: 400;
    color: var(--faint);
  }

  table.data.list td:first-child { font-size: 16px; font-weight: 700; }

  /* Значение из нескольких частей (название с артикулом, поле с заметкой) стоит
     в одном span: иначе каждая часть стала бы отдельной колонкой карточки. */
  table.data.list td > span { min-width: 0; }
  table.data.list td input { max-width: 100%; }
  /* В карточке места хватает: номер переносится по знакам, а не обрезается. */
  table.data.list td .ref { max-width: 100%; white-space: normal; }

  /* Экран правки: подпись стоит над полем, и поле занимает карточку по ширине —
     рядом с подписью наименованию оставалась половина строки. */
  table.data.items-edit td { flex-direction: column; gap: 2px; text-align: left; }
  table.data.items-edit td:first-child { font-size: 14px; font-weight: 400; }
  table.data.items-edit td:first-child input { min-width: 0; }

  /* Список выбора и кнопка в карточке позиции: справа, не шире карточки. */
  table.data.list td form.in-row { justify-content: flex-end; min-width: 0; }
  table.data.list td select { max-width: 100%; }

  /* Счёт позиции в карточке — номер и согласование одной строкой: места хватает. */
  table.data.list td .invoice-ref small { display: inline; width: auto; min-width: 0; }
  table.data.list td .invoice-ref a { max-width: none; }
  table.data.list td .invoice-refs { white-space: normal; }

  /* Список в панели (`.panel`): записи — строками с разделителем внутри панели, а не карточками
     с рамкой в рамке. */
  .panel > table.data.list { max-width: none; padding: 0 16px; }
  .panel > table.data.list tr {
    margin: 0;
    padding: 10px 0;
    border: 0;
    border-bottom: 1px solid var(--eg-border-soft);
    border-radius: 0;
    box-shadow: none;
  }
  .panel > table.data.list tr:last-child { border-bottom: 0; }
}

/* «Что мне сделать» ниже 1280 px — карточки, как в макете склада: метка раздела мелкими
   прописными, жирный заголовок, серое пояснение, кнопка по ширине содержимого под ними.
   Подзаголовок раздела уходит из вида (скринридер его читает): метка стоит в каждой карточке.
   Пары «подпись — значение» здесь не нужны, подписи колонок скрыты; срок — мелкой строкой
   под пояснением, без срока — прочерк, как в таблице. Правила стоят после общих правил
   карточки списка: селекторы у них такой же весомости. */
@media (max-width: 1279px) {
  .tasks-lead { margin: -8px 0 16px; font-size: 14px; }
  /* Подзаголовок раздела — строкой над карточками мелкими прописными, справа — «Всего: N», как
     «УКАЗАТЬ НАЛИЧИЕ … 1» в макете склада: без него число раздела висело бы без названия. */
  .tasks-section { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; column-gap: 12px; max-width: 560px; }
  .tasks-section > * { grid-column: 1 / -1; }
  .tasks-section > h2 {
    grid-column: 1;
    margin: 18px 0 8px;
    font-size: var(--eg-fs-12);
    line-height: var(--eg-lh-12);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--muted);
  }
  .tasks-section > h2 + .list-status { grid-column: 2; margin: 18px 0 8px; }
  .tasks-section table.data.list,
  .tasks-section table.data.list tbody,
  .tasks-section table.data.list tr { display: block; }
  .tasks-section table.data.list { max-width: 560px; border: 0; background: none; }
  .tasks-section table.data.list thead { display: none; }
  .tasks-section table.data.list tr {
    margin-bottom: 12px;
    padding: 16px 18px 18px;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--eg-r-lg);
    box-shadow: var(--eg-shadow-1);
  }
  .tasks-section table.data.list tr::before {
    content: attr(data-kicker);
    display: block;
    margin-bottom: 8px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--muted);
  }
  .tasks-section table.data.list td,
  .tasks-section table.data.list td.cut {
    display: block;
    width: auto;
    max-width: none;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    overflow: visible;
    white-space: normal;
    text-align: left;
  }
  .tasks-section table.data.list td::before { content: none; }
  /* Точка «в срок» без цвета на карточке только сдвигала бы строку: её там нет. */
  .tasks-section table.data.list td .dot:not(.late):not(.soon) { display: none; }
  .tasks-section table.data.list td:first-child { font-size: 18px; line-height: 1.3; }
  .tasks-section table.data.list td:first-child a { color: var(--text); }
  .tasks-section table.data.list td:nth-child(2) { margin-top: 6px; font-size: 15px; color: var(--muted); }
  .tasks-section table.data.list td[data-label="Срок"] { margin-top: 8px; font-size: 14px; color: var(--muted); }
  .tasks-section table.data.list td[data-label=""] { margin-top: 16px; }
  .tasks-section table.data.list td form.in-row { justify-content: flex-start; }
  /* Главное действие карточки — оранжевое с чёрным текстом, высотой для пальца; «Нет» рядом
     с «Да, принято» остаётся с рамкой. */
  .tasks-section table.data.list td > a.button,
  .tasks-section table.data.list td > form > button:not(:disabled),
  .tasks-section table.data.list td form.in-row > button:not(:disabled) {
    padding: 11px 18px;
    background: var(--accent);
    border-color: var(--accent);
    color: var(--eg-on-action);
  }
  .tasks-section table.data.list td form.in-row > a.button,
  .tasks-section table.data.list td button:disabled { padding: 11px 18px; }
  .tasks-section table.data.list td .why {
    display: block;
    flex-basis: 100%;
    max-width: none;
    margin: 6px 0 0;
    overflow: visible;
    white-space: normal;
  }
}

/* «Ждут вашего решения»: карточка счёта под телефон, как на макете руководителя.
   Верх карточки — ссылка в счёт, кнопки под ним одной ширины. */
.eyebrow { display: block; margin-bottom: 4px; font-size: 14px; font-weight: 400; color: var(--muted); }
.decide {
  max-width: 520px;
  margin: 0 0 12px;
  padding: 16px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  box-shadow: var(--eg-shadow-1);
}
.decide-open { display: block; color: inherit; text-decoration: none; }
.decide-top { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.decide-supplier { font-size: 17px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.decide-days { flex-shrink: 0; font-size: 14px; color: var(--muted); }
.decide-sum { display: block; margin: 8px 0 12px; font-size: 32px; line-height: 1.1; font-weight: 700; }
.decide-fact { display: flex; gap: 12px; padding: 3px 0; font-size: 15px; }
.decide-fact span { flex: 0 0 76px; color: var(--muted); }
.decide-fact b { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.decide-buttons { display: flex; gap: 10px; margin-top: 14px; }
.decide-buttons > form,
.decide-buttons > .danger { flex: 1 1 0; margin: 0; }
.decide-buttons button,
.decide-buttons a.button { display: block; width: 100%; padding: 12px 8px; text-align: center; }

/* «Срезы» (блок 09), по образцу пульта: кнопки готовых срезов, строка выбора, таблица с итогом.
   Поле строки выбора — с подписью, текст у поля (ошибка или подсказка) — под ним; объекты,
   юрлица, поставщики, разделы и показатели — флажками в раскрывающемся списке поверх страницы. */
.slice-export { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.slice-export .why { margin-left: 0; }
.slice-form { align-items: flex-start; }
.slice-form .field { display: inline-flex; flex-direction: column; gap: 2px; min-width: 0; max-width: 100%; }
.slice-form .period { display: inline-flex; flex-wrap: wrap; gap: 8px; }
/* Текст у поля переносится в ширину поля, а не раздвигает его: нулевая ширина с наименьшей во всё поле. */
.slice-form .field > .errorlist,
.slice-form .field > .note { width: 0; min-width: 100%; margin: 0; padding: 0; font-size: 13px; }
.slice-form .field > small:empty { display: none; }
.slice-form input[type="text"] { width: 240px; max-width: 100%; }
.slice-form details { position: relative; }
.slice-form summary {
  position: relative;
  max-width: 260px;
  padding: 7px 32px 7px 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--eg-r-md);
  background: var(--card);
  line-height: 20px;
  list-style: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}
.slice-form summary::-webkit-details-marker { display: none; }
/* Уголок справа, как у списка выбора. */
.slice-form summary::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 14px;
  width: 6px;
  height: 6px;
  margin-top: -5px;
  border-right: 1.5px solid var(--muted);
  border-bottom: 1.5px solid var(--muted);
  transform: rotate(45deg);
}
.slice-form details[open] > summary { border-color: var(--eg-focus); }
.slice-form .choices {
  position: absolute;
  z-index: 3;
  top: calc(100% + 4px);
  left: 0;
  display: block;
  min-width: 100%;
  width: max-content;
  max-width: 340px;
  max-height: 320px;
  overflow-y: auto;
  padding: 6px 12px;
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: var(--eg-r-md);
  box-shadow: var(--eg-shadow-2);
}
.slice-form .choices label { display: flex; align-items: flex-start; gap: 8px; padding: 4px 0; color: var(--text); }
.slice-form .choices input { margin: 3px 0 0; }

/* Таблица среза: при колонках-поставщиках она бывает шире окна и прокручивается в своём блоке,
   а не раздвигает страницу; названия колонок переносятся по словам. Итоговые строки — жирные
   на сером, без нового цвета. Найденные наименования — колонками. */
.slice-table { max-width: 100%; overflow-x: auto; }
table.data.slice th { white-space: normal; }
table.data.slice tr.total td { font-weight: 700; background: var(--soft); }
.slice-names { columns: 3 300px; column-gap: 32px; margin: 0; padding-left: 18px; font-size: 14px; }
.slice-names li { break-inside: avoid; overflow-wrap: anywhere; }
/* Только в таблице (от 1280 px): правила весомее правил карточки. Поля ячеек поуже, как в списке
   счетов: колонок у среза с колонками много; название строки не сжимается мельче 120 px. */
@media (min-width: 1280px) {
  table.data.slice th,
  table.data.slice td { padding-left: 8px; padding-right: 8px; }
  table.data.slice td.cut { width: 30%; min-width: 120px; }
}
/* Карточки (ниже 1280 px): итог — последние карточки, серые целиком. */
@media (max-width: 1279px) {
  table.data.list.slice tr.total { background: var(--soft); }
  table.data.list.slice tr.total td { background: none; }
}
/* Телефон: поля строки выбора — друг под другом на всю ширину, раскрытый список — в потоке
   страницы, а не поверх: справа ему не хватило бы места. */
@media (max-width: 720px) {
  .slice-form .field,
  .slice-form details,
  .slice-form summary,
  .slice-form input[type="text"] { width: 100%; max-width: 100%; }
  .slice-form .field > label { justify-content: space-between; }
  .slice-form .field select { flex: 1 1 auto; min-width: 0; max-width: 100%; }
  .slice-form .choices { position: static; width: auto; max-width: none; margin-top: 4px; box-shadow: none; }
  .slice-names { columns: 1; }
}

/* «Уведомления» (блок 10): текст — главное в строке, ему почти вся ширина; непрочитанное —
   жирным и с графитовой точкой, прочитанное — обычным. */
table.data.notices td:first-child { font-weight: 400; }
table.data.notices tr.unread td:first-child { font-weight: 700; }
table.data.notices .dot { margin-right: 8px; }
.dot.unread { background: var(--eg-shell-active); }
/* Только в таблице (от 1280 px): правило весомее `td.cut { width: auto }` карточки. */
@media (min-width: 1280px) {
  table.data.notices td.cut { width: 85%; }
}
/* Карточки (ниже 1280 px) — как лента: текст во всю карточку, под ним время мелко и серым;
   подписи «Уведомление» и «Когда» здесь лишние. */
@media (max-width: 1279px) {
  table.data.list.notices td,
  table.data.list.notices td.cut { display: block; text-align: left; }
  table.data.list.notices td::before { content: none; }
  table.data.list.notices td:first-child { font-size: 15px; font-weight: 400; }
  table.data.list.notices tr.unread td:first-child { font-weight: 700; }
  table.data.list.notices td + td { margin-top: 4px; font-size: 13px; color: var(--muted); }
}
/* «Куда присылать» над лентой — в рамке: это настройка, а не уведомление. Кнопка и её
   состояние — одной строкой (на телефоне состояние уходит под кнопку), под ними подсказка. */
.channels {
  max-width: 760px;
  margin: 0 0 22px;
  padding: 14px 18px 16px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
}
.channels h2 { margin: 0 0 10px; font-size: 16px; }
.channels p { margin: 0; }
.push-line, .telegram-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
.push-line .why, .telegram-line .why { margin-left: 0; }
.push-line + .note { margin-top: 8px; }
/* Telegram — под пушем, через черту; ссылка с кодом и подсказка — под кнопкой. Ссылка длинная:
   на телефоне она переносится, а не раздвигает страницу. */
#telegram { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); }
#telegram form + .telegram-line, #telegram .telegram-line + .note { margin-top: 8px; }
#telegram a { overflow-wrap: anywhere; }
/* C07/C08: формы карточки и раскрываемые значения мобильных списков. */
.destination-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.destination-form select { width: auto; }
.item-link { min-width: 0; max-width: 100%; }
.item-link summary { cursor: pointer; white-space: normal; }
.item-link form { margin-top: 8px; white-space: normal; }
.item-link select { max-width: 100%; min-width: 0; }
/* «Изменить привязку» и «Разделить по объектам» в строке позиции счёта — тихие ссылки мелким
   шрифтом с уголком: раскрывают форму под собой. «Разделить» — под выбором объекта, форма — на
   светло-сером, строками «объект | кол-во». */
.item-link > summary {
  display: inline;
  font-size: var(--eg-fs-13);
  line-height: var(--eg-lh-13);
  color: var(--muted);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
  list-style: none;
}
.item-link > summary::-webkit-details-marker { display: none; }
.item-link > summary::after {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin: 0 3px 2px 5px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
}
.item-link[open] > summary::after { margin-bottom: -1px; transform: rotate(-135deg); }
.item-link > summary:hover { color: var(--text); text-decoration-color: currentColor; }
details.item-split { display: block; }
.item-split-body:has(form) { margin-top: 6px; padding: 10px 12px; background: var(--soft); border-radius: var(--eg-r-md); }
.item-split-body form.split-form { margin: 0; }
form.split-form .split-part {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 72px;
  gap: 8px;
  align-items: start;
  margin-bottom: 8px;
}
form.split-form .split-part .field { margin: 0; }
form.split-form .hint { margin: 0 0 8px; font-size: 13px; color: var(--muted); white-space: normal; }
form.split-form .buttons { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 0; }
.cut-value { display: contents; }
@media (max-width: 1279px) {
  table.data.list td.cut > .cut-value {
    display: block; flex: 1; min-width: 0; overflow: hidden;
    white-space: nowrap; text-overflow: ellipsis; cursor: pointer;
  }
  table.data.list td.cut > .cut-value.expanded {
    white-space: normal; overflow: visible; overflow-wrap: anywhere;
  }
  table.data.list td.cut > .cut-value:not(.expanded) * { white-space: nowrap; }
  table.data.list td.cut > .cut-value:not(.expanded) br { display: none; }
  table.data.list td.cut > .cut-value:focus-visible {
    outline: 2px solid currentColor; outline-offset: 2px;
  }
  table.data.list td > div:has(.item-link) { min-width: 0; max-width: 65%; }
}

/* Куски для соседних тасков (бриф 03.11.2026, `interfaces.md` сборки, «Оформление: основа»):
   облик готов заранее, разметку строят их таски. */

/* «Показать ещё» (core/_more.html): строка-кнопка последней в списке; причина сбоя подгрузки —
   в той же строке рядом с кнопкой. */
tr.more-row td { padding: 8px 12px; text-align: center; background: var(--soft); }
table.data tbody tr.more-row:hover td { background: var(--soft); }
a.button.more { min-width: 200px; text-align: center; }
tr.more-row .note { margin-left: 12px; font-size: 13px; }

/* Группы «Проверить»: строка группы — кнопка во всю ширину «вид · причина — N» с уголком;
   раскрытая — уголок вниз. Строки группы и «Показать ещё» — в том же tbody. */
tbody.group tr.group-row td { padding: 0; background: var(--soft); border-bottom: 1px solid var(--line); }
table.data tbody.group tr.group-row:hover td { background: var(--soft); }
tbody.group button.group-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: var(--eg-h-row);
  padding: 8px 12px;
  border: 0;
  border-radius: 0;
  background: none;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  text-align: left;
}
tbody.group button.group-toggle:hover { background: var(--panel); }
tbody.group button.group-toggle::before {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  margin: 0 2px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
}
tbody.group button.group-toggle[aria-expanded="true"]::before { transform: rotate(45deg); }

/* Части позиции «объект — количество — сумма» — строки под позицией: мельче и на сером,
   в таблице — с отступом и уголком. */
tr.part-row td { padding-top: 4px; padding-bottom: 4px; font-size: 13px; color: var(--muted); background: var(--soft); }
@media (min-width: 1280px) {
  table.data tr.part-row td:first-child { padding-left: 24px; font-weight: 400; }
  table.data tr.part-row td:first-child::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 8px;
    border-left: 1px solid var(--line-strong);
    border-bottom: 1px solid var(--line-strong);
    vertical-align: 3px;
  }
}

/* Просмотр файла счёта (invoices/_file_view.html): PDF — во всю ширину столбца, картинка —
   не шире его, текст вместо файла — на белой панели. Высоту встроенного PDF задаёт место: экран
   проверки — правило `.review-file iframe` выше, боковой столбец карточки — здесь. В карточке
   просмотр раскрывается нажатием (details.file-lazy). */
.file-view iframe {
  display: block;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  background: var(--soft);
}
.card-side .file-view iframe { height: 60vh; min-height: 320px; }
.file-view img {
  display: block;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  background: var(--card);
}
.file-view p {
  margin: 0;
  padding: 12px 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--eg-r-lg);
  color: var(--muted);
}
.file-view p strong { color: var(--text); }
details.file-lazy { margin: 8px 0 16px; }
details.file-lazy > summary {
  display: inline-block;
  padding: 5px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--eg-r-md);
  background: var(--card);
  font-size: 14px;
  font-weight: 600;
  list-style: none;
  cursor: pointer;
}
details.file-lazy > summary::-webkit-details-marker { display: none; }
details.file-lazy > summary:hover { background: var(--soft); }
details.file-lazy[open] > summary { margin-bottom: 8px; }
.file-lazy-body .note { margin: 0; }

/* Плашки отметок — этап позиции, оплата, отгрузка, документы — всегда со словом: сделано —
   зелёная, частично — янтарная, нет — серая; красная — только просрочка и блокировка. Значок
   перед словом (● ◐ ○) читается и без цвета. Этап — серая плашка с номером шага `<span class="n">`.
   В строке 36 px плашка не раздвигает её: отрицательные поля съедают лишнюю высоту. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 22px;
  margin: -1px 0;
  padding: 0 8px;
  border-radius: var(--eg-r-sm);
  background: var(--eg-neutral-bg);
  color: var(--eg-neutral-fg);
  font-size: var(--eg-fs-13);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  vertical-align: middle;
}
.chip-done { background: var(--eg-ok-bg); color: var(--eg-ok-fg); }
.chip-part { background: var(--eg-warn-bg); color: var(--eg-warn-fg); }
.chip-none { background: var(--eg-neutral-bg); color: var(--eg-neutral-fg); }
.chip-late { background: var(--eg-danger-bg); color: var(--eg-danger-fg); }
/* «Не нужна» (позиция закрыта остатками, документ не требуется) — пунктир без заливки, слово серым. */
.chip-na { border: 1px dashed var(--eg-slate-400); background: none; color: var(--muted); }
.chip-done::before,
.chip-part::before,
.chip-none::before,
.chip-na::before {
  content: "";
  flex: none;
  width: 9px;
  height: 9px;
  border: 1.5px solid currentColor;
  border-radius: 50%;
  box-sizing: border-box;
}
.chip-done::before { background: currentColor; }
.chip-part::before { background: linear-gradient(90deg, currentColor 50%, transparent 50%); }
.chip-na::before { border-style: dashed; }
.chip-stage { padding-left: 3px; background: var(--eg-neutral-bg); color: var(--text); font-weight: 500; }
.chip-stage .n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  border-radius: 3px;
  background: var(--card);
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Этап «Отгружено» и «Закрыта» — плашка этапа зелёным, как отметка «сделано»: номер шага вместо
   значка. У отменённой заявки номера нет — поля плашки обычные. */
.chip-stage.chip-done { background: var(--eg-ok-bg); color: var(--eg-ok-fg); }
.chip-stage.chip-done::before { content: none; }
.chip-stage.chip-done .n { color: var(--eg-ok-fg); }
.chip-stage:not(:has(.n)) { padding-left: 8px; }
/* Плашки отметок в строке списка не раздвигают строку и стоят по её линии текста. */
table.data td .chip { vertical-align: top; margin: -1px 0; }
/* В тесных таблицах — заявки и счета по десять колонок, позиции заявки — плашки плотнее: шрифт
   12 px, поля 6 px. С обычными плашками эти списки на окне 1280 px выходили за окно. */
table.data.requisitions .chip,
table.data.invoices .chip,
#positions > table.data .chip { gap: 4px; padding: 0 6px; font-size: var(--eg-fs-12); }
table.data.requisitions .chip-stage,
#positions > table.data .chip-stage { padding-left: 3px; }
table.data.requisitions .chip-stage:not(:has(.n)) { padding-left: 6px; }
/* Плашка этапа в таблице позиций заявки не переносится внутри себя (ремонт ветки F1): таблица шире
   панели прокручивается внутри неё (static/css/screens/requisitions.css). */

/* Полоска прогресса (пульт «По объектам», «Выполнение» в списке заявок): серый трек, зелёная
   заливка, как в эталоне; ширина заливки — `style="width: N%"` в разметке. */
.bar { display: flex; height: 6px; border-radius: 3px; background: var(--eg-bar-track); overflow: hidden; }
.bar > i { display: block; height: 100%; background: var(--eg-ok-dot); }
/* «Выполнение» в списке заявок (spec №124): мини-полоска и «отгружено X из Y» в одну строку. */
.shipped-share { display: inline-flex; align-items: center; gap: 8px; }
.shipped-share .bar { flex: none; width: 56px; }
/* «Выполнение» объекта на пульте (spec №121), как в эталоне: над полоской «N заявок» и «62 %»
   жирно, справа от неё — «13 из 21». */
.site-share {
  display: grid;
  grid-template-columns: minmax(40px, 1fr) 76px;
  align-items: center;
  gap: 3px 10px;
  min-width: 132px;
}
.site-share small { font-size: var(--eg-fs-12); line-height: var(--eg-lh-12); }
.site-share strong,
.site-share small:last-child { justify-self: end; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Ниже 1280 px строки — карточки: «Показать ещё» и строка группы карточкой не рисуются —
   кнопка во всю ширину; части позиции — серые карточки под позицией. */
@media (max-width: 1279px) {
  table.data.list tr.more-row,
  table.data.list tr.group-row { padding: 0; background: none; border: 0; box-shadow: none; }
  table.data.list tr.more-row td,
  table.data.list tr.group-row td { display: block; padding: 0; text-align: left; background: none; }
  table.data.list tr.more-row td::before,
  table.data.list tr.group-row td::before { content: none; }
  table.data.list tr.more-row a.button.more { display: block; width: 100%; }
  table.data.list tr.more-row .note { display: block; margin: 8px 0 0; }
  table.data.list tr.group-row button.group-toggle {
    padding: 12px 14px;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--eg-r-lg);
  }
  table.data.list tr.part-row { margin: -6px 0 10px 16px; padding: 6px 12px; background: var(--soft); box-shadow: none; }
  table.data.list tr.part-row td:empty { display: none; }
}

/* Ширина столбцов (static/js/table-columns.js, spec №113): ручка у правого края заголовка —
   только там, где список — таблица (от 1280 px); заданные ширины — доли таблицы, раскладка
   по ним, а длинное в ячейке обрезается многоточием. */
.col-grip { display: none; }
@media (min-width: 1280px) {
  .col-grip {
    display: block;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 9px;
    cursor: col-resize;
    touch-action: none;
  }
  .col-grip::after {
    content: "";
    position: absolute;
    top: 8px;
    bottom: 8px;
    right: 3px;
    width: 2px;
    border-radius: 1px;
  }
  table.data th:hover .col-grip::after { background: var(--line-strong); }
  table.data th .col-grip:hover::after { background: var(--text); }
  table.data.cols-set { table-layout: fixed; }
  table.data.cols-set th,
  table.data.list.cols-set:not(.wrap) td { overflow: hidden; text-overflow: ellipsis; }
}
