/* LogTrack DEYA — фирменный дизайн (2026-08-28, редизайн 2026-09-02).
   Палитра взята из логотипа Deya (фирменный красный #DA1F26). Шрифт — Inter
   (самостоятельный хостинг, WOFF2, licence: vendor/fonts/Inter-LICENSE.txt),
   единая гарнитура для заголовков и текста — заменил Manrope+системный шрифт
   (см. план миграции, Sprint 3 п.3.6). Табличные цифры (KPI-плитки, таблицы)
   — моноширинные через font-variant-numeric: tabular-nums, чтобы колонки
   с числами не "прыгали" при обновлении. Токены объявлены как custom
   properties, темы light/dark/corporate переопределяют только их —
   компоненты стилизуются через токены. */

@font-face {
  font-family: "Inter";
  font-weight: 400;
  font-style: normal;
  src: url("../vendor/fonts/Inter-Regular.woff2") format("woff2");
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  font-weight: 500;
  font-style: normal;
  src: url("../vendor/fonts/Inter-Medium.woff2") format("woff2");
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  font-weight: 600;
  font-style: normal;
  src: url("../vendor/fonts/Inter-SemiBold.woff2") format("woff2");
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  font-weight: 700;
  font-style: normal;
  src: url("../vendor/fonts/Inter-Bold.woff2") format("woff2");
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  font-weight: 800;
  font-style: normal;
  src: url("../vendor/fonts/Inter-ExtraBold.woff2") format("woff2");
  font-display: swap;
}

:root {
  /* Красный — ИСКЛЮЧИТЕЛЬНО логотип / астериски обязательных полей / алерты */
  --red: #ef4444;
  --red-dark: #dc2626;
  --red-tint: #fee2e2;

  /* Рутинная интерактивность — фирменный красный акцент DEYA #DA1F26 */
  --accent-ui: #DA1F26;
  --accent-ui-dark: #b8141a;
  --accent-ui-soft: rgba(218, 31, 38, 0.08);
  --focus-ring-ui: rgba(218, 31, 38, 0.25);

  /* "В процессе" (степпер рейса) — благородный янтарь */
  /* Тёмно-янтарный, а не #d97706: янтарный текст на янтарной подложке
     --current-bg давал контраст 2.86:1 при норме 4.5:1 — таймер обратного
     отсчёта в состоянии «на грани» читался хуже всего именно тогда, когда на
     него нужно смотреть. Здесь 6.4:1. */
  --current: #92400e;
  --current-bg: #fef3c7;

  /* Чистая палитра Apple Pro — светлая тема */
  --ink: #1d1d1f;
  --ink-soft: #48484a;
  /* Контраст WCAG AA: 3.62:1 -> 4.64:1 на фоне страницы. Токен применялся к
     тексту 11.5-12.5px, где требуется 4.5:1, а не 3:1. */
  --muted: #6D6D72;
  --paper: #f5f5f7;
  --surface: #ffffff;
  /* Текст на ЦВЕТНОЙ заливке (фирменный красный, статусные зелёный/красный).
     Раньше в этих местах стоял --surface — и в светлой теме он давал белый
     текст, а в тёмных темах тёмный: белое на красном превращалось в тёмное
     на красном. Токен постоянный во всех темах, как и сама заливка. */
  --on-fill: #ffffff;
  --border: #e5e5ea;

  /* Диффузные тени Apple Elevation */
  --elevation-1: 0 1px 3px rgba(0, 0, 0, 0.04), 0 4px 16px rgba(0, 0, 0, 0.04);
  --elevation-2: 0 4px 8px rgba(0, 0, 0, 0.06), 0 12px 28px rgba(0, 0, 0, 0.08);
  --elevation-3: 0 12px 32px rgba(0, 0, 0, 0.12), 0 24px 54px rgba(0, 0, 0, 0.14);
  --shadow: var(--elevation-1);

  --z-sticky-nav: 100;
  --app-nav-height: 58px;
  --z-dropdown: 20;
  --z-overlay: 2000;

  /* Сочные и легко читаемые статусы (WCAG AAA compliant) */
  --status-green: #065f46;
  --status-green-bg: #d1fae5;
  --status-amber: #92400e;
  --status-amber-bg: #fef3c7;
  --status-orange: #9a3412;
  --status-orange-bg: #ffedd5;
  /* [FIX Ф-6] Убран дубликат --status-orange/--status-orange-bg (строки 95-96
     были копией 93-94 — случайно вставлены дважды) */
  --status-red: #991b1b;
  --chart-series-1: #2563eb;
  --chart-series-2: #8b5cf6;
  --chart-series-3: #06b6d4;
  --chart-series-4: #ea580c;
  --chart-series-5: #10b981;
  --surface-sunken: #f8fafc;
  --status-red-bg: #fee2e2;
  --status-gray: #334155;
  --status-gray-bg: #f1f5f9;
  /* [FIX ВИЗ-3] Токены для badge-blue / vbadge-cap / vbadge-vol — раньше
     эти бейджи использовали хардкод-цвета и требовали дублирующих правил
     для тёмной темы. Теперь цвета — токены, темы переопределяют их. */
  --status-blue: #1e40af;
  --status-blue-bg: #dbeafe;
  --status-blue-border: #bfdbfe;
  --status-sky: #0369a1;
  --status-sky-bg: #e0f2fe;
  --status-sky-border: #bae6fd;
  --status-vol: #15803d;
  --status-vol-bg: #dcfce7;
  --status-vol-border: #bbf7d0;
  /* [FIX ЛЕГ-1] --status-purple использовался в коде (GTrackerChart,
     warehouse_head, UnifiedFleetMap) с fallback, но НИ РАЗУ не был объявлен —
     та же проблема, что у --paper-soft/--radius-md (ВИЗ-5). Объявляем. */
  --status-purple: #9333ea;
  --status-purple-bg: rgba(168, 85, 247, 0.12);
  --status-purple-border: rgba(168, 85, 247, 0.3);
  /* Заливки под БЕЛЫМ текстом: плашки меток на карте и фирменные кнопки.
     Значения одинаковы во всех темах и подобраны под белый (4.99:1 … 9.4:1).
     Обычные --accent-ui и --status-* для этого не годятся: они задуманы как
     цвета ТЕКСТА и в тёмных темах намеренно светлее ради читаемости самого
     текста. Белым по ним выходило от 1.67:1 до 3.9:1 — плашки меток на карте
     в тёмной теме читались хуже всего. Одно и то же значение нельзя
     одновременно быть светлым текстом и тёмной заливкой, поэтому токенов
     два набора.
     --brand-fill-dark — та же заливка для состояния наведения: она должна
     быть ТЕМНЕЕ основной, а --accent-ui-dark в тёмных темах наоборот
     светлеет (это цвет текста), и белым по нему выходило 3.76:1. */
  --brand-fill: #DA1F26;
  --brand-fill-dark: #b8141a;
  --status-green-fill: #065f46;
  --status-amber-fill: #92400e;
  --status-red-fill: #991b1b;
  --status-gray-fill: #334155;

  --font-display: "Inter", -apple-system, BlinkMacSystemFont, "SF Pro Display", sans-serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
  --font-data: "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --radius: 14px;
  --radius-sm: 8px;
  /* [FIX Ф-5] Добавлены --radius-md и --radius-lg — использовались в коде,
     но не были определены. fallback через var(--radius) не работает —
     браузер игнорирует всё свойство если переменная не найдена. */
  --radius-md: 10px;
  --radius-lg: 14px;
  /* [FIX Ф-5] --paper-soft — мягкий фон для hover-состояний в списках и
     карточках. Используется в warehouse.css и UnifiedFleetMap.vue, но
     не был определён. Браузер рендерил background: invalid → transparent. */
  --paper-soft: #f8fafc;
  --map-filter: none;

  --header-bg: #ffffff;
  --header-fg: #0f172a;
  --header-muted: #64748b;
  --surface-sunken: #f1f5f9;
}

/* Тёмная тема — Графит / Нейтральный антрацит DEYA */
:root[data-theme="dark"] ,
:root[data-theme="graphite"] {
  --ink: #f4f4f5;
  --ink-soft: #d4d4d8;
  --muted: #a1a1aa;
  --paper: #121316;
  --surface: #1a1b1e;
  --on-fill: #ffffff;
  --surface-sunken: #101114;
  --border: rgba(255, 255, 255, 0.1);
  --elevation-1: 0 1px 3px rgba(0, 0, 0, 0.6), 0 8px 24px rgba(0, 0, 0, 0.45);
  --elevation-2: 0 4px 8px rgba(0, 0, 0, 0.65), 0 16px 36px rgba(0, 0, 0, 0.55);
  --elevation-3: 0 8px 16px rgba(0, 0, 0, 0.7), 0 28px 60px rgba(0, 0, 0, 0.65);
  --shadow: var(--elevation-1);
  --red: #f87171;
  --red-dark: #ef4444;
  --red-tint: rgba(239, 68, 68, 0.2);
  /* Фирменный #DA1F26 на тёмном фоне даёт 3.72:1 — провал AA для текста.
     Оттенок сохранён, светлота поднята: 4.94:1 на --paper и 4.58:1 на
     --surface. В светлой теме токен остаётся фирменным без изменений. */
  --accent-ui: #ef4444;
  --accent-ui-dark: #ef4444;
  --accent-ui-soft: rgba(239, 68, 68, 0.18);
  --focus-ring-ui: rgba(239, 68, 68, 0.45);

  --current: #fbbf24;
  --current-bg: rgba(251, 191, 36, 0.15);
  --status-green: #34d399;
  --status-green-bg: rgba(52, 211, 153, 0.15);
  --status-amber: #fbbf24;
  --status-amber-bg: rgba(251, 191, 36, 0.15);
  --status-orange: #fb923c;
  --status-orange-bg: rgba(251, 146, 60, 0.15);
  --status-red: #f87171;
  --status-red-bg: rgba(248, 113, 113, 0.18);
  --status-gray: #94a3b8;
  --status-gray-bg: rgba(148, 163, 184, 0.15);
  /* [FIX ВИЗ-3] Graphite-тема: токены бейджей + Ф-5 (paper-soft/radius) */
  --status-blue: #93c5fd;
  --status-blue-bg: #172554;
  --status-blue-border: #1e40af;
  --status-sky: #7dd3fc;
  --status-sky-bg: rgba(3, 105, 161, 0.25);
  --status-sky-border: rgba(125, 211, 252, 0.3);
  --status-vol: #86efac;
  --status-vol-bg: rgba(21, 128, 61, 0.25);
  --status-vol-border: rgba(134, 239, 172, 0.3);
  --paper-soft: rgba(255, 255, 255, 0.04);
  --radius-md: 10px;
  --radius-lg: 14px;
  /* Заливки под БЕЛЫМ текстом: плашки меток на карте и фирменные кнопки.
     Значения одинаковы во всех темах и подобраны под белый (4.99:1 … 9.4:1).
     Обычные --accent-ui и --status-* для этого не годятся: они задуманы как
     цвета ТЕКСТА и в тёмных темах намеренно светлее ради читаемости самого
     текста. Белым по ним выходило от 1.67:1 до 3.9:1 — плашки меток на карте
     в тёмной теме читались хуже всего. Одно и то же значение нельзя
     одновременно быть светлым текстом и тёмной заливкой, поэтому токенов
     два набора.
     --brand-fill-dark — та же заливка для состояния наведения: она должна
     быть ТЕМНЕЕ основной, а --accent-ui-dark в тёмных темах наоборот
     светлеет (это цвет текста), и белым по нему выходило 3.76:1. */
  --brand-fill: #DA1F26;
  --brand-fill-dark: #b8141a;
  --status-green-fill: #065f46;
  --status-amber-fill: #92400e;
  --status-red-fill: #991b1b;
  --status-gray-fill: #334155;
  --map-filter: none;

  --header-bg: rgba(26, 27, 30, 0.95);
  --header-fg: #f4f4f5;
  --header-muted: #a1a1aa;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="corporate"]) {
    --ink: #f4f4f5;
    --ink-soft: #d4d4d8;
    --muted: #a1a1aa;
    --paper: #121316;
    --surface: #1a1b1e;
    --on-fill: #ffffff;
    --surface-sunken: #101114;
    --border: rgba(255, 255, 255, 0.1);
    --elevation-1: 0 1px 3px rgba(0, 0, 0, 0.6), 0 8px 24px rgba(0, 0, 0, 0.45);
    --elevation-2: 0 4px 8px rgba(0, 0, 0, 0.65), 0 16px 36px rgba(0, 0, 0, 0.55);
    --elevation-3: 0 8px 16px rgba(0, 0, 0, 0.7), 0 28px 60px rgba(0, 0, 0, 0.65);
    --shadow: var(--elevation-1);
    --red: #f87171;
    --red-dark: #ef4444;
    --red-tint: rgba(239, 68, 68, 0.2);
    --accent-ui: #ef4444;
    --accent-ui-dark: #ef4444;
    --accent-ui-soft: rgba(239, 68, 68, 0.18);
    --focus-ring-ui: rgba(239, 68, 68, 0.45);

    --current: #fbbf24;
    --current-bg: rgba(251, 191, 36, 0.15);
    --status-green: #34d399;
    --status-green-bg: rgba(52, 211, 153, 0.15);
    --status-amber: #fbbf24;
    --status-amber-bg: rgba(251, 191, 36, 0.15);
    --status-orange: #fb923c;
    --status-orange-bg: rgba(251, 146, 60, 0.15);
    /* [FIX Ф-6] Убран дубликат --status-orange/--status-orange-bg */
    --status-red: #f87171;
    --status-red-bg: rgba(248, 113, 113, 0.18);
    --status-gray: #94a3b8;
    --status-gray-bg: rgba(148, 163, 184, 0.15);
    /* [FIX ВИЗ-3] Dark-тема: токены бейджей */
    --status-blue: #93c5fd;
    --status-blue-bg: #172554;
    --status-blue-border: #1e40af;
    --status-sky: #7dd3fc;
    --status-sky-bg: rgba(3, 105, 161, 0.25);
    --status-sky-border: rgba(125, 211, 252, 0.3);
    --status-vol: #86efac;
    --status-vol-bg: rgba(21, 128, 61, 0.25);
    --status-vol-border: rgba(134, 239, 172, 0.3);
  /* Заливки под БЕЛЫМ текстом: плашки меток на карте и фирменные кнопки.
     Значения одинаковы во всех темах и подобраны под белый (4.99:1 … 9.4:1).
     Обычные --accent-ui и --status-* для этого не годятся: они задуманы как
     цвета ТЕКСТА и в тёмных темах намеренно светлее ради читаемости самого
     текста. Белым по ним выходило от 1.67:1 до 3.9:1 — плашки меток на карте
     в тёмной теме читались хуже всего. Одно и то же значение нельзя
     одновременно быть светлым текстом и тёмной заливкой, поэтому токенов
     два набора.
     --brand-fill-dark — та же заливка для состояния наведения: она должна
     быть ТЕМНЕЕ основной, а --accent-ui-dark в тёмных темах наоборот
     светлеет (это цвет текста), и белым по нему выходило 3.76:1. */
  --brand-fill: #DA1F26;
  --brand-fill-dark: #b8141a;
  --status-green-fill: #065f46;
  --status-amber-fill: #92400e;
  --status-red-fill: #991b1b;
  --status-gray-fill: #334155;
    --map-filter: none;
    /* [FIX Ф-5] Dark-тема: --paper-soft, --radius-md, --radius-lg */
    --paper-soft: rgba(255, 255, 255, 0.04);
    --radius-md: 10px;
    --radius-lg: 14px;

    --header-bg: rgba(26, 27, 30, 0.95);
    --header-fg: #f4f4f5;
    --header-muted: #a1a1aa;
  }
}

