/* ==========================================================================
   WB REDASH ANALYTICS DASHBOARD - STYLESHEET
   ========================================================================== */

/* Inter лежит в public/fonts — не тянется с fonts.googleapis.com. Внешний CDN
   блокировал первую отрисовку ожиданием чужого домена, а если он недоступен,
   интерфейс молча падал на Segoe UI.

   Ось вариативная (font-weight: 300 800) намеренно. Раньше разметка просила
   начертания 550, 650, 720, 750 и 760, которых не было в наборе статических
   файлов, — браузер молча округлял. Теперь начертаний четыре (--fw-text,
   --fw-label, --fw-title, --fw-num), но вариативный файл остаётся: он даёт
   ровно 500 и 600, а не ближайшее из имеющегося.

   unicode-range обязателен: без него браузер скачает все subset'ы разом.
   Про обновление файлов — public/fonts/Inter.LICENSE.txt. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url(fonts/inter-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url(fonts/inter-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url(fonts/inter-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url(fonts/inter-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   ТОКЕНЫ — визуальный язык «Пульт»
   ==========================================================================

   Значения выведены из OKLCH, но в CSS попадают посчитанными шестнадцатеричными
   кодами: сборщика у проекта нет, а браузерное `oklch()` при выходе за охват
   sRGB подгоняет цвет по-своему — макет и стенд начинают расходиться.

   Светлота в OKLCH перцептивная: одинаковая L даёт одинаковую видимую громкость
   на любом тоне, поэтому жёлтый перестаёт кричать громче синего без ручной
   подгонки каждого оттенка. Меняете цвет — меняйте L и H в рецепте и
   пересчитывайте семейство целиком; точечная правка одного hex ломает
   равновесие ряда.

   Имена токенов исторические — их знает не только этот файл, но и инлайновые
   стили в public/js и разметка. Поэтому менялись значения, а не имена.

   17.09 — значения переведены на палитру референса A (переработка дизайна/
   Referens-A-Smena): тёплая нейтраль, янтарный акцент, три семейства
   состояний из макета. Холодные info/discovery/replacement у макета нет —
   оставлены. Контрасты: text-dim 4.86:1 к --bg-input, белый на заливке
   кнопки 5.08:1, чернила семейств на своих плашках 5.0–6.1:1 (светлая),
   5.7–8.2:1 (тёмная).
   ========================================================================== */

:root {
  /* НЕЙТРАЛЬ. Холодная, под фирменный стиль WB (17.09, журнал 16): белый с
     графитовым текстом; прежняя тёплая бежевая референса A снята.
     Ни чистого белого фона, ни чистого чёрного текста: предельный контраст
     даёт halation — текст вибрирует, и на восьмом часу смены это чувствуется.
     Отношение основного текста к карточке держим около 14:1, а не 21:1. */
  --bg-dark: #f3f3f6;        /* фон страницы                       */
  --bg-card: #fbfbfd;        /* карточка, таблица                  */
  --bg-card-hover: #ececf1;  /* наведение, выделенная строка       */
  --bg-header: #fbfbfd;      /* шапка и рельс навигации            */
  --bg-input: #ebebf0;       /* поле ввода, зебра, шапка таблицы   */

  --border-color: #dcdce3;   /* волосяная граница между блоками    */
  /* ТОЛЬКО разделитель секций: 1.4–1.9:1 к поверхностям. Границей органа
     управления и планкой состояния его ставить нельзя — порог 3:1 не берётся.
     Для этого есть --line-ctl и солидный слой семейств. */
  --border-strong: #c6c6d0;
  /* Граница органа управления: поле, селект, вторичная кнопка. 3.52:1 к худшей
     поверхности. До «Пульта» здесь стоял --border-color — 1.2:1, то есть поля
     на экране были практически без границ. */
  --line-ctl: #77778a;
  --border-accent: #cb11ab;

  --text-main: #1a1a24;   /* основной текст, 16.7:1 к карточке              */
  --text-muted: #55556a;  /* вторичный,       7.0:1                         */
  --text-dim: #63637a;    /* подписи, мета,   4.91:1 к худшей (--bg-input)  */

  /* АКЦЕНТ — фирменная фуксия Wildberries #CB11AB (17.09, журнал 16) вместо
     оранжевой референса A; глубокий фиолет #481173 — у --accent-purple.
     Контрасты пересчитаны под те же пороги (4.5:1 текст, 3:1 обводка). */
  --accent-primary: #a30d89;        /* акцентный текст и планка, 6.83:1     */
  --accent-primary-fill: #cb11ab;   /* заливка главной кнопки, белый 4.99:1 */
  --accent-primary-hover: #b30f97;  /* она же под курсором                  */
  --accent-primary-soft: #fbe6f6;   /* выделенная строка, подсветка         */
  --accent-primary-border: #cb11ab; /* обводка активного, планка            */
  --accent-on-primary: #ffffff;

  /* СОСТОЯНИЕ — пять семейств, три слоя, одна формула светлоты.
     Рецепт: ink L .430 · rail L .585 · wash L .955
     Тона: свободна 250 · в работе 82 · закрыта 150 · срочно 27 · чужая 300

     ink  — текст на плашке и цветное число.  Порог 4.5:1, держит 6.8–8.2.
     rail — планка, точка, иконка, обводка.   Порог 3:1,   держит 3.8–4.3.
     wash — заливка плашки и подсветка строки. Фон, не носитель смысла.

     Раньше слои были полупрозрачными rgba: оттенок плашки зависел от того, на
     какой строке она лежит, и на зебре бейджи выцветали. Плотный цвет читается
     одинаково на карточке, на зебре и на подсвеченной строке. */

  /* Солидный слой (rail) — планки inset 4px, обводки чипов, иконки. */
  --info-solid: #2c7fcb;
  /* Чернила предупреждения на фоне --warning-soft (аудит 11.09): прежний
     #9d7413 давал 3,73:1 при норме 4,5 — «Б и V, сумма» в календаре,
     «проверить» в заменах, «Сотрудник неактивен»; #7a5a0c — 5,6:1. */
  --warning-solid: #8a5a06;
  --success-solid: #1f6b45;
  --danger-solid: #9a2f28;
  --discovery-solid: #1a6e7f;

  /* Раздел «Замены» — своя пара цветов, НЕ семантические токены выше.
     Исходящие («из моей группы») голубые, входящие («пришли в группу»)
     фиолетовые: пара несёт направление замены, а не статус.

     Почему отдельные токены, а не --info-solid/--discovery-solid: соседи по
     смыслу уже заняты и стоят рядом в той же легенде календаря. --info-* —
     это «Н, рабочий день» (.calendar-day-work), и «З» на голубом --info-solid
     слился бы с «Н» в одной сетке. --discovery-* — статус «В работе у другого
     модератора», а --accent-primary — «S, обучение» (.calendar-day-study) и
     вся интерфейсная хрома. Взяв их, мы бы ещё и привязали цвет замены к
     чужой настройке: перекрасят статус — поедет замена. Ровно этот рассинхрон
     уже был багом однажды (см. .calendar-day-replacement ниже).
     Контрасты: --replacement-out 5.93:1 к карточке, --replacement-in 6.98:1. */
  --replacement-out: #0369a1;
  --replacement-in: #7e22ce;

  /* Чернильный слой семейств. Имена исторические: разметка использует их как
     цвет текста поверх соответствующей заливки (.badge-good, .badge-warning,
     .ticket-stat-*), поэтому здесь ink, а не rail — иначе текст просядет. */
  --accent-cyan: var(--accent-primary);
  --accent-blue: #185287;
  --accent-info: #185287;
  --accent-green: #1f6b45;
  --accent-amber: #8a5a06;
  --accent-orange: #8a5a06;
  --accent-rose: #9a2f28;
  --accent-purple: #481173;
  --accent-indigo: #481173;

  /* Заливка (wash) и обводка (rail) плашек.
     Имена --info-soft и --warning-soft прибиты tests/test_frontend_modules.py:
     тест требует буквальных строк `background: var(--info-soft)` и
     `let statusStyle = "background: var(--warning-soft)` в public/js/tickets.js.
     Убрать имена можно только вместе с правкой теста — иначе npm test зелёный,
     а фон плашек молча пропал. */
  --info-soft: #e5f2ff;
  --info-border: #2c7fcb;
  --success-soft: #e0efe6;
  --success-border: #1f6b45;
  --warning-soft: #f7ebd4;
  --warning-border: #8a5a06;
  --danger-soft: #f8e3e0;
  --danger-border: #9a2f28;

  /* Отдельная пара для «В работе у другого модератора» — бирюза, а не фиолет:
     фиолет теперь занят акцентом WB. Раньше плашка брала
     --accent-primary-soft, но это токен интерфейсной хромы (подсветка,
     выделение, ховеры), и поднимать его до плотности плашек нельзя —
     покраснеет половина экрана. Статусу нужен свой слой. */
  --discovery-soft: #e4f3f6;
  --discovery-border: #1a6e7f;

  /* Тихий слой для больших поверхностей — ячеек календаря и фоновых плиток.
     Заливка плашек на них была бы пёстрой: площадь несопоставима. Это тот же
     wash, разбавленный карточкой наполовину. */
  --info-wash: #f0f7fe;
  --warning-wash: #f8f1e4;
  --success-wash: #ecf3ed;
  --danger-wash: #f8edea;

  /* Подсветка строки — полный wash: строка таблицы это не фоновая плитка,
     а сообщение, и оно должно читаться на прокрутке. */
  --danger-row: #f8e3e0;
  --warning-row: #f7ebd4;

  /* ТИПОГРАФИКА. Семь ступеней с малым шагом: плотный интерфейс не терпит
     большой типографической разницы — она рвёт сетку. Значения в px, а не в
     rem: rem считается от базы 16px, и вся шкала уезжала на дробные размеры
     (13.6, 11.84, 14.4), которых нет ни в одном рецепте. */
  --fs-1: 12px;  /* мета, единицы, подпись под числом */
  --fs-2: 13px;  /* чипы, бейджи, вторичный текст     */
  --fs-3: 14px;  /* базовый в таблицах                */
  --fs-4: 15px;  /* базовый интерфейсный              */
  --fs-5: 17px;  /* заголовок карточки                */
  --fs-6: 20px;  /* заголовок раздела                 */
  --fs-7: 28px;  /* крупное число                     */

  --lh-tight: 1.25;
  --lh-table: 1.4;
  --lh-text: 1.5;

  /* Четыре начертания. Больше ступеней глаз не различает, а сетка от них
     расползается. До «Пульта» их было четырнадцать, включая 550, 650, 720,
     750 и 760. */
  /* Редизайн 16.09 (референс Linear): плотность держится на размере и цвете,
     не на жирности — начертания вернулись к сдержанным. Толстые/чёрные из
     версии 15.09 не подошли. */
  --fw-text: 400;
  --fw-label: 500;
  --fw-title: 600;
  --fw-num: 600;

  /* ФОРМА. Редизайн 16.09: острые углы 15.09 читались как «плакат», не как
     рабочий инструмент — Linear держит малый, единообразный радиус. */
  --radius-sm: 5px;
  --radius-md: 7px;
  --radius-lg: 10px;

  /* ВЫСОТА ОРГАНОВ УПРАВЛЕНИЯ. Раньше её не задавал никто: высота собиралась
     из паддинга и `line-height: normal` того шрифта, который подставит
     браузер. На 120 видимых кнопках это давало 12 разных высот, а в подвале
     модалки автораспределения главная кнопка стояла на 2px ниже «Отмены» —
     у неё инлайновый `border: none`, у соседней рамка `.btn` в 1px.
     34px выбраны не с потолка: столько же занимает группа чипов периода
     (26px чип + по 3px поля + рамка), и вся строка фильтров встаёт в один
     рост. */
  --h-ctl: 34px;     /* кнопка, поле, селект   */
  --h-ctl-sm: 26px;  /* чип внутри группы      */
  --h-ctl-lg: 42px;  /* кнопка во всю ширину   */

  /* ГЛУБИНА в три уровня, тень только у третьего:
     0 — фон страницы; 1 — карточка: поверхность на ступень выше плюс
     волосяная граница, без тени; 2 — настоящий оверлей: модалка, поповер,
     нижняя кромка липкой шапки. Граница вместо тени держит плотность: тени на
     плотной сетке дают грязь и съедают воздух, которого и так нет. */
  /* Редизайн 16.09: жёсткая оффсет-тень 15.09 была даже громче исходных
     мягких — на плотном экране это шум. Linear почти не использует тень на
     карточках (глубину даёт разница фона, не отбрасываемая тень); тень
     остаётся только у настоящего оверлея (модалка, поповер), и она мягкая. */
  --elev-1: 0 0 0 1px var(--border-color);
  --shadow-sm: var(--elev-1);
  --shadow-md: 0 12px 32px -8px rgba(15, 18, 23, 0.28), 0 0 0 1px var(--border-color);
  --shadow-sticky: 0 4px 10px -6px rgba(15, 18, 23, 0.35);

  /* Кольцо фокуса видно на любой поверхности: сначала подложка цветом панели,
     затем акцент. Без подложки акцент сливается с тёмной строкой таблицы. */
  --focus: 0 0 0 2px var(--bg-card), 0 0 0 4px var(--accent-primary-fill);
  --shadow-glow: var(--focus);

  /* Aliases used by dynamically rendered cards. */
  --panel-2: var(--bg-input);
  --border: var(--border-color);
  --text-2: var(--text-main);

  --transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease, box-shadow 0.12s ease, transform 0.12s ease;

  /* Шкала отступов и движения — панель фильтров и переключатель разделов
     (визуальный слой «Пульт») собраны на ней. */
  --s-2: 4px;
  --s-3: 6px;
  --s-4: 8px;
  --s-5: 12px;
  --s-6: 16px;
  --dur-2: 170ms;   /* появление и уход мелкого элемента, поворот каретки */
  --dur-3: 260ms;   /* панель, выпадающий список */
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);   /* вход: быстро → мягко */
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);     /* перемещение */
}

/* Смена темы (public/js/ui.js, btnToggleTheme) добавляет этот класс на
   <html> ровно на один кадр. Без него смена data-theme дёргает --transition
   (строка выше) сразу на каждой .btn и каждой строке каждой таблицы во
   всех вкладках разом — сотни элементов красились вразнобой одним тяжёлым
   style-recalc, часть кнопок на кадр рендерилась пустой. Пробовали
   View Transition (кросс-фейд снимка до/после) — на дашборде с плотными
   таблицами он размывал весь экран в "лагающее" пятно, ощущалось хуже.
   Поэтому переход не анимируем вообще — тема переключается мгновенно. */
