:root {
  /* --- Фирменные цвета (чром: топбар, кнопки, акценты) --- */
  --brand-navy: #0b1f3a;
  --brand-navy-2: #14335c;
  --brand-yellow: #f5b700;
  --brand-yellow-dark: #c99400;

  /* --- Контент: поверхности и текст (адаптируются под тему) --- */
  --surface-1: #ffffff;
  --surface-2: #f4f6f9;
  --page-plane: #eef1f6;
  --text-primary: #10141c;
  --text-secondary: #4d5566;
  --text-muted: #838a99;
  --gridline: #e6e9ef;
  --baseline: #c7cdd9;
  --border: rgba(11, 31, 58, 0.10);
  --shadow: 0 1px 2px rgba(11, 31, 58, 0.06), 0 8px 24px rgba(11, 31, 58, 0.06);

  /* --- Данные: валидированная категориальная палитра (dataviz-скилл), --- */
  /* --- порядок начинается с blue/yellow — ближе к фирменным цветам --- */
  --series-1: #2a78d6; /* выручка */
  --series-2: #eda100; /* маржа */
  --series-3: #1baf7a; /* себестоимость / доп. ряд */
  --series-4: #e34948;
  --series-5: #8a63d2; /* наценка */
  --series-6: #0aa5a0; /* доп. метрика (доставка/разгрузка/самовывоз/возвраты) */

  --stage-top: #86b6ef;
  --stage-confirmed: #2a78d6;
  --stage-success: #104281;

  --status-good: #0ca30c;
  --status-warning: #fab219;
  --status-critical: #d03b3b;
}

@media (prefers-color-scheme: dark) {
  :root {
    --surface-1: #161a23;
    --surface-2: #1d222d;
    --page-plane: #0e1116;
    --text-primary: #f5f6f8;
    --text-secondary: #b7bdca;
    --text-muted: #838a99;
    --gridline: #2a2f3a;
    --baseline: #3a4152;
    --border: rgba(255, 255, 255, 0.08);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.35);

    --series-1: #3987e5;
    --series-2: #c98500;
    --series-3: #199e70;
    --series-4: #e66767;
    --series-5: #9c7ce0;
    --series-6: #1cbdb8;

    --stage-top: #6da7ec;
    --stage-confirmed: #2a78d6;
    --stage-success: #184f95;
  }
}

/* --- Ручное переключение темы (кнопка в топбаре, theme-toggle.js) ---
   Без выбора пользователя тема по-прежнему следует prefers-color-scheme
   (правило выше) — [data-theme] на <html> появляется только после явного
   клика (или если раньше уже выбирали — см. инлайн-скрипт в base.html).
   :root[data-theme="..."] специфичнее голого :root внутри @media, поэтому
   всегда перебивает системную тему, независимо от порядка правил в файле. */
:root[data-theme="dark"] {
  --surface-1: #161a23;
  --surface-2: #1d222d;
  --page-plane: #0e1116;
  --text-primary: #f5f6f8;
  --text-secondary: #b7bdca;
  --text-muted: #838a99;
  --gridline: #2a2f3a;
  --baseline: #3a4152;
  --border: rgba(255, 255, 255, 0.08);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.35);
  --series-1: #3987e5;
  --series-2: #c98500;
  --series-3: #199e70;
  --series-4: #e66767;
  --series-5: #9c7ce0;
  --series-6: #1cbdb8;
  --stage-top: #6da7ec;
  --stage-confirmed: #2a78d6;
  --stage-success: #184f95;
}
:root[data-theme="light"] {
  --surface-1: #ffffff;
  --surface-2: #f4f6f9;
  --page-plane: #eef1f6;
  --text-primary: #10141c;
  --text-secondary: #4d5566;
  --text-muted: #838a99;
  --gridline: #e6e9ef;
  --baseline: #c7cdd9;
  --border: rgba(11, 31, 58, 0.10);
  --shadow: 0 1px 2px rgba(11, 31, 58, 0.06), 0 8px 24px rgba(11, 31, 58, 0.06);
  --series-1: #2a78d6;
  --series-2: #eda100;
  --series-3: #1baf7a;
  --series-4: #e34948;
  --series-5: #8a63d2;
  --series-6: #0aa5a0;
  --stage-top: #86b6ef;
  --stage-confirmed: #2a78d6;
  --stage-success: #104281;
}
:root[data-theme="dark"] .stat-value.accent { color: var(--brand-yellow); }
:root[data-theme="light"] .stat-value.accent { color: var(--brand-navy); }
:root[data-theme="dark"] .order-phone-link.accent { color: var(--brand-yellow); }
:root[data-theme="light"] .order-phone-link.accent { color: var(--brand-navy); }
:root[data-theme="dark"] .login-box h1 { color: var(--brand-yellow); }
:root[data-theme="light"] .login-box h1 { color: var(--brand-navy); }

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--page-plane);
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
}

/* --- Топбар: фирменный навы+жёлтый, не зависит от темы --- */
.topbar {
  display: flex;
  align-items: center;
  gap: 28px;
  padding: 0 24px;
  height: 56px;
  background: linear-gradient(90deg, var(--brand-navy), var(--brand-navy-2));
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.15);
  position: sticky;
  top: 0;
  z-index: 10;
}

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 15px;
  color: #fff;
  text-decoration: none;
  letter-spacing: 0.2px;
}
.brand-logo {
  width: 18px;
  height: 18px;
  display: block;
}

.nav { display: flex; gap: 4px; flex: 1; }
.nav a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: rgba(255, 255, 255, 0.72);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  padding: 8px 14px;
  border-radius: 7px;
  transition: background 0.15s, color 0.15s;
}
.nav a:hover { color: #fff; background: rgba(255, 255, 255, 0.08); }
.nav a.active { color: var(--brand-navy); background: var(--brand-yellow); }
.nav-icon { width: 15px; height: 15px; }

/* --- Бургер-меню разделов (см. CLAUDE.md) — на широком десктопе не
   показывается вообще (.nav всегда виден в строке); ниже порога .nav
   выпадает панелью под топбаром, открывается/закрывается этой кнопкой
   (dashboard.js: initNavBurger, класс .nav-open — не переиспользуем
   .op-picker-panel/[hidden], т.к. выше порога .nav должен быть виден
   ВСЕГДА независимо от состояния кнопки, а [hidden] так просто не
   выключить обратно без лишних оговорок в каждом брейкпоинте).
   Порог — 1440px, а не 900px как у остальных "планшетных" правил ниже:
   при всех разделах меню (Продажи/Склад/Финансы/.../Настройки) топбар
   упирается в ~1418px собственного контента (проверено вживую) — это
   ПРЕДСУЩЕСТВУЮЩАЯ проблема, не привнесённая адаптивом, но она означает,
   что бургер должен появляться раньше обычного "планшетного" 900px,
   иначе на ноутбучных 1280-1366px топбар обрезается по правому краю уже
   сегодня, без какого-либо телефона/планшета. */
.nav-burger { display: none; }
@media (max-width: 1440px) {
  .nav-burger { display: inline-flex; }
  .nav {
    display: none;
    position: absolute;
    top: 56px;
    left: 0;
    right: 0;
    z-index: 20;
    flex-direction: column;
    gap: 2px;
    padding: 8px;
    background: linear-gradient(180deg, var(--brand-navy), var(--brand-navy-2));
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
  }
  .nav.nav-open { display: flex; }
  .nav a { width: 100%; }
}
@media (max-width: 900px) {
  .topbar { gap: 10px; padding: 0 12px; }
}
@media (max-width: 480px) {
  .user { display: none; }
}

/* --- Иконки: базовый inline-SVG (см. _macros.html: macro icon) --- */
.icon { flex-shrink: 0; display: inline-block; vertical-align: middle; }

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: rgba(255, 255, 255, 0.72);
  cursor: pointer;
}
.icon-btn:hover { color: #fff; background: rgba(255, 255, 255, 0.08); }
.icon-btn.active { color: var(--brand-navy); background: var(--brand-yellow); }

/* --- Переключатель темы: два SVG в разметке всегда, виден только один
   (какую тему предлагает включить клик — солнце на тёмной теме, луна на
   светлой) — переключает theme-toggle.js добавлением/снятием классов на
   самой кнопке, без привязки к prefers-color-scheme напрямую (иначе кнопка
   не отражала бы явный выбор пользователя, только системный). --- */
.theme-icon { width: 17px; height: 17px; }
.theme-icon-moon { display: none; }
#theme-toggle.is-dark .theme-icon-sun { display: none; }
#theme-toggle.is-dark .theme-icon-moon { display: block; }

.user { color: rgba(255, 255, 255, 0.85); font-size: 13px; }

.topbar form { margin: 0; }
.topbar button.link-btn {
  background: none;
  border: none;
  color: rgba(255, 255, 255, 0.72);
  cursor: pointer;
  font-size: 13px;
  padding: 6px 10px;
}
.topbar button.link-btn:hover { color: #fff; }

/* --- Подраздел (второй уровень навигации внутри раздела, например
   "Продажи" -> "Главная сводка") — просто текст, без плашек-кнопок, в
   отличие от .nav/.topbar (те на тёмном фоне и заметно крупнее). --- */
.subnav {
  display: flex;
  gap: 16px;
  padding: 4px 24px;
  align-items: center;
  background: var(--surface-1);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  flex-wrap: nowrap;
}
.subnav a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary);
  text-decoration: none;
  padding: 4px 0;
  white-space: nowrap;
  flex-shrink: 0;
}
.subnav a:hover { color: var(--text-primary); }
.subnav a.active { color: var(--series-1); font-weight: 600; }
.subnav-icon { width: 14px; height: 14px; }