/* Корпоративная представительская тема DEYA (фото штаб-квартиры) */
:root[data-theme="corporate"] {
  --ink: #f8fafc;
  --ink-soft: #cbd5e1;
  --muted: #94a3b8;
  --paper: #0e111a;
  --surface: #151a26;
  --on-fill: #ffffff;
  --surface-sunken: #0a0d14;
  --border: rgba(218, 31, 38, 0.25);
  --elevation-1: 0 1px 3px rgba(0, 0, 0, 0.5), 0 4px 16px rgba(0, 0, 0, 0.4);
  --elevation-2: 0 4px 8px rgba(0, 0, 0, 0.6), 0 12px 28px rgba(0, 0, 0, 0.5);
  --elevation-3: 0 12px 32px rgba(0, 0, 0, 0.7), 0 24px 54px rgba(0, 0, 0, 0.6);
  --shadow: var(--elevation-1);

  --brand-primary: #151a26;
  --brand-primary-dark: #0a0d14;
  --brand-secondary: #f59e0b;
  --brand-secondary-bg: rgba(245, 158, 11, 0.15);

  --header-bg: rgba(14, 17, 26, 0.95);
  --header-fg: #ffffff;
  --header-muted: #cbd5e1;

  --accent-ui: #ef4444;
  /* [FIX ВИЗ-16] В corporate-теме --accent-ui-dark стоял тёмным (#b8141a), как
     в светлой, — хотя сама тема тёмная: --paper #0e111a, --surface #151a26.
     Тёмно-красный текст на тёмном фоне давал 2.83:1 (кнопка «Разбор
     рекламации» в карточке рейса). Приведено к остальным тёмным темам. */
  --accent-ui-dark: #ef4444;
  --accent-ui-soft: rgba(239, 68, 68, 0.2);
  --focus-ring-ui: rgba(239, 68, 68, 0.45);

  --current: #fbbf24;
  --current-bg: rgba(251, 191, 36, 0.18);
  --status-green: #34d399;
  --status-green-bg: rgba(52, 211, 153, 0.18);
  --status-amber: #fbbf24;
  --status-amber-bg: rgba(251, 191, 36, 0.18);
  --status-orange: #fb923c;
  --status-orange-bg: rgba(251, 146, 60, 0.18);
  /* [FIX Ф-6] Убран дубликат --status-orange/--status-orange-bg */
  --status-red: #f87171;
  --status-red-bg: rgba(248, 113, 113, 0.18);
  --status-gray: #94a3b8;
  --status-gray-bg: rgba(148, 163, 184, 0.18);
  /* [FIX ВИЗ-3] Corporate-тема: токены бейджей */
  --status-blue: #93c5fd;
  --status-blue-bg: #172554;
  --status-blue-border: #1e40af;
  --status-sky: #7dd3fc;
  --status-sky-bg: rgba(3, 105, 161, 0.25);
  --status-sky-border: rgba(125, 211, 252, 0.3);
  --status-vol: #86efac;
  --status-vol-bg: rgba(21, 128, 61, 0.25);
  --status-vol-border: rgba(134, 239, 172, 0.3);
  /* Заливки под БЕЛЫМ текстом: плашки меток на карте и фирменные кнопки.
     Значения одинаковы во всех темах и подобраны под белый (4.99:1 … 9.4:1).
     Обычные --accent-ui и --status-* для этого не годятся: они задуманы как
     цвета ТЕКСТА и в тёмных темах намеренно светлее ради читаемости самого
     текста. Белым по ним выходило от 1.67:1 до 3.9:1 — плашки меток на карте
     в тёмной теме читались хуже всего. Одно и то же значение нельзя
     одновременно быть светлым текстом и тёмной заливкой, поэтому токенов
     два набора.
     --brand-fill-dark — та же заливка для состояния наведения: она должна
     быть ТЕМНЕЕ основной, а --accent-ui-dark в тёмных темах наоборот
     светлеет (это цвет текста), и белым по нему выходило 3.76:1. */
  --brand-fill: #DA1F26;
  --brand-fill-dark: #b8141a;
  --status-green-fill: #065f46;
  --status-amber-fill: #92400e;
  --status-red-fill: #991b1b;
  --status-gray-fill: #334155;
  --map-filter: none;
  /* [FIX Ф-5] Corporate-тема: --paper-soft, --radius-md, --radius-lg */
  --paper-soft: rgba(255, 255, 255, 0.04);
  --radius-md: 10px;
  --radius-lg: 14px;
}

* {
  box-sizing: border-box;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--muted);
}

body {
  font-family: var(--font-body);
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.45;
}
/* Фото предприятия — только в теме "corporate" (Sprint C, Д6). Заменяет
   абстрактный силуэт vendor/bg-building.svg на реальное фото
   (static/img/bg-company.jpg) с CSS-дуотоном без внешних инструментов и без
   трассировки в вектор — при замене фото эффект пересчитывается сам.
   Два псевдоэлемента, а не один: filter применяется ПОСЛЕ композитинга
   background-blend-mode на одном элементе, поэтому grayscale+blend в одном
   правиле гасят друг друга (проверено визуально — фото оставалось серым).
   Раскладка на ::before (фото, обесцвечено через filter) + ::after (заливка
   --brand-primary, mix-blend-mode:color красит по яркости фото снизу) —
   стандартный CSS-приём дуотона, blend-mode которого требует ДВУХ слоёв.
   Оба сидят позади контента по порядку в DOM — карточки со своим --surface
   перекрывают их везде, кроме отступов, как и раньше с SVG-версией. */
:root[data-theme="corporate"] body::before {
  content: "";
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  background-image: url("../img/office-hq.jpg");
  background-size: cover;
  background-position: center 35%;
  filter: blur(2px) brightness(0.35) contrast(1.08);
  opacity: 0.38;
  pointer-events: none;
  z-index: -1;
}
:root[data-theme="corporate"] body::after {
  content: "";
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  background: radial-gradient(circle at 50% 25%, rgba(14, 18, 28, 0.72) 0%, rgba(10, 12, 18, 0.94) 100%);
  pointer-events: none;
  z-index: -1;
}

header {
  background: var(--header-bg);
  color: var(--header-fg);
  padding: 10px 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow);
}
header .brand {
  display: flex;
  align-items: center;
  gap: 14px;
}
header .brand-logo {
  height: 42px;
  display: block;
  border-radius: 6px;
  /* Лого несёт фирменный красный сам по себе — на графитовой шапке это
     единственное пятно бренд-цвета, ничего дополнительно "спасать" не нужно. */
  padding: 4px;
  background: var(--paper);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}
header .brand-page {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 17px;
  letter-spacing: 0.2px;
  color: var(--header-fg);
}
header a {
  color: var(--header-muted);
  text-decoration: none;
  font-weight: 600;
  transition: color 0.15s ease;
}
header #whoami {
  font-weight: 600;
  color: var(--header-muted);
  font-size: 13px;
  display: inline-flex;
  align-items: center;
}
header button {
  margin: 0;
}
header #logoutBtn {
  margin: 0 0 0 10px;
  padding: 6px 14px;
  font-size: 13px;
  min-height: 36px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
}
   красный сюда не допускается (зарезервирован за лого/астериском/алертами). */
.header-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--header-muted);
  cursor: pointer;
  transition: all 0.15s ease;
}
.header-icon-btn:hover { background: var(--accent-ui-soft); color: var(--accent-ui); border-color: transparent; }
.header-icon-btn svg { width: 19px; height: 19px; flex-shrink: 0; }
.header-icon-btn .icon-moon { display: none; }
.header-icon-btn .icon-corporate { display: none; }
:root[data-theme="dark"] .header-icon-btn.theme-toggle .icon-sun ,
:root[data-theme="graphite"] .header-icon-btn.theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .header-icon-btn.theme-toggle .icon-moon ,
:root[data-theme="graphite"] .header-icon-btn.theme-toggle .icon-moon { display: inline-flex; }
:root[data-theme="corporate"] .header-icon-btn.theme-toggle .icon-sun { display: none; }
:root[data-theme="corporate"] .header-icon-btn.theme-toggle .icon-corporate { display: inline-flex; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="corporate"]) .header-icon-btn.theme-toggle .icon-sun { display: none; }
  :root:not([data-theme="light"]):not([data-theme="corporate"]) .header-icon-btn.theme-toggle .icon-moon { display: inline-flex; }
}

/* SPA-объединение (2026-08-29): вместо отдельных страниц/вкладок — один
   скроллящийся документ, разделы показываются по правам оператора. Нав —
   быстрые якорные ссылки; при нехватке места переносится на новую строку
   (flex-wrap), а не уходит в горизонтальный скролл — тот же принцип, что и
   у .stepper (см. правило "никаких полос прокрутки" в CLAUDE.md проекта). */
.app-nav {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky-nav);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 12px 24px;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}
.app-nav a {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 13px;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 8px 18px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--paper);
  white-space: nowrap;
  transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
  cursor: pointer;
}
.app-nav a:hover {
  border-color: var(--accent-ui);
  color: var(--accent-ui);
  background: var(--accent-ui-soft);
  transform: translateY(-1px);
}
.app-nav a.active {
  border-color: var(--accent-ui);
  background: var(--brand-fill);
  color: #ffffff !important;
  box-shadow: 0 4px 14px var(--accent-ui-soft, rgba(239, 68, 68, 0.3));
  transform: translateY(-1px);
}

/* Вкладки в секции «Настройки» */
.settings-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 14px 18px;
  margin-bottom: 20px;
}
.settings-tabs button {
  margin: 0;
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 999px;
  white-space: nowrap;
  min-height: 36px;
}

.checklist input[type="checkbox"], input[type="checkbox"] { accent-color: var(--accent-ui); }

.page-section { scroll-margin-top: 60px; }
.page-section:not(:first-child) {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

main {
  padding: 16px 20px 60px;
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
  box-sizing: border-box;
  overflow-x: hidden;
}
@media (min-width: 1280px) {
  main {
    max-width: 1560px;
  }
}

h1, h2, h3 {
  font-family: var(--font-display);
  color: var(--ink);
  text-wrap: balance;
}
h1 { font-size: 27px; font-weight: 800; letter-spacing: -0.3px; margin: 0 0 16px; }
h2 { font-size: 17px; font-weight: 800; letter-spacing: -0.1px; margin: 0 0 14px; }
h3 { font-size: 13px; font-weight: 700; margin: 0 0 8px; }

form.card, .card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px;
  margin-bottom: 20px;
  transition: transform 0.22s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.22s ease, border-color 0.22s ease;
}

.card:hover {
  transform: translateY(-2px);
  box-shadow: var(--elevation-2);
}

/* Фото компании на экране входа (просьба пользователя, отложенная с
   прошлой сессии — 26.09.2026): баннер внутри карточки логина и подложка
   на весь экран, обе используют уже лежащий в проекте img/bg-company.jpg. */
.login-card-foto {
  display: block;
  width: calc(100% + 40px);
  margin: 0 -20px 16px;
  height: 160px;
  object-fit: cover;
  border-radius: var(--radius) var(--radius) 0 0;
}

body.login-screen {
  background-image: linear-gradient(rgba(10, 14, 22, 0.55), rgba(10, 14, 22, 0.55)), url('../img/bg-company.jpg');
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
  min-height: 100vh;
}

/* Едва заметная подложка на рабочих экранах (просьба пользователя
   26.09.2026: "стоит добавлять" + "только приглушить, чтобы не
   напрягала") — фиксированный слой ЗА контентом, а не под текстом
   карточек: карточки (.card) непрозрачны и полностью перекрывают его,
   видна только в зазорах между блоками. Отдельный псевдоэлемент, а не
   background на body: opacity на самом body погасил бы весь интерфейс,
   а не только фон. Не показывается на экране входа — там уже своя,
   более заметная подложка (body.login-screen выше). */
body:not(.login-screen)::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background-image: url('../img/bg-company.jpg');
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
  /* [FIX 26.09.2026] 0.05 на белом фоне почти не читалась ("очень плохо
     видно") — на светлом фоне контраст ниже, чем на тёмном, тот же
     процент непрозрачности выглядит слабее. */
  opacity: 0.14;
  pointer-events: none;
}

:root[data-theme="dark"] body:not(.login-screen)::before,
:root[data-theme="graphite"] body:not(.login-screen)::before {
  opacity: 0.1;
}

:root[data-theme="dark"] form.card,
:root[data-theme="graphite"] form.card,
:root[data-theme="dark"] .card ,
:root[data-theme="graphite"] .card {
  background: rgba(17, 24, 39, 0.85);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.5);
}

:root[data-theme="dark"] .card:hover ,
:root[data-theme="graphite"] .card:hover {
  border-color: rgba(56, 189, 248, 0.35);
  /* [FIX Ф-3] Заменён хардкод blue-shadow rgba(56,189,248,...) на
     var(--accent-ui-soft) — синий не из палитры, в фирменном красном
     диссонировал. Теперь hover-glow совпадает с акцент-цветом темы. */
  box-shadow: 0 12px 30px -4px rgba(0, 0, 0, 0.7), 0 0 15px var(--accent-ui-soft, rgba(239, 68, 68, 0.18));
}

:root[data-theme="corporate"] form.card,
:root[data-theme="corporate"] .card {
  background: rgba(15, 28, 63, 0.88);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(56, 189, 248, 0.18);
  box-shadow: 0 4px 20px -2px rgba(5, 10, 25, 0.6);
}

:root[data-theme="corporate"] .card:hover {
  border-color: rgba(245, 158, 11, 0.4);
  box-shadow: 0 12px 30px -4px rgba(5, 10, 25, 0.8), 0 0 15px rgba(245, 158, 11, 0.15);
}

label {
  display: block;
  margin-top: 12px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--ink-soft);
}

input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
select,
textarea {
  width: 100%;
  padding: 9px 10px;
  margin-top: 4px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-family: inherit;
  background: var(--surface);
  color: var(--ink);
  min-height: 40px;
  box-sizing: border-box;
}
textarea { min-height: 60px; }
input:not([type="checkbox"]):not([type="radio"]):focus,
select:focus,
textarea:focus {
  outline: none;
  box-shadow: 0 0 0 3px var(--focus-ring-ui);
  border-color: var(--accent-ui);
}

/* Элегантные, компактные радио-кнопки и чекбоксы без искажения размеров */
input[type="checkbox"],
input[type="radio"] {
  width: 16px !important;
  height: 16px !important;
  min-height: 16px !important;
  max-height: 16px !important;
  margin: 0 !important;
  padding: 0 !important;
  display: inline-block !important;
  vertical-align: middle !important;
  accent-color: var(--accent-ui) !important;
  cursor: pointer !important;
  box-shadow: none !important;
  border: 1px solid var(--border) !important;
  background: var(--surface) !important;
  border-radius: 4px;
  flex-shrink: 0;
}
input[type="radio"] {
  border-radius: 50% !important;
}
/* Автозаполнение браузера красит поле голубым в любой теме, если не
   переопределить явно (утечка стиля, найдено при дизайн-ревью). */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 1000px var(--surface) inset;
  -webkit-text-fill-color: var(--ink);
  transition: background-color 9999s ease-in-out 0s;
}

.form-section {
  border-top: 1px solid var(--border);
  margin-top: 16px;
  padding-top: 14px;
}
.form-section:first-of-type { border-top: none; margin-top: 0; padding-top: 0; }
.form-section-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--muted);
  margin: 0 0 10px;
}

/* Кнопка-обёртка не красится фирменным фоном.
   Глобальное правило ниже заливает ЛЮБУЮ кнопку брендовым красным. Для
   кнопок-обёрток — тех, что оборачивают госномер, бейдж или значок ради
   клика, — это означало красный прямоугольник вместо прозрачного фона:
   белый госномер оказывался на красной плашке, а зелёная оценка G-сенсора
   превращалась в аварийную.
   Правило стоит ПЕРЕД глобальным и работает через !important, потому что у
   селектора по тегу тот же вес, а подключается он позже. Класс
   bg-transparent уже проставлен в разметке — здесь мы просто даём
   объявленному намерению победить. */
/* [ОТКАТ Ф-1] ВАЖНО: правила ниже ДОЛЖНЫ оставаться unlayered.
   Была попытка обернуть их в @layer base «чтобы Tailwind-утилиты могли
   побеждать». Это сломало интерфейс: base-слой имеет МЕНЬШИЙ приоритет, чем
   utilities, поэтому утилиты вида text-[var(--ink)] начали перебивать
   button{color:#fff} — текст на фирменных красных кнопках становился тёмным
   и пропадал. Плюс поехало отображение таблички госномера (она лежит внутри
   кнопки-обёртки).
   Прозрачные кнопки-обёртки и так работают: у button.bg-transparent ниже
   стоит !important, который бьёт unlayered button{}. Возвращаем как было. */
button.bg-transparent,
button.bg-transparent:hover,
button.bg-transparent:focus,
button.bg-transparent:active {
  background: transparent !important;
  background-image: none !important;
  color: inherit !important;
  box-shadow: none;
}

button {
  background: var(--brand-fill);
  color: #fff;
  border: none;
  padding: 7px 16px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  margin-top: 0;
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  min-height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: background 0.15s ease, transform 0.05s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
button:hover { background: var(--brand-fill-dark); }
button:active { transform: translateY(1px); }
button.btn-primary, button[type="submit"] {
  min-height: 42px;
  padding: 10px 20px;
  font-size: 13px;
  font-weight: 700;
}
button.btn-sm, button.secondary.btn-sm {
  min-height: 28px;
  padding: 3px 10px;
  font-size: 11.5px;
  /* [FIX Ф-4] border-radius: 6px был хардкодом — теперь --radius-sm
     (8px), согласован с остальными кнопками. */
  border-radius: var(--radius-sm);
}
button.secondary { background: var(--surface); color: var(--ink); border: 1px solid var(--border); font-weight: 500; }
button.secondary:hover { background: var(--paper); border-color: var(--muted); }
/* [FIX FE-15] Заблокированная кнопка: серый фон --muted с почти чёрным текстом
   давал 3.27:1 при норме 4.5:1 (нашла приёмка на кнопке «В архив» — она
   заблокирована, пока вид топлива используется машинами). Светлый фон и
   приглушённый текст дают 4.7:1, а признак «недоступно» остаётся: курсор и
   цвет границы. Прозрачность убрана намеренно — она снижает контраст ещё
   сильнее, а вычислить её приёмка не может. */
button:disabled {
  background: var(--surface-sunken);
  color: var(--muted);
  border-color: var(--border);
  cursor: not-allowed;
}

/* Инцидент 2026-09-18: спрайт-иконки (.ds-ico-inline, ~50 использований по
   всему приложению — кнопки тулбара, плитки состояния парка, заголовки
   KPI-карточек) не имели ни одного правила размера. SVG без width/height и
   без viewBox на самом теге по умолчанию занимает 300x150 CSS px — кнопки
   "Обновить"/"Скрыть карту" на экране диспетчера раздувались до пустых
   328x138 блоков, неотличимых от карточек-контейнеров, а сам значок при
   этом не отрисовывался вовсе (использование <use> на <symbol> без
   явных width/height схлопывает генерируемое содержимое в 0x0, хотя сам
   SVG-бокс остаётся 300x150). Задаём размер, привязанный к em, чтобы значок
   масштабировался вместе с текстом кнопки/подписи, а не был жёстко к 16px. */
.ds-ico-inline {
  display: inline-block;
  width: 1em;
  height: 1em;
  flex: none;
  vertical-align: -0.15em;
}

/* Внутри flex/grid контейнеров и панелей сбрасываем верхний отступ у кнопок и инпутов */
.flex > button,
.flex > input,
.flex > select,
.flex > textarea,
.grid > button,
header button,
.header-icon-btn,
.settings-tabs button,
.app-nav a,
.app-nav button {
  margin-top: 0;
}

.table-scroll {
  overflow-x: auto;
  /* Высота ограничена намеренно, и это решает сразу две задачи.
     Первая: справочник автопарка на 43 машины растягивал экран Настроек до
     4786px — до нижних вкладок приходилось прокручивать мимо всей таблицы.
     Вторая: у th в проекте объявлен position: sticky, но без ограничения
     высоты у контейнера липнуть ему было не к чему, и шапка уезжала поверх
     содержимого страницы. Теперь она липнет внутри своего окна. */
  overflow-y: auto;
  max-height: 62vh;
  max-width: 100%;
  margin-top: 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  scrollbar-width: thin;
}
.table-scroll::-webkit-scrollbar {
  height: 6px;
  width: 6px;
}
.table-scroll::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 4px;
}
.table-scroll::-webkit-scrollbar-thumb:hover {
  background: var(--muted);
}