.theme-switching,
.theme-switching * {
  transition: none !important;
}

/* ТЁМНАЯ ТЕМА. Не осветление светлой и не её инверсия: тот же рецепт,
   прочитанный в другую сторону — заливка темнее карточки, чернила светлее.
   Рецепт состояний: ink L .815 · rail L .700 · wash L .290 */
:root[data-theme="dark"] {
  --bg-dark: #121218;
  --bg-card: #1a1a22;
  --bg-card-hover: #22222c;
  --bg-header: #1a1a22;
  --bg-input: #22222c;

  --border-color: #30303c;
  --border-strong: #3d3d4a;
  --line-ctl: #7f7f92;
  --border-accent: #f07ad9;

  --text-main: #e8e8ee;   /* 14.2:1 к карточке — не #fff, иначе halation */
  --text-muted: #a9a9b8;  /*  7.45:1 */
  --text-dim: #8e8e9e;    /*  4.89:1 к худшей (--bg-input) */

  --accent-primary: #f07ad9;        /* 6.99:1 к карточке — светлая фуксия для текста */
  --accent-primary-fill: #cb11ab;   /* та же фирменная заливка, что в светлой; белый текст 4.99:1 */
  --accent-primary-hover: #dc2bbd;
  --accent-primary-soft: #33162e;
  --accent-primary-border: #f07ad9;
  --accent-on-primary: #ffffff;   /* фуксия тёмная — на ней белый текст, 4.99:1 */

  /* Здесь порог 3:1 проходили все и раньше, правка — про баланс громкости
     внутри семьи: жёлтый кричал заметно громче соседей, красный был тише всех.
     Теперь пять статусов звучат в один голос. */
  --info-solid: #57a3ef;
  --warning-solid: #e0b04a;
  --success-solid: #57c98b;
  --danger-solid: #e2756a;
  --discovery-solid: #5fc2d2;

  /* Тёмная тема оставляет ровно те значения, что были захардкожены в разметке:
     7.96:1 и 6.45:1 к карточке — здесь исходные цвета читались и менять их
     незачем. */
  --replacement-out: #38bdf8;
  --replacement-in: #c084fc;

  --accent-cyan: var(--accent-primary);
  --accent-blue: #93c8fe;
  --accent-info: #93c8fe;
  --accent-green: #57c98b;
  --accent-amber: #e0b04a;
  --accent-orange: #e0b04a;
  --accent-rose: #e2756a;
  --accent-purple: #c9a6f0;
  --accent-indigo: #c9a6f0;

  --info-soft: #1c2d3e;
  --info-border: #57a3ef;
  --success-soft: #122419;
  --success-border: #57c98b;
  --warning-soft: #251e10;
  --warning-border: #e0b04a;
  --danger-soft: #2a1614;
  --danger-border: #e2756a;

  --discovery-soft: #12303a;
  --discovery-border: #5fc2d2;

  --info-wash: #1a2530;
  --warning-wash: #1d1b13;
  --success-wash: #131e18;
  --danger-wash: #1f1715;

  --danger-row: #2a1614;
  --warning-row: #251e10;

  --elev-1: 0 0 0 1px var(--border-color);
  --shadow-sm: var(--elev-1);
  --shadow-md: 0 16px 40px -10px rgba(0, 0, 0, 0.55), 0 0 0 1px var(--border-color);
  --shadow-sticky: 0 4px 12px -6px rgba(0, 0, 0, 0.6);
  --shadow-glow: var(--focus);
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background-color: var(--bg-dark);
  color: var(--text-main);
  min-height: 100vh;
  display: flex;
  overflow-x: hidden;
  /* База интерфейса — 14px, а не унаследованные от браузера 16: плотный
     инструмент из чисел и подписей на 16px рассыпается по вертикали. */
  font-size: var(--fs-4);
  line-height: var(--lh-text);
  -webkit-font-smoothing: antialiased;
}

/* Контролы не наследуют шрифт от body — так устроены UA-таблицы браузеров.
   Без этого правила Chrome набирал кнопки, поля и селекты своим `13.333px
   Arial`, а `textarea` и `input[type=date]` — моноширинным. Замер на живой
   странице давал 244 контрола Arial, 32 monospace и 2 Inter из 278.

   Больно это било по реестру заявок: там почти каждая ячейка — живой `select`,
   и строка таблицы набиралась двумя шрифтами сразу при одинаковом 13px. Arial
   при том же кегле на 5% уже Inter (x-height 6.73 против 7.09), поэтому
   контролы выглядели мельче собственных подписей, а цифры в них шли
   пропорциональными вместо табличных.

   `line-height` намеренно не наследуется: у контролов это `normal` (≈1.21), у
   body — 1.5, и наследование добавило бы каждой кнопке ~4px. Высота кнопок
   задаётся явно ниже, в `.btn`.

   Правило стоит выше частных: `--fs-2` на чипах и `--fs-3` в таблице заявок
   объявлены позже и перебивают `inherit` сами. */
button,
input,
select,
textarea,
optgroup {
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
}

/* Chrome рисует поля даты и месяца собственным моноширинным шрифтом и не
   отдаёт их правилу выше через `font-family: inherit` на всех контролах —
   у них своя внутренняя разметка. Задаём отдельно. */
input[type="date"],
input[type="month"],
input[type="time"],
input[type="datetime-local"] {
  font-family: inherit;
}

/* Браузер даёт заголовкам `font-weight: bold`, то есть 700, а 700 в этом языке
   отдано числам. Без явной ступени каждый h1…h6 без собственного правила
   приезжал жирнее метрики, ради которой экран и сделан. */
h1, h2, h3, h4, h5, h6 {
  font-weight: var(--fw-title);
}

/* Нативные флажок и переключатель приходят от браузера по 13px. Рядом с
   органами управления в 34px это выглядит недоделанным, а попасть по ним
   мышью тяжело. Порог WCAG 2.5.8 они и так проходят — в разметке каждый
   лежит внутри `<label>`, и кликается вся подпись, — но сам квадратик
   поднимаем до 16px и красим в акцент, чтобы он был из того же набора,
   что и всё остальное. */
input[type="checkbox"],
input[type="radio"] {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  accent-color: var(--accent-primary-fill);
  cursor: pointer;
}

.ui-icon {
  width: 1.1em;
  height: 1.1em;
  display: inline-block;
  flex: 0 0 auto;
  vertical-align: -0.16em;
  pointer-events: none;
}

.ui-icon.is-spinning { animation: icon-spin 0.8s linear infinite; }
.ui-icon.sort-up { transform: rotate(180deg); }

.icon-heading,
.icon-label {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}

.icon-heading .ui-icon { color: var(--accent-cyan); }
.ui-icon-lg { width: 1.35em; height: 1.35em; }
.ui-icon-hero { width: 2.5rem; height: 2.5rem; }
.text-success { color: var(--accent-green); }
.text-warning { color: var(--accent-amber); }
.text-danger { color: var(--accent-rose); }

@keyframes icon-spin { to { transform: rotate(360deg); } }

/* ==========================================================================
   РЕЙЛ РАЗДЕЛОВ — 60 px, только иконки (этап 4, обвязка по референсу A)
   Пункты .nav-item — квадраты 38×38 с подсказкой в title; подписи спрятаны.
   Хабы («Моя группа», «Мой кабинет») раскрывают подпункты флайаутом справа
   по наведению/фокусу (.nav-submenu). Панель фильтров реестра больше здесь
   не живёт — она внутри вкладки «Заявки» (.ticket-filter-col ниже).
   ========================================================================== */
.sidebar {
  width: 60px;
  flex: 0 0 60px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 14px 0;
  background: var(--bg-header);
  border-right: 1px solid var(--border-color);
  z-index: 10;
  position: sticky;
  top: 0;
  align-self: flex-start;
  height: 100vh;
}

#navMenuHost {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 100%;
}

.brand {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-sm);
  background: var(--accent-primary-fill);
  color: var(--accent-on-primary);
  margin-bottom: 10px;
}

.brand .ui-icon { width: 16px; height: 16px; }

.nav-menu {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  list-style: none;
  width: 100%;
}

.nav-menu > li { position: relative; }

.nav-item {
  position: relative;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--text-dim);
  cursor: pointer;
  transition: var(--transition);
  text-decoration: none;
}

/* Подписи пунктов остаются в разметке ради скринридера и флайаута, на рейле
   их не видно. */
.nav-item > span:not(.nav-icon):not(.nav-badge) {
  position: absolute;
  width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

.nav-item:hover {
  background: var(--bg-card-hover);
  color: var(--text-main);
}

.nav-item.active {
  border-color: var(--line-ctl);
  background: var(--bg-input);
  color: var(--text-main);
}

.nav-icon {
  width: 17px;
  height: 17px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: currentColor;
}

.nav-item .nav-badge {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 14px;
  height: 14px;
  padding: 0 4px;
  font-size: 9px;
  line-height: 14px;
}

/* Флайаут подпунктов хаба: появляется справа от иконки по наведению и по
   клавиатурному фокусу внутри. */
.nav-item-accordion { list-style: none; }

.nav-submenu {
  display: none;
  position: absolute;
  left: 46px;
  top: -4px;
  z-index: 20;
  width: 200px;
  padding: 6px;
  list-style: none;
  border: 1px solid var(--line-ctl);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  box-shadow: var(--shadow-md);
}

.nav-submenu::before {
  /* Невидимый мост между иконкой и флайаутом: курсор не теряет hover на зазоре. */
  content: '';
  position: absolute;
  left: -10px;
  top: 0;
  width: 10px;
  height: 100%;
}

.nav-item-accordion:hover .nav-submenu,
.nav-item-accordion:focus-within .nav-submenu { display: block; }

.nav-subitem {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 7px 9px;
  color: var(--text-main);
  text-decoration: none;
  font-size: var(--fs-3);
  border-radius: var(--radius-sm);
  transition: var(--transition);
  white-space: nowrap;
}

.nav-subitem:hover { background: var(--bg-card-hover); }

.nav-subitem.active {
  color: var(--accent-primary);
  background: var(--accent-primary-soft);
  font-weight: var(--fw-title);
}

.subitem-icon {
  width: 16px;
  height: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: currentColor;
}

/* ==========================================================================
   ПАНЕЛЬ ФИЛЬТРОВ РЕЕСТРА — левая колонка вкладки «Заявки»
   Вкладка .tab-with-rail — флекс-строка: колонка 236px + .ticket-main.
   Спрятанное состояние (data-filters="hidden" на <html>): колонка сжимается до
   56px со счётчиками статусов (.rail-stub), сама панель уезжает за край и
   выезжает по наведению/фокусу поверх таблицы.
   ========================================================================== */
.tab-with-rail {
  display: flex;
  align-items: stretch;
  min-width: 0;
  /* Вкладка занимает всю ширину контента без отступов .content-area. */
  margin: calc(-1 * var(--content-pad));
  min-height: calc(100vh - 57px);
}

.ticket-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 18px;
}

.ticket-filter-col {
  --rail-w: 236px;
  --rail-stub: 56px;
  position: sticky;
  top: 57px;
  align-self: flex-start;
  flex: 0 0 var(--rail-w);
  width: var(--rail-w);
  height: calc(100vh - 57px);
  display: flex;
  flex-direction: column;
  background: var(--bg-header);
  border-right: 1px solid var(--border-color);
  z-index: 8;
}

:root[data-filters="hidden"] .ticket-filter-col {
  flex-basis: var(--rail-stub);
  width: var(--rail-stub);
}

:root[data-filters="hidden"] .ticket-filter-rail {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--rail-w);
  height: 100%;
  z-index: 100;
  transform: translateX(-100%);
  transition: transform var(--dur-3) var(--ease-in-out) 0.3s, box-shadow var(--dur-3) var(--ease-out);
}

:root.filters-switching[data-filters="hidden"] .ticket-filter-rail { transition-delay: 0s; }

:root[data-filters="hidden"] .ticket-filter-col:hover .ticket-filter-rail,
:root[data-filters="hidden"] .ticket-filter-col:has(:focus-visible) .ticket-filter-rail,
:root[data-filters="hidden"] .ticket-filter-col:has(input:focus) .ticket-filter-rail {
  transform: none;
  transition-delay: 0.15s;
  box-shadow: var(--shadow-md);
}

.rail-peek-tab { display: none; }

:root[data-filters="hidden"] .rail-peek-tab {
  order: -1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 100%;
  height: 26px;
  padding: 0;
  border: none;
  border-bottom: 1px solid var(--border-color);
  background: var(--bg-input);
  color: var(--text-muted);
  cursor: pointer;
  transition: var(--transition);
  animation: railFadeIn var(--dur-2) var(--ease-out);
}

:root[data-filters="hidden"] .rail-peek-tab:hover {
  background: var(--bg-card-hover);
  color: var(--text-main);
}

.rail-peek-tab:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: -2px;
  box-shadow: none;
}

.rail-peek-tab .ui-icon { width: 12px; height: 12px; }

.rail-stub { display: none; }

:root[data-filters="hidden"] .rail-stub {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 4px 3px;
  overflow: hidden;
  animation: railFadeIn var(--dur-2) var(--ease-out);
}

@keyframes railFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.rail-stub-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  height: var(--h-ctl);
  border-radius: var(--radius-sm);
  color: var(--text-main);
}

.rail-stub-item .ui-icon { width: 15px; height: 15px; color: var(--text-muted); }

.rail-stub-num {
  font-size: var(--fs-1);
  font-weight: var(--fw-num);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.rail-stub-item.is-info.has-value { color: var(--accent-primary); background: var(--accent-primary-soft); }
.rail-stub-item.is-info.has-value .ui-icon { color: var(--accent-primary); }
.rail-stub-item.is-warning.has-value,
.rail-stub-item.is-attention.has-value { color: var(--accent-amber); background: var(--warning-soft); }
.rail-stub-item.is-warning.has-value .ui-icon,
.rail-stub-item.is-attention.has-value .ui-icon { color: var(--accent-amber); }
.rail-stub-item.is-danger.has-value { color: var(--accent-rose); background: var(--danger-soft); }
.rail-stub-item.is-danger.has-value .ui-icon { color: var(--accent-rose); }

@media (hover: none) {
  :root[data-filters="hidden"] .ticket-filter-col:hover .ticket-filter-rail { transform: translateX(-100%); }
}

.sidebar-footer {
  margin-top: auto;
  padding-top: 1rem;
  border-top: 1px solid var(--border-color);
  font-size: var(--fs-3);
  color: var(--text-dim);
}

.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.6rem;
  background: var(--success-soft);
  color: var(--accent-green);
  border: 1px solid var(--success-border);
  border-radius: 9999px;
  font-size: var(--fs-2);
  font-weight: var(--fw-label);
}