main { padding: 14px 24px 24px; }
@media (max-width: 640px) { main { padding: 12px 12px 16px; } }

h1 { font-size: 22px; margin: 0 0 4px; letter-spacing: -0.2px; }
h2 { font-size: 15px; color: var(--text-secondary); margin: 0 0 14px; font-weight: 600; }
.page-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 10px; flex-wrap: wrap; }
.page-head h1 { margin: 0; }
.page-sub { color: var(--text-muted); font-size: 13px; margin: 0 0 20px; }
.page-head .page-sub { margin: 0; }

/* --- Кнопки --- */
button, .btn {
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  border-radius: 7px;
  border: none;
  cursor: pointer;
  padding: 8px 16px;
}
.btn-primary, .filters button, .login-box button {
  background: var(--brand-yellow);
  color: var(--brand-navy);
}
.btn-primary:hover, .filters button:hover, .login-box button:hover { background: var(--brand-yellow-dark); }
.btn-secondary {
  background: var(--surface-2);
  color: var(--text-secondary);
  border: 1px solid var(--border);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.btn-secondary:hover { color: var(--text-primary); border-color: var(--brand-navy); }
.btn-icon {
  padding: 8px 10px;
  justify-content: center;
  line-height: 1;
}
.btn-primary { display: inline-flex; align-items: center; gap: 6px; }
.btn .icon, .btn-primary .icon, .btn-secondary .icon { width: 14px; height: 14px; }
.table-card tfoot .icon { width: 14px; height: 14px; vertical-align: -3px; margin-right: 3px; }

/* --- Панель фильтров: пресеты периода + гранулярность + сравнение --- */
.controls {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow);
  padding: 14px 16px;
  margin-bottom: 12px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
}

.preset-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.controls-lead-icon { width: 15px; height: 15px; color: var(--text-muted); margin-right: 2px; }
.preset-pill {
  font-size: 13px;
  font-weight: 500;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-secondary);
  text-decoration: none;
  white-space: nowrap;
}
.preset-pill:hover { border-color: var(--brand-navy); color: var(--text-primary); }
.preset-pill.active {
  background: var(--brand-yellow);
  border-color: var(--brand-yellow);
  color: var(--brand-navy);
}

.control-group { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-secondary); flex-wrap: wrap; min-width: 0; }
/* Попап "Перепутали" — цена товара расчётная (не инпут, см. pricing/),
   всё должно остаться в одну строку с заголовком независимо от ширины
   диалога, а не переноситься под него. */
.misdelivered-price-row { flex-wrap: nowrap; }
.misdelivered-price-value { color: var(--text-muted); white-space: nowrap; }
.misdelivered-price-diff { font-weight: 600; white-space: nowrap; }
.misdelivered-price-diff.price-diff-overpay { color: var(--status-critical); }
.misdelivered-price-diff.price-diff-save { color: var(--status-good); }

/* --- Быстрые фильтры (Канал/Оплата/Покупка/Клиент) — компактные пилюли,
   без отдельной "Все": ничего не нажато = фильтр не применяется, повторный
   клик по активной снимает её же. --- */
.quick-filter-group { display: flex; gap: 4px; flex-wrap: wrap; }
.quick-filter-pill {
  font-size: 12.5px;
  font-weight: 500;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-secondary);
  text-decoration: none;
  white-space: nowrap;
}
.quick-filter-pill:hover { border-color: var(--brand-navy); color: var(--text-primary); }
.quick-filter-pill.active {
  background: var(--brand-yellow);
  border-color: var(--brand-yellow);
  color: var(--brand-navy);
}
.control-group input[type="date"], .control-group input[type="text"], .control-group select {
  font-size: 13px;
  padding: 5px 8px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
  min-width: 0;
  max-width: 100%;
}

/* --- Несколько фильтров "доп. поле" (динамические строки) --- */
.attr-filters { flex-wrap: wrap; align-items: flex-start; }
#attr-filter-rows { display: flex; flex-direction: column; gap: 6px; }
.attr-filter-row { display: flex; align-items: center; gap: 6px; }
.attr-remove-btn {
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 13px;
  padding: 4px 6px;
  border-radius: 6px;
}
.attr-remove-btn:hover { background: var(--surface-2); color: var(--status-critical); }
#attr-add-btn {
  border: 1px dashed var(--border);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 12.5px;
  padding: 5px 10px;
  border-radius: 6px;
  align-self: flex-start;
}
#attr-add-btn:hover { border-color: var(--brand-navy); color: var(--text-primary); }