/* [FIX БИЗ-24] Меню справочника — карточки в одну линию с горизонтальной
   прокруткой (требование владельца). Карточки одного размера, с иконкой,
   названием и коротким описанием: по описанию видно, что внутри раздела, и не
   нужно открывать его, чтобы понять. Ниже раскрывается только выбранный раздел. */
.spr-karty {
  display: flex;
  align-items: stretch;
  gap: 10px;
  overflow-x: auto;
  padding: 10px 12px;
  scrollbar-width: thin;
}
.spr-karty::-webkit-scrollbar { height: 6px; }
.spr-karty::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }

.spr-karta {
  flex: 0 0 232px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  min-height: 86px;
  padding: 10px 12px;
  text-align: left;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  cursor: pointer;
  white-space: normal;
}
/* [FIX FE-15] При наведении и в активном состоянии карточка остаётся СВЕТЛОЙ:
   общее правило `button:hover { background: var(--accent-ui-dark) }` красило её
   в тёмно-красный, а текст у карточек тёмный — получался чёрный текст на красном,
   который не читается (владелец увидел это на снимке сразу после клика).
   Правило владельца: на красном фоне текст только белый. Здесь красного фона нет
   вовсе — акцент показываем рамкой, поэтому правило не нарушается. */
.spr-karta:hover,
.spr-karta:focus-visible,
.spr-karta:active {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--accent-ui, #DA1F26);
}
/* Активная карточка того же размера, но с акцентом: видно, какой раздел раскрыт. */
.spr-karta:not(.secondary) {
  border-color: var(--accent-ui, #DA1F26);
  box-shadow: inset 0 -2px 0 var(--accent-ui, #DA1F26), 0 1px 3px rgba(0, 0, 0, 0.06);
}
.spr-karta .ds-ico-inline { width: 18px; height: 18px; }
.spr-karta-zag {
  font-size: 13px;
  font-weight: 700;
  line-height: 1.25;
}
.spr-karta-opis {
  font-size: 11.5px;
  color: var(--ink-soft);
  line-height: 1.3;
}
.spr-karta-razdelitel {
  flex: 0 0 1px;
  align-self: stretch;
  margin: 4px 2px;
  background: var(--border);
}

/* [FIX БИЗ-24] Первая колонка СПРАВОЧНЫХ таблиц закреплена по горизонтали.
   Жалоба владельца: в широких справочниках при прокрутке вбок теряется, какую
   строку правишь — название уезжает вместе с содержимым.
   Фон непрозрачный обязательно: сквозь закреплённую ячейку иначе видно
   уезжающие данные, и текст накладывается друг на друга.
   Токены общие для всех четырёх тем, поэтому правило работает и в graphite,
   и в тёмной, и в corporate.

   Почему перечислены ИМЕННО эти таблицы, а не все `.table-scroll`.
   Первая версия правила была общей — и закрепила колонку в таблице автопарка,
   где строка окрашена по статусу машины: непрозрачный фон ячейки перекрыл цвет
   строки, светлый текст оказался на светлом фоне. Приёмка поймала это как
   нарушение контраста (2.54:1 при норме 4.5:1) на госномерах. Справочники —
   те таблицы, где прокрутка мешает правке; таблицы состояний не трогаем.

   z-index у шапки выше, чем у строк: иначе при прокрутке заголовок первой
   колонки уходил бы под ячейки тела таблицы. */
:is(#spravochnikTable, #klientyTable, #tochkiTable, #avtoparkTable, #voditeliTable,
    #normativyTable, #prichinyTable, #proizvTable, #vygruzkaNormyTable, #smenyTable,
    #tochkiDriftTable) th:first-child,
:is(#spravochnikTable, #klientyTable, #tochkiTable, #avtoparkTable, #voditeliTable,
    #normativyTable, #prichinyTable, #proizvTable, #vygruzkaNormyTable, #smenyTable,
    #tochkiDriftTable) td:first-child {
  position: sticky;
  left: 0;
  background: var(--surface);
  z-index: 1;
}
:is(#spravochnikTable, #klientyTable, #tochkiTable, #avtoparkTable, #voditeliTable,
    #normativyTable, #prichinyTable, #proizvTable, #vygruzkaNormyTable, #smenyTable,
    #tochkiDriftTable) th:first-child {
  background: var(--surface-sunken);
  z-index: 2;
}
/* Название в первой колонке не должно разъезжаться по строкам: это опознавательный
   столбец, по нему ищут строку глазами. */
#spravochnikTable td:first-child {
  white-space: nowrap;
  max-width: 320px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* [FIX БИЗ-24] Таблица справочника ШИРЕ окна — и это правильно: владелец
   разрешил горизонтальную прокрутку именно для неё. Раньше 15 колонок
   сжимались под ширину окна (на узком экране до 634 px), названия и адреса
   переносились на несколько строк, и читать строку становилось тяжело.
   Минимальная ширина возвращает нормальные колонки, а первая колонка
   закреплена — при прокрутке вбок видно, какую строку правишь. */
#spravochnikTable {
  /* [FIX ВИЗ-7/10/11] Было 1560px. При пятнадцати колонках этого не хватало:
     пять последних получали по 19px (см. блок `#secTochki` ниже). 2102px —
     сумма заданных ширин колонок, поэтому каждая получает ровно свою. */
  min-width: 2102px;
}
#spravochnikTable th,
#spravochnikTable td {
  white-space: nowrap;
}
#spravochnikTable td:nth-child(4),
#spravochnikTable th:nth-child(4),
#spravochnikTable td:nth-child(7),
#spravochnikTable th:nth-child(7) {
  /* Адрес и владелец бывают длинными — им разрешаем многоточие, а не перенос. */
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
}
table {
  width: 100%;
  max-width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--surface);
  font-variant-numeric: tabular-nums;
  table-layout: auto;
}
th {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--surface);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink);
  padding: 11px 14px;
  border-bottom: 2px solid var(--border);
  white-space: nowrap;
}
td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  font-size: 13px;
  color: var(--ink);
  vertical-align: middle;
}

/* [FIX ВИЗ-12] Компактность и читаемость таблиц — общие правила для ВСЕХ таблиц.
   Зачем общие, а не по одной. Владелец прошёл раздел настроек и сказал: широкие
   строки, местами нет переносов, колонки уже символа — «вид плохой». Причины
   оказались общими для всех таблиц, поэтому и лечатся одним местом:

   1. Кнопки внутри таблиц. У общей `button` стоит `min-height: 36px` и
      `margin-top: 14px` — для формы это правильно, а в ячейке это распирает
      строку до 68px при тексте 11.5px (замер на справочнике). Кнопка в таблице
      должна быть компактной: строка возвращается к 30–37px.
   2. Заголовки переносятся по словам. Прежде `th` был `nowrap`, и в узкой
      колонке подпись превращалась в «ВЫГРУ...» — заголовок переставал
      сообщать, что в колонке. Перенос по словам сохраняет смысл.
   3. Отступы ячеек: 11px/14px давали строку от 44px даже там, где текст в одну
      строку. 6px/8px оставляют воздух, но не раздувают строку.

   Числа, даты, госномера и коды остаются неразрывными — их рвать нельзя,
   для них многоточие честнее переноса (см. `.ds-atomic` в design-system.css). */
table button {
  min-height: 24px;
  padding: 2px 8px;
  margin-top: 0;
  font-size: 11.5px;
}
th {
  white-space: normal;
  line-height: 1.25;
}
td, th {
  padding: 6px 8px;
}
tbody tr:nth-child(even) {
  background: var(--surface);
}
tbody tr:nth-child(odd) {
  background: rgba(0, 0, 0, 0.015);
}
:root[data-theme="dark"] tbody tr:nth-child(odd) ,
:root[data-theme="graphite"] tbody tr:nth-child(odd) {
  background: rgba(255, 255, 255, 0.02);
}
/* Наведение на строку — нейтральная подложка, а не фирменный красный.
   --accent-ui-soft это красный 8 %, и любая строка под курсором выглядела
   аварийной: пользователь принимал подсветку за признак проблемы в рейсе.
   Красный в интерфейсе зарезервирован под три места, подсветка строки в них
   не входит. */
tbody tr:hover {
  background: var(--ds-glass-2, rgba(0, 0, 0, 0.04)) !important;
}
td.truncate {
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.muted-text {
  color: var(--muted);
  font-size: 13px;
}

.error { color: var(--status-red); margin-top: 8px; font-weight: 600; }
.ok { color: var(--status-green); margin-top: 8px; font-weight: 600; }

.badge {
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  line-height: 1.3;
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge-green  { background: var(--status-green-bg);  color: var(--status-green);  border-color: rgba(6, 95, 70, 0.22); }
.badge-yellow { background: var(--status-amber-bg);  color: var(--status-amber);  border-color: rgba(146, 64, 14, 0.25); }
.badge-orange { background: var(--status-orange-bg); color: var(--status-orange); border-color: rgba(154, 52, 18, 0.25); }
.badge-red    { background: var(--status-red-bg);    color: var(--status-red);    border-color: rgba(153, 27, 27, 0.25); }
.badge-gray   { background: var(--status-gray-bg);   color: var(--status-gray);   border-color: rgba(51, 65, 85, 0.2); }
/* [FIX ВИЗ-3] badge-blue переведён на токены — раньше хардкод-цвета
   #dbeafe/#1e40af/#bfdbfe и отдельное правило для dark-темы ниже. */
.badge-blue   { background: var(--status-blue-bg);   color: var(--status-blue);   border-color: var(--status-blue-border); }

:root[data-theme="dark"] .badge-green  ,
:root[data-theme="graphite"] .badge-green  { border-color: rgba(110, 231, 183, 0.25); }
:root[data-theme="dark"] .badge-yellow ,
:root[data-theme="graphite"] .badge-yellow { border-color: rgba(253, 224, 71, 0.25); }
:root[data-theme="dark"] .badge-orange ,
:root[data-theme="graphite"] .badge-orange { border-color: rgba(253, 186, 116, 0.25); }
:root[data-theme="dark"] .badge-red    ,
:root[data-theme="graphite"] .badge-red    { border-color: rgba(252, 165, 165, 0.25); }
:root[data-theme="dark"] .badge-gray   ,
:root[data-theme="graphite"] .badge-gray   { border-color: rgba(203, 213, 225, 0.2); }
/* [FIX ВИЗ-3] badge-blue больше не нуждается в отдельном dark-правиле —
   цвета берутся из токенов --status-blue* (см. dark/corporate :root) */

/* Унифицированные бейджи характеристик ТС */
/* [FIX ВИЗ-3] vbadge-cap / vbadge-vol переведены на токены */
.vbadge-cap {
  font-size: 11.5px;
  font-weight: 600;
  font-family: monospace;
  background: var(--status-sky-bg);
  color: var(--status-sky);
  border: 1px solid var(--status-sky-border);
  padding: 1px 5px;
  border-radius: 4px;
  white-space: nowrap;
}
.vbadge-vol {
  font-size: 11.5px;
  font-weight: 600;
  font-family: monospace;
  background: var(--status-vol-bg);
  color: var(--status-vol);
  border: 1px solid var(--status-vol-border);
  padding: 1px 5px;
  border-radius: 4px;
  white-space: nowrap;
}
/* [FIX ВИЗ-3] Отдельные dark-правила для vbadge-cap/vol больше не нужны —
   значения зашиты в токены --status-sky и --status-vol для каждой темы.
   ВНИМАНИЕ: в тексте этого комментария НЕЛЬЗЯ писать последовательность
   «звёздочка-слэш» (она закрывает комментарий досрочно). В первой редакции
   она случайно попала в запись «--status-sky* / --status-vol*», комментарий
   оборвался, остаток склеился со следующим правилом .uz-plate — и браузер
   отбросил ВСЁ правило госномера: пропала рамка, поехали переносы строк. */

/* ==========================================================================
   НАСТОЯЩИЙ ГОСНОМЕР РЕСПУБЛИКИ УЗБЕКИСТАН (Uzbekistan License Plate)
   ========================================================================== */
.uz-plate {
  display: inline-flex;
  align-items: center;
  background: linear-gradient(180deg, #ffffff 0%, #f6f8fa 45%, #e9ecef 100%);
  border: 1.5px solid #1a1a1a;
  border-radius: 4px;
  box-shadow: 
    0 1px 2px rgba(0, 0, 0, 0.18),
    inset 0 1px 0 rgba(255, 255, 255, 0.95),
    inset 0 -1px 0 rgba(0, 0, 0, 0.1);
  padding: 0 4px;
  gap: 0;
  height: 24px;
  line-height: 1;
  font-family: 'DIN Alternate', 'DIN 1451', 'Trebuchet MS', 'Consolas', monospace;
  font-weight: 800;
  color: #111111;
  user-select: none;
  white-space: nowrap;
  vertical-align: middle;
  position: relative;
  box-sizing: border-box;
  text-shadow: 0 0.5px 0.5px rgba(255, 255, 255, 0.7);
  transition: transform 0.1s ease, box-shadow 0.15s ease;
}
.uz-plate:hover {
  transform: translateY(-0.5px);
  box-shadow: 
    0 2px 4px rgba(0, 0, 0, 0.25),
    inset 0 1px 0 rgba(255, 255, 255, 1);
}

/* Эффект монтажных заклепок номера */
.uz-plate-rivet {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #ffffff, #94a3b8 70%, #334155 100%);
  box-shadow: inset 0 0.5px 0.5px rgba(0,0,0,0.6);
  flex-shrink: 0;
}
.uz-plate-rivet.left {
  margin-right: 3px;
}
.uz-plate-rivet.right {
  margin-left: 3px;
}

/* Код региона: 25, 01, 10 и т.д. */
.uz-plate-region {
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.5px;
  padding: 0 2px 0 1px;
  color: #0f172a;
}

/* Разделитель между регионом и номером */
.uz-plate-divider {
  width: 1.5px;
  height: 16px;
  background-color: #1a1a1a;
  margin: 0 3px;
  flex-shrink: 0;
}

/* Основной блок номера: 332 LAA */
.uz-plate-number {
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.8px;
  padding: 0 4px 0 2px;
  color: #0f172a;
  text-transform: uppercase;
}

/* Правый блок: Флаг Узбекистана + надпись UZ */
.uz-plate-flag-box {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: 0 1px 0 3px;
  border-left: 1px solid #cbd5e1;
  flex-shrink: 0;
}

.uz-plate-flag-svg {
  width: 14px;
  height: 8px;
  border-radius: 1px;
  box-shadow: 0 0 1px rgba(0,0,0,0.4);
  display: block;
}

.uz-plate-uz-code {
  font-size: 8.5px;
  font-weight: 900;
  /* Настоящий узбекский номер набран #0099b5, но на белом поле таблички это
     3.37:1 — провал AA для текста 8.5px. Оттенок сохранён, светлота снижена
     на 27%: 4.65:1 даже на самом тёмном конце градиента таблички (#e9ecef). */
  color: #007388;
  line-height: 1;
  letter-spacing: 0.5px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

/* Варианты размеров госномера */
.uz-plate.uz-plate-sm {
  height: 22px;
  padding: 0 3px;
}
.uz-plate.uz-plate-sm .uz-plate-region { font-size: 11.5px; }
.uz-plate.uz-plate-sm .uz-plate-number { font-size: 11.5px; }
.uz-plate.uz-plate-sm .uz-plate-divider { height: 14px; margin: 0 2.5px; }
.uz-plate.uz-plate-sm .uz-plate-flag-svg { width: 12px; height: 7px; }
.uz-plate.uz-plate-sm .uz-plate-uz-code { font-size: 8.5px; }

.uz-plate.uz-plate-md {
  height: 25px;
  padding: 0 4px;
}
.uz-plate.uz-plate-md .uz-plate-region { font-size: 13px; }
.uz-plate.uz-plate-md .uz-plate-number { font-size: 13px; }
.uz-plate.uz-plate-md .uz-plate-divider { height: 17px; }

.uz-plate.uz-plate-lg {
  height: 30px;
  padding: 0 6px;
}
.uz-plate.uz-plate-lg .uz-plate-region { font-size: 17px; }
.uz-plate.uz-plate-lg .uz-plate-number { font-size: 17px; }
.uz-plate.uz-plate-lg .uz-plate-divider { height: 20px; }
.uz-plate.uz-plate-lg .uz-plate-flag-svg { width: 18px; height: 10px; }
.uz-plate.uz-plate-lg .uz-plate-uz-code { font-size: 8.5px; }

/* В темной теме настоящий номер остается металлическим белым, адаптируется тень */
:root[data-theme="dark"] .uz-plate ,
:root[data-theme="graphite"] .uz-plate {
  box-shadow: 
    0 2px 5px rgba(0, 0, 0, 0.5),
    inset 0 1px 0 rgba(255, 255, 255, 0.95);
  border-color: #0f172a;
}

/* ==========================================================================
   РЕАЛИСТИЧНЫЕ ТАКТИЛЬНЫЕ ПИКТОГРАММЫ (Tactile Badges & Pictograms)
   ========================================================================== */

/* 1. Персоналии (Мастер, Механик, Водитель) */
.person-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 8px 2px 4px;
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 11.5px;
  white-space: nowrap;
  box-shadow: 0 1px 2px rgba(0,0,0,0.03);
}
.person-pill-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  font-size: 11.5px;
}
.person-pill-name {
  font-weight: 700;
  color: var(--ink);
}
.person-pill-role {
  font-size: 10px;
  font-weight: 600;
  color: var(--ink-soft);
  background: var(--surface-sunken);
  padding: 1px 5px;
  border-radius: 4px;
}

/* 2. Источник Telegram */
.tg-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11.5px;
  font-weight: 600;
  /* #0284c7 на #f0f9ff давал 3.84:1 при норме 4.5 — имя отправителя заявки
     читалось хуже остального текста именно там, где его и читают: в списке
     заявок из Telegram. #075985 на том же фоне даёт 6.4:1. */
  color: #075985;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
  padding: 1px 6px;
  border-radius: 999px;
  margin-top: 3px;
  white-space: nowrap;
}
:root[data-theme="dark"] .tg-pill ,
:root[data-theme="graphite"] .tg-pill {
  background: rgba(2, 132, 199, 0.15);
  color: #38bdf8;
  border-color: rgba(56, 189, 248, 0.3);
}

/* 3. Способы оплаты (Наличные, Карта, Перечисление, В долг) */
.pay-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
  max-width: 100%;
  box-sizing: border-box;
  box-shadow: 0 1px 2px rgba(0,0,0,0.03);
  border: 1px solid transparent;
}
.pay-chip.pay-cash {
  background: #ecfdf5;
  color: #047857;
  border-color: #a7f3d0;
}
.pay-chip.pay-card {
  background: #eff6ff;
  color: #1d4ed8;
  border-color: #bfdbfe;
}
.pay-chip.pay-bank {
  background: #f5f3ff;
  color: #6d28d9;
  border-color: #ddd6fe;
}
.pay-chip.pay-debt {
  background: #fffbeb;
  color: #b45309;
  border-color: #fde68a;
}
:root[data-theme="dark"] .pay-chip.pay-cash ,
:root[data-theme="graphite"] .pay-chip.pay-cash {
  background: rgba(4, 120, 87, 0.2);
  color: #6ee7b7;
  border-color: rgba(110, 231, 183, 0.3);
}
:root[data-theme="dark"] .pay-chip.pay-card ,
:root[data-theme="graphite"] .pay-chip.pay-card {
  background: rgba(29, 78, 216, 0.2);
  color: #93c5fd;
  border-color: rgba(147, 197, 253, 0.3);
}
:root[data-theme="dark"] .pay-chip.pay-bank ,
:root[data-theme="graphite"] .pay-chip.pay-bank {
  background: rgba(109, 40, 217, 0.2);
  color: #c4b5fd;
  border-color: rgba(196, 181, 253, 0.3);
}
:root[data-theme="dark"] .pay-chip.pay-debt ,
:root[data-theme="graphite"] .pay-chip.pay-debt {
  background: rgba(180, 83, 9, 0.2);
  color: #fcd34d;
  border-color: rgba(252, 211, 77, 0.3);
}