.status-dot {
  width: 6px;
  height: 6px;
  background-color: var(--accent-green);
  border-radius: 50%;
  box-shadow: none;
}

/* Main Content Area */
/* overflow-y здесь был и молча ломал всё липкое: обёртка объявляла себя
   областью прокрутки, но у body задана только min-height, поэтому обёртка
   тянулась во всю высоту содержимого и не прокручивалась ни разу — ехал весь
   документ. Прокрутка одна — документ, от неё же считается sticky у левой
   колонки. */
.main-wrapper {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Шапка A: 57px, кикер над заголовком, sticky. */
.top-bar {
  background: var(--bg-header);
  border-bottom: 1px solid var(--border-color);
  padding: 8px 20px;
  min-height: 57px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  position: sticky;
  top: 0;
  z-index: 9;
}

.page-kicker {
  font-size: 11px;
  font-weight: var(--fw-title);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.header-title {
  font-size: 19px;
  font-weight: var(--fw-title);
  letter-spacing: -0.01em;
  line-height: 1.2;
}

.top-controls {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.top-bar-left {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-width: 0;
}

/* Иконочная кнопка — квадрат в рост обычной. Было три разных размера:
   переключатель темы 38px, .icon-btn 30px и крестик модалки 12×23. */
.theme-toggle {
  width: var(--h-ctl);
  height: var(--h-ctl);
  padding: 0;
  justify-content: center;
  font-size: var(--fs-5);
}

/* Высота задаётся токеном, а не паддингом: иначе её меняет каждый локальный
   отступ и каждая снятая рамка, и ряд кнопок в подвале модалки разъезжается.
   Паддинг остаётся только горизонтальным — он про ширину, не про рост.
   `white-space: nowrap` тоже про рост: при фиксированной высоте перенос
   строки вылезал бы за кнопку, а кнопке переноситься и не положено. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: var(--h-ctl);
  padding: 0 1.1rem;
  border-radius: var(--radius-md);
  font-size: var(--fs-4);
  font-weight: var(--fw-title);
  line-height: var(--lh-tight);
  white-space: nowrap;
  cursor: pointer;
  border: 1px solid transparent;
  transition: var(--transition);
}

.btn-primary {
  background: var(--accent-primary-fill);
  color: var(--accent-on-primary);
  box-shadow: none;
}

.btn-primary:hover {
  background: var(--accent-primary-hover);
}

.btn-secondary {
  background: var(--bg-input);
  color: var(--text-main);
  border-color: var(--line-ctl);
}

.btn-secondary:hover {
  background: var(--bg-card-hover);
  border-color: var(--accent-primary-border);
}

.btn-accent {
  background: var(--accent-primary-soft);
  color: var(--accent-cyan);
  border-color: var(--accent-primary-border);
}

.btn-accent:hover {
  background: var(--bg-card-hover);
}

.btn:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

/* Отклик на нажатие (аудит 11.09): 0.96 — заметно, но без театра; transform
   уже в --transition у .btn, возврат плавный. */
.btn:active:not(:disabled) {
  transform: scale(0.96);
}

/* Page Layout */
.content-area {
  --content-pad: 2rem;
  padding: var(--content-pad);
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
}

/* Data Connection & Date Filter Card */
.connection-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 1.25rem 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.connection-info {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.connection-icon {
  width: 42px;
  height: 42px;
  border-radius: var(--radius-md);
  background: var(--accent-primary-soft);
  border: 1px solid var(--accent-primary-border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-6);
  color: var(--accent-cyan);
}

.url-input-group {
  display: flex;
  gap: 0.5rem;
  flex: 1;
  max-width: 600px;
}

.url-input {
  flex: 1;
  background: var(--bg-input);
  border: 1px solid var(--line-ctl);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.85rem;
  color: var(--text-main);
  font-size: var(--fs-4);
  outline: none;
  transition: var(--transition);
}

.url-input:focus {
  border-color: var(--accent-cyan);
  box-shadow: var(--shadow-glow);
}

/* Date Filter Controls Styling */
.date-filter-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border-color);
  flex-wrap: wrap;
}

.date-filter-label {
  font-size: var(--fs-4);
  font-weight: var(--fw-label);
  color: var(--accent-cyan);
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.date-presets {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.date-chip {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  padding: 0.35rem 0.75rem;
  font-size: var(--fs-3);
  font-weight: var(--fw-label);
  cursor: pointer;
  transition: var(--transition);
}

.date-chip:hover {
  background: var(--bg-card-hover);
  color: var(--text-main);
}

.date-chip.active {
  background: var(--accent-primary-fill);
  color: var(--accent-on-primary);
  border-color: transparent;
  box-shadow: none;
}

.custom-date-group {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--fs-3);
  color: var(--text-muted);
}

.date-input {
  background: var(--bg-input);
  border: 1px solid var(--line-ctl);
  border-radius: var(--radius-sm);
  padding: 0.3rem 0.6rem;
  color: var(--text-main);
  font-size: var(--fs-3);
  outline: none;
}

.date-input:focus {
  border-color: var(--accent-cyan);
}

/* Key Metrics KPI Grid */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1.25rem;
}

.kpi-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 0.75rem;
  transition: var(--transition);
  position: relative;
  overflow: hidden;
}

.kpi-card:hover {
  border-color: var(--accent-primary-border);
}

.kpi-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.kpi-label {
  font-size: var(--fs-3);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: var(--fw-label);
}

.kpi-icon-badge {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-5);
}

.kpi-value {
  font-size: var(--fs-7);
  font-weight: var(--fw-num);
  letter-spacing: -0.03em;
  color: var(--text-main);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.kpi-footer {
  font-size: var(--fs-3);
  color: var(--text-dim);
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.kpi-trend-positive { color: var(--accent-green); font-weight: var(--fw-label); }
.kpi-trend-warning { color: var(--accent-amber); font-weight: var(--fw-label); }

/* Charts Section */
.charts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(450px, 1fr));
  gap: 1.5rem;
}

.chart-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.chart-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.chart-title {
  font-size: var(--fs-5);
  font-weight: var(--fw-title);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.chart-container {
  position: relative;
  width: 100%;
  height: 300px;
}

/* Data Table Section */
.table-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.table-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.search-box {
  position: relative;
  flex: 1;
  max-width: 320px;
}

.search-input {
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--line-ctl);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.85rem 0.5rem 2.2rem;
  color: var(--text-main);
  font-size: var(--fs-4);
  outline: none;
}

.search-icon {
  position: absolute;
  left: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-dim);
  font-size: var(--fs-4);
}

.table-container {
  width: 100%;
  overflow-x: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
  text-align: left;
  /* Таблица — не текст: своя ступень (13px) и своя интерлиньяжа, иначе строки
     разъезжаются и на экран влезает вдвое меньше заявок. */
  font-size: var(--fs-3);
  line-height: var(--lh-table);
}

/* Стиль A: шапка uppercase 11px, липкая внутри прокрутки контейнера, строки
   зеброй (tbody ниже). */
th {
  background: var(--bg-input);
  color: var(--text-dim);
  font-weight: var(--fw-title);
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: 0.04em;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
  position: sticky;
  top: 0;
  z-index: 1;
}

tbody tr:nth-child(even) { background: var(--bg-page); }

td {
  padding: 7px 10px;
  border-bottom: 1px solid var(--border-color);
  color: var(--text-main);
  white-space: nowrap;
  /* Моноширинные цифры: в таблицах здесь всюду столбцы дат, времени, ID и ШК,
     а у пропорциональных цифр Inter разная ширина — колонка «плывёт», и взгляд
     не может идти по ней вертикально. На буквы не влияет. */
  font-variant-numeric: tabular-nums;
}

tbody tr {
  transition: var(--transition);
  cursor: pointer;
}

tbody tr:hover {
  background: var(--bg-card-hover) !important;
}

.pill-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.55rem;
  border-radius: var(--radius-sm);
  font-size: var(--fs-2);
  font-weight: var(--fw-label);
}

.badge-exceeds { background: var(--success-soft); color: var(--accent-green); border: 1px solid var(--success-border); }
.badge-good { background: var(--info-soft); color: var(--accent-info); border: 1px solid var(--info-border); }
.badge-warning { background: var(--warning-soft); color: var(--accent-amber); border: 1px solid var(--warning-border); }
.badge-danger { background: var(--danger-soft); color: var(--accent-rose); border: 1px solid var(--danger-border); }

/* Modal Styling */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.48);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  opacity: 0;
  pointer-events: none;
  /* Закрытое окно прячем и от клавиатуры (аудит 11.09): одних opacity и
     pointer-events мало — кнопки и поля 28 закрытых окон (176 штук) оставались
     в обходе по Tab, фокус и Enter попадали в невидимые кнопки, экранные
     дикторы читали их содержимое. visibility: hidden убирает их и оттуда. */
  visibility: hidden;
  transition: var(--transition);
}

.modal-overlay.active {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
}

.modal-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  width: 90%;
  max-width: 650px;
  max-height: 85vh;
  overflow-y: auto;
  padding: 2rem;
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  transform: translateY(20px);
  transition: var(--transition);
}

.modal-overlay.active .modal-card {
  transform: translateY(0);
}

/* Дровер (боковая карточка заявки) — выезжает справа */
.ticket-drawer-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.48);
  backdrop-filter: blur(2px);
  display: flex;
  justify-content: flex-end;
  opacity: 0;
  pointer-events: none;
  visibility: hidden; /* то же, что у .modal-overlay выше */
  transition: var(--transition);
  z-index: 120;
}

.ticket-drawer-overlay.active {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
}

.ticket-drawer-panel {
  width: 460px;
  max-width: 94vw;
  height: 100%;
  background: var(--bg-card);
  border-left: 1px solid var(--border-color);
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
  transform: translateX(30px);
  transition: var(--transition);
  overflow: hidden;
}

.ticket-drawer-overlay.active .ticket-drawer-panel {
  transform: translateX(0);
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Редизайн 16.09 (референс Linear): цветная плашка на весь верх из версии
     15.09 была слишком громкой для окна, которое открывается десятки раз за
     смену — тонкая линия без своего фона и без цвета, как в Linear. */
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border-color);
}

/* Крестик закрытия был зоной клика 12×23 — меньше минимума WCAG 2.5.8 в
   24×24. Сам глиф остаётся прежним, растёт только площадь попадания. */
.modal-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--h-ctl);
  height: var(--h-ctl);
  flex: 0 0 auto;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: var(--fs-6);
  line-height: 1;
  cursor: pointer;
  transition: var(--transition);
}

.modal-close:hover {
  color: var(--text-main);
}

.code-block {
  background: var(--bg-dark);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  padding: 1rem;
  font-family: monospace;
  font-size: var(--fs-3);
  color: var(--accent-cyan);
  overflow-x: auto;
  white-space: pre-wrap;
}

@media (max-width: 900px) {
  .charts-grid { grid-template-columns: 1fr; }
}

/* ==========================================================================
   LOGIN SCREEN STYLES
   ========================================================================== */
.login-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--bg-dark);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 9999;
}

.login-overlay.active {
  display: flex;
}

/* Признак ставится инлайновым скриптом в <head> до первой отрисовки — иначе на
   каждой перезагрузке успевает мелькнуть карточка входа: разметка приходит с
   классом .active, а снимают его модули уже на DOMContentLoaded. Селектор
   специфичнее .login-overlay.active, поэтому перекрывает его. */
:root[data-auth="in"] .login-overlay {
  display: none;
}

.login-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 2.5rem;
  width: 100%;
  max-width: 420px;
  box-shadow: var(--shadow-md);
  text-align: center;
}

.login-logo {
  width: 60px;
  height: 60px;
  background: var(--accent-primary-fill);
  color: var(--accent-on-primary);
  font-size: var(--fs-6);
  font-weight: var(--fw-title);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  margin: 0 auto 1.5rem auto;
}

.login-title {
  font-size: var(--fs-6);
  font-weight: var(--fw-title);
  color: var(--text-main);
  margin-bottom: 0.5rem;
}

.login-subtitle {
  font-size: var(--fs-4);
  color: var(--text-muted);
  margin-bottom: 2rem;
}

.form-group {
  text-align: left;
  margin-bottom: 1.25rem;
}

.form-group label {
  display: block;
  font-size: var(--fs-4);
  color: var(--text-muted);
  margin-bottom: 0.5rem;
  font-weight: var(--fw-label);
}

.form-group input {
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--line-ctl);
  border-radius: var(--radius-sm);
  padding: 0.75rem 1rem;
  color: var(--text-main);
  font-size: var(--fs-4);
  outline: none;
  transition: var(--transition);
}

/* Чекбокс/радио внутри .form-group не должны наследовать стили текстовых
   полей выше — та же специфичность (0,1,1), но .form-group input идёт позже
   в файле и побеждала, растягивая чекбокс на всю ширину лейбла (см. отгул
   модератора в модалке «Смена»). */
.form-group input[type="checkbox"],
.form-group input[type="radio"] {
  width: 16px;
  height: 16px;
  padding: 0;
  flex: 0 0 auto;
}

.form-group input:focus {
  border-color: var(--accent-cyan);
}

/* Кнопка во всю ширину — вход и подтверждение в модалке. Ей нужен свой рост:
   рядом стоят поля формы, и 34px рабочей области смотрелись бы куцо. */
.btn-block {
  width: 100%;
  height: var(--h-ctl-lg);
  padding: 0 1.1rem;
  font-weight: var(--fw-title);
}

.login-error-msg {
  color: var(--accent-rose);
  background: var(--danger-soft);
  border: 1px solid var(--danger-border);
  border-radius: var(--radius-sm);
  padding: 0.75rem;
  font-size: var(--fs-4);
  margin-bottom: 1.25rem;
}
/* ==========================================================================
   CALENDAR & SCHEDULE STYLES
   ========================================================================== */