.segmented { display: flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
.segmented a {
  padding: 5px 12px;
  font-size: 13px;
  text-decoration: none;
  color: var(--text-secondary);
  background: var(--surface-2);
  border-right: 1px solid var(--border);
}
.segmented a:last-child { border-right: none; }
.segmented a.active { background: var(--brand-navy); color: #fff; }
/* .segmented с <button> вместо <a> (переключатель вида "Списком"/"По
   рейсам" на отчёте водителя — JS-переключение видимости, не навигация) —
   тот же внешний вид, сброшен браузерный стиль кнопки. */
.segmented button {
  padding: 5px 12px;
  font: inherit;
  font-size: 13px;
  border: none;
  border-right: 1px solid var(--border);
  cursor: pointer;
  color: var(--text-secondary);
  background: var(--surface-2);
}
.segmented button:last-child { border-right: none; }
.segmented button.active { background: var(--brand-navy); color: #fff; }
/* Переключатели вида (например "Разбивка: по сотрудникам/по группам/по
   складам/по источникам/по ЖК") на узком экране не помещаются в строку —
   .segmented { overflow: hidden } рассчитан на десктоп (только скругляет
   углы) и молча ОБРЕЗАЕТ лишние пункты, а не переносит — часть режимов
   становится физически недостижима с телефона. Ниже 900px меняем на
   горизонтальный скролл (углы контейнера всё равно скруглены и при
   overflow-x:auto — скругление живёт на border-radius самого .segmented,
   не зависит от hidden/auto). */
@media (max-width: 900px) {
  .segmented { overflow-x: auto; }
  .segmented a, .segmented button { flex-shrink: 0; white-space: nowrap; }
}

/* --- Отчёты водителя: вкладки страницы отчёта (Точки/Деньги/На склад/
   Зарплата/История, 2026-08-11) — разбивка ВСЕЙ страницы на разделы, не
   локальный переключатель вида одной таблицы (как .segmented) — сознательно
   другой стиль (подчёркивание текста, не заполненная кнопка-пилюля), чтобы
   визуально не путаться с кнопками управления (Сдать выручку и т.п.),
   которые теперь разложены ВНУТРИ самих вкладок. Активный цвет — тот же
   --series-1, что у .subnav a.active вверху страницы (уже проверенный,
   контрастный в обеих темах, при этом другой акцент, чем жёлтый/навy у
   кнопок — снимает визуальное сходство). JS-переключение видимости
   панелей, состояние в location.hash (driver_reports.js). */
.page-tabs { display: flex; gap: 4px; margin: 20px 0 4px; flex-wrap: wrap; }
.page-tab-btn {
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-secondary);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 10px 14px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.page-tab-btn .icon { width: 15px; height: 15px; }
.page-tab-btn .tab-alert-icon { width: 13px; height: 13px; color: var(--color-danger, #c62828); }
.page-tab-btn:hover { color: var(--text-primary); }
.page-tab-btn.active { color: var(--series-1); border-bottom-color: var(--series-1); }

/* --- Отчёты водителя: кнопки внутри вкладки (Заправка/+Точка и т.п.,
   2026-08-11) — сознательно БЕЗ карточного фона .controls (тот уместен
   как самостоятельный блок тулбара, а не как строка кнопок внутри уже
   существующей вкладки — двойная "белая подложка" визуально дублировала
   границу вкладки прямо под ней). Отступ сверху — чтобы не липнуть к
   вкладкам; сами кнопки — с белым фоном (--surface-1, как у карточек),
   у обычных .btn-secondary фон --surface-2 (серый) сливался с фоном
   страницы (по просьбе пользователя). --- */
.tab-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 16px; margin-bottom: 16px; }
.tab-actions .btn-secondary { background: var(--surface-1); }

/* --- Отчёты водителя: сопоставление заказов с рейсами БТС (schema `bts`) --- */
.trip-match-icon { display: inline-flex; align-items: center; vertical-align: middle; margin-right: 4px; }
.trip-match-icon .icon { width: 15px; height: 15px; }
.trip-match-in_trip .trip-match-icon { color: var(--status-good); }
.trip-match-no_trip .trip-match-icon { color: var(--text-muted); }
.trip-match-extra .trip-match-icon { color: var(--status-warning); }
tr.trip-match-extra { background: rgba(250, 178, 25, 0.08); }
.trip-group-table { width: 100%; margin-bottom: 18px; }
/* Каждый рейс — отдельная <table>, ширина колонок по умолчанию считается
   независимо по содержимому своей таблицы — из-за этого столбцы "плыли"
   между блоками. Фиксируем колонки через общий colgroup (orders_colgroup
   в driver_report_detail.html), используется и во flat-, и в grouped-виде,
   чтобы они тоже совпадали при переключении. */
/* min-width — иначе table-layout:fixed с процентными <col> просто сжимает
   колонки до нечитаемой мешанины на узком экране вместо того, чтобы дать
   .table-wrap прокрутить их горизонтально (проценты делят ЛЮБУЮ ширину,
   которую получит сама таблица, overflow-x:auto родителя не включается,
   пока таблица не станет шире контейнера). */
.orders-table { table-layout: fixed; min-width: 720px; }
.trip-group-head th {
  background: var(--surface-2);
  font-size: 13px;
  text-transform: none;
  letter-spacing: normal;
  color: var(--text-primary);
  font-weight: 700;
  padding: 8px 10px;
}
/* Вся шапка рейса — кнопка сворачивания (клик по .trip-group-head, см.
   driver_reports.js), стрелка разворачивается вместе с содержимым.
   Свёрнуто — видна только строка с названием рейса, таблица заказов и
   строка-заголовок колонок скрыты (второй tr в thead). */
.trip-group-head { cursor: pointer; user-select: none; }
/* display:flex вешаем на внутренний span, не на сам th — th должен
   остаться table-cell, иначе colspan перестаёт растягивать ячейку на всю
   ширину таблицы и она сжимается по контенту. */
.trip-group-head-inner { display: flex; align-items: center; gap: 6px; }
.trip-toggle-icon { width: 16px; height: 16px; flex: none; transition: transform 0.15s ease; }
.trip-collapsed .trip-toggle-icon { transform: rotate(-90deg); }
.trip-collapsed thead tr:not(.trip-group-head), .trip-collapsed tbody { display: none; }

/* --- Выпадающий мультивыбор с чекбоксами (замена select[multiple]) --- */
.multiselect { position: relative; display: inline-block; }
.multiselect-toggle {
  font-size: 13px;
  padding: 5px 10px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
  cursor: pointer;
  min-width: 140px;
  max-width: 240px;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.multiselect-toggle:hover { border-color: var(--brand-navy); }
.multiselect-panel {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 20;
  min-width: 220px;
  max-height: 260px;
  overflow-y: auto;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow);
  padding: 6px;
}
.multiselect.open .multiselect-panel { display: block; }
.multiselect-panel label {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 6px;
  font-size: 13px;
  border-radius: 5px;
  cursor: pointer;
  white-space: nowrap;
}
.multiselect-panel label:hover { background: var(--surface-2); }
.multiselect-panel input[type="checkbox"] { accent-color: var(--brand-navy); width: 14px; height: 14px; flex-shrink: 0; margin: 0; }

.toggle-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
}
.toggle-label input { accent-color: var(--brand-navy); width: 15px; height: 15px; cursor: pointer; margin: 0; }

/* --- Строка режимов сравнения (переносится на новую строку внутри той же
   карточки .controls — flex-basis:100% всегда начинает новую строку в
   родительском flex-wrap) --- */
.compare-controls {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
  font-size: 13px;
  color: var(--text-secondary);
}
.compare-period-inputs { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-secondary); flex-wrap: wrap; }
.compare-period-inputs input[type="date"] {
  font-size: 13px;
  padding: 5px 8px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
}

/* --- Иконка-подсказка (заменяет текстовые примечания под плитками) --- */
.info-icon {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1px solid var(--baseline);
  color: var(--text-muted);
  font-size: 12px;
  font-style: italic;
  font-family: Georgia, "Times New Roman", serif;
  cursor: default;
  user-select: none;
}
.info-icon:hover, .info-icon:focus { border-color: var(--brand-navy); color: var(--brand-navy); outline: none; }
.info-tooltip {
  display: none;
  position: absolute;
  top: 24px;
  right: 0;
  z-index: 5;
  width: 340px;
  max-width: 60vw;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface-1);
  box-shadow: var(--shadow);
  color: var(--text-secondary);
  font-size: 12.5px;
  font-style: normal;
  line-height: 1.5;
  text-align: left;
}
.info-icon:hover .info-tooltip, .info-icon:focus .info-tooltip { display: block; }

/* --- Статы --- */
.stat-row { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; margin-bottom: 20px; }
@media (max-width: 1100px) { .stat-row { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 640px) { .stat-row { grid-template-columns: repeat(2, 1fr); } }
.stat-tile {
  position: relative;
  min-width: 0;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow);
  padding: 16px 18px;
}
.stat-tile.metric-hidden { display: none; }

/* --- Иконка глаза в углу плитки — режим конфиденциальности одной метрики
   (dashboard.js: initMetricPrivacy). Показана всегда полупрозрачно, ярче
   на hover — не должна перетягивать внимание от самих цифр. --- */
.metric-eye-btn {
  position: absolute; top: 8px; right: 8px;
  width: 20px; height: 20px; padding: 0; border: none; background: transparent;
  color: var(--text-muted); cursor: pointer; border-radius: 4px;
  display: inline-flex; align-items: center; justify-content: center;
  opacity: 0.45;
}
.metric-eye-btn:hover { opacity: 1; background: var(--surface-2); }
.metric-eye-btn .icon { width: 14px; height: 14px; }
.metric-eye-icon-off { display: none; }
.metric-blurred .metric-eye-btn { opacity: 0.85; }
.metric-blurred .metric-eye-icon-open { display: none; }
.metric-blurred .metric-eye-icon-off { display: inline-flex; }
/* Размывается только само значение (числа) — подпись/иконки остаются
   читаемыми, чтобы было понятно, какая именно метрика скрыта. */
.metric-blurred .stat-value, .metric-blurred .dual-slot {
  filter: blur(7px);
  user-select: none;
}

/* --- Кнопка "Настроить метрики" (dashboard.js: initMetricSettings) —
   переиспользует готовые .multiselect/.multiselect-panel (тот же чекбокс-
   список без поиска, что и у фильтров Владелец/Проект/Склад, см. выше),
   только без формы/initMultiSelects — переключение мгновенное, в
   localStorage, а не в query-параметр. #metric-settings-slot — просто
   якорь в шапке страницы, куда JS вставляет кнопку+панель. --- */
#metric-settings-slot { display: inline-flex; margin-left: auto; }
.metric-settings-toggle .icon { width: 15px; height: 15px; }
/* Кнопка живёт у правого края шапки (margin-left: auto на слоте) —
   стандартное .multiselect-panel{left:0} уводило бы панель за край
   экрана, поэтому здесь открываем её от правого края кнопки. */
.metric-settings-wrap .multiselect-panel { left: auto; right: 0; }
.stat-label {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 12.5px;
  color: var(--text-muted);
  font-weight: 500;
}
.stat-label .info-icon { width: 14px; height: 14px; font-size: 10px; }
.stat-label .icon { width: 14px; height: 14px; }
.stat-value.stat-value-accent { color: var(--series-1); }
.stat-value { display: block; font-size: 26px; font-weight: 700; margin-top: 4px; letter-spacing: -0.3px; }
/* Вторая строка плитки без сравнения (например, "N приёмок" на /finance) —
   тот же приглушённый стиль, что и у .stat-delta-abs. */
.stat-sub { display: block; margin-top: 6px; font-size: 12.5px; font-weight: 500; color: var(--text-muted); }
/* Короткая приписка в шапке карточки (итог за период на /finance). */
.card-head-note { font-size: 12.5px; color: var(--text-muted); font-weight: 500; }
.stat-value.accent { color: var(--brand-navy); }
@media (prefers-color-scheme: dark) {
  .stat-value.accent { color: var(--brand-yellow); }
}

/* --- Изменение к предыдущему периоду (стрелка + % + абсолют) --- */
.stat-delta { display: block; margin-top: 6px; font-size: 12.5px; font-weight: 600; white-space: nowrap; }
.stat-delta-up { color: var(--status-good); }
.stat-delta-down { color: var(--status-critical); }
.stat-delta-flat { color: var(--text-muted); }
.stat-delta-abs { font-weight: 500; color: var(--text-muted); }

/* --- Плитка с двумя переключаемыми метриками (заказы/товары, разгрузки/
   комиссия и т.п.) — заголовок работает как переключатель "какая метрика
   основная" (крупная, со сравнением), вторая показывается мелко в скобках,
   без сравнения. Чисто на клиенте (оба значения уже отрисованы сервером),
   переключение не требует перезагрузки страницы. Заголовки — тот же шрифт/
   цвет/начертание, что и у обычных однозначных плиток (.stat-label) —
   активная сторона отмечается не жирным, а жёлтым пунктирным подчёркиванием. --- */
.dual-toggle { display: inline-flex; align-items: center; gap: 6px; }
.dual-toggle-btn {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  border-radius: 2px;
}
/* Разделитель — отдельный элемент, не ::after у кнопки: некоторые браузеры
   всё равно продолжают подчёркивание родителя через псевдоэлемент, а тут
   это просто сосед, к подчёркиванию кнопки отношения не имеющий. */
.dual-toggle-sep { color: var(--text-muted); }
.dual-metric[data-primary="a"] .dual-toggle-btn[data-role="a"],
.dual-metric[data-primary="b"] .dual-toggle-btn[data-role="b"] {
  text-decoration: underline dashed var(--brand-yellow);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
.dual-toggle-btn:focus-visible { outline: 1px dashed var(--brand-yellow); outline-offset: 2px; }

.dual-metric .stat-value { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px; }
.dual-slot[data-role="a"] { order: 1; }
.dual-slot[data-role="b"] { order: 2; font-size: 14px; font-weight: 500; color: var(--text-muted); }
.dual-slot[data-role="b"]::before { content: "("; }
.dual-slot[data-role="b"]::after { content: ")"; }
.dual-metric[data-primary="b"] .dual-slot[data-role="a"] { order: 2; font-size: 14px; font-weight: 500; color: var(--text-muted); }
.dual-metric[data-primary="b"] .dual-slot[data-role="a"]::before { content: "("; }
.dual-metric[data-primary="b"] .dual-slot[data-role="a"]::after { content: ")"; }
.dual-metric[data-primary="b"] .dual-slot[data-role="b"] { order: 1; font-size: 26px; font-weight: 700; color: inherit; }
.dual-metric[data-primary="b"] .dual-slot[data-role="b"]::before { content: none; }
.dual-metric[data-primary="b"] .dual-slot[data-role="b"]::after { content: none; }

.dual-delta { display: block; }
.dual-delta[data-role="b"] { display: none; }
.dual-metric[data-primary="b"] .dual-delta[data-role="a"] { display: none; }
.dual-metric[data-primary="b"] .dual-delta[data-role="b"] { display: block; }

/* --- Карточки графика/таблицы --- */
.chart-card, .table-card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow);
  padding: 18px;
  margin-bottom: 20px;
}
.chart-card .card-head, .table-card .card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
/* .card-head с justify-content:space-between растягивает ЛЮБЫЕ 2 прямых
   ребёнка на разные края — если единственные дети это <h2> и значок
   подсказки (stat_info), значок улетал в правый край вместо места сразу
   после заголовка (2026-08-11, найдено на "+ Точка"). Группируем
   заголовок+значок в один флекс-блок, тогда пара "title, что-то ещё"
   (ссылка/бейдж) снова ровно 2 ребёнка card-head, и всё на своих местах
   независимо от того, есть третий элемент в шапке или нет. */