/* 4. Категории ремонта */
.cat-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 6px;
  font-size: 11.5px;
  font-weight: 700;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--border);
  white-space: nowrap;
}
.cat-chip.cat-gbo {
  background: #fff7ed;
  color: #c2410c;
  border-color: #ffedd5;
}
.cat-chip.cat-to {
  background: #f0fdf4;
  color: #15803d;
  border-color: #dcfce7;
}
.cat-chip.cat-chassis {
  background: #f8fafc;
  color: #334155;
  border-color: #e2e8f0;
}
:root[data-theme="dark"] .cat-chip.cat-gbo ,
:root[data-theme="graphite"] .cat-chip.cat-gbo {
  background: rgba(194, 65, 12, 0.2);
  color: #fb923c;
  border-color: rgba(251, 146, 60, 0.3);
}
:root[data-theme="dark"] .cat-chip.cat-to ,
:root[data-theme="graphite"] .cat-chip.cat-to {
  background: rgba(21, 128, 61, 0.2);
  color: #86efac;
  border-color: rgba(134, 239, 172, 0.3);
}
:root[data-theme="dark"] .cat-chip.cat-chassis ,
:root[data-theme="graphite"] .cat-chip.cat-chassis {
  background: rgba(51, 65, 85, 0.2);
  color: #cbd5e1;
  border-color: rgba(203, 213, 225, 0.3);
}

/* 5. Спидометр / Одометр */
.odo-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 7px;
  border-radius: 6px;
  font-size: 11.5px;
  font-family: var(--font-display);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  background: var(--surface-sunken);
  color: var(--ink);
  border: 1px solid var(--border);
  white-space: nowrap;
}

/* 6. Стоимость ремонта / Финансовый блок */
.cost-pill {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
}
.cost-pill-usd {
  font-size: 13px;
  font-weight: 800;
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  /* [FIX ВИЗ-16] Токен вместо хардкода: прежний список исключений для
     тёмных тем забыл corporate, и «$ 3,91» оставался тёмно-зелёным на
     тёмном фоне (3.17:1). --status-green в каждой теме уже тот самый цвет. */
  color: var(--status-green);
  white-space: nowrap;
}
.cost-pill-uzs {
  font-size: 10px;
  font-weight: 600;
  color: var(--ink-soft);
  white-space: nowrap;
}

/* 7. Медиа-чипы (Фото, Видео-кружочек, Telegram) */
.media-chip, .tg-link-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  cursor: pointer;
  user-select: none;
  transition: transform 0.1s ease, background 0.15s ease, border-color 0.15s ease;
  white-space: nowrap;
  text-decoration: none;
}
.tg-link-chip {
  background: var(--accent-ui-soft, rgba(239, 68, 68, 0.1));
  color: var(--accent-ui, #ef4444);
  border: 1px solid var(--accent-ui);
}
.tg-link-chip:hover {
  background: var(--brand-fill);
  color: #ffffff;
  transform: translateY(-1px);
}
.media-chip-photo {
  background: var(--surface-sunken);
  color: var(--ink);
  border: 1px solid var(--border);
}
.media-chip-photo:hover {
  background: var(--paper-soft);
  transform: translateY(-1px);
}
.media-chip-video {
  background: var(--status-purple-bg, rgba(168, 85, 247, 0.12));
  color: var(--status-purple, #9333ea);
  border: 1px solid var(--status-purple-border, rgba(168, 85, 247, 0.3));
}
.media-chip-video:hover {
  background: var(--status-purple-bg, rgba(168, 85, 247, 0.22));
  transform: translateY(-1px);
}
:root[data-theme="dark"] .tg-link-chip,
:root[data-theme="graphite"] .tg-link-chip,
:root[data-theme="corporate"] .tg-link-chip {
  background: rgba(59, 130, 246, 0.15);
  color: #60a5fa;
  border-color: rgba(96, 165, 250, 0.4);
}
:root[data-theme="dark"] .tg-link-chip:hover,
:root[data-theme="graphite"] .tg-link-chip:hover,
:root[data-theme="corporate"] .tg-link-chip:hover {
  background: #2563eb;
  color: #ffffff;
}
:root[data-theme="dark"] .media-chip-photo,
:root[data-theme="graphite"] .media-chip-photo,
:root[data-theme="corporate"] .media-chip-photo {
  background: rgba(255, 255, 255, 0.06);
  color: var(--ink);
  border-color: var(--border);
}
:root[data-theme="dark"] .media-chip-video,
:root[data-theme="graphite"] .media-chip-video,
:root[data-theme="corporate"] .media-chip-video {
  background: rgba(168, 85, 247, 0.18);
  color: #c084fc;
  border-color: rgba(192, 132, 252, 0.35);
}

/* ===================================================================== */
/* БЛОК МОНИТОРИНГА АВТОПАРКА (РЕЕСТР ТС, КАТЕГОРИИ, СТАТУСЫ) */
/* ===================================================================== */
.fleet-roster-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.fleet-roster-card:hover {
  border-color: var(--accent-ui);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.07);
}
.fleet-roster-card.is-repair {
  background: var(--status-red-bg);
  border-color: rgba(220, 38, 38, 0.35);
}
.fleet-roster-card.is-repair:hover {
  border-color: var(--status-red);
}
.fleet-roster-card.is-trip {
  background: var(--status-amber-bg);
  border-color: rgba(217, 119, 6, 0.35);
}
.fleet-roster-card.is-trip:hover {
  border-color: var(--status-amber);
}
.fleet-roster-card.is-ready {
  background: var(--surface);
}

.fleet-card-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 6px;
  border-bottom: 1px dashed var(--border);
}

.fleet-cat-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11.5px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 6px;
  background: var(--surface-sunken);
  color: var(--ink-soft);
  border: 1px solid var(--border);
}

.status-badge-repair {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--status-red);
  background: rgba(220, 38, 38, 0.12);
  padding: 2px 8px;
  border-radius: 12px;
  border: 1px solid rgba(220, 38, 38, 0.25);
}

.status-badge-trip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--status-amber);
  background: rgba(217, 119, 6, 0.12);
  padding: 2px 8px;
  border-radius: 12px;
  border: 1px solid rgba(217, 119, 6, 0.25);
}

.status-badge-ready {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--status-green);
  background: rgba(22, 163, 74, 0.12);
  padding: 2px 8px;
  border-radius: 12px;
  border: 1px solid rgba(22, 163, 74, 0.25);
}

.status-dot-pulse {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  display: inline-block;
}
.status-dot-pulse.red {
  background: var(--status-red);
  box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.2);
}
.status-dot-pulse.amber {
  background: var(--status-amber);
  box-shadow: 0 0 0 2px rgba(217, 119, 6, 0.2);
}
.status-dot-pulse.green {
  background: var(--status-green);
  box-shadow: 0 0 0 2px rgba(22, 163, 74, 0.2);
}

.fleet-card-model {
  min-height: 20px;
  display: flex;
  align-items: center;
}

.fleet-card-specs {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.spec-pill {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  padding: 2px 6px;
  border-radius: 6px;
  white-space: nowrap;
}
.spec-pill.muted {
  color: var(--ink-soft);
  font-weight: 500;
}

.fleet-card-status-info {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 8px;
  font-size: 11.5px;
  min-height: 48px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.repair-notice {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.repair-prichina-text {
  font-size: 11.5px;
  color: var(--status-red);
  font-weight: 600;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.fleet-action-btn {
  background: var(--status-red);
  color: #fff;
  border: none;
  font-size: 10px;
  font-weight: 700;
  padding: 4px 8px;
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
  transition: opacity 0.15s;
}
.fleet-action-btn:hover {
  opacity: 0.9;
}

.trip-notice {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  font-size: 11.5px;
}
.trip-id-chip {
  background: var(--accent-ui-soft);
  color: var(--accent-ui);
  font-weight: 700;
  padding: 2px 6px;
  border-radius: 4px;
}
.driver-name {
  color: var(--ink-soft);
  font-weight: 600;
  max-width: 130px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ready-notice {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11.5px;
  color: var(--ink-soft);
}

.fleet-card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 6px;
  border-top: 1px solid var(--border);
  font-size: 11.5px;
}

.map-focus-btn {
  background: transparent;
  /* [FIX ВИЗ-17] Было `var(--accent-ui)` — фирменный красный как ЦВЕТ ТЕКСТА
     даёт 4.09:1 на светлой карточке при норме 4.5:1 (замер приёмки на вкладке
     «Парк»). Тёмный вариант того же цвета — 6.66:1. Красный как заливка
     остаётся в hover, там текст белый. */
  color: var(--accent-ui-dark, #b8141a);
  border: 1px solid var(--accent-ui-dark, #b8141a);
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.15s;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.map-focus-btn:hover {
  background: var(--brand-fill);
  color: #fff;
}

/* ==========================================================================
   ЕДИНАЯ ЛЕГЕНДА КАРТ (унификация 2026-09-21)
   ==========================================================================
   До этой правки легенды на 7 картах были свёрстаны каждая своими
   utility-классами и различались: радиусом (rounded-lg 8px против rounded-xl
   12px), паддингом (p-2 против p-2.5), размером точки (w-2 против w-2.5),
   зазором (gap-1.5 против gap-2), шрифтом (--ds-f2 против --ds-f3) и
   положением (bottom-2 против bottom-3). Часть цветов была хардкодом
   (bg-emerald-500, bg-purple-600) вне токенов.
   Здесь — единственный источник стилей: разметка легенд ссылается на
   .map-legend и его элементы, а размеры/цвета заданы один раз.
   Класс .map-floating-legend, который уже стоял в разметке карт, оставлен
   как совместимый алиас. */
.map-legend,
.map-floating-legend {
  position: absolute;
  right: 12px;
  bottom: 12px;
  z-index: 400;
  max-width: 240px;
  padding: 10px;
  background: color-mix(in srgb, var(--surface) 95%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--elevation-2);
  font-size: var(--ds-f3);
  line-height: 1.35;
  color: var(--ink);
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* Легенда должна оставаться кликабельной, даже если контейнер карты
     отключает события (RepairMiniMap ставил pointer-events-auto вручную). */
  pointer-events: auto;
}
/* Компактный вариант — только для мини-карт (высота 220px), меняет
   ИСКЛЮЧИТЕЛЬНО максимальную ширину. Всё остальное общее. */
.map-legend--compact { max-width: 200px; }

.map-legend__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--border);
  font-weight: 700;
  color: var(--ink);
}
.map-legend__title { display: inline-flex; align-items: center; gap: 4px; }
.map-legend__actions { display: inline-flex; align-items: center; gap: 6px; }
.map-legend__reset {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  min-height: 0;
  font-size: var(--ds-f2);
  color: var(--accent-ui);
  text-decoration: underline;
  cursor: pointer;
}
.map-legend__close {
  background: none;
  border: none;
  padding: 2px 4px;
  margin: 0;
  min-height: 0;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.map-legend__close:hover { color: var(--ink); background: var(--paper-soft); }

.map-legend__body { display: flex; flex-direction: column; gap: 4px; }
.map-legend__row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 1px 2px;
  border-radius: var(--radius-sm);
}
.map-legend__row--clickable { cursor: pointer; transition: background 0.15s, opacity 0.15s; }
.map-legend__row--clickable:hover { background: var(--paper-soft); }
.map-legend__row--muted { opacity: 0.4; }
.map-legend__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  display: inline-block;
}
/* Вариант точки-кружка с иконкой внутри (легенда инцидентов G-сенсора):
   размер задаётся здесь, чтобы совпадал на всех картах. */
.map-legend__dot--icon {
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--ds-f2);
  color: #fff;
}
/* Линия-образец в легенде (план/факт маршрута) — единая длина и толщина. */
.map-legend__line {
  width: 16px;
  height: 0;
  flex-shrink: 0;
  display: inline-block;
  border-radius: 2px;
}
.map-legend__label { color: var(--ink); }
.map-legend__ico { display: inline-flex; align-items: center; flex-shrink: 0; }

.map-legend__foot {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding-top: 5px;
  border-top: 1px solid var(--border);
  color: var(--muted);
}
.map-legend__foot-item { display: inline-flex; align-items: center; gap: 4px; }


.role-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; }
.role-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 22px 16px;
  text-align: center;
  cursor: pointer;
  font-family: var(--font-display);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  transition: border-color 0.15s ease, transform 0.1s ease;
}
.role-card:hover { border-color: var(--accent-ui); transform: translateY(-2px); }

/* Единая дизайн-система KPI-плиток (Пункт 17 Дорожной карты). Подъём при
   наведении и появление при монтировании (27.09.2026) — раньше transform
   был объявлен в transition, но ничего его не запускало на hover: плитка
   меняла только цвет рамки. Тот же класс используется на Дашборде,
   Автопарке, Складе (через WarehouseScreen.vue) и Разборе рейса — правка
   здесь одна на все экраны, без правки каждого .vue-файла. */
.kpi-card-unified {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 106px;
  cursor: default;
  transition: border-color 0.15s ease, transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 0.22s ease;
  animation: ds-rise 0.4s cubic-bezier(0.2, 0.7, 0.2, 1) backwards;
}
.kpi-card-unified:hover {
  border-color: var(--accent-ui);
  transform: translateY(-2px);
  box-shadow: var(--ds-sh-hi, 0 8px 20px rgba(0, 0, 0, 0.1));
}
@media (prefers-reduced-motion: reduce) {
  .kpi-card-unified { animation: none; transition: border-color 0.15s ease; }
  .kpi-card-unified:hover { transform: none; box-shadow: var(--shadow); }
}
.kpi-card-unified .kpi-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}
.kpi-card-title { font-size: 13px; font-weight: 600; text-transform: none; line-height: 1.3; letter-spacing: 0; color: var(--ink-soft); }
.kpi-card-unified .kpi-card-icon {
  font-size: 13px;
  line-height: 1;
}
.kpi-card-value { font-size: 27px; font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; line-height: 1.05; }
.kpi-card-unified .kpi-card-footer {
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-top: 8px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  line-height: 1.25;
}