.calendar-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 1rem;
}

.calendar-table th, .calendar-table td {
  border: 1px solid var(--border-color);
  padding: 0.65rem 0.5rem;
  text-align: center;
  font-size: var(--fs-3);
  min-width: 35px;
}

.calendar-table th {
  background: var(--bg-header);
  font-weight: var(--fw-label);
  color: var(--text-muted);
}

/* Ячейки календаря берут тихий слой: заливка плашек на сетке из тридцати
   клеток даёт рябь, а не информацию. */
.calendar-day-work {
  background: var(--info-wash) !important;
  color: var(--accent-info);
  font-weight: var(--fw-title);
}

.calendar-day-off {
  background: rgba(156, 163, 175, 0.05) !important;
  color: var(--text-dim);
}

.calendar-day-sick {
  background: var(--danger-wash) !important;
  color: var(--accent-rose);
  font-weight: var(--fw-title);
}

.calendar-day-vacation {
  background: var(--success-wash) !important;
  color: var(--accent-green);
  font-weight: var(--fw-title);
}

.calendar-day-study {
  background: var(--accent-primary-soft) !important;
  color: var(--accent-primary);
  font-weight: var(--fw-title);
}

/* Цвет замены — тот же самый, что и во всём разделе «Замены» (index.html,
   replacements.js): бейджи, заголовки групп, лейблы. Раньше клетка «З» на
   графике красилась в amber — цвет замены не совпадал с её же цветом в
   разделе «Замены», и рассинхрон пришлось чинить.
   Единый источник теперь один — --replacement-out (см. :root): цвет по-прежнему
   свой, не привязан к семантическим статусам, но у него есть отдельное значение
   на каждую тему. До этого здесь стоял литерал #38bdf8, который в светлой теме
   давал 2.14:1. */
.calendar-day-replacement {
  background: rgba(56, 189, 248, 0.10) !important;
  color: var(--replacement-out);
  font-weight: var(--fw-title);
}

.schedule-legend-code {
  display: inline-flex;
  min-width: 1.8rem;
  justify-content: center;
  padding: 0.15rem 0.5rem;
  border-radius: var(--radius-sm);
}

.legend-inline-code {
  background: transparent !important;
}

.sv-only {
  display: inherit;
}

.staff-filter-chip {
  background: transparent;
  color: var(--text-muted);
  border: none;
  padding: 0.35rem 0.75rem;
  font-size: var(--fs-3);
  font-weight: var(--fw-label);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: var(--transition);
}

.staff-filter-chip:hover {
  color: var(--text-main);
  background: var(--accent-primary-soft);
}

.staff-filter-chip.active {
  background: var(--accent-primary-fill);
  color: var(--accent-on-primary);
  box-shadow: none;
}

.badge-warning-rose {
  background: var(--danger-soft) !important;
  color: var(--accent-rose) !important;
  border: 1px solid var(--danger-border) !important;
  font-weight: var(--fw-label);
}

.badge-warning-cyan {
  background: var(--info-soft) !important;
  color: var(--accent-info) !important;
  border: 1px solid var(--info-border) !important;
  font-weight: var(--fw-label);
}

/* Tickets workspace */
.ticket-toolbar,
.ticket-filter-panel,
.ticket-summary-bar {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
}

.ticket-toolbar {
  display: grid;
  grid-template-columns: minmax(240px, 1fr) minmax(0, auto);
  align-items: start;
  gap: 1rem 1.5rem;
  margin-bottom: 1rem;
  padding: 1.15rem 1.25rem;
  border-radius: var(--radius-lg);
}

.ticket-heading {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.ticket-heading-icon {
  width: 38px;
  height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  background: var(--accent-primary-soft);
  color: var(--accent-primary);
  font-size: var(--fs-5);
}

.ticket-heading h2 {
  color: var(--text-main);
  font-size: var(--fs-5);
  font-weight: var(--fw-title);
  letter-spacing: -0.02em;
}

.ticket-heading p {
  color: var(--text-muted);
  font-size: var(--fs-3);
  margin-top: 0.18rem;
}

.ticket-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.55rem;
  flex-wrap: wrap;
}

.ticket-actions .btn,
.ticket-scope-btn,
.ticket-chip,
.ticket-chip-group button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.42rem;
}

.ticket-actions .btn {
  min-height: var(--h-ctl);
  padding: 0.52rem 0.78rem !important;
  border-radius: var(--radius-md);
  font-size: var(--fs-3) !important;
  font-weight: var(--fw-title) !important;
}

.ticket-auto-toggle {
  min-height: var(--h-ctl);
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.48rem 0.7rem;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  background: var(--bg-input);
  color: var(--text-main);
  cursor: pointer;
  font-size: var(--fs-3);
  font-weight: var(--fw-label);
  white-space: nowrap;
}

.ticket-auto-toggle .ui-icon { color: var(--accent-amber); }



/* ==========================================================================
   ПАНЕЛЬ ФИЛЬТРОВ РЕЕСТРА
   Живёт в левой колонке (#sidebarPanel, см. «Левая колонка» выше) и заполняет
   её целиком: фон, рамку и отступы несёт она, а не .sidebar — так спрятанное
   состояние сводится к сдвигу одного элемента.

   Порядок внутри: поиск, статус, категория, решение, команда, период.
   «Решение» и «Команда» свёрнуты по умолчанию (RAIL_GROUPS_DEFAULT в
   js/tickets.js).
   ========================================================================== */
.ticket-filter-rail {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  gap: var(--s-4);
  padding: var(--s-6) var(--s-5);
  background: var(--bg-header);
  border-right: 1px solid var(--border-color);
  /* Страховка: если групп станет больше, чем высоты окна, прокрутится сама
     панель, а не уедет за нижний край. */
  overflow-y: auto;
  overscroll-behavior: contain;
}

.rail-head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--border-color);
}

.rail-title {
  color: var(--text-main);
  font-size: var(--fs-3);
  font-weight: var(--fw-title);
}

.rail-count {
  margin-left: auto;
  color: var(--text-muted);
  font-size: var(--fs-1);
  font-weight: var(--fw-title);
  white-space: nowrap;
}

/* Кнопки в шапке панели: сброс фильтров и булавка. Обе --h-ctl-sm, обе молчат
   цветом, пока их не трогают. Подписи и состояния ставят
   renderFilterPanelToggle() (js/ui.js) и syncTicketRailReset() (js/tickets.js). */
.rail-head-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--h-ctl-sm);
  height: var(--h-ctl-sm);
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-dim);
  cursor: pointer;
  transition: var(--transition);
}

.rail-head-btn:hover { background: var(--bg-input); color: var(--text-main); }
.rail-head-btn .ui-icon { width: 13px; height: 13px; }

/* Закреплённая панель — акцентная булавка на подложке, откреплённая — та же
   булавка приглушёнными чернилами без фона. */
.rail-head-btn.is-active {
  color: var(--accent-cyan);
  background: var(--accent-primary-soft);
}

/* Сброс появляется, только когда есть что сбрасывать. Красным при наведении:
   действие разрушительное для того, что пользователь настроил. */
.rail-head-btn.is-reset:hover { background: var(--danger-soft); color: var(--accent-rose); }

.rail-group {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding-top: var(--s-4);
  border-top: 1px solid var(--border-color);
}

/* Первая группа идёт сразу под шапкой панели — своей черты ей не нужно. */
.rail-head + .rail-group { padding-top: 0; border-top: none; }

/* Заголовок группы — опора для взгляда, поэтому это самый заметный текст в
   панели после её собственного заголовка. */
.rail-label {
  color: var(--text-main);
  font-size: var(--fs-2);
  font-weight: var(--fw-title);
}

.rail-group-head {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  width: 100%;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}

.rail-group-head:hover .rail-label { color: var(--accent-cyan); }

.rail-caret {
  flex-shrink: 0;
  width: 12px;
  height: 12px;
  color: var(--text-muted);
  transition: transform var(--dur-2) var(--ease-out);
}

/* У свёрнутой группы справа — выбранное значение. Иначе активный фильтр
   прячется вместе с группой и объяснить короткий список становится нечем. */
.rail-group-hint {
  margin-left: auto;
  overflow: hidden;
  color: var(--accent-cyan);
  font-size: var(--fs-1);
  font-weight: var(--fw-label);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.rail-group.is-collapsed .rail-group-body { display: none; }
.rail-group.is-collapsed .rail-caret { transform: rotate(-90deg); }

.rail-group-body {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

/* Трекер статусов — он же фильтр по статусу: строка на значение, «иконка ·
   название · число». Это единственное место, где семь чисел видны целиком;
   второй, урезанный их вид — узкая полоса у спрятанной панели (.rail-stub).
   Классы .ticket-status-chip и data-status общие с прежней разметкой, поэтому
   клик и подсветка выбранного не изменились. */
.ticket-stat-tracker {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.ticket-stat-tracker .ticket-status-chip {
  min-width: 0;
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--s-4);
  /* Высота токеном, а не следствием паддинга: семь дробных строк не влезали
     в невысокое окно целиком. */
  min-height: var(--h-ctl);
  padding: 0 var(--s-4);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  color: var(--text-muted);
  font: inherit;
  font-size: var(--fs-2);
  font-weight: var(--fw-label);
  line-height: 1.25;
  text-align: left;
  white-space: normal;
  cursor: pointer;
  transition: var(--transition);
}

.ticket-stat-tracker .ticket-status-chip:hover { border-color: var(--border-strong); color: var(--text-main); }

/* Выбранная строка обводится контуром, а не тенью: box-shadow тут занят
   цветной полосой .has-value (ниже). outline-offset отрицательный — контур
   садится ровно на место рамки, рамка одна. */
.ticket-stat-tracker .ticket-status-chip.active {
  outline: 2px solid var(--accent-primary);
  outline-offset: -1px;
  border-color: transparent;
  color: var(--text-main);
  font-weight: var(--fw-title);
}

.ticket-stat-tracker .ticket-status-chip:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
  box-shadow: none;
}

.ticket-status-chip-label { flex: 1; min-width: 0; }

.ticket-stat-icon {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  border-radius: var(--radius-sm);
  color: var(--accent-primary);
  background: var(--accent-primary-soft);
}

.ticket-stat-icon .ui-icon { width: 14px; height: 14px; }

.ticket-stat-count {
  flex: 0 0 auto;
  color: var(--text-main);
  font-size: var(--fs-5);
  font-weight: var(--fw-num);
  letter-spacing: -0.03em;
  /* Числа меняются при фильтрации — без табличных цифр столбец справа
     дёргается по ширине. */
  font-variant-numeric: tabular-nums;
}

/* Ненулевой счётчик у «требующих внимания» статусов красит строку цветом
   статуса, даже когда фильтр не выбран (has-value ставит setStat в
   js/tickets.js). «В работе» и «Назначено, не в работе» — одна жёлтая семья,
   разводит их форма: пунктирная рамка у второй. */
.ticket-status-chip.has-value:not(.active)[data-status="unassigned"] {
  background: var(--info-soft); border-color: var(--info-border); box-shadow: inset 4px 0 0 var(--info-solid);
}
.ticket-status-chip.has-value:not(.active)[data-status="unassigned"] .ticket-stat-icon { color: var(--accent-info); background: var(--info-wash); }
.ticket-status-chip.has-value:not(.active)[data-status="unassigned"] .ticket-stat-count { color: var(--accent-info); }
.ticket-status-chip.has-value:not(.active)[data-status="В работе"],
.ticket-status-chip.has-value:not(.active)[data-status="assigned-idle"] {
  background: var(--warning-soft); border-color: var(--warning-border); box-shadow: inset 4px 0 0 var(--warning-solid);
}
.ticket-status-chip.has-value:not(.active)[data-status="В работе"] .ticket-stat-icon,
.ticket-status-chip.has-value:not(.active)[data-status="assigned-idle"] .ticket-stat-icon { color: var(--accent-amber); background: var(--warning-wash); }
.ticket-status-chip.has-value:not(.active)[data-status="В работе"] .ticket-stat-count,
.ticket-status-chip.has-value:not(.active)[data-status="assigned-idle"] .ticket-stat-count { color: var(--accent-amber); }
.ticket-status-chip.has-value:not(.active)[data-status="assigned-idle"] { border-style: dashed; }
.ticket-status-chip.has-value:not(.active)[data-status="urgent"] {
  background: var(--danger-soft); border-color: var(--danger-border); box-shadow: inset 4px 0 0 var(--danger-solid);
}
.ticket-status-chip.has-value:not(.active)[data-status="urgent"] .ticket-stat-icon { color: var(--accent-rose); background: var(--danger-wash); }
.ticket-status-chip.has-value:not(.active)[data-status="urgent"] .ticket-stat-count { color: var(--accent-rose); }

/* Группа чипов. Живёт только внутри панели фильтров, поэтому !important здесь
   больше не нужны. */
.ticket-chip-group {
  display: flex;
  align-items: center;
  gap: 3px;
  flex-wrap: wrap;
  width: 100%;
}

.ticket-chip-group button {
  height: var(--h-ctl-sm);
  padding: 0 var(--s-4);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-input);
  color: var(--text-muted);
  font-size: var(--fs-2);
  font-weight: var(--fw-label);
  white-space: nowrap;
  cursor: pointer;
  transition: var(--transition);
}

.ticket-chip-group button:hover { color: var(--text-main); background: var(--bg-card-hover); border-color: var(--border-strong); }
.ticket-chip-group button.active { color: var(--accent-on-primary); background: var(--accent-primary-fill); border-color: var(--accent-primary-fill); font-weight: var(--fw-title); }

/* Активный чип статуса и решения надевает цвет самого статуса: фильтр
   подсказывает цветовой словарь таблицы, а не спорит с ним. Заливка и чернила
   те же, что у плашки в строке, поэтому контраст уже проверен. Обводка 2px
   отделяет выбранный чип от невыбранных, не полагаясь на один только оттенок. */