.card-head-title { display: flex; align-items: center; gap: 6px; }
.chart-empty { color: var(--text-muted); font-style: italic; padding: 40px 0; text-align: center; }
.table-card-subhead {
  font-size: 14px; color: var(--text-secondary); font-weight: 600;
  margin: 20px 0 10px; padding-top: 16px; border-top: 1px solid var(--border);
}

/* Настройки -> Документация -> Поиск (settings_docs_search.html) — content
   записей хранится готовым HTML (см. settings/queries.py), эти правила
   задают типографику ЧИТАЕМОГО текста внутри .doc-entry, не общий сброс. */
.doc-card { max-width: 760px; }
.doc-entry { font-size: 14px; line-height: 1.6; color: var(--text-primary); }
.doc-entry > *:first-child { margin-top: 0; }
.doc-entry > *:last-child { margin-bottom: 0; }
.doc-entry p { margin: 0 0 12px; }
.doc-entry ul { margin: 0 0 12px; padding-left: 20px; }
.doc-entry li { margin-bottom: 4px; }
.doc-entry h3 {
  font-size: 14px; color: var(--text-secondary); font-weight: 700;
  margin: 24px 0 10px; padding-top: 16px; border-top: 1px solid var(--border);
}
.doc-entry code {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 4px; padding: 1px 6px; font-size: 0.9em;
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
}
.doc-level { background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; margin-bottom: 12px; }
.doc-level-head { display: flex; align-items: center; gap: 8px; font-weight: 700; margin-bottom: 6px; }
.doc-substep { margin: 10px 0 10px 4px; padding-left: 12px; border-left: 2px solid var(--border); }
.doc-substep:last-child { margin-bottom: 0; }
.doc-substep-title { font-weight: 600; margin-bottom: 3px; }
.doc-example {
  margin-top: 8px; padding: 8px 12px; border-radius: 8px;
  background: var(--surface-1); border-left: 3px solid var(--status-good); font-size: 13px;
}
.doc-example-label {
  display: block; font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; color: var(--text-muted); margin-bottom: 4px;
}
/* Дерево топологии WMS (wms/templates/topology.html + wms.js) — табличный
   вид: склад -> ряд -> стеллаж -> уровень -> ячейка, каждый узел
   разворачивается кликом без перезагрузки. Все строки (независимо от
   глубины вложенности) используют ОДИН и тот же grid-template-columns —
   отступ вложенности задаётся padding-left только у .tree-name-cell
   (инлайн-стиль, посчитан из depth), поэтому колонка "Ячейки" всегда
   выровнена вертикально, сама строка не сдвигается целиком. Единственный
   счётчик — "Ячейки" (по просьбе пользователя 2026-08-03: Ряды/Стеллажи/
   Уровни оказались не нужны в этом виде) — но он всегда АГРЕГАТ по всему
   поддереву узла (сколько ячеек внутри, на любой глубине), не счётчик
   прямых детей. */
.btn-sm { padding: 4px 8px; font-size: 12px; }
.wh-tree, .wh-tree ul.tree-children { list-style: none; margin: 0; padding: 0; }
.wh-tree ul.tree-children { margin-top: 2px; }
.tree-node { margin-bottom: 1px; }
.tree-header, .tree-row {
  display: grid;
  /* Последние 3 колонки — ФИКСИРОВАННОЙ ширины, не auto: .tree-row каждого
     узла — свой независимый grid (не общая таблица), auto считал бы
     ширину по содержимому ЭТОЙ конкретной строки (кнопка "+ Ряд" есть не
     у всех — например, у склада с подскладами её нет вовсе, см.
     topology.html) — из-за этого 1fr у имени "доедал" разное количество
     места в разных строках, и колонка "Ячейки" съезжала относительно
     заголовка и других строк. Фиксированная ширина убирает эту
     зависимость от содержимого конкретной строки. */
  grid-template-columns: minmax(160px, 1fr) 64px 110px 100px 90px;
  align-items: center; gap: 8px; padding: 5px 6px;
  border-radius: 6px; font-size: 13px;
}
.tree-header {
  font-size: 11px; font-weight: 600; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.02em; padding: 0 6px 6px;
}
.tree-header span:not(:first-child) { text-align: center; }
.tree-row:hover { background: var(--surface-2); }
.tree-name-cell { display: flex; align-items: center; gap: 8px; min-width: 0; }
.tree-toggle {
  background: none; border: none; cursor: pointer; color: var(--text-muted);
  font-size: 11px; width: 16px; flex: none; text-align: center; padding: 0;
}
.tree-toggle-spacer { display: inline-block; width: 16px; flex: none; }
.tree-label { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tree-store-meta { color: var(--text-muted); font-size: 12px; white-space: nowrap; }
.tree-count { text-align: center; color: var(--text-secondary); font-size: 12.5px; }
.tree-delete-form { display: inline; margin: 0; }
.cell-type-select, .cell-capacity-input { width: 100%; box-sizing: border-box; }

/* --- Попапы-<dialog> (сейчас используются только в "Отчётах водителя" —
   корректировка/оплата/проверка комплектации на карточке заказа; начать-
   завершить день/сдать выручку/заправка на отчёте — но стиль общий на
   элемент dialog, не завязан на конкретные id, чтобы работал для любых
   будущих попапов кабинета тоже). --- */
dialog {
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow);
  background: var(--surface-1);
  color: var(--text-primary);
  padding: 20px;
  min-width: 280px;
  max-width: min(480px, 92vw);
  max-height: 85vh;
  overflow-y: auto;
}
dialog::backdrop { background: rgba(11, 31, 58, 0.35); }
dialog h3 { margin: 0 0 12px; font-size: 15px; }
dialog .control-group { margin-bottom: 10px; }

/* --- Отчёты водителя: чек-лист "Проверка комплектации" (таблица) --- */
#picking-check-dialog input[type="checkbox"] { accent-color: var(--brand-navy); width: 16px; height: 16px; cursor: pointer; }

/* --- Отчёты водителя: чек-лист "Выгрузка клиенту" — чек-бокс крупнее,
   т.к. попап рассчитан на использование прямо от машины (по просьбе
   пользователя) --- */
#delivery-check-dialog input[type="checkbox"] { accent-color: var(--brand-navy); width: 22px; height: 22px; cursor: pointer; }

/* --- Отчёты водителя: попап "Выгрузка клиенту" — кнопка "Проблема" как
   иконка (не текстовая кнопка, строки попапа компактнее) + количество,
   уже отменённое по этой позиции, справа от иконки --- */
.problem-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--status-warning);
  cursor: pointer;
  vertical-align: middle;
}
.problem-icon-btn:hover { background: var(--surface-1); border-color: var(--status-warning); }
.problem-icon-btn .icon { width: 15px; height: 15px; }
.payment-warning { display: flex; align-items: center; gap: 6px; color: var(--status-warning); font-weight: 600; }
.payment-warning .icon { width: 15px; height: 15px; }

/* --- Отчёты водителя: попап "Оплата" — ползунок доли нал/карта для
   смешанного способа (двигает оба поля суммы синхронно) --- */
.payment-slider-group { gap: 10px; }
.payment-slider { flex: 1; accent-color: var(--brand-navy); cursor: pointer; }
.payment-slider-label { font-size: 12.5px; color: var(--text-secondary); white-space: nowrap; min-width: 70px; }
#payment-slider-card-label { text-align: right; }
/* --- Отчёты водителя: попап "Выгрузка клиенту" — статус по позиции
   (кол-во совпало + штрихкод отсканирован + нет корректировок) и сканер
   камерой --- */
.delivery-status-icon { display: inline-flex; align-items: center; }
.delivery-status-icon .icon { width: 18px; height: 18px; }
.delivery-status-icon-check, .delivery-status-icon-scanned, .delivery-status-icon-pending { display: none; }
.delivery-status-ok .delivery-status-icon-check { display: inline-flex; color: var(--status-good); }
.delivery-status-pending .delivery-status-icon-pending { display: inline-flex; color: var(--text-muted); }
/* Штрихкод реально отсканирован (а не просто совпало количество без
   штрихкода/скана) — та же зелёная подсветка, но иконка штрихкода вместо
   галочки, чтобы отличать способ подтверждения. */