.inline-form { border-top: 1px dashed var(--border); margin-top: 10px; padding-top: 14px; }
.checklist label { display: inline-block; margin-right: 16px; font-size: 13px; }
.checklist input { width: auto; min-height: auto; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; }

/* Grid/widget-layout вместо сплошной ленты карточек (Sprint C, Д4) —
   применяется точечно (класс "dash-grid" на секции), не глобально на все
   .page-section: складские/диспетчерская секции монтируют Vue-приложение
   в один div и их не касается. ".span-full" — для карточек с широкими
   таблицами/картой/BI-графиками, которым сжатие в колонку повредило бы
   читаемость; без класса карточка встаёт в авто-колонку (напр. "Точность
   планирования" + "Срезы" — обе узкие, естественно встают рядом). */
.dash-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
  gap: 20px;
  align-items: start;
}
.dash-grid > h1 { grid-column: 1 / -1; margin: 0; }

/* Панель вкладок занимает всю строку сетки.
   Без этого она оказывалась одним элементом в колонке шириной 433 px при
   доступных 1338 и не помещалась в один ряд: «Водители» переносились на
   вторую строку, панель становилась вдвое выше и сдвигала вниз всю
   страницу. Разница была всего 18 пикселей, но платили за неё 80 по
   высоте на каждом открытии дашборда. */
.dash-grid > .fleet-tabbar { grid-column: 1 / -1; }
.dash-grid > .span-full,
.dash-grid > .card.span-full { grid-column: 1 / -1; width: 100%; box-sizing: border-box; }
/* .card задаёт margin-bottom:20px для ленточной раскладки — внутри grid это
   даст двойной отступ (margin + gap), нейтрализуем на грид-детях. */
.dash-grid > .card { margin-bottom: 0; }

.card-header-split {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.header-title-zone {
  flex: 1 1 auto;
}
.header-title-zone h1,
.header-title-zone h2 {
  text-wrap: normal !important;
}
.header-actions-zone {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Переключение разделов (index.html activateSection, решение 2026-09-03)
   скрывает секции через classList, а не только inline style.display —
   .dash-grid{display:grid!important} иначе побеждает inline "display:none"
   у скрытой вкладки "Дашборд" (важность одинаковая, но inline-стиль не
   участвует в каскаде по специфичности классов; правило ниже той же
   специфичности, но идёт позже в файле и потому выигрывает). */
.is-hidden { display: none !important; }

/* Статус-панель рейса (стадии/трек/таймер) — токенизировано под тему.
   Без max-height/overflow: правило проекта — никаких скроллов внутри
   карточек, высота всегда по контенту (см. CLAUDE.md проекта). */
.status-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

/* Слева текст (дедлайн/статус/степпер), справа компактная миниатюра карты —
   карте не нужна полная ширина страницы, как было раньше. */
.status-panel-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(220px, 280px);
  gap: 18px;
  /* stretch (не start) — карта тянется по высоте до размера текстовой
     колонки, без пустого места снизу/сбоку (замечание пользователя:
     "не должно быть свободных областей"). */
  align-items: stretch;
}
/* min-width:0 обязателен — иначе степпер (не сжимаемые шаги внутри своего
   overflow-x:auto) тянет за собой всю grid-колонку и толкает миниатюру карты
   за пределы экрана, создавая горизонтальную прокрутку страницы. */
.status-left { min-width: 0; }
.status-right { min-width: 0; display: flex; flex-direction: column; }

/* Таймер — самое важное число на панели, ему нужен наибольший визуальный вес
   (независимый вывод обоих дизайн-ревью: раньше это был мелкий текст сбоку). */
.status-timer {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 800;
  padding: 4px 12px;
  border-radius: 999px;
  white-space: nowrap;
}
.status-timer.ok      { color: var(--status-green); background: var(--status-green-bg); }
.status-timer.warn    { color: var(--current);      background: var(--current-bg); }
.status-timer.overdue { color: var(--status-red);   background: var(--status-red-bg); }

/* Степпер стадий рейса, сгруппированный по смыслу (Загрузка / К дилеру /
   Выгрузка и возврат) — рельса + кружки-шаги вместо мешка тегов. Группы
   переносятся на новую строку при нехватке места (flex-wrap), НЕ уходят в
   горизонтальный скролл — в интерфейсе не должно быть полос прокрутки. */
.stepper {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  row-gap: 14px;
  column-gap: 18px;
  padding: 4px 2px 8px;
  margin-bottom: 4px;
}
.stepper-group {
  display: flex;
  flex-direction: column;
}
.stepper-group-title {
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--muted);
  margin: 0 0 6px 2px;
}
.stepper-group-steps {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  row-gap: 8px;
}
.step {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-shrink: 0;
  width: 84px;
}
.step-dot {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11.5px;
  font-weight: 800;
  font-family: var(--font-display);
  flex-shrink: 0;
}
.step.done .step-dot {
  background: var(--status-green);
  color: #fff;
}
.step.done.late .step-dot {
  background: var(--status-red);
}
.step.done.late .step-label {
  color: var(--status-red);
}
.step.current .step-dot {
  background: var(--current);
  color: #fff;
  box-shadow: 0 0 0 4px var(--current-bg);
}
.step.future .step-dot {
  background: var(--paper);
  border: 1px solid var(--border);
  color: var(--muted);
}
.step-label {
  font-size: 10px;
  line-height: 1.25;
  margin-top: 5px;
  text-align: center;
  color: var(--muted);
}
.step.current .step-label { color: var(--current); font-weight: 700; }
.step.done .step-label { color: var(--ink-soft); }
.step-connector {
  flex: 1 1 20px;
  height: 2px;
  min-width: 16px;
  background: var(--border);
  margin-top: 12px;
}
.step-connector.done { background: var(--status-green); }

.trip-map {
  width: 100%;
  height: 280px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
/* Миниатюра в правой колонке статус-панели — компактнее, чем полноширинная
   карта (та осталась доступна другим местам, если понадобится). */
.trip-map-thumb { flex: 1 1 auto; height: auto; min-height: 190px; }

/* Кнопка "развернуть карту на весь экран" — поверх миниатюры (rightCol с
   position:relative) либо поверх полноэкранного оверлея. */
/* Кнопка "моя геолокация" на карте (Sprint D, Д18) — тот же визуальный язык,
   что и стандартные leaflet-bar контролы (зум), просто с эмодзи вместо +/-. */
.map-locate-btn {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  line-height: 1;
  background: #fff;
  cursor: pointer;
  border: none;
}
.map-locate-btn:hover { background: #f4f4f4; }

.map-expand-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 10;
  width: 30px;
  height: 30px;
  min-height: 0;
  padding: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  border: none;
  border-radius: var(--radius-sm);
  font-size: 13px;
  cursor: pointer;
}
.map-expand-btn:hover { background: rgba(0, 0, 0, 0.75); }

.map-fullscreen-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px;
}
.map-fullscreen-overlay .trip-map {
  width: 100%;
  height: 100%;
  max-width: 1400px;
}
/* Приглушённый вид бесплатных тайлов OSM через CSS-фильтр (не через платный
   тайл-провайдер — CARTO отменил анонимный бесплатный доступ). В тёмной теме
   --map-filter дополнительно инвертирует тайлы, чтобы карта не била по глазам
   белым фоном на чёрной странице. */
.trip-map .leaflet-tile-pane { filter: var(--map-filter); }

/* Модалка "Новый рейс" (см. план миграции, Sprint 1, шаг 1.2 — форма
   создания рейса вынесена из постоянно видимой части экрана "Диспетчер" в
   модальное окно). Та же схема, что у .map-fullscreen-overlay (уже
   established паттерн в проекте) — position:fixed/inset:0/backdrop, поэтому
   не заводим второй визуальный язык для одного и того же типа UI. Скролл
   ВНУТРИ .trip-create-modal-panel — намеренное исключение из общего правила
   "никаких скроллов в карточках" (см. CLAUDE.md): это не карточка на
   странице, а модальный диалог поверх контента, стандартный паттерн, когда
   форма выше вьюпорта — в отличие от инцидента с status-panel, тут скролл
   ожидаем и не маскируется под "часть страницы". */
.trip-create-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 32px 16px;
}
.trip-create-modal-panel {
  width: 100%;
  max-width: 900px;
  max-height: calc(100vh - 64px);
  overflow-y: auto;
  overflow-x: hidden;
  background: var(--paper);
  border-radius: 20px;
  padding: 24px;
  position: relative;
  box-sizing: border-box;
  box-shadow: var(--elevation-3);
}
.trip-create-modal-close {
  position: absolute;
  top: 16px;
  right: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--ink);
  border-radius: 999px;
  width: 36px;
  height: 36px;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  z-index: 1;
}
.trip-create-modal-close:hover { background: var(--border); }

/* ===== Форма "Новый рейс" — карточки/floating-label/комбобокс/fullscreen
   (графитовый редизайн, 2026-08-29). ===== */

.trip-form-cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  align-items: start;
  margin-bottom: 20px;
}
@media (max-width: 980px) { .trip-form-cards { grid-template-columns: 1fr; } }

.form-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  transition: transform 0.3s ease, opacity 0.3s ease;
}
.form-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}
.form-card-head h3 {
  margin: 0;
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: 9px;
}
.step-badge {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--accent-ui-soft);
  color: var(--accent-ui);
  font-size: 11.5px;
  font-weight: 800;
  font-family: var(--font-display);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.form-card-body { padding: 16px; display: flex; flex-direction: column; gap: 14px; }
.form-expand-btn {
  width: 28px;
  height: 28px;
  min-height: 0;
  margin: 0;
  padding: 0;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: transparent;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.15s ease;
}
.form-expand-btn:hover { background: var(--accent-ui-soft); color: var(--accent-ui); border-color: transparent; }
.form-expand-btn svg { width: 14px; height: 14px; }
.form-expand-btn .icon-collapse { display: none; }
.form-card.is-expanded .form-expand-btn .icon-expand { display: none; }
.form-card.is-expanded .form-expand-btn .icon-collapse { display: flex; }
/* Разворот без position:fixed/overflow — карточка физически переносится в
   начало формы и растягивается на всю ширину В ПОТОКЕ документа, поэтому при
   переполнении скроллится страница целиком (правило "никаких скроллов внутри
   карточек" из CLAUDE.md проекта не допускает даже fullscreen-исключений). */
.form-card.is-expanded { grid-column: 1 / -1; }
.trip-form-cards.has-expanded > .form-card:not(.is-expanded) { opacity: 0.35; pointer-events: none; }

/* floating label */
.ffield { position: relative; }
.ffield input, .ffield select, .ffield textarea {
  padding: 18px 12px 7px;
  min-height: 46px;
}
.ffield textarea { padding-top: 20px; }
.ffield label {
  position: absolute;
  left: 12px;
  top: 14px;
  margin: 0;
  color: var(--muted);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
  pointer-events: none;
  transform-origin: left top;
  transition: transform 0.15s ease, top 0.15s ease, color 0.15s ease;
}
.ffield input::placeholder, .ffield textarea::placeholder { color: transparent; }
.ffield input:focus + label, .ffield input:not(:placeholder-shown) + label,
.ffield textarea:focus + label, .ffield textarea:not(:placeholder-shown) + label,
.ffield.always-float label {
  top: 6px;
  transform: scale(0.76);
  color: var(--muted);
}
.ffield input:focus + label, .ffield textarea:focus + label { color: var(--accent-ui); }
.ffield.required label::after { content: " *"; color: var(--red); }

/* combobox (progressive enhancement over a real <select>, see common.js
   enhanceCombobox — the <select> stays in the DOM and holds the real value,
   dispatcher.js's existing submit/populate logic is untouched) */
.combo-wrap { position: relative; }
.combo-wrap select { position: absolute; opacity: 0; pointer-events: none; }
.combo-input { padding-right: 32px !important; cursor: pointer; }
.combo-chevron {
  position: absolute; right: 10px; top: 16px; width: 15px; height: 15px;
  color: var(--muted); pointer-events: none; transition: transform 0.2s ease, color 0.2s ease;
}
.combo-wrap.open .combo-chevron { transform: rotate(180deg); color: var(--accent-ui); }
.combo-panel {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: var(--z-dropdown);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm);
  box-shadow: var(--elevation-2); max-height: 220px; overflow-y: auto;
  margin: 0; padding: 5px; list-style: none;
  opacity: 0; transform: translateY(-4px); pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease;
}
.combo-wrap.open .combo-panel { opacity: 1; transform: translateY(0); pointer-events: auto; }
.combo-panel li {
  padding: 8px 9px; border-radius: 6px; cursor: pointer; font-size: 13px; color: var(--ink-soft);
}
.combo-panel li:hover, .combo-panel li.active-option { background: var(--accent-ui-soft); color: var(--accent-ui); }
.combo-panel .empty { color: var(--muted); padding: 10px; text-align: center; cursor: default; }
.combo-panel .empty:hover { background: none; }

/* switch (Есть догруз) */
.ui-switch-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.ui-switch-row .sw-label { font-size: 13px; font-weight: 600; color: var(--ink-soft); }
.ui-switch-row .sw-hint { display: block; font-size: 11.5px; color: var(--muted); margin-top: 1px; font-weight: 500; }
.ui-switch {
  position: relative; width: 40px; height: 23px; border-radius: 999px; border: none; cursor: pointer;
  background: var(--border); flex-shrink: 0; transition: background-color 0.2s ease;
}
.ui-switch::after {
  content: ""; position: absolute; top: 2.5px; left: 2.5px; width: 18px; height: 18px; border-radius: 50%;
  background: #fff; transition: transform 0.2s ease; box-shadow: 0 1px 2px rgba(0,0,0,.3);
}
.ui-switch.on { background: var(--brand-fill); }
.ui-switch.on::after { transform: translateX(17px); }

/* route preview */
.route-preview {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  padding: 10px; background: var(--paper); border: 1px dashed var(--border); border-radius: var(--radius-sm);
}
.route-pill {
  display: flex; align-items: center; gap: 5px; padding: 5px 9px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--border); font-size: 11.5px; font-weight: 600;
  color: var(--ink-soft); white-space: nowrap;
}
.route-pill.filled { color: var(--accent-ui); border-color: transparent; background: var(--accent-ui-soft); }
.route-arrow { color: var(--muted); }
.route-empty { color: var(--muted); font-size: 11.5px; }

/* П27/П28 (Фаза 4, план "LogTrack DEYA волна 3"): 3-уровневые media-queries —
   Desktop (по умолчанию, без media-запроса) → Tablet (761-1024px, планшеты
   складского персонала, укрупнённые контролы) → Mobile (≤760px, уже
   существовавший брейкпойнт, дополнен тач-таргетами). Отдельного "YMS" с
   горизонтальными свайпами в проекте нет (нет самостоятельного модуля с
   таким названием/поведением) — пункт директивы про свайпы неприменим к
   текущей функциональности, не пропущен по недосмотру. */
@media (min-width: 761px) and (max-width: 1024px) {
  button, input:not([type="checkbox"]):not([type="radio"]), select { min-height: 44px; }
  .step { width: 72px; }
}

/* Пункт 4 Дорожной карты: исключение горизонтального скролла на планшетах (760-980px) */
@media (max-width: 980px) {
  .status-panel-grid {
    grid-template-columns: 1fr;
  }
  .trip-map-thumb {
    height: 240px;
  }
}

@media (max-width: 760px) {
  main { padding: 16px 12px 48px; }
  .grid-2 { grid-template-columns: 1fr; }
  header { padding: 10px 14px; }
  header .brand-page { font-size: 13px; }
  form.card, .card { padding: 14px; border-radius: var(--radius-sm); }
  h1 { font-size: 21px; }
  h2 { font-size: 17px; }
  table { font-size: 13px; }
  th, td { padding: 8px; }
  button.btn-block { width: 100%; }
  button, input:not([type="checkbox"]):not([type="radio"]), select { min-height: 40px; }
  .status-panel button,
  .header-icon-btn,
  .trip-create-modal-close,
  .form-expand-btn,
  .settings-tabs button,
  .app-nav a,
  header button,
  .flex button,
  button {
    width: auto;
  }
  .step { width: 64px; }
  .step-label { font-size: 10px; }
  .status-timer { font-size: 13px; }
  .status-panel-grid { grid-template-columns: 1fr; }
  .trip-map-thumb { height: 220px; }
}

/* Пункт 29: font-size 16px на мобильных устройствах во избежание WebKit авто-зума на iOS */
@media (max-width: 768px) {
  input:not([type="checkbox"]):not([type="radio"]), select, textarea {
    font-size: 17px !important;
  }
}

/* Склад 1/2 (П27) — эргономичные touch-таргеты на планшетах */
#sklad1-app button, #sklad1-app input:not([type="checkbox"]):not([type="radio"]), #sklad1-app select,
#sklad2-app button, #sklad2-app input:not([type="checkbox"]):not([type="radio"]), #sklad2-app select {
  min-height: 44px;
}
#sklad1-app { font-size: 13px; }
#sklad2-app { font-size: 13px; }