.ticket-status-chip.active[data-status="В работе"],
.ticket-status-chip.active[data-status="assigned-idle"],
.ticket-decision-chip.active[data-decision="Запрос видео"] {
  background: var(--warning-soft); color: var(--accent-amber); border-color: transparent;
  box-shadow: inset 0 0 0 2px var(--warning-solid);
}
.ticket-decision-chip.active[data-decision="Согласование"] {
  background: var(--info-soft); color: var(--accent-info); border-color: transparent;
  box-shadow: inset 0 0 0 2px var(--info-solid);
}
/* «Без ID» — акцент (макет A): свободная заявка — то, что надо взять. */
.ticket-status-chip.active[data-status="unassigned"] {
  background: var(--accent-primary-soft); color: var(--accent-primary); border-color: transparent;
  box-shadow: inset 0 0 0 2px var(--accent-primary-fill);
}
.ticket-status-chip.active[data-status="Закрыта"],
.ticket-decision-chip.active[data-decision="Одобрили"] {
  background: var(--success-soft); color: var(--accent-green); border-color: transparent;
  box-shadow: inset 0 0 0 2px var(--success-solid);
}
.ticket-status-chip.active[data-status="urgent"],
.ticket-decision-chip.active[data-decision="Отказ"] {
  background: var(--danger-soft); color: var(--accent-rose); border-color: transparent;
  box-shadow: inset 0 0 0 2px var(--danger-solid);
}
.ticket-status-chip.active[data-status="В работе у другого модератора"] {
  background: var(--discovery-soft); color: var(--accent-purple); border-color: transparent;
  box-shadow: inset 0 0 0 2px var(--discovery-solid);
}
.ticket-status-chip.active[data-status="Закрыта ранее"],
.ticket-decision-chip.active[data-decision="Без решения"] {
  background: var(--bg-input); color: var(--text-main); border-color: transparent;
  box-shadow: inset 0 0 0 2px var(--border-strong);
}
/* Цветная строка трекера: контур выбора убираем — рамку даёт цвет статуса. */
.ticket-stat-tracker .ticket-status-chip.active[data-status]:not([data-status="all"]) { outline: none; }

/* Категории — строками во всю ширину, а не чипами. Названия приходят из
   TICKET_CATEGORIES и по длине непредсказуемы: чипами в узкой колонке они
   резались многоточием. Точка слева отличает выбранную строку не одним цветом. */
.ticket-chip-group.is-list {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.ticket-chip-group.is-list button {
  width: 100%;
  height: auto;
  min-height: var(--h-ctl-sm);
  padding: var(--s-2) var(--s-4);
  border-color: transparent;
  background: none;
  text-align: left;
  white-space: normal;
  display: flex;
  align-items: center;
  gap: var(--s-4);
}

.ticket-chip-group.is-list button::before {
  content: "";
  flex-shrink: 0;
  width: 9px;
  height: 9px;
  border: 1px solid var(--line-ctl);
  border-radius: 50%;
}

.ticket-chip-group.is-list button.active::before {
  border-color: currentColor;
  background: currentColor;
  box-shadow: inset 0 0 0 2px var(--bg-header);
}

.ticket-chip-group.is-list button.active {
  background: var(--accent-primary-soft);
  border-color: transparent;
  color: var(--accent-cyan);
}

/* Иконка забирает у подписи около 18px — в узкой колонке подпись важнее. */
.ticket-filter-rail .ticket-chip-group .ui-icon { display: none; }

.ticket-filter-rail .search-input {
  width: 100%;
  height: var(--h-ctl);
  padding-top: 0;
  padding-bottom: 0;
  font-size: var(--fs-3);
}

/* Свой диапазон: поля во всю ширину, а не рядом друг с другом — узкому полю
   даты не хватает места на дд.мм.гггг. */
.rail-dates { display: grid; gap: 4px; }
/* Поля своего диапазона видны только после чипа «Свой…» — иначе три контрола
   по 26px занимают полпанели ради редкого сценария. */
#railGroupPeriod:not(.is-custom) .rail-dates { display: none; }

.rail-dates input[type="date"] {
  width: 100%;
  height: var(--h-ctl-sm);
  padding: 0 var(--s-4);
  border: 1px solid var(--line-ctl);
  border-radius: var(--radius-sm);
  background: var(--bg-input);
  color: var(--text-main);
  font-family: inherit;
  font-size: var(--fs-2);
}

.rail-dates .btn {
  height: var(--h-ctl-sm);
  justify-content: center;
  padding: 0 var(--s-4);
}

#inputTicketSearch {
  min-height: var(--h-ctl);
  color: var(--text-main) !important;
}

.ticket-search-wrap { position: relative; }
.ticket-search-wrap .ui-icon { position: absolute; left: 0.7rem; top: 50%; transform: translateY(-50%); color: var(--text-dim); }
.ticket-search-wrap input { padding-left: 2.2rem !important; }

.ticket-summary-bar {
  justify-content: space-between;
  gap: 0.8rem;
  padding: 0.48rem 0.72rem;
  border-color: var(--accent-primary-border);
  border-radius: var(--radius-md);
  background: var(--accent-primary-soft);
  color: var(--accent-primary);
  font-size: var(--fs-2);
  font-weight: var(--fw-label);
}

.ticket-summary-bar span:last-child { color: var(--text-main); }

#tab-tickets .table-card {
  border-radius: var(--radius-md);
}

#tab-tickets .table-container { border: 1px solid var(--border-color); border-radius: var(--radius-md); }
#tab-tickets table { font-size: var(--fs-3); }
#tab-tickets thead tr { background: var(--bg-input) !important; text-transform: none !important; }
#tab-tickets th { color: var(--text-muted); font-weight: var(--fw-label); }
#tab-tickets td { color: var(--text-main); }
#tab-tickets tbody tr:last-child td { border-bottom: 0; }
#tab-tickets select,
#tab-tickets input[type="text"],
#tab-tickets input[type="date"] { border-radius: var(--radius-sm) !important; }

/* Реестр заявок на узких экранах требовал долгой прокрутки вправо — колонки
   свободного текста (причина/комментарии) держали фиксированную ширину под
   САМЫЙ длинный возможный текст. Полный текст остаётся доступен по наводке
   (title) и в карточке заявки по клику на строку — здесь только визуальная
   ширина в самой таблице. */
.ticket-cell-truncate {
  display: inline-block;
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}
input.ticket-cell-truncate { max-width: 100%; }

.icon-btn {
  width: var(--h-ctl);
  height: var(--h-ctl);
  padding: 0 !important;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm) !important;
}

  .ticket-filter-rail .search-input { max-width: 340px; }
}

/* ==========================================================================
   THEME COMPATIBILITY — legacy inline styles
   ========================================================================== */
:root {
  color-scheme: light;
}

:root[data-theme="dark"] {
  color-scheme: dark;
}

/* Было --accent-primary-soft — тот же почти-фоновый токен, что у подсветки
   строки таблицы (едва отличим от bg что в светлой, что в тёмной теме).
   Для выделения ТЕКСТА (копировать/поправить букву) нужен реальный контраст,
   не тонкий намёк — берём тот же fill+on-primary, что у активных кнопок/чипов
   (уже проверенный контраст текста поверх, см. комментарии у токенов ниже). */
::selection {
  background: var(--accent-primary-fill);
  color: var(--accent-on-primary);
}

/* Числа не должны плясать при обновлении по SSE: у пропорциональных цифр Inter
   разная ширина, и колонка «плывёт» на каждом обновлении. :where() — чтобы
   правило не перебивало ничьих частных настроек. */
:where(td, th, .kpi-value, .ticket-stat-value, .num) {
  font-variant-numeric: tabular-nums;
}

/* Кольцо фокуса объявлено через :is(), а не :where(). У :where() нулевая
   специфичность, поэтому любое позднее правило со своей box-shadow — плашка с
   планкой, активный чип, карточка с тенью — молча съедало кольцо, и обход
   табом переставал быть виден.
   `outline` прозрачный, а не `none`: в forced-colors (высокая контрастность
   Windows) box-shadow не отрисовывается вовсе, и `none` оставил бы обход табом
   без единого индикатора. Прозрачный контур там перекрашивается системой. */
:is(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid transparent;
  outline-offset: 2px;
  box-shadow: var(--focus);
}

/* Инлайновые поля, которые рисует public/js, берут волосяную границу блоков —
   1.2:1 к поверхности, то есть поля выглядят безрамочными. Поднимаем их до
   --line-ctl тем же приёмом, каким чинятся легаси-инлайны ниже: селектором по
   инлайновому стилю, без правки скриптов. */
input[style*="var(--border-color)"],
select[style*="var(--border-color)"],
textarea[style*="var(--border-color)"] {
  border-color: var(--line-ctl) !important;
}

/* color-scheme (выше) заставляет браузер рисовать раскрытый список <select>
   своей встроенной тёмной/светлой палитрой — она генерическая, не наши
   токены, и в тёмной теме давала тусклый текст, слабо отличимый от фона и
   между собой (несколько вариантов статуса читались одинаково блёкло).
   background/color на <option> Chromium поверх этого уважает — задаём явно
   нашими токенами, чтобы список читался так же, как остальной интерфейс. */
select option {
  background: var(--bg-card);
  color: var(--text-main);
}

::-webkit-scrollbar-track {
  background: var(--bg-input) !important;
}

::-webkit-scrollbar-thumb {
  background: var(--text-dim) !important;
  border-color: var(--bg-input) !important;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted) !important;
}

/* Правило чинит легаси-инлайны со светлым текстом в светлой теме. Плашки
   статуса и решения из него исключены: они сами задают чернила под свою
   заливку, а !important здесь перекрашивал их обратно в --text-main, из-за
   чего цвет оставался только в фоне. */
:root:not([data-theme="dark"]) input,
:root:not([data-theme="dark"]) select:not(.status-select),
:root:not([data-theme="dark"]) textarea {
  color: var(--text-main) !important;
}

/* Keep selected filters unmistakable without relying on a bright gradient. */
.date-chip.active,
.staff-filter-chip.active {
  background: var(--accent-primary-fill) !important;
  color: var(--accent-on-primary) !important;
  border-color: transparent !important;
  box-shadow: none !important;
}

/* One primary action per toolbar; supporting actions stay neutral. */
#btnOpenImportTicketsModal,
#btnOpenAddIncomingModal,
#btnAddMyIncomingGuest,
#btnGoToSchedule,
#btnSaveImportTickets,
#btnRunAutoDistribute {
  background: var(--accent-primary-fill) !important;
  color: var(--accent-on-primary) !important;
  border-color: transparent !important;
  box-shadow: none !important;
}

#btnOpenAutoDistributeModal {
  background: var(--bg-input) !important;
  color: var(--text-main) !important;
  border-color: var(--border-color) !important;
  box-shadow: none !important;
}

#btnBulkUrgentOn,
#btnBulkUrgentOff,
#btnBulkDelete,
#btnDeleteStaff {
  background: var(--danger-soft) !important;
  color: var(--accent-rose) !important;
  border-color: var(--danger-border) !important;
  box-shadow: none !important;
}

#liveIndicator {
  box-shadow: none !important;
}

.brand-icon,
.login-logo,
.btn-primary,
.date-chip.active,
.staff-filter-chip.active,
button[style*="linear-gradient"],
button[style*="background: var(--accent"],
button[style*="background:var(--accent"],
span[style*="background: var(--accent-rose)"],
span[style*="background: var(--accent-green)"] {
  color: var(--accent-on-primary) !important;
}

/* Уведомления (issue #142): колокольчик, бейджи, панель, всплывашки */

.nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.2rem;
  height: 1.2rem;
  padding: 0 0.35rem;
  border-radius: 999px;
  background: var(--accent-rose);
  color: var(--bg-card);
  font-size: var(--fs-1);
  font-weight: var(--fw-title);
  line-height: 1;
}

.notif-bell-wrap {
  position: relative;
}

#btnNotifBell {
  position: relative;
}

#notifBellBadge {
  position: absolute;
  top: -0.3rem;
  right: -0.3rem;
  display: none;
  align-items: center;
  justify-content: center;
  min-width: 1.1rem;
  height: 1.1rem;
  padding: 0 0.3rem;
  border-radius: 999px;
  background: var(--accent-rose);
  color: var(--bg-card);
  font-size: var(--fs-1);
  font-weight: var(--fw-title);
  line-height: 1;
  box-shadow: 0 0 0 2px var(--bg-header);
}

#notifPanel {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  width: 360px;
  max-width: 90vw;
  max-height: 70vh;
  overflow-y: auto;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
  display: none;
  z-index: 200;
}

#notifPanel.open {
  display: block;
}

.notif-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
  font-weight: var(--fw-title);
  color: var(--text-main);
  font-size: var(--fs-4);
}

.notif-settings-btn {
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  padding: 0.2rem;
  line-height: 0;
  border-radius: var(--radius-md);
}

.notif-settings-btn:hover {
  color: var(--text-main);
  background: var(--bg-card-hover);
}

.notif-empty {
  padding: 1.5rem 1rem;
  text-align: center;
  color: var(--text-dim, var(--text-muted));
  font-size: var(--fs-4);
}

.notif-row {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.65rem 2.1rem 0.65rem 1rem;
  border-bottom: 1px solid var(--border-color);
  cursor: pointer;
  position: relative;
}

.notif-row-close {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  background: none;
  border: none;
  color: var(--text-dim, var(--text-muted));
  cursor: pointer;
  padding: 0.15rem;
  line-height: 0;
  border-radius: var(--radius-md);
  opacity: 0.55;
}

.notif-row-close:hover {
  opacity: 1;
  color: var(--accent-rose);
  background: var(--bg-card-hover);
}

.notif-row:last-child {
  border-bottom: none;
}

.notif-row:hover {
  background: var(--bg-card-hover);
}

.notif-row.unread {
  background: var(--info-soft, var(--bg-card-hover));
}

.notif-row-icon {
  flex-shrink: 0;
  color: var(--accent-cyan, var(--text-muted));
  margin-top: 0.1rem;
}

.notif-row-body {
  flex: 1;
  min-width: 0;
}

.notif-row-title {
  font-size: var(--fs-4);
  font-weight: var(--fw-title);
  color: var(--text-main);
}

.notif-row-text {
  font-size: var(--fs-3);
  color: var(--text-muted);
  margin-top: 0.15rem;
}

.notif-row-time {
  font-size: var(--fs-1);
  color: var(--text-dim, var(--text-muted));
  margin-top: 0.25rem;
}

.notif-dot {
  flex-shrink: 0;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--accent-cyan);
  margin-top: 0.35rem;
}

#toastContainer {
  position: fixed;
  top: 1rem;
  right: 1rem;
  z-index: 999;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  max-width: 340px;
}

.toast-card {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.2);
  padding: 0.75rem 0.85rem;
  cursor: pointer;
  animation: toastIn 0.2s ease-out;
}