.delivery-status-scanned .delivery-status-icon-check { display: none; }
.delivery-status-scanned .delivery-status-icon-scanned { display: inline-flex; color: var(--status-good); }
.delivery-shipped-btn { font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Подсвечена зелёным, когда позиция полностью подтверждена (см.
   PositionRow.delivery_confirmed) — тот же критерий, что и галка слева. */
.delivery-shipped-ok {
  background: rgba(12, 163, 12, 0.12);
  border-color: var(--status-good);
  color: var(--status-good);
}
.delivery-shipped-ok:hover { background: rgba(12, 163, 12, 0.2); }
/* Кнопка "Принять возврат" (см. driver_reports/queries/linked_returns.py)
   — та же зелёная подсветка "принято полностью", что и у "Выгружено". */
.return-receipt-btn { font-variant-numeric: tabular-nums; white-space: nowrap; }
.return-receipt-ok {
  background: rgba(12, 163, 12, 0.12);
  border-color: var(--status-good);
  color: var(--status-good);
}
.return-receipt-ok:hover { background: rgba(12, 163, 12, 0.2); }
/* Блок "Запланированный возврат" на карточке заказа — карточка на каждый
   привязанный возврат отдельно (их может быть несколько на один заказ). */
.linked-return-card { margin-bottom: 16px; }
.linked-return-card:last-child { margin-bottom: 0; }
/* Подсветка всей строки — та же позиция полностью выгружена/без
   корректировок (см. PositionRow.delivery_confirmed), и в таблице
   "Товары", и в попапе "Выгрузка клиенту" (см. data-delivery-confirmed-row). */
tr.row-delivery-confirmed > td { background: rgba(12, 163, 12, 0.08); }
/* Кол-во, списанное корректировкой ("Проблема") — прямо внутри кнопки
   "Выгружено" (0 / −1 / 3), а не отдельной плашкой рядом. */
.delivery-shipped-corrected { color: var(--status-critical); font-weight: 700; }
/* Диалоги "Выгрузка клиенту"/"Проверка комплектации" — таблица с
   несколькими колонками, стандартной ширины попапа (min(480px, 92vw))
   тесно; одинаковая ширина у обоих — те же по структуре таблицы. */
#delivery-check-dialog, #picking-check-dialog { max-width: min(720px, 96vw); }
/* Общие классы для ДВУХ сканеров (список позиций + попап одной позиции,
   см. driver_reports.js: startBarcodeScanner) — id у элементов свои
   (нужны JS для двух независимых видео/кнопок), стиль один. */
/* Поле ручного ввода штрихкода + кнопка-иконка сканера камерой в одной
   строке (вместо отдельной кнопки "Добавить" — поле само отправляется по
   Enter/потере фокуса, см. driver_reports.js). */
.barcode-input-group { margin-top: 8px; }
.barcode-input-group input[type="text"] { flex: 1; }
.delivery-scan-view { margin-top: 10px; }

/* --- Попап "Выгружено" по одной позиции: "Заказано"/"Осталось выгрузить" --- */
.delivery-ordered-info { display: flex; flex-wrap: wrap; gap: 4px 16px; }
.delivery-ordered-info .page-sub { margin: 0; }

/* Поле "Выгружено" со степпером -/+ рядом (уже, чем раньше, но выше — легче
   попасть пальцем) — кнопка сканера теперь в этой же строке, прижата
   к правому краю (margin-left: auto). */
.qty-stepper-group input[type="text"] {
  flex: none;
  width: 64px;
  height: 44px;
  box-sizing: border-box;
  text-align: center;
  font-size: 16px;
  font-weight: 600;
}
.qty-step-btn {
  width: 40px;
  height: 44px;
  flex: none;
  padding: 0;
  font-size: 20px;
  line-height: 1;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
  cursor: pointer;
}
.qty-step-btn:hover { border-color: var(--brand-navy); background: var(--surface-1); }
.qty-stepper-group #delivery-scan-btn { margin-left: auto; height: 44px; width: 44px; flex: none; }

/* Подсказка "сколько упаковок + сколько россыпью" (например "3 паллеты +
   18 шт.") — внутри той же карточки, что и кнопки упаковок, в общем ряду
   с ними (не отдельной строкой), серым — справочная, не требует внимания. */
#delivery-shipped-packs-hint { margin: 0; color: var(--text-muted); white-space: nowrap; }

/* Цифровая клавиатура (0-9 + очистить/стереть) под полем "Выгружено" —
   ввод количества тапами, без неудобной мобильной клавиатуры. */
.numpad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 10px; }
.numpad-btn {
  padding: 14px 0;
  font-size: 18px;
  font-weight: 600;
  font-family: inherit;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
  cursor: pointer;
}
.numpad-btn:hover { border-color: var(--brand-navy); background: var(--surface-1); }
.numpad-btn-muted { color: var(--text-secondary); }
.delivery-scan-video {
  width: 100%;
  max-height: 280px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: #000;
  object-fit: cover;
  display: block;
  margin-bottom: 8px;
}

/* --- Отчёты водителя: отчёт — плашка "Автомобиль" рядом с кнопками
   управления (Сдать выручку/Заправка/...), без подписи-лейбла — по
   высоте как соседние кнопки (см. title= для подсказки взамен лейбла). --- */
.vehicle-badge {
  display: inline-flex;
  align-items: center;
  height: 34px;
  padding: 0 16px;
  border-radius: 7px;
  background: var(--stage-confirmed);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  box-sizing: border-box;
}

/* --- Отчёты водителя: "Телематика БТС" — компактные метрики (2026-08-11):
   не крупные плитки .stat-tile (перебивали внимание от денег), но и не
   одна еле-заметная строка мелким текстом — маленькие подписанные чипы. --- */