/* П29 (Фаза 12): подсветка карточки рейса после перехода из эскалации */
@keyframes escalation-pulse {
  0%   { box-shadow: 0 0 0 4px var(--accent-ui); }
  60%  { box-shadow: 0 0 0 4px var(--accent-ui); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.escalation-highlight {
  animation: escalation-pulse 3s ease-out;
}

/* V-01: Анти-коллизия заголовка карточек (наименования никогда не наезжают на кнопки) */
.card-header-split {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-width: 0;
  margin-bottom: 12px;
}
.header-title-zone {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
}
.header-title-zone h3,
.header-title-zone h4 {
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 700;
  color: var(--ink);
}
.header-actions-zone {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}

/* V-02: Полноэкранный режим карточек (⛶ Expand / ✕ Collapse) */
.card-fullscreen {
  position: fixed !important;
  inset: 16px !important;
  top: 16px !important;
  left: 16px !important;
  right: 16px !important;
  bottom: 16px !important;
  width: calc(100vw - 32px) !important;
  height: calc(100vh - 32px) !important;
  max-width: none !important;
  max-height: none !important;
  margin: 0 !important;
  transform: none !important; /* Предотвращает смещение из-за hover на карточке */
  backdrop-filter: none !important;
  z-index: 3000 !important;
  border-radius: 16px !important;
  box-shadow: 0 25px 60px rgba(0, 0, 0, 0.45) !important;
  background: var(--surface) !important;
  display: flex !important;
  flex-direction: column !important;
  overflow: hidden !important;
}
.card-fullscreen > :not(.card-header-split):not(.analytics-hub-header) {
  flex: 1 1 auto;
  overflow-y: auto !important;
  min-height: 0;
}
body.has-card-fullscreen {
  overflow: hidden !important;
}
.executive-summary-card {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  overflow-x: clip;
}
.executive-summary-card .role-grid {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}
.executive-summary-card .kpi-card-unified {
  min-width: 0;
  box-sizing: border-box;
}
.card-expand-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink-soft);
  cursor: pointer;
  transition: all 0.15s ease;
  font-size: 13px;
  line-height: 1;
  padding: 0;
  flex-shrink: 0;
}
.card-expand-btn:hover {
  background: var(--accent-ui-soft);
  color: var(--accent-ui);
  border-color: var(--accent-ui);
}

/* Стандартизированный светофор 13-14px с текстовыми подписями (Дизайн-система 2.0) */
.traffic-dot {
  width: 13px !important;
  height: 13px !important;
  min-width: 13px !important;
  min-height: 13px !important;
  border-radius: 50% !important;
  display: inline-block !important;
  flex-shrink: 0 !important;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.2);
  background: var(--status-gray);
  vertical-align: middle;
}
.traffic-dot.green, .status-traffic-green .traffic-dot {
  background: var(--status-green) !important;
  box-shadow: 0 0 8px rgba(6, 95, 70, 0.45) !important;
}
.traffic-dot.yellow, .traffic-dot.amber, .status-traffic-yellow .traffic-dot, .status-traffic-orange .traffic-dot {
  background: var(--status-amber) !important;
  box-shadow: 0 0 8px rgba(217, 119, 6, 0.45) !important;
}
.traffic-dot.red, .status-traffic-red .traffic-dot {
  background: var(--status-red) !important;
  box-shadow: 0 0 8px rgba(220, 38, 38, 0.45) !important;
}

/* V-05: Плавающая полупрозрачная легенда карты (Glassmorphism Legend) */
.map-glass-legend {
  position: absolute;
  bottom: 14px;
  right: 14px;
  z-index: 500;
  background: rgba(255, 255, 255, 0.88);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 8px 12px;
  font-size: 11.5px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  color: var(--ink);
  display: flex;
  flex-direction: column;
  gap: 5px;
  pointer-events: auto;
}
:root[data-theme="dark"] .map-glass-legend ,
:root[data-theme="graphite"] .map-glass-legend {
  background: rgba(24, 24, 28, 0.88);
}
.legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 500;
}
.legend-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* П4: Пульсирующий аварийный маяк для ТС с критическим срывом SLA */
@keyframes pulseEmergency {
  0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.8); }
  70% { transform: scale(1.15); box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); }
  100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
}
.pulse-emergency {
  animation: pulseEmergency 1.4s infinite ease-in-out !important;
}

/* ==========================================================================
   Modern Leaflet Map Controls & Fix for Overgrown Layers
   ========================================================================== */

/* Предотвращение любых искажений стандартных Leaflet контролов */
.leaflet-control-layers {
  background: var(--surface) !important;
  color: var(--ink) !important;
  border: 1px solid var(--border) !important;
  border-radius: var(--radius-sm, 8px) !important;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15) !important;
  padding: 6px 12px !important;
  font-family: inherit !important;
  font-size: 13px !important;
}
:root[data-theme="dark"] .leaflet-control-layers ,
:root[data-theme="graphite"] .leaflet-control-layers {
  background: rgba(24, 24, 28, 0.95) !important;
  border-color: rgba(255, 255, 255, 0.15) !important;
}
.leaflet-control-layers-base label {
  display: flex !important;
  align-items: center !important;
  gap: 8px !important;
  margin: 4px 0 !important;
  cursor: pointer !important;
  font-weight: 500 !important;
}
.leaflet-control-layers-selector {
  width: 15px !important;
  height: 15px !important;
  min-height: 15px !important;
  max-height: 15px !important;
  margin: 0 !important;
  padding: 0 !important;
  accent-color: var(--accent-ui) !important;
  cursor: pointer !important;
}

/* Современный сегментированный переключатель слоёв карты (Pills) */
.map-layer-pills {
  display: flex;
  align-items: center;
  gap: 4px;
  background: rgba(255, 255, 255, 0.88);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 3px 4px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.1);
  margin-top: 10px;
  margin-right: 10px;
}
:root[data-theme="dark"] .map-layer-pills ,
:root[data-theme="graphite"] .map-layer-pills {
  background: rgba(24, 24, 28, 0.88);
  border-color: rgba(255, 255, 255, 0.12);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
}
.map-layer-pills .layer-pill {
  border: none !important;
  background: transparent !important;
  color: var(--ink-soft) !important;
  font-size: 11.5px;
  font-weight: 600;
  padding: 5px 12px;
  margin: 0 !important;
  min-height: 28px !important;
  height: 28px;
  border-radius: 14px !important;
  cursor: pointer;
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  white-space: nowrap;
  box-shadow: none !important;
}
.map-layer-pills .layer-pill:hover {
  background: rgba(0, 0, 0, 0.06) !important;
  color: var(--ink) !important;
  transform: translateY(-1px);
}
:root[data-theme="dark"] .map-layer-pills .layer-pill:hover ,
:root[data-theme="graphite"] .map-layer-pills .layer-pill:hover {
  background: rgba(255, 255, 255, 0.12) !important;
  color: #fff !important;
}
.map-layer-pills .layer-pill.active {
  background: var(--brand-fill) !important;
  color: #ffffff !important;
  box-shadow: 0 2px 8px var(--accent-ui-soft, rgba(239, 68, 68, 0.35)) !important;
}

/* Кнопки зума и геолокации карты Leaflet */
.leaflet-bar {
  border-radius: 10px !important;
  overflow: hidden !important;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12) !important;
  border: 1px solid var(--border) !important;
}
.leaflet-bar a {
  background: var(--surface) !important;
  color: var(--ink) !important;
  border-bottom: 1px solid var(--border) !important;
  transition: background 0.15s ease, color 0.15s ease !important;
  font-weight: bold !important;
}
.leaflet-bar a:hover {
  background: var(--paper) !important;
  color: var(--accent-ui) !important;
}
:root[data-theme="dark"] .leaflet-bar a ,
:root[data-theme="graphite"] .leaflet-bar a {
  background: rgba(24, 24, 28, 0.9) !important;
  color: #fff !important;
}
/* Ссылка в подписи карты («Leaflet»). Библиотека красит её в #0078A8
   правилом `.leaflet-container a` на полупрозрачной белой подложке — замер в
   браузере дал 3.64:1 при норме AA 4.5:1. Токен темы здесь не годится:
   подложку подписи Leaflet задаёт белой жёстко, а токены текста в тёмных
   темах светлые и на белом пропадают. Поэтому фиксированный тёмный тон —
   7.6:1 на светлой подложке и 6.4:1 даже если под картой окажется чёрный
   спутниковый снимок. */
.leaflet-container .leaflet-control-attribution a {
  color: #12455c !important;
}
.map-locate-btn {
  background: var(--surface) !important;
  color: var(--ink) !important;
  border-radius: 8px !important;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12) !important;
  border: 1px solid var(--border) !important;
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1) !important;
}
.map-locate-btn:hover {
  background: var(--accent-ui-soft) !important;
  color: var(--accent-ui) !important;
  transform: scale(1.08);
}
:root[data-theme="dark"] .map-locate-btn ,
:root[data-theme="graphite"] .map-locate-btn {
  background: rgba(24, 24, 28, 0.9) !important;
  color: #fff !important;
}

/* ==========================================================================
   Micro-Animations & UI Fluidity
   ========================================================================== */

/* Плавное появление секций при переключении вкладок */
.page-section:not(.is-hidden) {
  animation: sectionFadeIn 0.2s ease-out;
}
@keyframes sectionFadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* Тактильные микро-анимации кнопок */
button:not(.layer-pill):not(.card-expand-btn),
.btn {
  transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease, transform 0.12s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.18s ease !important;
}
button:hover:not(:disabled):not(.layer-pill):not(.card-expand-btn),
.btn:hover:not(:disabled) {
  transform: translateY(-1px);
}
button:active:not(:disabled):not(.layer-pill):not(.card-expand-btn),
.btn:active:not(:disabled) {
  transform: translateY(1px) scale(0.98);
}

/* Элегантное наведение на навигационные табы */
.app-nav a {
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.app-nav a:hover:not(.active) {
  background: var(--paper);
  transform: translateY(-1px);
}
.app-nav a:active {
  transform: scale(0.97);
}

/* Мягкая подсветка строк таблиц */
tbody tr {
  transition: background-color 0.15s ease;
}
/* Второе объявление того же правила — ниже по файлу и потому побеждало.
   Оставлено на месте намеренно: убрать его значит менять порядок каскада,
   а цвет теперь один и тот же в обоих. */
tbody tr:hover {
  background-color: var(--ds-glass-2, rgba(0, 0, 0, 0.04)) !important;
}

/* Подсветка + подъём карточек (27.09.2026: раньше .ds-lift/.ds-anim из
   design-system.css применялись точечно, только к статичным блокам сводки
   дашборда через JS — на 6 Vue-экранах (диспетчер, склад, автопарк и т.д.)
   класс .card используется повсеместно, но без анимации. Правим здесь один
   раз, а не в каждом .vue-файле: правило глобальное, подхватывается любым
   экраном, где есть .card, без пересборки бандлов. */
.card {
  transition: border-color 0.2s ease, box-shadow 0.22s ease, transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1);
  animation: ds-rise 0.4s cubic-bezier(0.2, 0.7, 0.2, 1) backwards;
}
.card:hover {
  border-color: rgba(0, 113, 227, 0.25);
  transform: translateY(-2px);
  box-shadow: var(--ds-sh-hi, 0 8px 20px rgba(0, 0, 0, 0.1));
}
@media (prefers-reduced-motion: reduce) {
  .card { animation: none; transition: border-color 0.2s ease; }
  .card:hover { transform: none; box-shadow: none; }
}

/* Плавное появление модальных окон */
.map-fullscreen-overlay,
.trip-create-modal-overlay {
  animation: modalOverlayIn 0.2s ease-out forwards;
}
@keyframes modalOverlayIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.trip-create-modal-panel {
  animation: modalPanelIn 0.25s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes modalPanelIn {
  from {
    opacity: 0;
    transform: scale(0.97) translateY(8px);
  }
  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

/* ========================================================
   BI Дашборд: Пресеты периода, Аналитический Хаб и Живой Поиск
   ======================================================== */
.dash-quick-controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}

.period-quick-presets {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  background: var(--bg);
  padding: 3px;
  border-radius: 20px;
  border: 1px solid var(--border);
}

.preset-pill {
  border: none !important;
  background: transparent !important;
  color: var(--ink-soft) !important;
  font-size: 13px !important;
  font-weight: 500 !important;
  padding: 4px 12px !important;
  border-radius: 16px !important;
  cursor: pointer !important;
  min-height: 28px !important;
  height: 28px !important;
  line-height: 20px !important;
  transition: all 0.16s ease !important;
}

.preset-pill:hover {
  color: var(--ink) !important;
  background: var(--paper) !important;
  transform: none !important;
}

.preset-pill.active {
  background: var(--brand-fill) !important;
  color: #fff !important;
  font-weight: 600 !important;
  box-shadow: 0 1px 4px rgba(0, 113, 227, 0.25) !important;
}

/* Аналитический Хаб срезов */
.analytics-hub-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 14px;
}

.analytics-pills {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  background: var(--bg);
  padding: 4px;
  border-radius: 24px;
  border: 1px solid var(--border);
}

.analytics-tab-btn {
  border: none !important;
  background: transparent !important;
  color: var(--ink-soft) !important;
  font-size: 13px !important;
  font-weight: 500 !important;
  padding: 6px 14px !important;
  border-radius: 18px !important;
  cursor: pointer !important;
  min-height: 32px !important;
  height: 32px !important;
  display: inline-flex !important;
  align-items: center !important;
  gap: 6px !important;
  transition: all 0.18s cubic-bezier(0.16, 1, 0.3, 1) !important;
}

.analytics-tab-btn:hover {
  color: var(--ink) !important;
  background: var(--paper) !important;
  transform: translateY(-1px) !important;
}

.analytics-tab-btn.active {
  background: var(--brand-fill) !important;
  color: #fff !important;
  font-weight: 600 !important;
  box-shadow: 0 2px 6px rgba(0, 113, 227, 0.3) !important;
}

/* Строки живого поиска по таблицам */
.table-search-input {
  padding: 6px 12px !important;
  font-size: 13px !important;
  height: 36px !important;
  min-height: 36px !important;
  box-sizing: border-box !important;
  border: 1px solid var(--border) !important;
  border-radius: 8px !important;
  background: var(--paper) !important;
  color: var(--ink) !important;
  transition: border-color 0.15s ease, box-shadow 0.15s ease !important;
}

.table-search-input:focus {
  outline: none !important;
  border-color: var(--accent-ui) !important;
  box-shadow: 0 0 0 3px var(--accent-ui-soft) !important;
}

/* Быстрые фильтры статусов */
.status-filter-pills {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.status-filter-pill {
  border: 1px solid var(--border) !important;
  background: var(--paper) !important;
  color: var(--ink-soft) !important;
  font-size: 11.5px !important;
  padding: 4px 10px !important;
  border-radius: 14px !important;
  cursor: pointer !important;
  min-height: 28px !important;
  height: 28px !important;
  transition: all 0.15s ease !important;
}

.status-filter-pill:hover {
  border-color: var(--accent-ui) !important;
  color: var(--ink) !important;
}

.status-filter-pill.active {
  background: var(--accent-ui-soft) !important;
  border-color: var(--accent-ui) !important;
  color: var(--accent-ui) !important;
  font-weight: 600 !important;
}

/* ===== Пакет микро-анимаций LogTrack Modern UI ===== */
@keyframes radar-ping {
  0% { transform: scale(1); opacity: 0.85; }
  70% { transform: scale(2.4); opacity: 0; }
  100% { transform: scale(2.4); opacity: 0; }
}

.radar-live-dot {
  position: relative;
  display: inline-flex;
  width: 9px;
  height: 9px;
}
.radar-live-dot::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--status-green);
  animation: radar-ping 1.8s cubic-bezier(0, 0, 0.2, 1) infinite;
}
.radar-live-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--status-green);
}

@keyframes sla-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.82; transform: scale(1.02); }
}

.sla-alert-pulse {
  animation: sla-pulse 2s ease-in-out infinite;
}

@keyframes shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

.skeleton-shimmer {
  background: linear-gradient(90deg, var(--surface) 25%, var(--surface-sunken) 50%, var(--surface) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
}

/* Плавный аккордеон и переходы */
.smooth-accordion {
  transition: max-height 0.3s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease;
}

.truck-bubble {
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.2s ease;
}
.truck-bubble:hover {
  transform: translateY(-2px) scale(1.04);
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.4);
}

/* Модальные диалоги подтверждения (showConfirmDialog / showAlertDialog) */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 3000;
  background: rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}
.modal-overlay.active {
  opacity: 1;
  pointer-events: auto;
}
.modal-card {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--elevation-3);
  max-width: 480px;
  width: 100%;
  transform: translateY(12px) scale(0.97);
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
  overflow: hidden;
}
.modal-overlay.active .modal-card {
  transform: translateY(0) scale(1);
}
.modal-card-header {
  padding: 16px 20px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  border-bottom: 1px solid var(--border);
}
.modal-card-header.is-danger {
  background: var(--status-red-bg);
  color: var(--status-red);
}
.modal-card-header.is-warning {
  background: var(--status-amber-bg);
  color: var(--status-amber);
}
.modal-card-header h3 {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
}
.modal-card-body {
  padding: 18px 20px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink);
  white-space: pre-wrap;
  word-break: break-word;
}
.modal-card-actions {
  padding: 12px 20px;
  background: var(--surface-sunken);
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
}
.modal-card-actions button {
  min-height: 38px;
  padding: 8px 18px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 10px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.modal-btn-confirm {
  background: var(--brand-fill);
  color: #fff;
  border: 1px solid var(--accent-ui-dark);
}
.modal-btn-confirm:hover {
  background: var(--accent-ui-dark);
}
.modal-btn-confirm.is-danger {
  background: var(--status-red);
  color: #fff;
  border-color: var(--status-red);
}
.modal-btn-confirm.is-danger:hover {
  background: var(--red-dark);
}
.modal-btn-confirm.is-warning {
  background: var(--status-amber);
  color: #fff;
  border-color: var(--status-amber);
}
.modal-btn-cancel {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
}
.modal-btn-cancel:hover {
  background: var(--paper);
}

/* Универсальное модальное окно переобновления данных (Resync Modal) */
.resync-modal-card {
  max-width: 580px;
  width: 95%;
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--elevation-3);
  border: 1px solid var(--border);
  overflow: hidden;
}
.resync-preset-btn {
  padding: 6px 10px;
  font-size: 11.5px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  transition: all 0.15s ease;
}
.resync-preset-btn:hover {
  background: var(--surface-sunken);
  border-color: var(--accent-ui);
}
.resync-preset-btn.active {
  background: var(--brand-fill) !important;
  color: #fff !important;
  font-weight: 700;
  border-color: var(--accent-ui) !important;
}