@keyframes toastIn {
  from { transform: translateX(16px); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

.toast-icon {
  flex-shrink: 0;
  color: var(--accent-cyan, var(--text-muted));
  margin-top: 0.1rem;
}

.toast-body {
  flex: 1;
  min-width: 0;
}

.toast-title {
  font-size: var(--fs-4);
  font-weight: var(--fw-title);
  color: var(--text-main);
}

.toast-text {
  font-size: var(--fs-3);
  color: var(--text-muted);
  margin-top: 0.15rem;
}

@keyframes notifFlash {
  0%, 100% { box-shadow: none; }
  25% { box-shadow: 0 0 0 3px var(--accent-cyan); }
  75% { box-shadow: 0 0 0 3px var(--accent-cyan); }
}
.notif-flash {
  animation: notifFlash 1.8s ease-in-out;
}

.toast-close {
  flex-shrink: 0;
  background: none;
  border: none;
  color: var(--text-dim, var(--text-muted));
  cursor: pointer;
  padding: 0.1rem;
  line-height: 0;
}

/* Кликабельный список результатов поиска по справочнику (замена нативного
   <datalist>, который ненадёжно выбирался в паре с ILIKE-поиском по
   произвольной строке — см. issue про поиск подменяющего в «Заменах»). */
.staff-search-results {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  z-index: 60;
  margin-top: 2px;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  max-height: 220px;
  overflow-y: auto;
  display: none;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.staff-search-results.active {
  display: block;
}
.staff-search-results .staff-search-item {
  padding: 0.5rem 0.7rem;
  cursor: pointer;
  font-size: var(--fs-4);
  color: var(--text-main);
  border-bottom: 1px solid var(--border-color);
}
.staff-search-results .staff-search-item:last-child {
  border-bottom: none;
}
.staff-search-results .staff-search-item:hover,
.staff-search-results .staff-search-item.is-active {
  background: var(--bg-card-hover);
  color: var(--accent-cyan);
}
.staff-search-results .staff-search-sub {
  display: block;
  font-size: var(--fs-2);
  color: var(--text-muted);
  margin-top: 0.1rem;
}
.staff-search-results .staff-search-empty {
  padding: 0.5rem 0.7rem;
  font-size: var(--fs-3);
  color: var(--text-muted);
}

/* Свой пикер дат/месяцев вместо нативных input[type=date]/input[type=month]
   — issue #224, public/js/dashDate.js. Кликабельность всего поля обеспечивает
   dashDate.js (перехват mousedown), здесь только визуальная подсказка. */
input[type="date"],
input[type="month"] {
  cursor: pointer;
}

.dash-date-panel {
  position: fixed;
  z-index: 200;
  width: 264px;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 0.7rem;
}
.dash-date-panel-month {
  width: 220px;
}
.dash-date-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}
.dash-date-label {
  font-weight: var(--fw-title);
  font-size: var(--fs-4);
  color: var(--text-main);
}
.dash-date-nav {
  background: transparent;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: var(--fs-5);
  line-height: 1;
  padding: 0.2rem 0.5rem;
  border-radius: var(--radius-md);
}
.dash-date-nav:hover {
  background: var(--bg-card-hover);
  color: var(--text-main);
}
.dash-date-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin-bottom: 0.15rem;
}
.dash-date-weekday {
  text-align: center;
  font-size: var(--fs-1);
  color: var(--text-dim);
  padding: 0.2rem 0;
}
.dash-date-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}
.dash-date-day {
  background: transparent;
  border: none;
  color: var(--text-main);
  font-size: var(--fs-3);
  padding: 0.4rem 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.dash-date-day:hover {
  background: var(--bg-card-hover);
}
.dash-date-day.is-dim {
  color: var(--text-dim);
  opacity: 0.55;
}
.dash-date-day.is-today {
  box-shadow: inset 0 0 0 1px var(--accent-primary-border);
  font-weight: var(--fw-title);
}
.dash-date-day.is-selected {
  background: var(--accent-primary-fill);
  color: var(--accent-on-primary);
  font-weight: var(--fw-title);
}
.dash-date-month-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
}
.dash-date-month-cell {
  background: transparent;
  border: none;
  color: var(--text-main);
  font-size: var(--fs-3);
  padding: 0.55rem 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.dash-date-month-cell:hover {
  background: var(--bg-card-hover);
}
.dash-date-month-cell.is-today {
  box-shadow: inset 0 0 0 1px var(--accent-primary-border);
  font-weight: var(--fw-title);
}
.dash-date-month-cell.is-selected {
  background: var(--accent-primary-fill);
  color: var(--accent-on-primary);
  font-weight: var(--fw-title);
}
.dash-date-footer {
  display: flex;
  justify-content: space-between;
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border-color);
}
.dash-date-footer-btn {
  background: transparent;
  border: none;
  color: var(--accent-primary);
  font-size: var(--fs-3);
  cursor: pointer;
  padding: 0.2rem 0.3rem;
}
.dash-date-footer-btn:hover {
  text-decoration: underline;
}

/* «Уменьшить движение» в настройках системы (аудит 11.09): без анимаций и
   плавных переходов — сразу конечное состояние. Статичные подсказки (цвет,
   иконка, текст) остаются: движение нигде не единственный сигнал. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   ЭКРАН «СМЕНА» (СВ) — этап 4, макет Adapt-1-Smena-SV. Каркас в index.html
   (#tab-shift), содержимое рисует js/shift.js. Всё на токенах выше.
   ========================================================================== */
.shift-head { display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem; }
.shift-meta { font-size: var(--fs-2); color: var(--text-dim); }
.shift-head-actions { margin-left: auto; display: flex; gap: 0.5rem; }

#tab-shift .is-accent { color: var(--accent-primary); }
#tab-shift .is-ok { color: var(--accent-green); }
#tab-shift .is-warn { color: var(--accent-amber); }
#tab-shift .is-bad { color: var(--accent-rose); }
#tab-shift .muted { color: var(--text-dim); }
#tab-shift .num { text-align: right; font-variant-numeric: tabular-nums; }

.shift-grid { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 1.25rem; align-items: start; }
.shift-main, .shift-aside { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }
.shift-aside { padding-left: 1.25rem; border-left: 1px solid var(--border-color); }
@media (max-width: 1100px) {
  .shift-grid { grid-template-columns: minmax(0, 1fr); }
  .shift-aside { padding-left: 0; border-left: none; }
}

.shift-section-head { display: flex; align-items: center; gap: 8px; }
.shift-section-head h2 { font-size: var(--fs-4); font-weight: var(--fw-title); margin: 0; }
.shift-section-head .ui-icon { width: 15px; height: 15px; color: var(--text-muted); }
.shift-section-head .shift-icon-bad { color: var(--danger-solid); }
.shift-section-head .shift-icon-warn { color: var(--warning-solid); }
.shift-section-meta { font-size: var(--fs-2); color: var(--text-dim); }
.shift-sort { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }
.shift-sort-btn, .shift-btn, .shift-link {
  height: var(--h-ctl-sm); padding: 0 9px; border: 1px solid var(--border-color); border-radius: var(--radius-sm);
  background: none; color: var(--text-muted); font: inherit; font-size: var(--fs-1); cursor: pointer;
}
.shift-sort-btn.active { background: var(--bg-input); border-color: var(--border-strong); color: var(--text-main); font-weight: var(--fw-title); }
.shift-btn { font-size: var(--fs-2); }
.shift-btn.is-ok { border-color: var(--success-border); background: var(--success-soft); color: var(--accent-green); font-weight: var(--fw-title); }
.shift-link { margin-left: auto; border: none; padding: 0; color: var(--accent-primary); }
.shift-pill { font-size: var(--fs-1); padding: 1px 6px; border-radius: 999px; background: var(--bg-input); border: 1px solid var(--border-color); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.shift-pill.is-bad { background: var(--danger-soft); border-color: var(--danger-soft); color: var(--accent-rose); }
.shift-pill.is-warn { background: var(--warning-soft); border-color: var(--warning-soft); color: var(--accent-amber); }

.shift-card { border: 1px solid var(--border-color); border-radius: var(--radius-md); overflow: hidden; background: var(--bg-card); }
.shift-wl-row {
  display: grid; grid-template-columns: minmax(0, 2.5fr) minmax(70px, 1fr) minmax(48px, .5fr) minmax(48px, .5fr) minmax(70px, .8fr) 26px;
  gap: 8px; align-items: center; padding: 10px 14px; border-bottom: 1px solid var(--border-color); font-size: var(--fs-3);
}
.shift-wl-head { padding: 9px 14px; background: var(--bg-input); font-size: 11px; font-weight: var(--fw-title); letter-spacing: .07em; text-transform: uppercase; color: var(--text-dim); }
.shift-wl-name { display: flex; align-items: center; gap: 8px; min-width: 0; }
.shift-avatar { width: 26px; height: 26px; flex: 0 0 auto; display: grid; place-items: center; border-radius: var(--radius-sm); background: var(--bg-input); color: var(--text-muted); font-size: 10px; font-weight: var(--fw-num); }
.shift-avatar.is-warn { background: var(--warning-soft); color: var(--accent-amber); }
.shift-avatar.is-bad { background: var(--danger-soft); color: var(--accent-rose); }
.shift-wl-text { min-width: 0; display: flex; flex-direction: column; }
.shift-wl-title { font-weight: var(--fw-title); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.shift-wl-note { font-size: var(--fs-1); color: var(--text-dim); }
.shift-guest { font-size: var(--fs-1); font-weight: var(--fw-label); padding: 1px 6px; border-radius: 999px; background: var(--discovery-soft); color: var(--accent-purple); }
.shift-wl-bar { display: flex; align-items: center; gap: 7px; }
.shift-wl-bar b { font-size: var(--fs-2); font-weight: var(--fw-num); font-variant-numeric: tabular-nums; }
.shift-bar { flex: 1; height: 6px; border-radius: 3px; background: var(--bg-input); overflow: hidden; }
.shift-bar > span { display: block; height: 100%; background: var(--accent-primary-fill); }
.shift-bar > .is-warn { background: var(--warning-solid); }
.shift-bar > .is-bad { background: var(--danger-solid); }
.shift-icon-btn { width: 26px; height: 26px; display: grid; place-items: center; border: 1px solid var(--border-color); border-radius: var(--radius-sm); background: none; color: var(--text-muted); cursor: pointer; }
.shift-icon-btn .ui-icon { width: 13px; height: 13px; }
.shift-icon-btn.is-accent { border-color: var(--accent-primary-border); background: var(--accent-primary-soft); color: var(--accent-primary); }
.shift-wl-foot { display: flex; align-items: center; gap: 10px; padding: 9px 14px; font-size: var(--fs-1); color: var(--text-dim); }
.shift-wl-foot:empty { display: none; }

.shift-banner {
  display: flex; align-items: center; gap: 10px; padding: 11px 14px;
  border: 1px solid var(--accent-primary-border); border-radius: var(--radius-md);
  background: var(--accent-primary-soft); color: var(--accent-primary); font-size: var(--fs-3);
}
.shift-banner .ui-icon { width: 16px; height: 16px; flex: 0 0 auto; }
.shift-banner > span { flex: 1; min-width: 0; }
.shift-banner .btn { height: 30px; font-size: var(--fs-2); }

.shift-block { display: flex; flex-direction: column; gap: 9px; }
.shift-block .shift-section-head h2 { font-size: var(--fs-3); }
.shift-list { display: flex; flex-direction: column; gap: 7px; }
.shift-item { padding: 9px 11px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); background: var(--bg-card); font-size: var(--fs-2); }
.shift-item-head { display: flex; align-items: baseline; gap: 6px; }
.shift-item-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; color: var(--text-muted); font-size: var(--fs-1); }
.shift-item-text b { color: var(--text-main); font-size: var(--fs-2); font-weight: var(--fw-title); }
.shift-item-actions { display: flex; gap: 6px; margin-top: 8px; }
.shift-item-btn, .shift-item-row { display: flex; align-items: center; gap: 9px; width: 100%; text-align: left; font: inherit; cursor: pointer; }
.shift-item-btn .shift-item-text, .shift-item-row .shift-item-text { flex: 1; }
.shift-item-btn { border-left: 3px solid var(--border-strong); }
.shift-item-btn.is-warn { border-left-color: var(--warning-solid); }
.shift-item-btn.is-bad { border-left-color: var(--danger-solid); }
.shift-item-btn .ui-icon { width: 13px; height: 13px; color: var(--text-dim); flex: 0 0 auto; }
.shift-item-row.is-dashed { border-style: dashed; border-color: var(--border-strong); background: none; cursor: default; }
.shift-item-row .num { font-size: var(--fs-2); white-space: nowrap; }
.shift-empty { padding: 0.9rem 0; text-align: center; font-size: var(--fs-2); color: var(--text-dim); }

/* ==========================================================================
   РАЗБОР ЗАЯВОК — главный экран модератора (этап 4, макет Adapt-3-Razbor).
   Вкладка занимает всю область без отступов: полоса счётчиков, ниже сетка
   «очередь | заявка». Помощник — оверлей внутри колонки заявки, не третья
   колонка (на 800 px ей нет места).
   ========================================================================== */
.rz {
  flex-direction: column;
  margin: calc(-1 * var(--content-pad));
  height: calc(100vh - 57px);
  min-width: 0;
}

.rz-stats {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 1px;
  background: var(--border-color);
  border-bottom: 1px solid var(--border-color);
  flex: 0 0 auto;
}