.metric-chip-row { display: flex; flex-wrap: wrap; gap: 8px 10px; margin-top: 4px; }
.metric-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 7px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  white-space: nowrap;
}
.metric-chip-label { font-size: 11.5px; color: var(--text-muted); font-weight: 600; }
.metric-chip-value { font-size: 13px; color: var(--text-primary); font-weight: 700; }
.metric-chip-danger { background: rgba(198, 40, 40, 0.08); border-color: var(--color-danger, #c62828); }
.metric-chip-danger .metric-chip-label,
.metric-chip-danger .metric-chip-value { color: var(--color-danger, #c62828); }
.timing-warning {
  display: flex; align-items: center; gap: 6px;
  margin-top: 10px; font-size: 13px; font-weight: 600; color: var(--color-danger, #c62828);
}
.timing-warning .icon { width: 16px; height: 16px; flex-shrink: 0; }

/* --- Отчёты водителя: карточка заказа, блок "Финансы" — "Долг" --- */
.debt-owed { color: var(--status-critical); }
.debt-settled { color: var(--status-good); }
.debt-overpaid { color: var(--status-warning); }

/* --- Отчёты водителя: карточка заказа — иконка-ссылка на МойСклад рядом
   с номером заказа (просто открывает исходник, без текста кнопки) --- */
.ms-link-icon { display: inline-flex; align-items: center; color: var(--text-muted); vertical-align: middle; }
.ms-link-icon:hover { color: var(--brand-navy); }
.ms-link-icon .icon { width: 18px; height: 18px; }

/* --- Отчёты водителя: карточка заказа — компактная "шапка" (адрес/
   клиент+принимающий одной строкой/этаж-лифт-расстояние лейблами) --- */
.order-header-card { margin-bottom: 16px; }
.order-address-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.order-address { font-size: 16px; font-weight: 700; margin: 0 0 4px; }
.order-client-line { font-size: 13px; color: var(--text-secondary); margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.order-client-label { color: var(--text-muted); font-weight: 600; }
.order-note { font-size: 13px; color: var(--text-secondary); margin: 6px 0 0; white-space: pre-line; }
.order-phone-link { display: inline-flex; align-items: center; gap: 4px; text-decoration: underline; color: var(--text-secondary); }
.order-phone-link:hover { color: var(--brand-navy); }
.order-phone-link .icon { width: 14px; height: 14px; }
.order-labels { display: flex; flex-wrap: wrap; align-content: flex-start; gap: 6px; margin: 0; }
.order-label {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 12px;
  color: var(--text-secondary);
}

/* --- Отчёты водителя: отчёт — иконка "заказана разгрузка" в списке заказов --- */
.unload-flag-icon { display: inline-flex; align-items: center; vertical-align: middle; color: var(--text-secondary); }
.unload-flag-icon .icon { width: 14px; height: 14px; }

/* --- Отчёты водителя: иконка "точка у поставщика" (icon("logistics")) в
   таблицах "Список"/"Расчёт зарплаты"/"+Точка" — без явного размера SVG
   рендерится в браузерном дефолте (~300×300), см. баг 2026-08-12. */
.point-type-icon { width: 15px; height: 15px; vertical-align: -3px; margin-right: 2px; }

/* --- Отчёты водителя: карточка заказа — код/штрихкод товара в попапах
   "Проверка комплектации"/"Выгрузка клиенту" --- */
.position-meta { font-size: 11px; color: var(--text-muted); }
/* Миниатюра товара (60x60, см. driver_reports/thumbnails.py) перед
   названием — серый плейсхолдер тем же object-fit, пока/если фото нет. */
.position-name-cell { display: flex; align-items: center; gap: 10px; }
.product-thumb { width: 60px; height: 60px; object-fit: cover; border-radius: 6px; border: 1px solid var(--border); background: var(--surface-2); flex: none; }
.product-thumb-sm { width: 32px; height: 32px; object-fit: cover; border-radius: 4px; border: 1px solid var(--border); background: var(--surface-2); flex: none; }

/* --- Отчёты водителя: попап "Проблема" — под-выбор решения (Довозим/Не
   довозим и т.д., см. RESOLUTIONS_BY_PROBLEM_TYPE) переиспользует
   .segmented (немного пунктов, ряд без переноса); скидка "Брак" — 10
   пунктов (5-50%), нужен перенос строк, поэтому своя раскладка. --- */
.discount-toggle { display: flex; flex-wrap: wrap; gap: 6px; }
.discount-pct-btn {
  padding: 6px 10px;
  font: inherit;
  font-size: 13px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
  cursor: pointer;
}
.discount-pct-btn.active { background: var(--brand-navy); color: #fff; border-color: var(--brand-navy); }

/* --- Отчёты водителя: попап поиска товара "загружен по ошибке"
   (Перепутали) — список результатов поиска по штрихкоду/названию. --- */
.search-results-list { display: flex; flex-direction: column; gap: 6px; max-height: 240px; overflow-y: auto; margin-top: 8px; }
.search-result-item { text-align: left; display: flex; align-items: center; gap: 10px; }
/* Название (своя строка) + код/штрихкод (.position-meta) и плашки
   служебных пометок — ОДНОЙ строкой (плашки прижаты к правому краю через
   margin-left:auto на .name-tag-badges, а не justify-content — работает
   одинаково, есть у товара код/штрихкод или нет, см. search/products.py,
   tags/_split_name_tags). */
.search-result-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.search-result-meta-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.name-tag-badges { display: flex; flex-wrap: wrap; gap: 4px; margin-left: auto; }
.name-tag-badge {
  display: inline-block; padding: 1px 6px; border-radius: 4px;
  font-size: 10.5px; font-weight: 600; line-height: 1.5; white-space: nowrap;
  background: var(--surface-2); color: var(--text-muted); border: 1px solid var(--border);
}
/* Цвета плашек — по смыслу пометки (2026-08-10, по прямому пожеланию):
   %/%% - зелёный (скидка), Акция/Распродажа - оранжевый (промо),
   Уценка/Брак/Срок годности/"нужен поддон" - красный (проблема/требование).
   "█" вообще не показывается (см. classifyNameTag в driver_reports.js/
   problem_reports.js) — назначение неизвестно, не пытаемся угадывать. */
.name-tag-badge-green { background: rgba(12, 163, 12, 0.12); color: var(--status-good); border-color: rgba(12, 163, 12, 0.3); }
.name-tag-badge-orange { background: rgba(250, 178, 25, 0.14); color: var(--status-warning); border-color: rgba(250, 178, 25, 0.35); }
.name-tag-badge-red { background: rgba(208, 59, 59, 0.12); color: var(--status-critical); border-color: rgba(208, 59, 59, 0.3); }
/* Розничная цена в результатах поиска — справа от кода/штрихкода (2026-08-10,
   по прямому пожеланию: синим и жирным, чтобы не терялась среди серого
   .position-meta). */
.search-result-price { color: var(--series-1); font-weight: 700; white-space: nowrap; }
/* Подсветка нулевого уровня поиска (см. search/products.py,
   _highlight_matches) — фрагменты, буквально совпавшие с введённым
   запросом, тот же приём, что в поиске товара самого МойСклад. */
.search-highlight { background: none; color: var(--brand-yellow-dark); font-weight: 700; }
/* Попапы поиска товара (unknown-item/misdelivered-search) — шире общего
   дефолта dialog (480px), т.к. названия товаров с миниатюрой длиннее и
   переносятся в несколько строк на обычной ширине. Явный width (не только
   max-width) — иначе <dialog> по умолчанию ужимается по контенту, и
   попап "пляшет" по ширине от товара к товару при повторном поиске. */
dialog:has(.search-results-list) { width: min(640px, 92vw); max-width: min(640px, 92vw); }

/* --- Отчёты водителя: "История оплат" — строка возврата денег, тот же
   приём, что и знак минус у корректировки (.delivery-shipped-corrected). --- */
.refund-amount { color: var(--status-critical); font-weight: 700; }

/* --- Отчёты водителя: попап "Проблема" — кнопки "Сделать фото"/"Выбрать
   из галереи" (вместо голого <input type="file">) + превью ещё не
   загруженных фото (сжатая JPEG-миниатюра через canvas, см.
   makePhotoThumbnail в driver_reports.js) с крестиком удаления. --- */
.photo-capture-buttons { display: flex; gap: 8px; }
.photo-preview-list { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.photo-preview-item { position: relative; width: 72px; height: 72px; border-radius: 8px; overflow: hidden; border: 1px solid var(--border); }
.photo-preview-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-preview-remove {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 20px;
  height: 20px;
  line-height: 18px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 14px;
  cursor: pointer;
}
/* Уже сохранённые на сервере фото (показаны при открытии на редактирование,
   см. showExistingCorrectionPhotos) — без крестика удаления, слегка
   притушены, чтобы отличались от только что выбранных, ещё не сохранённых. */
.photo-preview-existing { opacity: 0.75; }

/* --- Отчёты водителя: карточка заказа — лейбл "Комплектация проверена"
   (вместо неактивной кнопки, наверху рядом с остальными кнопками) --- */
#picking-check-status { display: inline-flex; align-items: center; gap: 5px; }
#picking-check-status .icon { width: 13px; height: 13px; }

/* --- Отчёты водителя: фото при приёмке/сдаче автомобиля --- */
.photo-grid { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.photo-thumb {
  display: block;
  width: 100px;
  height: 100px;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--border);
}
.photo-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Фото проблемы к корректировке ("Перепутали"/"Брак") — компактные
   миниатюры рядом с плашкой корректировки в таблице "Товары". */
.correction-item { display: inline-flex; align-items: center; gap: 4px; margin: 2px 0; }
.correction-photos { display: inline-flex; gap: 4px; }
.photo-thumb-sm { width: 26px; height: 26px; border-radius: 5px; }
/* Статус отправки корректировки в МойСклад (после "Завершить", см.
   driver_reports/ms_write_dispatch.py) — ссылки на созданные документы
   или иконка ошибки с текстом в title. */
.correction-ms-sync { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; }
.correction-ms-sync-ok a { color: var(--color-success, #2e7d32); text-decoration: underline; }
.correction-ms-sync-error { color: var(--color-danger, #c62828); }
.correction-ms-sync-error .icon { width: 14px; height: 14px; }

/* --- Легенда графика в виде кнопок (вместо стандартной echarts-легенды) --- */
.chart-legend { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 12px; }
.legend-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid var(--pill-color, var(--border));
  background: transparent;
  color: var(--text-primary);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: opacity 0.15s ease;
}
.legend-pill .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--pill-color, var(--text-muted)); flex: none; }
.legend-pill.is-inactive { opacity: 0.4; border-color: var(--border); font-weight: 500; }

/* --- Иконка "показать на графике по строкам разбивки" у заголовков
   столбцов таблицы "Разбивка" (/sales), см. initBreakdownChartLinks --- */
.breakdown-chart-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-left: 6px;
  padding: 0;
  border: none;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  vertical-align: middle;
  opacity: 0.6;
  transition: opacity 0.15s ease, color 0.15s ease;
}
.breakdown-chart-link svg { width: 14px; height: 14px; }
.breakdown-chart-link:hover { opacity: 1; color: var(--cat-accent, var(--series-1)); }
.breakdown-chart-link.active { opacity: 1; color: var(--cat-accent, var(--series-1)); }

/* --- Переключатели видимых колонок таблицы --- */
.column-toggles { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; }
.column-toggles label {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 12.5px;
  color: var(--text-secondary);
  cursor: pointer;
}
.column-toggles input { accent-color: var(--brand-navy); margin: 0; }

table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
th, td { text-align: left; padding: 9px 10px; border-bottom: 1px solid var(--gridline); }
th { color: var(--text-muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; }
tbody tr:hover { background: var(--surface-2); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
td.empty { text-align: center; color: var(--text-muted); font-style: italic; }
th.is-hidden, td.is-hidden { display: none; }
tr.is-hidden { display: none; }
.table-card tfoot td { font-weight: 700; background: var(--surface-2); border-top: 2px solid var(--border); }

/* --- Раскрывающиеся группы разбивки (/finance "день × поставщик" и т.п.) --- */
.group-toggle {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-align: left;
}
.group-row td { font-weight: 600; }
.group-row.is-expanded .group-toggle,
.group-child.is-expanded .group-toggle { color: var(--brand-navy); }
.group-child td { color: var(--text-secondary); }
.group-child-label { padding-left: 26px; }
.group-leaf td { color: var(--text-muted); font-size: 12.5px; }
.group-leaf-label { padding-left: 46px; }
.group-leaf-label a { color: var(--series-1); text-decoration: none; }
.group-leaf-label a:hover { text-decoration: underline; }

.badge { padding: 3px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 600; color: #fff; display: inline-flex; align-items: center; gap: 4px; }
.badge .icon { width: 12px; height: 12px; }
.badge-top { background: var(--stage-top); color: #0b1f3a; }
.badge-confirmed { background: var(--stage-confirmed); }
.badge-success { background: var(--stage-success); }
.badge-pending { background: var(--text-muted); }
/* Личный счёт контрагента (Этап 2) — те же цвета, что у debt-owed/
   debt-overpaid (критично/предупреждение), но как плашка (белый текст на
   заливке), а не просто цвет текста. */
.badge-critical { background: var(--status-critical); }
.badge-accent { background: var(--status-warning); }

/* Шкала % выполнения приёмки (wms/receiving.html) — узкая полоска под
   бейджем статуса, цвет заливки завязан на тот же статус (принимается/
   успешно/с расхождениями), что и цвет самого бейджа рядом. */
.receiving-progress { width: 90px; height: 6px; border-radius: 3px; background: var(--surface-2); overflow: hidden; margin-bottom: 4px; }
.receiving-progress-fill { height: 100%; border-radius: 3px; }
.receiving-progress-in_progress { background: var(--text-muted); }
.receiving-progress-success { background: var(--stage-success); }
.receiving-progress-discrepancy { background: var(--status-critical); }
/* <button class="badge ...">: сбрасываем браузерный вид кнопки, сама
   плашка выглядит как раньше (когда была <span>), просто ещё и кликабельна
   (корректировки на карточке заказа — открывает попап редактирования). */
button.badge { border: none; font: inherit; cursor: pointer; }
/* <a class="badge ...">: та же идея, что у button.badge выше — плашка
   личного счёта кликабельна (ведёт на разворот проводок контрагента), но
   должна выглядеть как обычная плашка, не как ссылка. */
a.badge { text-decoration: none; display: inline-block; }

.pagination { display: flex; gap: 6px; margin-top: 14px; flex-wrap: wrap; }
.pagination a {
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  text-decoration: none;
  color: var(--text-secondary);
  font-size: 13px;
}
.pagination a.active { background: var(--brand-navy); color: #fff; border-color: var(--brand-navy); }

.login-box {
  max-width: 340px;
  margin: 90px auto;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow);
  padding: 28px;
}
.login-box h1 { display: flex; align-items: center; gap: 10px; color: var(--brand-navy); }
.login-icon { width: 22px; height: 22px; }
@media (prefers-color-scheme: dark) { .login-box h1 { color: var(--brand-yellow); } }
.login-box .hint { color: var(--text-secondary); font-size: 13px; margin-top: -8px; }
.login-box label { display: flex; flex-direction: column; gap: 4px; margin-bottom: 14px; font-size: 13px; color: var(--text-secondary); }
.login-box input { padding: 9px; font-size: 14px; border-radius: 7px; border: 1px solid var(--border); background: var(--surface-2); color: var(--text-primary); }
.error { color: var(--status-critical); font-size: 13px; }

/* ======================================================================
   Каталог сырых таблиц (бывший кабинет репликатора, src/replicator/webapp)
   — перенесён при слиянии в одно приложение. Правила скоупятся под
   .catalog-page (обёртка вокруг {% block content %} в catalog_*.html),
   чтобы не спорить с одноимёнными глобальными классами дашбордов
   (.badge-success, table/th/td, .error и т.п. — тут другой визуальный
   регистр: плотная таблица данных, а не карточки отчётов). Цветовые токены
   переиспользуют существующие (--series-1 вместо статичного --brand-navy —
   он адаптируется под тему, что важно для интерактивных акцентов на фоне
   контента, а не только в хроме).
   ====================================================================== */
.catalog-page {
  --cat-accent: var(--series-1);
  --cat-accent-hover: var(--brand-navy);
  --cat-accent-soft: rgba(42, 120, 214, 0.12);
  --cat-radius: 10px;
  --cat-radius-sm: 7px;
  --cat-shadow-md: 0 4px 12px rgba(11, 31, 58, 0.12);
}
@media (prefers-color-scheme: dark) {
  .catalog-page { --cat-accent-soft: rgba(57, 135, 229, 0.18); }
}

.catalog-page a { color: var(--cat-accent); }

.catalog-page button {
  font: inherit;
  font-size: 0.83rem;
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-primary);
  border-radius: var(--cat-radius-sm);
  padding: 0.4rem 0.8rem;
  cursor: pointer;
}
.catalog-page button:hover { border-color: var(--cat-accent); }

.catalog-page input, .catalog-page select {
  font: inherit;
  font-size: 0.83rem;
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-primary);
  border-radius: var(--cat-radius-sm);
  padding: 0.35rem 0.55rem;
}
.catalog-page input:focus, .catalog-page select:focus {
  outline: none;
  border-color: var(--cat-accent);
  box-shadow: 0 0 0 3px var(--cat-accent-soft);
}

.catalog-page .nav-group { margin-bottom: 2rem; }
.catalog-page .nav-group h2 {
  font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted); font-weight: 600; margin-bottom: 0.75rem;
}
.catalog-page .nav-list { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 0.6rem; }
.catalog-page .nav-list li {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--cat-radius);
  box-shadow: var(--shadow);
  transition: box-shadow 0.15s ease, transform 0.1s ease, border-color 0.15s ease;
}
.catalog-page .nav-list li:hover { box-shadow: var(--cat-shadow-md); transform: translateY(-1px); border-color: var(--cat-accent); }
.catalog-page .nav-list a { display: block; padding: 0.85rem 1rem; text-decoration: none; color: var(--text-primary); font-weight: 500; font-size: 0.92rem; }
.catalog-page .nav-list li.empty { padding: 0.85rem 1rem; color: var(--text-muted); font-size: 0.92rem; }

.catalog-page .toolbar { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.9rem; flex-wrap: wrap; }
.catalog-page .toolbar input[type="search"] { flex: 0 1 320px; padding: 0.5rem 0.75rem; }
.catalog-page .total { color: var(--text-muted); font-size: 0.83rem; }
.catalog-page .toolbar > .ms-dropdown:last-child { margin-left: auto; }

/* --- Иконка-лупа внутри поля поиска (toolbar каталога) --- */
.catalog-page .search-wrap { position: relative; display: inline-flex; flex: 0 1 320px; }
.catalog-page .search-wrap .search-icon {
  position: absolute; left: 0.6rem; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; color: var(--text-muted); pointer-events: none;
}
.catalog-page .search-wrap input[type="search"] { flex: 1 1 auto; padding-left: 1.9rem; }
.catalog-page button .btn-icon-inline { width: 13px; height: 13px; margin-right: 0.35rem; }

/* --- Панель фильтров: сетка карточек-блоков по полю (п.3/п.6 требований
   к разделу "Документы"), а не плоский список строк, как раньше. --- */
.catalog-page .filters {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--cat-radius);
  box-shadow: var(--shadow);
  padding: 1rem;
  margin-bottom: 1rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 0.85rem 1.1rem;
  align-items: start;
}
/* Тот же класс проблем, что у .op-picker-panel/.filter-block-range ниже —
   .filters сворачивается через [hidden] (см. toggle-filters в catalog.js),
   а unconditional display:grid перебивал бы это. */
.catalog-page .filters[hidden] { display: none; }
/* .filter-block/.op-picker/.ms-dropdown — раньше жили только под
   .catalog-page, теперь глобальные (без префикса): те же виджеты нужны и
   фильтру доп.полей в отчётах (/sales, /sklad — см. dashboard.js
   initAttrFilters), а не только каталогу. --cat-accent/--cat-radius-sm/
   --cat-shadow-md определены только внутри .catalog-page — вне неё
   используются фолбэки на обычные токены отчётов (var(--series-1) и т.п.),
   внутри .catalog-page фолбэк не участвует, побеждает её собственное
   значение. */
.filter-block { display: flex; flex-direction: column; gap: 0.35rem; min-width: 0; }
.filter-block-head { display: flex; align-items: center; gap: 0.35rem; }
.filter-block-label {
  font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted);
}
.filter-block > input, .filter-block > select { width: 100%; }
.filter-block-range { display: flex; gap: 0.4rem; }
.filter-block-range[hidden] { display: none; }
.filter-block-range input { width: 0; flex: 1 1 0; }

/* --- Иконка выбора оператора (содержит/не содержит/диапазон и т.п.) — тот
   же визуальный приём, что .info-popover, только список пунктов вместо
   текста, и иконка сама меняется под текущий выбор. --- */
.op-picker { position: relative; display: inline-flex; }
.op-picker-trigger {
  width: 1.5rem; height: 1.5rem; padding: 0; border-radius: 50%;
  font-size: 0.8rem; line-height: 1; display: inline-flex;
  align-items: center; justify-content: center; color: var(--cat-accent, var(--series-1));
  border: 1px solid var(--border); background: var(--surface-2); cursor: pointer; flex-shrink: 0;
}
.op-picker-panel {
  position: absolute; z-index: 30; top: 1.9rem; left: 0;
  background: var(--surface-1); border: 1px solid var(--border);
  border-radius: var(--cat-radius-sm, 7px); box-shadow: var(--cat-shadow-md, var(--shadow));
  padding: 0.3rem; min-width: 210px; max-width: calc(100vw - 32px);
  display: flex; flex-direction: column;
}
/* [hidden] лежит в UA-стилях как `display: none` с низкой специфичностью —
   класс .op-picker-panel { display: flex } её перебивает, и панель была
   видна сразу после загрузки страницы, до первого клика. Явный override
   с самим атрибутом в селекторе решает это без побочных эффектов на JS
   (тот по-прежнему просто ставит/снимает hidden). */
.op-picker-panel[hidden] { display: none; }
.op-picker-item {
  border: none; background: none; text-align: left; padding: 0.4rem 0.55rem;
  border-radius: var(--cat-radius-sm, 7px); font-size: 0.85rem; white-space: nowrap;
}
.op-picker-item:hover { background: var(--surface-2); border-color: transparent; }

/* Попап выбора периода у кнопки "Скачать Excel" (/sales) — тот же
   .op-picker-panel/.op-picker-item, что и у op-picker'а доп.полей, но
   триггер — обычная .btn-secondary, а не маленькая круглая кнопка-иконка,
   поэтому панели нужен больший отступ сверху. Кнопка обычно стоит у
   правого края карточки "Разбивка" — базовый .op-picker-panel растёт от
   left:0 вправо и вылезает за границу окна, здесь вместо этого растим
   от правого края триггера влево (right:0, left:auto). */
.export-picker .op-picker-panel { top: 2.5rem; left: auto; right: 0; }

/* --- Чекбокс-дропдаун с поиском: и тулбарный "Статус" каталога, и любой
   справочник-фильтр в панели (каталога или доп.поля отчёта). --- */
.ms-dropdown { position: relative; display: inline-flex; }
.ms-dropdown-trigger { min-width: 140px; text-align: left; white-space: nowrap; }
.ms-dropdown-trigger.active { border-color: var(--cat-accent, var(--series-1)); color: var(--cat-accent, var(--series-1)); font-weight: 600; }
.filter-block-dictionary .ms-dropdown-trigger { width: 100%; }
.ms-dropdown-panel {
  position: absolute; z-index: 30; top: 2.4rem; left: 0;
  background: var(--surface-1); border: 1px solid var(--border);
  border-radius: var(--cat-radius-sm, 7px); box-shadow: var(--cat-shadow-md, var(--shadow));
  padding: 0.5rem; min-width: 230px; max-width: min(320px, calc(100vw - 32px));
}
.catalog-page .column-settings .ms-dropdown-panel { right: 0; left: auto; max-height: 340px; overflow-y: auto; }
.ms-dropdown-panel input[type="text"] { width: 100%; margin-bottom: 0.4rem; }
.ms-dropdown-list { max-height: 240px; overflow-y: auto; display: flex; flex-direction: column; }
.ms-dropdown-item {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.3rem 0.35rem;
  border-radius: var(--cat-radius-sm, 7px); font-size: 0.85rem; cursor: pointer;
}
.ms-dropdown-item:hover { background: var(--surface-2); }
.ms-dropdown-item input { width: auto; accent-color: var(--cat-accent, var(--series-1)); }
.ms-dropdown-empty { font-size: 0.82rem; color: var(--text-muted); padding: 0.3rem 0.35rem; }

/* .table-wrap — обёртка вокруг <table> с горизонтальным скроллом на узких
   экранах (адаптив под планшет/телефон, см. CLAUDE.md). Голое правило —
   для таблиц, у которых карточку уже рисует родитель (.table-card и т.п.,
   не дублировать рамку/тень); .catalog-page .table-wrap ниже добавляет
   СВОЮ рамку/тень поверх — там .table-wrap исторически сам служит
   карточкой (таблица не вложена в .table-card). */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; min-width: 0; width: 100%; }
.catalog-page .table-wrap {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--cat-radius);
  box-shadow: var(--shadow);
}
.catalog-page table { border-collapse: collapse; width: 100%; font-size: 0.9rem; }
.catalog-page th, .catalog-page td { padding: 0.6rem 0.85rem; text-align: left; white-space: nowrap; border-bottom: 1px solid var(--border); }
.catalog-page th {
  background: var(--surface-2);
  color: var(--text-muted);
  font-weight: 600;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  cursor: pointer;
  position: sticky;
  top: 0;
}
.catalog-page tbody tr:last-child td { border-bottom: none; }
.catalog-page tbody tr:hover { background: var(--surface-2); }
.catalog-page td a { text-decoration: none; }
.catalog-page tfoot td {
  font-weight: 700;
  background: var(--surface-2);
  border-top: 2px solid var(--border);
  border-bottom: none;
}

/* --- Таблица с фиксированной шириной колонок (/verify-counterparties) ---
   table-layout: fixed + colgroup вместо обычного auto-layout — иначе
   длинные значения (имя контрагента, список дублей) растягивают таблицу
   за пределы экрана вместо того, чтобы обрезаться по границе колонки. */
/* min-width — та же причина, что у .orders-table выше: table-layout:fixed
   иначе просто сжимает колонки под любую ширину контейнера вместо скролла. */
.verify-table { table-layout: fixed; min-width: 720px; }
/* .cell-tooltip-wrap специально БЕЗ overflow:hidden — сам тултип абсолютно
   спозиционирован внутри неё (см. ниже) и его контейнер, если поставить
   overflow:hidden на любого предка между тултипом и .cell-tooltip-wrap,
   будет обрезан вместе с текстом (классическая ловушка: overflow:hidden
   обрезает и абсолютно спозиционированных потомков, не только обычный
   контент) — поэтому обрезка текста живёт отдельно, во вложенном
   .cell-truncate, а не на этой обёртке и не на самой <td>. */
.verify-table .cell-tooltip-wrap {
  position: relative;
  display: block;
  max-width: 100%;
}
.verify-table .cell-truncate {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: default;
}
.verify-table .cell-tooltip {
  display: none;
  position: absolute;
  z-index: 20;
  /* top:100% вплотную, БЕЗ margin-top — зазор между строкой и тултипом это
     "мёртвая зона", где курсор не наведён ни на .cell-tooltip-wrap (тултип
     не в потоке, в высоту обёртки не входит), ни на сам тултип: наведение
     срывается на полпути, и тултип успевает скрыться раньше, чем курсор
     доедет до него. Отступ сверху — padding самого тултипа (это уже часть
     его наводимой области, зоны без наведения не создаёт). */
  top: 100%;
  left: 0;
  padding: 16px 12px 10px;
  min-width: 220px;
  max-width: 420px;
  border-radius: var(--cat-radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-1);
  box-shadow: var(--cat-shadow-md);
  color: var(--text-primary);
  font-size: 0.85rem;
  line-height: 1.45;
  white-space: normal;
  word-break: break-word;
}
.verify-table .cell-tooltip-wrap:hover .cell-tooltip,
.verify-table .cell-tooltip-wrap:focus-within .cell-tooltip,
.verify-table .cell-tooltip:hover { display: block; }

.catalog-page .pager { display: flex; align-items: center; gap: 0.9rem; margin-top: 1rem; }
.catalog-page .pager span { color: var(--text-muted); font-size: 0.88rem; }

.catalog-page .detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 0.9rem 1.5rem;
  margin-bottom: 1.5rem;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--cat-radius);
  box-shadow: var(--shadow);
  padding: 1.25rem;
}
.catalog-page .detail-grid .field { display: flex; flex-direction: column; gap: 0.15rem; }
.catalog-page .detail-grid .field .label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }

.catalog-page .info-popover { position: relative; display: inline-block; margin-left: 0.4rem; }
.catalog-page .info-trigger {
  width: 1.3rem; height: 1.3rem; padding: 0; border-radius: 50%;
  font-size: 0.72rem; line-height: 1; display: inline-flex;
  align-items: center; justify-content: center; color: var(--text-muted);
  border: 1px solid var(--border); background: var(--surface-1); cursor: pointer;
}
.catalog-page .info-panel {
  position: absolute; z-index: 30; top: 1.7rem; left: 0;
  background: var(--surface-1); border: 1px solid var(--border);
  border-radius: var(--cat-radius-sm); box-shadow: var(--cat-shadow-md);
  padding: 0.6rem; min-width: 240px; max-width: min(380px, calc(100vw - 32px)); white-space: normal;
}
.catalog-page .info-panel pre {
  margin: 0.4rem 0 0; white-space: pre-wrap; word-break: break-all;
  font-size: 0.78rem; max-height: 260px; overflow: auto;
}
.catalog-page .info-copy {
  font-size: 0.75rem; padding: 0.25rem 0.55rem; border: 1px solid var(--border);
  background: var(--surface-2); border-radius: var(--cat-radius-sm); cursor: pointer;
}

.catalog-page .badge {
  display: inline-block; margin-left: 0.5rem; padding: 0.05rem 0.5rem;
  border-radius: 999px; font-size: 0.72rem; font-weight: 600; vertical-align: middle;
}
.catalog-page .badge-archived { background: rgba(217, 119, 6, 0.14); color: #b45309; }
.catalog-page .badge-status { background: var(--cat-accent-soft); color: var(--cat-accent); }
.catalog-page .badge-success { background: rgba(22, 163, 74, 0.14); color: #16a34a; }
.catalog-page .badge-neutral { background: rgba(107, 114, 128, 0.14); color: var(--text-muted); }
@media (prefers-color-scheme: dark) {
  .catalog-page .badge-archived { background: rgba(251, 191, 36, 0.16); color: #fbbf24; }
  .catalog-page .badge-success { background: rgba(74, 222, 128, 0.16); color: #4ade80; }
}

.catalog-page #archived-toggle { margin-right: 0.25rem; }

.catalog-page .header-groups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1.1rem 2rem;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--cat-radius);
  box-shadow: var(--shadow);
  padding: 1.25rem;
  margin: 0.75rem 0 1.5rem;
}
.catalog-page .header-group { display: flex; flex-direction: column; gap: 0.9rem; }

/* Индикатор загрузки при переходе по фильтрам/пресетам/группировке —
   вся навигация на /sales обычная (полная перезагрузка страницы, не
   AJAX), поэтому старая страница остаётся на экране, пока грузится
   новая — dashboard.js (initNavLoading) вешает body.is-navigating сразу
   по клику/сабмиту, снимать класс не нужно: следующая страница грузится
   с нуля. */
#nav-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 30%;
  background: var(--series-1);
  z-index: 3000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
body.is-navigating #nav-progress {
  opacity: 1;
  animation: nav-progress-run 1.1s ease-in-out infinite;
}
@keyframes nav-progress-run {
  0%   { left: -30%; width: 30%; }
  55%  { left: 55%;  width: 45%; }
  100% { left: 100%; width: 30%; }
}

.reload-blur-target { position: relative; transition: filter 0.15s ease; }
body.is-navigating .reload-blur-target {
  filter: blur(3px);
  pointer-events: none;
}
body.is-navigating .reload-blur-target::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 5;
  border-radius: 12px;
  background: rgba(127, 127, 127, 0.08);
}
body.is-navigating .chart-card.reload-blur-target::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 32px;
  height: 32px;
  margin: -16px 0 0 -16px;
  border-radius: 50%;
  border: 3px solid var(--border);
  border-top-color: var(--series-1);
  z-index: 6;
  animation: nav-spinner-spin 0.7s linear infinite;
}
@keyframes nav-spinner-spin {
  to { transform: rotate(360deg); }
}