/* Стили таблицы скоринга и активных рейсов */
.score-flex-box {
  display: flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}

/* ==========================================================================
   ИНТЕРАКТИВНЫЕ ПОДСКАЗКИ KPI И МЕТРИК (ФОРМУЛЫ + ОПРЕДЕЛЕНИЯ)
   ========================================================================== */
.kpi-tooltip-anchor {
  position: relative;
  cursor: help;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.kpi-info-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  font-size: 10px;
  font-weight: 700;
  background: var(--surface-sunken);
  color: var(--muted);
  border: 1px solid var(--border);
  transition: all 0.15s ease;
  user-select: none;
}
.kpi-tooltip-anchor {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.kpi-card-unified:hover .kpi-info-icon,
.kpi-tooltip-anchor:hover .kpi-info-icon {
  background: var(--accent-ui-soft);
  color: var(--accent-ui);
  border-color: var(--accent-ui);
}

.kpi-tooltip-popup {
  display: none;
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  width: 280px;
  max-width: min(280px, 90vw);
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.28);
  z-index: 1050;
  text-align: left;
}
.kpi-tooltip-anchor:hover .kpi-tooltip-popup,
.kpi-card-unified:hover .kpi-tooltip-popup,
.kpi-tooltip-anchor:focus-within .kpi-tooltip-popup {
  display: block;
}
.kpi-tooltip-popup.align-right {
  left: auto;
  right: 0;
  transform: none;
}
.kpi-tooltip-popup.align-left {
  left: 0;
  transform: none;
}
.kpi-tooltip-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--accent-ui);
  margin-bottom: 4px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.kpi-tooltip-def {
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--ink-soft);
  margin-bottom: 8px;
}
.kpi-tooltip-formula-box {
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent-ui);
  border-radius: 4px;
  padding: 6px 8px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 11.5px;
  color: var(--ink);
  margin-bottom: 8px;
  word-break: break-all;
  white-space: pre-wrap;
}
/* Единица измерения — третья обязательная часть подсказки рядом с назначением
   и формулой. Отдельной строкой, а не в скобках у значения: в скобках она
   теряется среди нормативов и порогов. */
.kpi-tooltip-unit {
  font-size: var(--ds-f3);
  color: var(--ink-soft);
  margin-bottom: 8px;
}

.kpi-tooltip-target {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--status-amber, #d97706);
  display: flex;
  align-items: center;
  gap: 5px;
}

/* Единица измерения показателя. Приглушённее норматива: норматив — это
   требование, а единица — уточнение к цифре. Само значение выделено
   моноширинным начертанием, чтобы «м3» и «т/ч» не путались с текстом. */
.kpi-tooltip-unit {
  font-size: 11.5px;
  color: var(--ds-tx-3, #6D6D77);
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 2px;
}

.kpi-tooltip-unit-value {
  font-family: var(--ds-fm, ui-monospace, monospace);
  font-weight: 600;
  color: var(--ds-tx-2, #54545E);
}

/* ==========================================================================
   ПУНКТ 18: КАРТОЧКА СКЛАДА (GPS-автозакрытие, быстрая кнопка, мини-карта)
   ========================================================================== */
.sklad-quick-close-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 38px;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 600;
  border-radius: var(--radius-sm);
  background: var(--brand-fill);
  color: #fff;
  border: 1px solid var(--accent-ui-dark);
  cursor: pointer;
  transition: all 0.15s ease;
}
.sklad-quick-close-btn:hover {
  background: var(--accent-ui-dark);
  box-shadow: 0 2px 6px rgba(0,0,0,0.15);
}
.sklad-quick-close-btn.is-closed {
  background: var(--surface-sunken);
  color: var(--muted);
  border-color: var(--border);
  cursor: default;
}
.sklad-distance-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-sunken);
  color: var(--ink-soft);
}
.sklad-distance-badge.is-near {
  background: rgba(16, 185, 129, 0.12);
  color: var(--status-green, #10b981);
  border-color: rgba(16, 185, 129, 0.3);
}
.sklad-distance-badge.is-away {
  background: rgba(245, 158, 11, 0.12);
  color: var(--status-amber, #f59e0b);
  border-color: rgba(245, 158, 11, 0.3);
}

.sklad-minimap-card {
  width: 100%;
  height: 200px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  overflow: hidden;
  position: relative;
  margin-top: 10px;
}
.sklad-info-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-top: 10px;
  font-size: 11.5px;
}
.sklad-info-strip a {
  color: var(--accent-ui);
  text-decoration: none;
  font-weight: 600;
}
.sklad-info-strip a:hover {
  text-decoration: underline;
}

/* ==========================================================================
   ВКЛАДКА «РАЗБОР РЕЙСА» (TRIP INVESTIGATION & DOSSIER)
   ========================================================================== */
.investigation-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 100%;
  /* Плавающая кнопка «DEYA AI» (.ai-copilot-container.is-floating,
     bottom:24px/right:24px, компонент общий для всех экранов — не трогаем
     его самого) в развёрнутом виде перекрывала последнюю колонку таблицы
     «Хронология этапов». Резерв снизу — не костыль поверх виджета, а место
     под него у ЭТОГО экрана, тот же приём, что предлагает сама задача:
     "padding-bottom у main на её высоту". */
  padding-bottom: 90px;
}
.investigation-search-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 18px;
  box-shadow: var(--elevation-1);
}
.investigation-search-bar .field-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.investigation-search-bar .field-item label:first-of-type {
  /* :first-of-type, не голый label — у поля «Только аномалии» теперь ДВА
     label-а (подпись сверху + функциональный label вокруг чекбокса, как у
     остальных полей строки поиска, для выравнивания по базовой линии).
     Второй должен остаться со своим шрифтом (Tailwind text-xs), а не
     наследовать uppercase/11.5px подписи. */
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
}
.investigation-search-bar input[type="text"],
.investigation-search-bar input[type="date"],
.investigation-search-bar select {
  height: 38px;
  padding: 0 12px;
  font-size: 13px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-sunken);
  color: var(--ink);
  transition: border-color 0.15s ease;
  min-width: 150px;
}
.investigation-search-bar input:focus,
.investigation-search-bar select:focus {
  outline: none;
  border-color: var(--accent-ui);
}
.investigation-layout {
  /* Решение владельца (25.09.2026, устно, поверх исходного письменного
     промпта): список рейсов ВСЕГДА горизонтальная лента с прокруткой, на
     любой ширине экрана — не двухколоночный мастер-детейл. Досье во всю
     ширину под лентой. */
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.investigation-sidebar {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  box-shadow: var(--elevation-1);
}
.investigation-sidebar-scroll {
  display: flex;
  flex-direction: row;
  gap: 8px;
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 4px;
  scrollbar-width: thin;
  /* Подсказка прокрутки — лента не обрывается на полуслове по краю. */
  scroll-snap-type: x proximity;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent 100%);
}
.investigation-item {
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 6px 9px;
  cursor: pointer;
  transition: all 0.15s ease;
  display: flex;
  flex-direction: column;
  gap: 3px;
  /* Ширина карточки адаптируется под содержимое (номер рейса, госномер,
     клиент), а не фиксирована — короткие карточки не растягиваются
     искусственно, длинные не обрезают клиента раньше времени. min/max —
     чтобы карточка не схлопнулась в нечитаемую полоску и не растянулась
     на половину экрана из-за одного длинного названия клиента. */
  flex: 0 0 auto;
  width: auto;
  min-width: 220px;
  max-width: 340px;
  scroll-snap-align: start;
}
.investigation-item:hover {
  border-color: var(--accent-ui);
  background: var(--accent-ui-soft);
}
.investigation-item.is-selected {
  border-color: var(--accent-ui);
  background: var(--accent-ui-soft);
  box-shadow: 0 0 0 1px var(--accent-ui);
}
.investigation-item .trip-id {
  font-family: var(--ds-fm);
  font-weight: 700;
  font-size: 13px;
  color: var(--ink);
}
.investigation-item .trip-route {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.investigation-item .trip-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11.5px;
  color: var(--ink-soft);
}

/* Карточка рейса — указатель, по которому выбирают рейс; разбирают его
   справа. Шесть строк на четыре факта отнимали ширину у рабочей зоны, ради
   которой на экран и заходят. */
.investigation-item .trip-verh,
.investigation-item .trip-niz {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.investigation-item .trip-verh .trip-id {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 11.5px;
}

.investigation-item .trip-status {
  flex: none;
  font-size: 10px;
  font-weight: 600;
  padding: 1px 7px;
  border-radius: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--ink-soft);
  white-space: nowrap;
}

.investigation-item .trip-otif {
  flex: none;
  display: inline-flex;
  align-items: center;
}

.investigation-item .trip-otif.opozdanie { color: var(--status-red); }
.investigation-item .trip-otif.vovremya { color: var(--status-green); }

.investigation-item .trip-niz .trip-route {
  /* Клиент — ключевое поле выбора рейса, обрезать многоточием нельзя
     (явное требование владельца): базовый класс .trip-route (выше) даёт
     ellipsis, здесь отменяем его и разрешаем перенос на 2 строки — карточка
     и так адаптивной ширины (см. .investigation-item), высота колонки
     подстраивается сама (flex-direction: column). */
  flex: 1 1 auto;
  min-width: 64px;
  font-weight: 500;
  color: var(--ink-soft);
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

.investigation-item .trip-data,
.investigation-item .trip-dlitelnost,
.investigation-item .trip-ocenka {
  flex: none;
  font-size: var(--ds-f2);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.investigation-item .trip-dlitelnost {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.investigation-item .trip-ocenka {
  padding: 0 5px;
  border-radius: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
}
.investigation-item .badge-anomaly {
  font-size: 10px;
  font-weight: 700;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--status-red-bg);
  color: var(--status-red);
  border: 1px solid var(--status-red);
}
.investigation-dossier {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 20px;
  box-shadow: var(--elevation-1);
  min-height: 500px;
  min-width: 0; /* внутри флекс-колонки .investigation-layout — без этого
                   длинный текст (гос.номер, ФИО) не даёт блоку сжаться и
                   распирает разметку вбок */
}
.investigation-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  /* Правка от 25.09.2026, второй заход: первая версия ставила
     flex-wrap:nowrap и жёстко несжимаемый .actions (flex:none), чтобы
     любой ценой удержать заголовок и кнопки в одну строку. Побочный
     эффект — ширина, которую требовал этот nowrap-минимум, оказывалась
     больше, чем реально нужно контенту, и раздувала колонку. Перенос на
     вторую строку — не проблема сам по себе (правило проекта, см.
     CLAUDE.md «Дизайн / UI»): пусть переносится, когда это компактнее,
     чем удерживать всё в одну строку любой ценой. */
  flex-wrap: wrap;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}
.investigation-header > div:first-child {
  flex: 1 1 auto;
  min-width: 0;
}
.investigation-header .title {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 700;
  color: var(--ink);
  margin: 0;
}
.investigation-header .subtitle {
  font-size: 13px;
  color: var(--ink-soft);
  margin: 0;
  line-height: 1.5;
  /* В двухколоночной раскладке (≥1280px, Правка «Разбор рейса») колонка
     досье стала уже, чем была в одноколоночной вёрстке — при исходном
     flex-wrap строка «Клиент · Транспорт · Водитель · телефон» переносила
     каждый пункт на свою строку и раздувала шапку до 160px+ вместо целевых
     90px. Текст не удаляется (title показывает целиком при наведении,
     ничего не потеряно) — просто не переносится построчно. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.investigation-header .actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  /* flex:none убран — держал блок кнопок несжимаемым фиксированной
     ширины (~384px), что и раздувало заголовок. Кнопки сами переносятся
     (flex-wrap:wrap выше), участвуя в общей раскладке наравне с левым
     блоком, а не поверх неё. */
  flex: 0 1 auto;
}
.investigation-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 38px;
  padding: 0 14px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s ease;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
}
.investigation-btn:hover {
  background: var(--surface-sunken);
  border-color: var(--ink-soft);
}
.investigation-btn-primary {
  background: var(--brand-fill) !important;
  color: #fff !important;
  border-color: var(--accent-ui-dark) !important;
}
.investigation-btn-primary:hover {
  background: var(--accent-ui-dark) !important;
}
.investigation-btn-telegram {
  /* Фирменная синева Telegram #229ed9 под белым текстом даёт 3.02:1.
     Оттенок сохранён, светлота снижена до прохождения нормы: 4.72:1. */
  background: #1b7ba9 !important;
  color: #fff !important;
  border-color: #1b85b8 !important;
}
.investigation-btn-telegram:hover {
  background: #1b85b8 !important;
}

.investigation-stages-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.investigation-stages-table th {
  text-align: left;
  padding: 8px 10px;
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--border);
  color: var(--ink-soft);
  font-weight: 600;
}
.investigation-stages-table td {
  padding: 9px 10px;
  border-bottom: 1px solid var(--border);
  color: var(--ink);
}
.investigation-map-box {
  width: 100%;
  height: 380px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  overflow: hidden;
  position: relative;
  /* Раньше было "transition: all" — вместе со сменой position: relative
     → fixed при входе в полноэкранный режим это ломало анимацию width/
     height (calc(100vw/vh - 32px)): "position" дискретно переключается
     в середине transition, и оставшаяся половина анимации width/height
     считает уже неверный containing block — карта застревала на старом
     маленьком размере, хотя position/top/left уже были fixed/16px.
     Переход только по визуальным свойствам убирает эту ловушку. */
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}
.investigation-map-box.is-fullscreen {
  position: fixed;
  inset: 16px;
  width: calc(100vw - 32px);
  height: calc(100vh - 32px);
  z-index: 9999;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
  border-radius: var(--radius-md);
  border: 2px solid var(--accent-ui);
}
.investigation-map-overlay-close-btn {
  position: fixed;
  top: 32px;
  right: 48px;
  z-index: 10000;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  background: var(--surface);
  color: var(--ink);
  border-radius: 999px;
  border: 1px solid var(--border);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.investigation-map-overlay-close-btn:hover {
  background: var(--surface-sunken);
  color: var(--accent-ui);
}
.investigation-tabs-nav {
  display: flex;
  border-bottom: 1px solid var(--border);
  gap: 8px;
}
.investigation-tab-btn {
  padding: 8px 14px;
  border: none;
  background: none;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all 0.15s ease;
}
.investigation-tab-btn.is-active {
  color: var(--accent-ui);
  border-bottom-color: var(--accent-ui);
}
.investigation-feed-list {
  max-height: 280px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 0;
}
.investigation-feed-item {
  padding: 8px 12px;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 11.5px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.investigation-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(3px);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.investigation-modal-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
  width: 100%;
  max-width: 620px;
  max-height: 90vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}
.investigation-modal-header {
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--surface-sunken);
}
.investigation-modal-body {
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.investigation-modal-footer {
  padding: 14px 20px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  background: var(--surface-sunken);
}

.kpi-card-value,
.wh-kpi-value,
td.num,
[data-tabular] {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
}

.kpi-card-value .kpi-unit { font-size: 13px; font-weight: 600; color: var(--ink-soft); }
.kpi-card-unified { border-left: 3px solid var(--border); }
.kpi-card-unified.is-primary   .kpi-card-value { font-size: 27px; }
.kpi-card-unified.is-secondary .kpi-card-value { font-size: 21px; }
.kpi-card-unified.is-primary   { min-height: 160px; }
.kpi-card-unified.is-secondary { min-height: 96px; }
.kpi-card-unified.is-green { border-left-color: var(--status-green) !important; }
.kpi-card-unified.is-amber { border-left-color: var(--status-amber) !important; }
.kpi-card-unified.is-red { border-left-color: var(--status-red) !important; }
.kpi-card-unified.is-nodata { border-left-color: var(--border) !important; border-style: dashed; }

.kpi-card-value.g { color: var(--status-green); }
.kpi-card-value.a { color: var(--status-amber); }
.kpi-card-value.r { color: var(--status-red); }
.kpi-card-value.none { font-size: 17px; font-weight: 600; color: var(--muted); }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
  border: 1px solid transparent;
}
.badge.g { background: var(--status-green-bg); color: var(--status-green); border-color: var(--status-green); }
.badge.a { background: var(--status-amber-bg); color: var(--status-amber); border-color: var(--status-amber); }
.badge.r { background: var(--status-red-bg); color: var(--status-red); border-color: var(--status-red); }
.badge.n { background: var(--paper); color: var(--muted); border-color: var(--border); }
.cov { font-variant-numeric: tabular-nums; font-size: 11.5px; }
.cov.low { color: var(--status-amber); font-weight: 700; }

.wh-pill, .wh-wh-btn, .pill-btn, button {
  min-height: 44px;
}
.wh-pill-group, .pill-group {
  align-items: center;
}

/* Структурированные группы KPI (Сводка руководителя) */
.kpi-blocks-container {
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-top: 16px;
}