.rz-stat { padding: 12px 16px; background: var(--bg-card); display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.rz-stat-label, .rz-attr-label { font-size: 11px; font-weight: var(--fw-title); letter-spacing: .06em; text-transform: uppercase; color: var(--text-dim); }
.rz-stat-value { font-size: 28px; font-weight: var(--fw-title); line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.rz-stat-value.is-acc { color: var(--accent-primary); }
.rz-stat-value.is-warn { color: var(--accent-amber); }
.rz-stat-value.is-ok { color: var(--accent-green); }
.rz-stat-value.is-bad { color: var(--accent-rose); }
.rz-stat-value.is-info { color: var(--accent-info); }
button.rz-stat { border: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
button.rz-stat:hover { background: var(--bg-card-hover); }
.rz-stat-of { font-size: 13px; color: var(--text-dim); margin-left: 6px; font-weight: var(--fw-label); }
.rz-stat-sub { font-size: 11px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.rz-main {
  display: grid;
  grid-template-columns: minmax(280px, 26%) minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  flex: 1;
  min-height: 0;
}

.rz-queue-col { border-right: 1px solid var(--border-color); display: flex; flex-direction: column; min-width: 0; min-height: 0; }
/* Срезы очереди и вкладки помощника — плитки с рамкой, как трекер статусов в
   реестре (.ticket-stat-tracker .ticket-status-chip): выбранная обводится контуром,
   а не заливается. Срезы живут в шапке (#topBarActions, см. switchTab), одним рядом. */
.rz-scope { display: flex; gap: 3px; margin: 0; }
.rz-scope .ticket-scope-btn {
  flex: 1; min-width: 0;
  height: var(--h-ctl-sm); padding: 0 var(--s-4);
  border: 1px solid var(--border-color); border-radius: var(--radius-sm);
  background: var(--bg-card); color: var(--text-muted);
  font-size: var(--fs-1); font-weight: var(--fw-label); white-space: nowrap;
  cursor: pointer; transition: var(--transition);
}
.rz-scope .ticket-scope-btn:hover { border-color: var(--border-strong); color: var(--text-main); }
.rz-scope .ticket-scope-btn.active {
  outline: 2px solid var(--accent-primary); outline-offset: -1px;
  border-color: transparent; color: var(--text-main); font-weight: var(--fw-title);
}
.rz-scope .ticket-scope-btn:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }
#topBarActions .rz-scope .ticket-scope-btn { flex: none; }
.rz-count { font-size: 10px; padding: 0 5px; border-radius: 999px; background: var(--bg-input); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.ticket-scope-btn.active .rz-count { background: var(--accent-primary-soft); color: var(--accent-primary); }
.rz-queue { flex: 1; overflow-y: auto; display: flex; flex-direction: column; }
.rz-queue-foot { padding: 8px 12px; font-size: 11px; color: var(--text-dim); border-top: 1px solid var(--border-color); }

.rz-row {
  display: grid;
  grid-template-columns: 3px 1fr auto;
  gap: 0 10px;
  align-items: center;
  padding: 0;
  border: none;
  border-bottom: 1px solid var(--border-color);
  background: none;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  color: var(--text-main);
}
.rz-row:hover { background: var(--bg-card-hover); }
.rz-row[aria-pressed="true"] { background: var(--bg-card); }
.rz-stripe { align-self: stretch; background: var(--border-strong); }
.rz-stripe.is-acc { background: var(--accent-primary-fill); }
.rz-stripe.is-warn { background: var(--accent-amber); }
.rz-stripe.is-ok { background: var(--accent-green); }
.rz-stripe.is-bad { background: var(--accent-rose); }
.rz-row-mid { display: flex; flex-direction: column; gap: 3px; padding: 11px 0; min-width: 0; }
.rz-row-l1 { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.rz-shk { font-size: 14px; font-weight: var(--fw-title); font-variant-numeric: tabular-nums; }
.rz-shk.is-dim { color: var(--text-dim); }
.rz-flame { width: 12px; height: 12px; color: var(--accent-rose); }
.rz-chip { font-size: 10px; font-weight: var(--fw-title); letter-spacing: .04em; text-transform: uppercase; padding: 1px 5px; border-radius: 3px; background: var(--bg-input); color: var(--text-muted); }
.rz-chip.is-ok { background: var(--success-soft); color: var(--accent-green); }
.rz-chip.is-bad { background: var(--danger-soft); color: var(--accent-rose); }
.rz-row-sub { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rz-row-right { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; padding: 11px 12px 11px 0; }
.rz-row-time { font-size: 12px; font-weight: var(--fw-title); font-variant-numeric: tabular-nums; color: var(--text-muted); }
.rz-row-time.is-warn { color: var(--accent-amber); }
.rz-row-time.is-ok { color: var(--accent-green); }
.rz-row-time.is-acc { color: var(--accent-primary); }
.rz-row-status { font-size: 10px; color: var(--text-dim); }
.rz-empty { padding: 24px 16px; font-size: 13px; color: var(--text-dim); text-align: center; }

.rz-work-col { min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.rz-card { padding: 14px 20px; border-bottom: 1px solid var(--border-color); background: var(--bg-card); display: flex; flex-direction: column; gap: 8px; }
.rz-card-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.rz-card-shk { font-size: 24px; font-weight: var(--fw-title); letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
.rz-badge { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: var(--fw-title); padding: 3px 8px; border-radius: 4px; background: var(--bg-input); border: 1px solid var(--line-ctl); color: var(--text-muted); }
.rz-badge.is-warn { background: var(--warning-soft); color: var(--accent-amber); border-color: transparent; }
.rz-badge.is-ok { background: var(--success-soft); color: var(--accent-green); border-color: transparent; }
.rz-badge.is-acc { background: var(--accent-primary-soft); color: var(--accent-primary); border-color: transparent; }
.rz-badge.is-bad { background: var(--danger-soft); color: var(--accent-rose); border-color: transparent; }
.rz-badge .ui-icon { width: 12px; height: 12px; }
.rz-helper-btn { margin-left: auto; height: 32px; font-size: 12px; }
.rz-card-meta { font-size: 12px; color: var(--text-muted); }
.rz-pill { font-size: 11px; padding: 1px 6px; border-radius: 999px; background: var(--accent-primary-soft); color: var(--accent-primary); }
.rz-attr { display: inline-flex; flex-direction: column; gap: 2px; padding: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-md); background: var(--bg-page); font-size: 13px; align-self: flex-start; }

.rz-work-wrap { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
.rz-work { flex: 1; overflow-y: auto; padding: 16px 20px; display: flex; flex-direction: column; gap: 10px; }
.rz-tpl-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rz-tpl-chips { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; flex: 1; }
.rz-tpl { height: 26px; padding: 0 10px; border: 1px solid var(--line-ctl); border-radius: 5px; background: var(--bg-card); color: var(--text-muted); font-size: 11px; font-weight: var(--fw-label); cursor: pointer; font-family: inherit; }
.rz-tpl.active { border-color: var(--accent-primary-fill); background: var(--accent-primary-soft); color: var(--accent-primary); font-weight: var(--fw-title); }
.rz-draft-state { margin-left: auto; font-size: 11px; color: var(--accent-amber); }
.rz-builder { display: flex; gap: 6px; flex-wrap: wrap; padding: 6px 10px; border: 1px dashed var(--border-color); border-radius: var(--radius-md); }
.rz-text {
  flex: 1;
  min-height: 200px;
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--line-ctl);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  color: var(--text-main);
  font-family: "SF Mono", Consolas, monospace;
  font-size: 13px;
  line-height: 1.55;
  resize: none;
  white-space: pre-wrap;
}
.rz-details { border: 1px solid var(--border-color); border-radius: var(--radius-md); background: var(--bg-card); }
.rz-details summary { padding: 7px 12px; font-size: 11px; font-weight: var(--fw-title); color: var(--text-muted); cursor: pointer; }
.rz-details-body { padding: 4px 12px 10px 12px; font-size: 12px; line-height: 1.55; white-space: pre-wrap; border-left: 3px solid var(--accent-primary-fill); margin: 0 12px 10px; }
.rz-mono { font-family: "SF Mono", Consolas, monospace; font-size: 12px; }

.rz-select {
  height: 34px;
  padding: 0 10px;
  border: 1px solid var(--line-ctl);
  border-radius: var(--radius-md);
  background: var(--bg-input);
  color: var(--text-main);
  font-size: 13px;
  font-family: inherit;
  min-width: 0;
}
.rz-select:disabled { opacity: .6; }
.rz-status { font-weight: var(--fw-title); border-left-width: 3px; }
.rz-status.is-warn { background: var(--warning-soft); color: var(--accent-amber); border-color: var(--accent-amber); }
.rz-status.is-ok { background: var(--success-soft); color: var(--accent-green); border-color: var(--accent-green); }
.rz-status.is-acc { background: var(--accent-primary-soft); color: var(--accent-primary); border-color: var(--accent-primary-fill); }
.rz-comment { flex: 1; min-width: 140px; }
.rz-decision { border-top: 1px solid var(--border-color); background: var(--bg-card); padding: 12px 20px; display: flex; flex-direction: column; gap: 10px; }
.rz-dec-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.rz-approve, .rz-reject, .rz-take, .rz-pause {
  flex: 1;
  min-width: 140px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 42px;
  border-radius: 7px;
  font-size: 14px;
  font-weight: var(--fw-title);
  font-family: inherit;
  cursor: pointer;
}
.rz-approve { border: 1px solid var(--accent-green); background: var(--accent-green); color: var(--accent-on-primary); }
.rz-reject { border: 1px solid var(--accent-rose); background: var(--danger-soft); color: var(--accent-rose); }
/* Паузы «Запрос видео» / «Согласование»: вторичные, .is-on — пауза стоит,
   клик её снимает. */
.rz-pause { border: 1px solid var(--border-color); background: var(--bg-input); color: var(--text-main); }
.rz-pause.is-on { border-color: var(--info-border); background: var(--info-soft); color: var(--accent-info); }
.rz-dec-note { font-size: 12px; color: var(--text-dim); }
/* Второй, тихий ряд: редкие исходы (Закрыта ранее / У другого / Отдать в
   пул) и «Вернуть в работу» у закрытой — не спорят с основными кнопками. */
.rz-more {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 12px; border-radius: 6px;
  border: 1px solid transparent; background: transparent; color: var(--text-muted);
  font-size: var(--fs-2); font-family: inherit; cursor: pointer;
}
.rz-more:hover, .rz-more:focus-visible { border-color: var(--border-color); background: var(--bg-input); color: var(--text-main); }
.rz-dec-more { gap: 4px; }

.rz-aside {
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: 320px;
  max-width: 70%;
  display: flex;
  flex-direction: column;
  background: var(--bg-card);
  border-left: 1px solid var(--line-ctl);
  box-shadow: var(--shadow-md);
  z-index: 5;
}
.rz-aside-head { display: flex; align-items: center; gap: 6px; padding: 8px 10px; border-bottom: 1px solid var(--border-color); }
.rz-aside-head .icon-btn { margin-left: auto; width: 26px; height: 26px; }
.rz-aside-body { flex: 1; min-height: 0; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.rz-lbl { display: flex; flex-direction: column; gap: 3px; font-size: 10px; font-weight: var(--fw-title); letter-spacing: .06em; text-transform: uppercase; color: var(--text-dim); }
.rz-lbl .rz-select { height: 30px; font-size: 12px; text-transform: none; letter-spacing: 0; font-weight: var(--fw-label); }
.rz-wo-text { min-height: 96px; padding: 8px 10px; border: 1px solid var(--line-ctl); border-radius: var(--radius-md); background: var(--bg-page); color: var(--text-main); font-family: "SF Mono", Consolas, monospace; font-size: 12px; resize: vertical; }
.rz-note { font-size: 11px; padding: 6px 9px; border-left: 3px solid var(--accent-primary-fill); background: var(--bg-page); border-radius: 0 6px 6px 0; }
.rz-list { display: flex; flex-direction: column; gap: 6px; }
.rz-list-row { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border: 1px solid var(--border-color); border-radius: var(--radius-md); font-size: 12px; }
.rz-list-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* ==========================================================================
   ВАРИАНТ C — «РАБОЧИЙ РЕЙЛ + ПАНЕЛЬ». ПЕРЕНОС МАКЕТА В КОД
   ==========================================================================

   Блок дописывается В КОНЕЦ public/styles.css. Он стоит последним намеренно:
   правила выше перебиваются порядком каскада, а не !important и не раздутой
   специфичностью — значит вариант C снимается удалением одного блока, без
   разбора, что он там переопределил.

   !important стоит ровно в трёх местах, и каждое подписано: там, где значение
   приходит инлайновым style из разметки (шапка таблицы) или из строкового
   шаблона в public/js (пилюля статуса, кнопки .ticket-actions). Инлайновый
   стиль каскадом не перебивается.

   Новых токенов нет. Светлая и тёмная темы получаются сами: используются те
   же роли (--bg-header, --accent-primary-soft, --border-color …), что и во
   всём файле, поэтому [data-theme="dark"] работает без второй копии правил.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. РЕЙЛ РАЗДЕЛОВ — 84px, подпись под иконкой
   Ответ на «рейл только с иконками, непонятно куда жать»: подписи всегда
   видны, títle-онли пунктов не остаётся. Подписи в разметке короткие
   («Заявки», «Согл-я»), полное имя раздела — в title.
   -------------------------------------------------------------------------- */
.sidebar {
  width: 84px;
  flex: 0 0 84px;
  align-items: stretch;
  gap: 2px;
  padding: 10px 6px;
}

#navMenuHost {
  align-items: stretch;
  gap: 2px;
}

/* Логотип перестаёт быть заливной плашкой: на рейле с подписями он читается
   как шестой пункт меню. Остаётся знак акцентным цветом. */
.sidebar .brand {
  width: 100%;
  height: 38px;
  margin-bottom: 8px;
  border-radius: 0;
  background: none;
  color: var(--accent-primary);
}

.sidebar .brand .ui-icon { width: 20px; height: 20px; }

.nav-menu {
  align-items: stretch;
  gap: 2px;
}

.nav-item {
  width: auto;
  height: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 8px 2px;
  border: none;
  border-radius: 6px;
  color: var(--text-muted);
}

/* Подпись возвращается в поток: правило выше в файле уводит её в
   clip-rect(0 0 0 0) для скринридера. */
.nav-item > span:not(.nav-icon):not(.nav-badge) {
  position: static;
  width: auto;
  height: auto;
  overflow: visible;
  clip: auto;
  font-size: 11.5px;
  line-height: 1.15;
  text-align: center;
  white-space: nowrap;
}

.nav-item:hover {
  background: var(--bg-input);
  color: var(--text-main);
}

/* Активный раздел — подложка акцента и планка слева, как у выбранной строки
   фильтра. Рамка (прежнее .nav-item.active) на 84px читалась как кнопка. */
.nav-item.active {
  border-color: transparent;
  background: var(--accent-primary-soft);
  color: var(--accent-primary);
  box-shadow: inset 2px 0 0 var(--accent-primary-border);
}

.nav-item.active > span:not(.nav-icon):not(.nav-badge) { font-weight: var(--fw-title); }

.nav-icon { width: 18px; height: 18px; }

.nav-item .nav-badge {
  top: 4px;
  right: 12px;
  min-width: 16px;
  height: 16px;
  border-radius: 8px;
  font-size: 10px;
  line-height: 16px;
}

/* Флайаут «Моя группа» — единственный второй уровень: внутри рейла подпунктов
   нет. Открытие по :hover/:focus-within уже описано выше в файле. */
.nav-submenu {
  left: 78px;
  top: -6px;
  width: 230px;
  padding: 8px;
}

.nav-submenu::before { left: -8px; width: 8px; }

/* Заголовок флайаута — та же метка группы, что в панели фильтров. */
.nav-submenu-title {
  padding: 5px 9px 8px;
  font-size: 11px;
  font-weight: var(--fw-title);
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.nav-subitem-count {
  margin-left: auto;
  font-size: var(--fs-1);
  font-weight: var(--fw-num);
  font-variant-numeric: tabular-nums;
  color: var(--accent-amber);
}

/* Esc закрывает флайаут: снять :hover из JS нельзя, поэтому JS ставит на
   раздел класс, который гасит правило открытия (см. js-patches.md). */
.nav-item-accordion.is-muted:hover .nav-submenu,
.nav-item-accordion.is-muted:focus-within .nav-submenu { display: none; }

/* --------------------------------------------------------------------------
   2. ПОДВАЛ РЕЙЛА — уведомления, тема, пользователь
   Переехали из шапки: шапка дублировала сайдбар, а рядом с аватаром им и
   место — это «про меня», а не «про раздел».
   -------------------------------------------------------------------------- */
.rail-foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding-top: 10px;
  border-top: 1px solid var(--border-color);
}

.rail-foot .btn,
.rail-foot .rail-user {
  width: 34px;
  height: 34px;
  min-height: 0;
  padding: 0;
  border-radius: var(--radius-sm);
}

.rail-foot .btn {
  background: none;
  border-color: var(--border-color);
  color: var(--text-muted);
}

.rail-foot .btn:hover {
  background: var(--bg-input);
  border-color: var(--border-strong);
  color: var(--text-main);
}

.rail-user {
  display: grid;
  place-items: center;
  border: 1px solid var(--border-strong);
  background: var(--bg-input);
  color: var(--text-muted);
  font-size: var(--fs-1);
  font-weight: var(--fw-num);
  cursor: pointer;
}

/* Панель уведомлений раскрывалась вниз-влево от колокола в шапке. На рейле
   тот же расчёт уводит её за левый край экрана и вверх за пределы окна:
   открываем вправо от кнопки и прижимаем к её низу. */
.sidebar #notifPanel {
  top: auto;
  right: auto;
  bottom: 0;
  left: calc(100% + 8px);
}

/* --------------------------------------------------------------------------
   3. ШАПКА — 48px, хлебные крошки вместо кикера с заголовком
   Ответ на «непонятно, где ты находишься»: путь, живой индикатор и мета
   смены; справа — только ежедневные действия текущего раздела.
   -------------------------------------------------------------------------- */
.top-bar {
  min-height: 48px;
  padding: 0 18px;
  gap: 12px;
}

/* Дата уехала в мету крошек, а «Redash Analytics» на каждом экране шапке не
   нужна — раздел называет себя сам. */
.page-kicker { display: none; }

.top-crumbs {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  font-size: var(--fs-2);
  color: var(--text-dim);
}

.top-crumbs .ui-icon {
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
  color: var(--text-dim);
}

.top-crumbs .header-title {
  font-size: var(--fs-4);
  font-weight: var(--fw-title);
  letter-spacing: 0;
  color: var(--text-main);
  white-space: nowrap;
}

.top-crumb {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.top-meta {
  font-size: var(--fs-2);
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.top-controls { gap: 8px; }

/* Слот действий раздела: switchTab() переносит сюда панель активной вкладки
   (см. js-patches.md). Пусто — не занимает места. */
#topBarActions {
  display: flex;
  align-items: center;
  gap: 8px;
}

#topBarActions:empty { display: none; }

#topBarActions .btn {
  height: 30px;
  min-height: 30px;
  padding: 0 10px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-2);
}

/* Инлайновый padding из .ticket-actions .btn (он с !important в блоке выше). */
#topBarActions .ticket-actions .btn { padding: 0 10px !important; font-size: var(--fs-2) !important; }

#topBarActions .ticket-actions,
#topBarActions .shift-head-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  flex-wrap: nowrap;
}

/* Редкие действия — за иконкой настроек: «Причины решения» и
   «Автоназначение» это не ежедневная работа. */
#topBarActions .btn.icon-btn {
  width: 30px;
  padding: 0;
}

/* --------------------------------------------------------------------------
   4. ПАНЕЛЬ ФИЛЬТРОВ — 264px, единственная панель экрана
   Порядок групп по макету: поиск · статус · период · категория · решение ·
   команда. Задан order, а не перестановкой разметки: id и data-group нужны
   обработчикам в js/tickets.js там, где они есть.
   -------------------------------------------------------------------------- */
.ticket-filter-col { --rail-w: 264px; }

.ticket-filter-rail {
  gap: 0;
  padding: 0;
}

.rail-head {
  order: 0;
  padding: 11px 14px;
  border-bottom: 1px solid var(--border-color);
}

.rail-head::before {
  /* Иконка раздела «Фильтры» — маска не нужна, хватает подписи: символ
     фильтра берётся из спрайта в разметке (см. index-fragments.html). */
  content: none;
}

.rail-count {
  font-size: var(--fs-1);
  font-weight: var(--fw-num);
  font-variant-numeric: tabular-nums;
  color: var(--accent-primary);
}

.rail-group {
  padding: 10px 14px;
  border-top: none;
  border-bottom: 1px solid var(--border-color);
  gap: 7px;
}

.rail-group[data-group="search"]   { order: 1; padding: 12px 14px; }
.rail-group[data-group="status"]   { order: 2; padding: 10px 0; }
.rail-group[data-group="period"]   { order: 3; }
.rail-group[data-group="category"] { order: 4; }
.rail-group[data-group="decision"] { order: 5; }
.rail-group[data-group="team"]     { order: 6; }

.rail-group[data-group="status"] .rail-group-head { padding: 0 14px 8px; }

.rail-label {
  font-size: 11px;
  font-weight: var(--fw-title);
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.rail-group[data-group="search"] .rail-label { display: none; }

/* Статус — он же трекер смены: строка на значение, без рамок и радиусов.
   Семь строк по 28px влезают в невысокое окно целиком. */
.ticket-stat-tracker { gap: 0; }

.ticket-stat-tracker .ticket-status-chip {
  min-height: 0;
  gap: 9px;
  padding: 6px 14px;
  border: none;
  border-radius: 0;
  background: none;
  font-size: var(--fs-3);
}

.ticket-stat-tracker .ticket-status-chip:hover { background: var(--bg-input); }

.ticket-stat-tracker .ticket-status-chip.active,
.ticket-stat-tracker .ticket-status-chip.active[data-status] {
  border: none;
  background: var(--accent-primary-fill);
  color: var(--accent-on-primary);
  box-shadow: none;
  font-weight: var(--fw-title);
}

.ticket-stat-tracker .ticket-status-chip.active .ticket-stat-count,
.ticket-stat-tracker .ticket-status-chip.active .ticket-stat-icon { color: var(--accent-on-primary); }

.ticket-stat-tracker .ticket-status-chip .ticket-stat-icon {
  width: 14px;
  height: 14px;
  background: none;
  border-radius: 0;
}

.ticket-stat-tracker .ticket-stat-count {
  font-size: var(--fs-3);
  font-weight: var(--fw-num);
  font-variant-numeric: tabular-nums;
}

/* Чипы периода и решения — 26px, радиус 4. Категории остаются строками во всю
   ширину: названия из TICKET_CATEGORIES по длине непредсказуемы. */
.ticket-filter-rail .ticket-chip-group button {
  height: 26px;
  min-height: 26px;
  padding: 0 9px;
  border-radius: 4px;
  font-size: 12.5px;
}

.ticket-filter-rail .ticket-chip-group.is-list button {
  height: 28px;
  min-height: 28px;
  width: 100%;
  justify-content: flex-start;
  border: none;
}

/* Иконки решения нужны: они и есть разница между «Одобрено» и «Отказ» на
   первом взгляде. Правило выше в файле гасит иконки во всей панели. */
.ticket-filter-rail .ticket-decision-chip .ui-icon {
  display: inline-flex;
  width: 12px;
  height: 12px;
}

.ticket-filter-rail .ticket-decision-chip[data-decision="Одобрили"] .ui-icon { color: var(--success-solid); }
.ticket-filter-rail .ticket-decision-chip[data-decision="Отказ"] .ui-icon { color: var(--danger-solid); }
.ticket-filter-rail .ticket-decision-chip[data-decision="Запрос видео"] .ui-icon { color: var(--info-solid); }
.ticket-filter-rail .ticket-decision-chip[data-decision="Согласование"] .ui-icon { color: var(--accent-info); }

/* --------------------------------------------------------------------------
   5. РАБОЧАЯ ОБЛАСТЬ РЕЕСТРА
   Блок кнопок действий и «Пульс смены» из реестра уходят: действия — в шапку,
   счётчики — в трекер статусов панели.
   -------------------------------------------------------------------------- */
.ticket-toolbar { display: none; }

/* «Найдено» и период живут в шапке панели фильтров — строка над таблицей
   повторяла их и при прокрутке всё равно не была видна. */
.ticket-summary-bar { display: none; }

.ticket-main {
  gap: 0;
  padding: 0;
}

#ticketsTableCard {
  padding: 0 !important;
  border: none;
  border-radius: 0;
  background: none;
}

/* Полоса выделения — замена отдельного блока кнопок: появляется, когда
   выбрана хотя бы одна строка, и исчезает вместе с выделением. */
.ticket-bulk-bar {
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
  margin: 0;
  padding: 8px 18px;
  border: none;
  border-bottom: 1px solid var(--border-strong);
  border-radius: 0;
  background: var(--accent-primary-soft);
}

.ticket-bulk-bar .bulk-title {
  font-size: var(--fs-2);
  font-weight: var(--fw-title);
  color: var(--accent-primary);
}

.ticket-bulk-bar .bulk-sep {
  width: 1px;
  height: 18px;
  background: var(--border-strong);
}

.ticket-bulk-bar select,
.ticket-bulk-bar .btn {
  height: 26px;
  min-height: 26px;
  padding: 0 9px;
  border-radius: 4px;
  font-size: 12.5px;
}

.ticket-bulk-bar .btn:last-child { margin-left: auto; }

/* Таблица: плотность макета. padding в шапке приходит инлайновым style из
   разметки, в ячейках — из шаблона строки в js/tickets.js; оба перебиваются
   только !important. */
.tickets-table thead th {
  padding: 8px 9px !important;
  font-size: 11px;
  font-weight: var(--fw-title);
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.tickets-table tbody td {
  padding: 0 9px !important;
  height: 38px;
  font-size: var(--fs-3);
}

.tickets-table thead tr { border-bottom: 1px solid var(--border-strong); }
.tickets-table tbody tr { border-bottom: 1px solid var(--border-color); }

/* Статус остаётся живым select — это рабочий орган, а не бейдж. Пилюля с
   рамкой и заливкой снимается, остаётся точка цветом статуса и текст:
   в строке 38px девять пилюль в ряд давали пёстрый шум.
   Цвет приходит инлайном из statusStyle (js/tickets.js) — точка рисуется
   градиентом на currentColor, поэтому перекрашивается вместе с текстом. */
.tickets-table .status-select,
.tickets-table td > span[style*="border-left"] {
  padding: 0 0 0 14px !important;
  border: none !important;
  border-radius: 0 !important;
  background-color: transparent !important;
  background-image: radial-gradient(circle 3px at 4px 50%, currentColor 99%, transparent 100%) !important;
  background-repeat: no-repeat !important;
  font-size: var(--fs-2) !important;
  font-weight: var(--fw-label) !important;
}

/* Пагинация — одна, внизу, без дубля сверху (верхний блок удаляется из
   разметки, см. index-fragments.html). */
.ticket-pager {
  margin: 0 !important;
  padding: 9px 18px !important;
  border-top: 1px solid var(--border-strong);
  border-bottom: none !important;
  background: var(--bg-header);
}

.ticket-pager .btn {
  height: 26px;
  min-height: 26px;
  padding: 0 9px !important;
  border-radius: 4px;
  font-size: 12.5px !important;
}

.ticket-pager .js-ticket-page-info {
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-2) !important;
}

/* --------------------------------------------------------------------------
   6. СМЕНА — планка счётчиков и правая колонка
   Счётчики из #shiftKpi — та же .rz-stats, что у модератора на «Разборе»
   (кнопки вместо div: клик ведёт в реестр с фильтром).
   -------------------------------------------------------------------------- */
#tab-shift.tab-with-rail {
  display: flex;
  align-items: stretch;
  min-width: 0;
  margin: calc(-1 * var(--content-pad));
  min-height: calc(100vh - 48px);
}

.shift-dyn {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px 10px;
  margin: 0;
  padding: 2px 0;
  font-size: var(--fs-2);
}

.shift-dyn dt { color: var(--text-muted); }

.shift-dyn dd {
  margin: 0;
  font-weight: var(--fw-num);
  font-variant-numeric: tabular-nums;
  color: var(--text-main);
}

.shift-work {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* Шапка экрана «Смена» переехала в общую .top-bar: свои мета и кнопки этому
   разделу больше не нужны. */
.shift-head { display: none; }

.shift-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 1px;
  background: var(--border-color);
}

.shift-body > .shift-main,
.shift-body > .shift-aside {
  padding: 14px 18px;
  background: var(--bg-dark);
  border-left: none;
}

/* --------------------------------------------------------------------------
   7. АДАПТИВ
   Ширина рабочей области — 1fr, средние колонки таблицы — minmax(0, …fr):
   сетка не должна выпадать за контейнер при открытой панели. Ниже ~1200px
   панель фильтров открепляется сама (matchMedia в js/ui.js).
   -------------------------------------------------------------------------- */
@media (max-width: 1280px) {
  .shift-body { grid-template-columns: minmax(0, 1fr); }
  .shift-body > .shift-aside { border-top: 1px solid var(--border-color); }
}

@media (max-width: 1100px) {
  .top-meta { display: none; }
}