.kpi-group-block {
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.kpi-group-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.kpi-group-title-wrap {
  display: flex;
  align-items: center;
  gap: 12px;
}

.kpi-group-icon {
  font-size: 17px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  flex-shrink: 0;
}

.kpi-group-title {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
}

.kpi-group-subtitle {
  margin: 3px 0 0 0;
  font-size: 11.5px;
  color: var(--ink-soft);
}

.kpi-group-tag {
  font-size: 11.5px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 6px;
  background: var(--surface);
  color: var(--muted);
  border: 1px solid var(--border);
  white-space: nowrap;
}

/* B-4 (аудит 15.09 ч.2): ряды плиток заполняют всю ширину блока.
   Grid с фиксированными колонками оставлял дыру справа в неполном ряду
   (9 плиток = 5+4); flex-wrap с ростом растягивает каждый ряд до края. */
.kpi-group-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.kpi-group-grid > * {
  flex: 1 1 210px;
  min-width: 210px;
}

/* =====================================================================
   TCO (Полная стоимость 1 км) и Модуль Контроля Топлива
   ===================================================================== */
.tco-modal-card {
  max-width: 860px !important;
  width: 95% !important;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
}

.tco-modal-body {
  padding: 20px;
  overflow-y: auto;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink);
}

.tco-kpi-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}

.tco-mini-card {
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
}

.tco-mini-title {
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin-bottom: 4px;
  font-weight: 600;
}

.tco-mini-val {
  font-size: 17px;
  font-weight: 700;
  font-family: var(--ds-fm);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.tco-mini-sub {
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-top: 2px;
}

.tco-bar-wrap {
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 20px;
}

.tco-progress-bar {
  display: flex;
  height: 12px;
  border-radius: 6px;
  overflow: hidden;
  background: var(--border);
  margin: 10px 0;
}

.tco-prog-fuel {
  background: var(--brand-fill);
  transition: width 0.3s ease;
}

.tco-prog-parts {
  background: var(--status-amber);
  transition: width 0.3s ease;
}

.tco-legend {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
  font-size: 11.5px;
  color: var(--ink-soft);
}

.tco-legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
}

.tco-legend-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
}

.tco-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.tco-table th {
  text-align: left;
  padding: 8px 10px;
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--border);
  font-size: 11.5px;
  color: var(--muted);
  text-transform: uppercase;
}

.tco-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  font-variant-numeric: tabular-nums;
}

.tco-table tr:hover td {
  background: var(--surface-sunken);
}

/* =====================================================================
   AI Copilot Floating Card & Chat Thread Scrolling
   ===================================================================== */
.copilot-card-floating {
  max-height: calc(100vh - 40px) !important;
  max-height: calc(100dvh - 40px) !important;
  display: flex !important;
  flex-direction: column !important;
}

.copilot-card-floating .copilot-header,
.copilot-card-floating .copilot-tabs-nav {
  flex-shrink: 0 !important;
}

.copilot-card-floating .copilot-body {
  flex: 1 1 auto !important;
  min-height: 0 !important;
  overflow-y: auto !important;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) var(--surface-sunken);
}

.copilot-card-floating .copilot-chat-body {
  display: flex !important;
  flex-direction: column !important;
  flex: 1 1 auto !important;
  min-height: 0 !important;
}

.copilot-card-floating .chat-thread,
.copilot-chat-body .chat-thread {
  flex: 1 1 auto !important;
  min-height: 180px !important;
  max-height: calc(100vh - 320px) !important;
  overflow-y: auto !important;
  overscroll-behavior: contain;
  padding-right: 6px;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) var(--surface-sunken);
}

.copilot-card-floating .copilot-body::-webkit-scrollbar,
.copilot-card-floating .chat-thread::-webkit-scrollbar,
.copilot-chat-body .chat-thread::-webkit-scrollbar {
  width: 6px;
}

.copilot-card-floating .copilot-body::-webkit-scrollbar-track,
.copilot-card-floating .chat-thread::-webkit-scrollbar-track,
.copilot-chat-body .chat-thread::-webkit-scrollbar-track {
  background: var(--surface-sunken);
  border-radius: 3px;
}

.copilot-card-floating .copilot-body::-webkit-scrollbar-thumb,
.copilot-card-floating .chat-thread::-webkit-scrollbar-thumb,
.copilot-chat-body .chat-thread::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 3px;
}

.copilot-card-floating .copilot-body::-webkit-scrollbar-thumb:hover,
.copilot-card-floating .chat-thread::-webkit-scrollbar-thumb:hover,
.copilot-chat-body .chat-thread::-webkit-scrollbar-thumb:hover {
  background: var(--ink-soft);
}


/* Числовые поля — без стрелок-спиннеров.

   Браузер рисует спиннер в правом краю поля, и там же стоит подпись единицы
   измерения: «м³» и «чел» оказывались наполовину под стрелками. Отодвигать
   подпись ещё правее некуда — поле и так узкое, а сама стрелка в логистике
   бесполезна: вес набирают с накладной, а не щёлкают по одному килограмму. */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}

input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}


/* Норматив SLA: ряд кнопок и признак несохранённой правки.

   Пока правка не записана, карточка помечается рамкой: четыре поля в одном
   блоке, и без отметки непонятно, какое из них ещё не сохранено. */
.sla-normativ-knopki {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}

.sla-normativ-sohranit:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.est-nesohranyonnoe {
  border-color: var(--current, #92400e);
}

/* Раздел «Инструкция» (левое меню): рендер РУКОВОДСТВО.md */
.instruktsiya-telo h1 { font-size: 21px; margin: 18px 0 8px; }
.instruktsiya-telo h2 { font-size: 17px; margin: 22px 0 8px; border-bottom: 1px solid var(--border); padding-bottom: 4px; }
.instruktsiya-telo h3 { font-size: 13px; margin: 14px 0 6px; }
.instruktsiya-telo p, .instruktsiya-telo li { font-size: 13px; line-height: 1.55; }
.instruktsiya-telo ul { margin: 6px 0 10px 22px; }
.instruktsiya-telo code { background: var(--surface-sunken); border: 1px solid var(--border); border-radius: 4px; padding: 0 4px; font-size: 11.5px; }
.instruktsiya-telo pre { background: var(--surface-sunken); border: 1px solid var(--border); border-radius: 8px; padding: 10px; overflow-x: auto; font-size: 11.5px; margin: 8px 0; }
.instruktsiya-telo hr { border: none; border-top: 1px solid var(--border); margin: 16px 0; }
/* [FIX ВИЗ-14] Цитаты руководства. До этого правила они выводились абзацем с
   литеральным «>» в начале — тринадцать мест на экране. Полоса слева и
   утопленный фон показывают, что это врезка, а не обычный текст. */
.instruktsiya-telo blockquote {
  margin: 10px 0;
  padding: 8px 12px;
  border-left: 3px solid var(--accent-ui, #DA1F26);
  background: var(--surface-sunken);
  border-radius: 0 6px 6px 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink);
}
#instruktsiyaOglavlenie a { font-size: 11.5px; }

/* «Инструкция»: двухколоночная раскладка с липким оглавлением */
.instr-layout { display: flex; gap: 16px; align-items: flex-start; }
.instr-sidebar {
  width: 250px; flex: none;
  position: sticky; top: 16px;
  max-height: calc(100vh - 32px); overflow-y: auto;
}
.instr-sidebar-title { font-size: 13px; font-weight: 700; margin-bottom: 10px; }
.instr-sidebar nav { display: flex; flex-direction: column; gap: 2px; }
.instr-toc-link {
  display: block; padding: 5px 10px;
  font-size: 11.5px; line-height: 1.35;
  color: var(--ink-soft); text-decoration: none;
  border-left: 2px solid transparent; border-radius: 0 6px 6px 0;
}
.instr-toc-link:hover { background: var(--surface-hover); color: var(--ink); }
.instr-toc-link.active {
  border-left-color: var(--brand-fill);
  color: var(--ink); font-weight: 700;
  background: var(--surface-sunken);
}
.instr-content { flex: 1; min-width: 0; max-width: 940px; }
.instruktsiya-telo figure { margin: 12px 0 16px; }
.instruktsiya-telo figure img {
  max-width: 100%; display: block;
  border: 1px solid var(--border); border-radius: 11px;
  box-shadow: 0 4px 18px rgba(0,0,0,.10);
}
.instruktsiya-telo figcaption {
  font-size: 11.5px; color: var(--muted);
  margin-top: 6px; text-align: center;
}
.instruktsiya-telo h2 { scroll-margin-top: 16px; }
#instrNaverh {
  position: fixed; right: 26px; bottom: 26px; z-index: 40;
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface); color: var(--ink);
  font-size: 17px; cursor: pointer;
  opacity: 0; pointer-events: none; transition: opacity .2s ease;
  box-shadow: 0 4px 14px rgba(0,0,0,.15);
}
#instrNaverh.viden { opacity: 1; pointer-events: auto; }
#instrNaverh:hover { background: var(--surface-hover); }
@media (max-width: 1100px) {
  /* align-items: flex-start в двухколоночной раскладке — про высоту (cross
     axis строки). После смены на flex-direction: column cross axis — это
     ширина, и то же flex-start больше не растягивает .instr-content, а даёт
     ему сжаться/вырасти по предпочитаемой ширине контента: длинный h1 без
     переноса требовал 551px в контейнере шириной 378px — заголовок обрезался
     за краем экрана, а не переносился по словам. */
  .instr-layout { flex-direction: column; align-items: stretch; }
  .instr-sidebar { position: static; width: 100%; max-height: none; }
  .instr-sidebar nav { flex-direction: row; flex-wrap: wrap; gap: 4px 10px; }
  .instr-toc-link { border-left: none; border-radius: 6px; }
  .instr-content { max-width: 100%; }
}

/* Фиксированный сайдбар инструкции резервирует свою колонку в раскладке */
.instr-layout.s-fiksirovannym .instr-content { margin-left: 266px; }

/* Настройки: порядок в типографике и группировке (замечание 15.09).
   Правила заперты в #sec-settings, чтобы не перекрашивать другие экраны. */
#sec-settings .grid-2, #sec-settings .grid-3 { gap: 10px 16px; }
#sec-settings label {
  display: block; font-size: 11.5px; font-weight: 600;
  color: var(--ink-soft); margin: 0 0 4px;
}
#sec-settings section.card > h2 { margin-bottom: 4px; }
#sec-settings section.card > h2 + p { margin-top: 0; }
/* Форма добавления отделена от таблицы линией и воздухом */
#sec-settings section.card > h3 {
  margin: 20px 0 10px; padding-top: 16px;
  border-top: 1px solid var(--border);
}
#sec-settings .table-scroll { margin-top: 10px; }
#sec-settings th {
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-soft); padding: 8px 12px;
}
#sec-settings td { padding: 8px 12px; }
/* Кнопки действий в строках — компактные, не раздувают таблицу */
#sec-settings td button {
  padding: 3px 10px; font-size: 11.5px;
}
.spr-actions { white-space: nowrap; }
.spr-actions button + button { margin-left: 6px; }
.spr-del-btn:hover { color: var(--status-red); border-color: var(--status-red); }

/* Таблицы внутри инструкции */
.instruktsiya-telo table { width: 100%; border-collapse: collapse; margin: 4px 0; }
.instruktsiya-telo th {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-soft); text-align: left; padding: 6px 10px;
  border-bottom: 1px solid var(--border);
}
.instruktsiya-telo td {
  font-size: 13px; padding: 6px 10px;
  border-bottom: 1px solid var(--border);
}

/* Вкладка «Обслуживание» */
.obsl-plitki { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; }
.obsl-plitka {
  flex: 1 1 170px; min-width: 170px;
  border: 1px solid var(--border); border-radius: 11px;
  background: var(--surface-sunken); padding: 10px 12px;
}
.obsl-znach { font-size: 17px; font-weight: 800; }
.obsl-podpis { font-size: 11.5px; color: var(--ink-soft); font-weight: 600; margin-top: 2px; }
.obsl-sub { font-size: 10px; color: var(--muted); margin-top: 4px; overflow-wrap: anywhere; }

/* [FIX ВИЗ-7] Ширины ВСЕХ пятнадцати колонок справочника.
   Было: ширины заданы только для th:nth-child(1)…(10), и в сумме они давали
   94%. При `table-layout: fixed` остаток (6%) делили пять последних колонок —
   по 19 px каждая. Отступы ячейки 12+12 = 24 px, то есть ширина содержимого
   выходила ОТРИЦАТЕЛЬНОЙ: в колонках «Выгрузка, т/10 мин», «Погрузка, мин»,
   «Выгрузка, мин», «Оформление, мин» и в колонке действий не отображалось
   ничего — ни значения, ни одной буквы. Замер: 112 строк, пусто во всех 112
   ячейках каждой из этих колонок. Комментарий выше обещал «умещается без
   скролла», но [FIX БИЗ-24] добавил пять колонок и min-width, а ширины
   не обновил — обещание осталось, колонки пропали.

   Ширины в пикселях, а не в процентах: проценты при fixed-раскладке снова
   отдали бы «остаток всем», и ошибка вернулась бы при добавлении колонки.
   Сумма равна min-width таблицы, поэтому колонка получает ровно заданное. */
#secTochki table { table-layout: fixed; width: 100%; }
#secTochki td, #secTochki th { overflow: hidden; text-overflow: ellipsis; }

/* [FIX ВИЗ-10] Метрики читаемости. Что было не так после первой правки:
   1) строка 68 px при тексте 11.5 px — строку распирала кнопка «Редактировать»:
      у общей `button` стоит `min-height: 36px` и `margin-top: 14px`, плюс
      отступы ячейки 8+8. Отсюда «широкие строки» и ощущение поломки вёрстки;
   2) заголовки числовых колонок не помещались даже с переносом: при ширине
      78 px и отступах 24 px под текст оставалось 54 px, а слово «Выгрузка,»
      требует 62 px — на экране было «ВЫГРУ...». Поэтому числовым колонкам
      отдано 106 px, а «Оформлению» — 136;
   3) данные набраны 13 px вместо 11.5 px: это следующая ступень шкалы проекта
      (проверка шрифтов не пропускает дробные и произвольные размеры), и на
      пятнадцати колонках разница в читаемости заметна.
   Ширины колонок пересчитаны под 13 px: имена, адреса и владельцы получают
   200–240 px вместо 135–165, поэтому «*ANGLESEY FO...» превращается в название
   целиком. Полная сумма — min-width таблицы; прокрутка вбок для неё разрешена
   владельцем, а первая колонка закреплена, поэтому строка не теряется. */
#secTochki th, #secTochki td { padding: 6px 8px; }
#secTochki td { font-size: 13px; }
#secTochki th { font-size: 11.5px; line-height: 1.25; white-space: normal; }
#secTochki .spr-actions button {
  min-height: 24px;
  padding: 2px 8px;
  margin-top: 0;
  font-size: 11.5px;
}

/* [FIX ВИЗ-11] Перенос в колонках с текстом.
   Правило проекта (`design-system.css`, «ПРАВИЛА ПЕРЕНОСА ТЕКСТА») прямо
   называет адреса точек и наименования клиентов случаем `.ds-wrap` — переносить
   по словам. Здесь же все они стояли на nowrap с многоточием, и замер показал,
   сколько теряется: адрес обрезан в 56 ячейках из 111, владелец — в 20,
   контакт — в 17, название — в 14. Адрес точки при этом самое нужное: по нему
   точку и находят. Теперь эти колонки переносятся, а числа, телефон, координаты
   и код остаются неразрывными — их рвать нельзя, и многоточие для них честнее.
   Строка вырастает только там, где текст действительно длинный. */
#secTochki td:nth-child(1),
#secTochki td:nth-child(3),
#secTochki td:nth-child(4),
#secTochki td:nth-child(7),
#secTochki td:nth-child(9) {
  white-space: normal;
  overflow-wrap: anywhere;
}
#secTochki th:nth-child(1)  { width: 220px; }  /* Название */
#secTochki th:nth-child(2)  { width: 132px; }  /* Код */
#secTochki th:nth-child(3)  { width: 130px; }  /* Тип */
#secTochki th:nth-child(4)  { width: 220px; }  /* Адрес */
#secTochki th:nth-child(5)  { width: 95px; }   /* Широта */
#secTochki th:nth-child(6)  { width: 100px; }  /* Долгота */
#secTochki th:nth-child(7)  { width: 190px; }  /* Владелец (клиент) */
#secTochki th:nth-child(8)  { width: 155px; }  /* Телефон */
#secTochki th:nth-child(9)  { width: 175px; }  /* Контакт */
#secTochki th:nth-child(10) { width: 106px; }  /* Выгрузка, м³/10 мин */
#secTochki th:nth-child(11) { width: 106px; }  /* Выгрузка, т/10 мин */
#secTochki th:nth-child(12) { width: 106px; }  /* Погрузка, мин */
#secTochki th:nth-child(13) { width: 106px; }  /* Выгрузка, мин */
#secTochki th:nth-child(14) { width: 136px; }  /* Оформление, мин */
#secTochki th:nth-child(15) { width: 125px; }  /* Действия */

/* [FIX ВИЗ-8] Матрица ролей и прав.
   Подписи прав — длинные фразы («Просмотр и правка справочников» и т. п.), и без
   переноса каждая колонка требовала своей полной ширины: замер дал таблицу
   2398 px при контейнере 1294 px, то есть 1104 px горизонтальной прокрутки.
   Разрешаем подписям переноситься и задаём колонке галочки разумный минимум:
   заголовок занимает две-три строки, зато вся матрица умещается на экране.
   Название роли тоже переносим — «Индивидуальные права (ФИО)» иначе распирало
   первую колонку. */
#roli_matrica th.rol-pravo {
  white-space: normal;
  overflow-wrap: anywhere;
  min-width: 64px;
  max-width: 112px;
  vertical-align: bottom;
}
#roli_matrica td:first-child,
#roli_matrica th:first-child {
  white-space: normal;
  overflow-wrap: anywhere;
  min-width: 140px;
}
