/* ============================================================================
   LogTrack DEYA — дизайн-система (Волна 6)
   Источник правды: согласованный скетч «микс компоновки» от 12.09.2026.

   Подключается ПЕРЕД style.css. Задаёт токены, шкалу кегля, материал стекла,
   анимацию и отклик на наведение. Старые правила из style.css постепенно
   переезжают сюда; до окончания переезда оба файла сосуществуют.

   Три вещи, которые этот файл чинит и которые нельзя откатывать:
   1. Шкала кегля: семь ступеней вместо девятнадцати размеров на одном экране
      (на «Автопарке» замерено 19, включая нечитаемые 6 и 7 px на 32 элементах).
   2. Переносы: 40 объявлений white-space:nowrap против 8 text-overflow:ellipsis
      означали, что примерно в 32 местах текст не переносится и не обрезается,
      а распирает контейнер вширь. Отсюда горизонтальный скролл.
   3. Фирменный красный живёт ровно в трёх местах: логотип, активный пункт
      навигации, главная кнопка действия экрана. Всё остальное нейтральное
      или статусное. Сейчас красным выкрашены «Центр», «Обновить», «Легенда»,
      счётчик «Все», три иконки в шапке и все столбцы диаграммы, из-за чего
      цвет перестал что-либо означать.
   ========================================================================= */

/* ─────────────────────────── ТОКЕНЫ: СВЕТЛАЯ ─────────────────────────── */
:root {
  /* Масштаб интерфейса. Меняется одна переменная — пересчитываются кегли,
     отступы, радиусы и размеры иконок. Значения: 0.88 / 1 / 1.16 */
  --z: 1;

  /* Подложка и панели */
  --ds-bg: #F2F3F7;
  --ds-bg-2: #E7E9F0;
  --ds-panel: #FFFFFF;
  --ds-sunk: rgba(9, 9, 15, 0.045);

  /* Чернила */
  --ds-tx: #0B0B0F;
  --ds-tx-2: #54545E;
  /* Контраст WCAG AA. Считается на фоне СТРАНИЦЫ (--ds-bg #F2F3F7),
   а не на белом: на белом значение проходило, а на реальном фоне
   давало 4.11:1 — разницы в пятнадцать единиц яркости хватило. */
  --ds-tx-3: #6D6D77;

  /* Разделители: волосяные линии вместо сплошных границ */
  --ds-hair: rgba(9, 9, 15, 0.09);
  --ds-hair-2: rgba(9, 9, 15, 0.06);

  /* Стекло */
  --ds-glass: rgba(255, 255, 255, 0.72);
  --ds-glass-2: rgba(255, 255, 255, 0.55);
  --ds-spec: rgba(255, 255, 255, 0.9);

  /* Тени: обычная и приподнятая (наведение) */
  --ds-sh: 0 1px 2px rgba(9, 9, 15, 0.05), 0 10px 34px -14px rgba(9, 9, 15, 0.22);
  --ds-sh-hi: 0 2px 4px rgba(9, 9, 15, 0.06), 0 22px 52px -18px rgba(9, 9, 15, 0.34);

  /* Бренд — ровно три места применения, см. шапку файла */
  --ds-brand: #DA1F26;
  /* Вспышка карточки KPI при смене значения (ds-value-flash) — не бренд
     как заливка/акцент, а мгновенный сигнал "значение обновилось", поэтому
     отдельный, сильно приглушённый токен, а не --ds-brand напрямую. */
  --ds-flash: rgba(218, 31, 38, 0.12);

  /* Статусы. Отдельная ось от бренда: цвет состояния никогда не фирменный. */
  --ds-ok: #12A150;
  --ds-warn: #D97706;
  /* [FIX FE-15] Красный для ТЕКСТА: --ds-crit (#E5484D) — цвет заливки, как
     текст на светлом он даёт 3.96:1 при норме 4.5:1 (нашла проверка кнопки
     «Выйти»). Тёмный вариант даёт ~6:1. */
  --ds-crit-text: #B8141A;
  /* [FIX FE-15] ТОТ ЖЕ янтарь, но для ТЕКСТА. #D97706 как цвет текста на белом
     даёт 3.19:1 при норме 4.5:1 (нашла приёмка: 25 подписей «не заполнен — срок
     следующего ТО»). #92400e даёт 7.0:1. Заливки и рамки продолжают брать
     --ds-warn: там яркость уместна, а читаемость определяет текст поверх. */
  --ds-warn-text: #92400e;
  --ds-crit: #E5484D;
  --ds-idle: #8E8E99;

  /* Категории показателей: время, объём, деньги, качество */
  --ds-c-time: #3B82C4;
  --ds-c-vol: #12A18E;
  --ds-c-money: #B08428;
  --ds-c-qual: #8B5CD6;

  /* Радиусы: концентрическая шкала вместо девятнадцати значений */
  --ds-rad: calc(18px * var(--z));
  --ds-rad-in: calc(11px * var(--z));
  --ds-rad-sm: calc(8px * var(--z));

  /* Шрифты */
  --ds-fs: "SF Pro Display", "SF Pro Text", -apple-system, BlinkMacSystemFont,
           "Segoe UI Variable Display", "Segoe UI", Inter, system-ui, sans-serif;
  --ds-fm: "SF Mono", "Cascadia Mono", "IBM Plex Mono", ui-monospace, Consolas, monospace;

  /* ШКАЛА КЕГЛЯ — семь ступеней. Дробные значения запрещены.
     Минимум для читаемого текста — f3. Ступени f1/f2 только для подписей. */
  --ds-f1: calc(8.5px * var(--z));   /* микроподпись, только UPPERCASE */
  --ds-f2: calc(10px * var(--z));    /* подпись, таблица */
  --ds-f3: calc(11.5px * var(--z));  /* основной текст */
  --ds-f4: calc(13px * var(--z));    /* врезка */
  --ds-f5: calc(17px * var(--z));    /* заголовок блока */
  --ds-f6: calc(21px * var(--z));    /* значение KPI */
  --ds-f7: calc(27px * var(--z));    /* заголовок экрана */

  /* ШКАЛА ОТСТУПОВ — шесть ступеней вместо 15 значений gap и 19 padding */
  --ds-s1: calc(4px * var(--z));
  --ds-s2: calc(8px * var(--z));
  --ds-s3: calc(12px * var(--z));
  --ds-s4: calc(16px * var(--z));
  --ds-s5: calc(24px * var(--z));
  --ds-s6: calc(32px * var(--z));

  /* Слои. Всё, что вне шкалы, считается ошибкой. */
  --ds-z-base: 1;
  --ds-z-sticky: 100;
  --ds-z-dropdown: 200;
  --ds-z-overlay: 1000;
  --ds-z-modal: 1100;
  --ds-z-toast: 1200;
}

/* ─────────────────────────── ТОКЕНЫ: ГРАФИТ ──────────────────────────── */
/* Нейтральный антрацит, а не сине-навигационный, как в текущей тёмной теме.
   Определён один раз: системная тёмная тема ссылается на этот же набор. */
:root[data-theme="graphite"],
:root[data-theme="dark"] {
  --ds-bg: #141416;
  --ds-bg-2: #0B0B0D;
  --ds-panel: #1A1A1F;
  --ds-sunk: rgba(0, 0, 0, 0.28);

  --ds-tx: #F4F4F6;
  --ds-tx-2: #A8A8B2;
  /* Контраст WCAG AA: графит: 3.80:1 -> 4.56:1 на тёмной панели */
  --ds-tx-3: #97979F;

  --ds-hair: rgba(255, 255, 255, 0.09);
  --ds-hair-2: rgba(255, 255, 255, 0.055);

  --ds-glass: rgba(46, 46, 52, 0.62);
  --ds-glass-2: rgba(38, 38, 44, 0.5);
  --ds-spec: rgba(255, 255, 255, 0.14);

  --ds-sh: 0 1px 2px rgba(0, 0, 0, 0.5), 0 14px 40px -16px rgba(0, 0, 0, 0.85);
  --ds-sh-hi: 0 2px 6px rgba(0, 0, 0, 0.6), 0 26px 58px -18px rgba(0, 0, 0, 0.95);

  --ds-brand: #FF4D54;
  --ds-flash: rgba(255, 77, 84, 0.16);
  --ds-ok: #30D158;
  --ds-warn: #FFA033;
  /* [FIX FE-15] На тёмном фоне янтарный и красный текст читаются — оставляем. */
  --ds-warn-text: #FFA033;
  --ds-crit-text: #FF6B6B;
  --ds-crit: #FF6B6B;
  --ds-idle: #8E8E99;

  --ds-c-time: #6BA6E8;
  --ds-c-vol: #3DD6BE;
  --ds-c-money: #E0B854;
  --ds-c-qual: #B08CF5;
}

/* Системная тёмная тема наследует графит, но только если пользователь
   не выбрал тему вручную. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="corporate"]) {
    --ds-bg: #141416;
    --ds-bg-2: #0B0B0D;
    --ds-panel: #1A1A1F;
    --ds-sunk: rgba(0, 0, 0, 0.28);
    --ds-tx: #F4F4F6;
    --ds-tx-2: #A8A8B2;
    /* Контраст WCAG AA: графит (медиазапрос): 3.80:1 -> 4.56:1 */
    --ds-tx-3: #97979F;
    --ds-hair: rgba(255, 255, 255, 0.09);
    --ds-hair-2: rgba(255, 255, 255, 0.055);
    --ds-glass: rgba(46, 46, 52, 0.62);
    --ds-glass-2: rgba(38, 38, 44, 0.5);
    --ds-spec: rgba(255, 255, 255, 0.14);
    --ds-sh: 0 1px 2px rgba(0, 0, 0, 0.5), 0 14px 40px -16px rgba(0, 0, 0, 0.85);
    --ds-sh-hi: 0 2px 6px rgba(0, 0, 0, 0.6), 0 26px 58px -18px rgba(0, 0, 0, 0.95);
    --ds-brand: #FF4D54;
    --ds-flash: rgba(255, 77, 84, 0.16);
    --ds-ok: #30D158;
    --ds-warn: #FFA033;
    --ds-warn-text: #FFA033;
    --ds-crit-text: #FF6B6B;
    --ds-crit: #FF6B6B;
    --ds-c-time: #6BA6E8;
    --ds-c-vol: #3DD6BE;
    --ds-c-money: #E0B854;
    --ds-c-qual: #B08CF5;
  }
}

/* ──────────────────────── ТОКЕНЫ: КОРПОРАТИВНАЯ ──────────────────────── */
/* Фото головного офиса подложкой всего интерфейса. Панели лежат на нём
   стеклом, читаемость держит затемняющая вуаль. */
:root[data-theme="corporate"] {
  --ds-bg: #0E1219;
  --ds-bg-2: #0B0E14;
  --ds-panel: rgba(20, 24, 33, 0.72);
  --ds-sunk: rgba(0, 0, 0, 0.3);

  --ds-tx: #FBFBFD;
  --ds-tx-2: #C3C6CE;
  --ds-tx-3: #8F949E;

  --ds-hair: rgba(255, 255, 255, 0.13);
  --ds-hair-2: rgba(255, 255, 255, 0.075);

  --ds-glass: rgba(20, 24, 33, 0.52);
  --ds-glass-2: rgba(16, 19, 27, 0.42);
  --ds-spec: rgba(255, 255, 255, 0.2);

  --ds-sh: 0 1px 2px rgba(0, 0, 0, 0.4), 0 18px 48px -18px rgba(0, 0, 0, 0.75);
  --ds-sh-hi: 0 3px 8px rgba(0, 0, 0, 0.5), 0 30px 64px -20px rgba(0, 0, 0, 0.9);

  --ds-brand: #FF5A60;
  --ds-flash: rgba(255, 90, 96, 0.16);
  --ds-ok: #3DDC6E;
  --ds-warn: #FFB040;
  --ds-warn-text: #FFB040;
  --ds-crit-text: #FF7A72;
  --ds-crit: #FF7A72;
  --ds-idle: #9AA0AC;

  --ds-c-time: #7DB4EE;
  --ds-c-vol: #4EDCC6;
  --ds-c-money: #E8C264;
  --ds-c-qual: #BB9BF7;

  --ds-office: url("../img/office-hq.jpg");
}

:root[data-theme="corporate"] body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  /* Запасное значение обязательно: токен объявлен только в корпоративной
     теме, и без него правило невалидно в остальных. */
  background-image: var(--ds-office, none);
  background-size: cover;
  background-position: center 62%;
}

:root[data-theme="corporate"] body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(8, 11, 17, 0.62) 0%, rgba(8, 11, 17, 0.78) 45%, rgba(8, 11, 17, 0.9) 100%),
    linear-gradient(100deg, rgba(8, 11, 17, 0.55) 0%, rgba(8, 11, 17, 0.2) 60%);
}

/* ───────────────────────────── МАТЕРИАЛ ──────────────────────────────── */
/* .ds-glass — основная панель, .ds-glass-2 — вложенная.
   Блик по верхней кромке (inset) обязателен: без него стекло выглядит
   плоской полупрозрачной плашкой. */
.ds-glass {
  background: var(--ds-glass);
  -webkit-backdrop-filter: blur(30px) saturate(190%);
  backdrop-filter: blur(30px) saturate(190%);
  border: 1px solid var(--ds-hair);
  border-radius: var(--ds-rad-in);
  box-shadow: var(--ds-sh), inset 0 1px 0 var(--ds-spec);
}

.ds-glass-2 {
  background: var(--ds-glass-2);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid var(--ds-hair-2);
  border-radius: var(--ds-rad-sm);
}

/* Фолбэк для слабых GPU и для тех, кто отключил прозрачность в системе.
   Без него backdrop-filter роняет частоту кадров на встроенной графике. */
@media (prefers-reduced-transparency: reduce) {
  .ds-glass,
  .ds-glass-2 {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: var(--ds-panel);
  }
}

@supports not (backdrop-filter: blur(1px)) {
  .ds-glass,
  .ds-glass-2 {
    background: var(--ds-panel);
  }
}

/* ───────────────────────────── АНИМАЦИЯ ──────────────────────────────── */
@keyframes ds-rise {
  from { opacity: 0; transform: translateY(9px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

@keyframes ds-sweep {
  from { opacity: 0; transform: translateX(-7px); }
  to   { opacity: 1; transform: none; }
}

@keyframes ds-grow {
  from { transform: scaleY(0.08); }
  to   { transform: scaleY(1); }
}

/* Каскад появления. Задержку выставляет разметка через --ds-delay,
   чтобы карточки всплывали по очереди, а не все разом. */
.ds-anim {
  animation: ds-rise 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) backwards;
  animation-delay: var(--ds-delay, 0s);
}

.ds-anim-nav {
  animation: ds-sweep 0.38s cubic-bezier(0.2, 0.7, 0.2, 1) backwards;
  animation-delay: var(--ds-delay, 0s);
}

.ds-anim-bar {
  animation: ds-grow 0.62s cubic-bezier(0.2, 0.8, 0.25, 1) backwards;
  transform-origin: bottom;
  animation-delay: var(--ds-delay, 0s);
}

/* ──────────────────────── ОТКЛИК НА НАВЕДЕНИЕ ────────────────────────── */
/* Карточка приподнимается, тень растёт, иконка поворачивается, последний
   столбец спарклайна тянется вверх. Только transform и box-shadow —
   свойства, которые браузер анимирует без перерасчёта раскладки. */
.ds-lift {
  transition:
    transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1),
    box-shadow 0.22s ease,
    border-color 0.22s ease,
    background 0.22s ease;
  will-change: transform;
}

.ds-lift:hover {
  transform: translateY(-3px);
  box-shadow: var(--ds-sh-hi), inset 0 1px 0 var(--ds-spec);
}

.ds-lift:hover .ds-ico { transform: scale(1.09) rotate(-4deg); }
.ds-lift:hover .ds-spark i.is-last { transform: scaleY(1.14); }

.ds-slide {
  transition: transform 0.2s cubic-bezier(0.2, 0.7, 0.2, 1), background 0.2s ease;
}
.ds-slide:hover { transform: translateX(2px); }

.ds-ico,
.ds-spark i {
  transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1), background 0.22s ease;
}

/* [FIX 26.09.2026] Три добавки к живости интерфейса (просьба владельца —
   аудит анимаций/компоновки, /claude-marketing--frontend-design):
   1) вспышка карточки KPI при смене значения — иначе автообновление раз в
      30с проходит незамеченным;
   2) мягкое появление панели при переключении подвкладок (.fleet-tabbar) —
      сейчас контент подменяется мгновенно, ощущается как "дёрнуло";
   3) заливка горизонтальной шкалы слева направо (скоринг водителей) — сейчас
      появляется уже заполненной, без ощущения "набора балла". */
@keyframes ds-value-flash {
  0% { background: var(--ds-flash, rgba(218, 31, 38, 0.12)); }
  100% { background: transparent; }
}
.ds-value-flash {
  animation: ds-value-flash 900ms ease-out;
}

@keyframes ds-tab-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
.ds-tab-panel-anim {
  animation: ds-tab-in 0.18s ease-out;
}

.ds-fill-anim {
  transition: width 0.6s cubic-bezier(0.2, 0.8, 0.25, 1);
}

/* Спиннер на кнопке "Применить"/"Обновить" — единственный признак того, что
   клик вообще что-то запустил, был не виден раньше: карточки просто молча
   подменялись данными спустя долю секунды. */
@keyframes ds-spin {
  to { transform: rotate(360deg); }
}
.ds-spin {
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-right: 6px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: ds-spin 0.6s linear infinite;
  vertical-align: -2px;
  opacity: 0.7;
}

/* Уважение к системной настройке: движение отключается полностью,
   но состояния остаются различимыми. */
@media (prefers-reduced-motion: reduce) {
  .ds-anim,
  .ds-anim-nav,
  .ds-anim-bar,
  .ds-value-flash,
  .ds-tab-panel-anim,
  .ds-spin { animation: none; border-right-color: currentColor; }

  .ds-lift,
  .ds-slide,
  .ds-ico,
  .ds-spark i,
  .ds-fill-anim { transition: none; }

  .ds-lift:hover,
  .ds-slide:hover { transform: none; }
}

/* ───────────────────────────── ТИПОГРАФИКА ───────────────────────────── */
.ds-f1 { font-size: var(--ds-f1); letter-spacing: 0.07em; text-transform: uppercase; font-weight: 600; }
.ds-f2 { font-size: var(--ds-f2); }
.ds-f3 { font-size: var(--ds-f3); }
.ds-f4 { font-size: var(--ds-f4); }
.ds-f5 { font-size: var(--ds-f5); font-weight: 650; letter-spacing: -0.022em; }
.ds-f6 { font-size: var(--ds-f6); font-weight: 650; letter-spacing: -0.032em; line-height: 1; }
.ds-f7 { font-size: var(--ds-f7); font-weight: 650; letter-spacing: -0.028em; line-height: 1.13; }

/* Цифры в колонках обязаны выстраиваться друг под другом. */
.ds-num {
  font-family: var(--ds-fm);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* ───────────────────── ПРАВИЛА ПЕРЕНОСА ТЕКСТА ───────────────────────── */
/* Три класса на три случая. Голый white-space:nowrap без одного из них
   считается ошибкой: именно он распирает таблицы вширь. */

/* 1. Не переносим, обрезаем многоточием. Обязательна подсказка title. */
.ds-clip {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* 2. Переносим по словам, при нужде разрываем длинное слово.
      Для наименований клиентов, адресов точек, примечаний. */
.ds-wrap {
  overflow-wrap: anywhere;
  word-break: normal;
}

/* 3. Не рвём никогда: госномер, дата, сумма, код рейса. */
.ds-atomic {
  white-space: nowrap;
  font-family: var(--ds-fm);
  font-variant-numeric: tabular-nums;
}

/* [FIX ВИЗ-13] 4. Многострочный текст с ограничением строк.
   Длинная фраза без ограничения растягивает строку таблицы: в «Ремонтах»
   автопарка причина ремонта давала строку 104px при тексте 11.5px (замер).
   Две строки и многоточие сохраняют компактность, полный текст — в title.
   Свойство вендорное, поэтому нужен и `display: -webkit-box`: без него
   `-webkit-line-clamp` не действует. */
.ds-clamp-2,
.ds-clamp-3 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
  line-height: 1.35;
}
.ds-clamp-2 { -webkit-line-clamp: 2; }
.ds-clamp-3 { -webkit-line-clamp: 3; }

/* ─────────────────────────── ФОКУС С КЛАВИАТУРЫ ──────────────────────── */
/* Сейчас в приложении видимый фокус есть только у полей ввода, а
   :focus-visible встречается ровно один раз на весь проект. Кнопки, ссылки
   навигации, вкладки и закрытие модалок не показывают фокус вообще. */
.ds-focus:focus-visible,
button:focus-visible,
a:focus-visible,
[tabindex]:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--ds-c-time);
  outline-offset: 2px;
  border-radius: var(--ds-rad-sm);
}

/* ──────────────────────────── СТАТУС-ТОЧКА ───────────────────────────── */
/* Цвет всегда сопровождается словом рядом: состояние не кодируется одним
   цветом, иначе оно недоступно при дальтонизме и в печати. */
.ds-dot {
  width: calc(6px * var(--z));
  height: calc(6px * var(--z));
  border-radius: 50%;
  flex: none;
  display: inline-block;
  box-shadow: 0 0 0 2.5px color-mix(in srgb, currentColor 20%, transparent);
}

.ds-dot--ok   { background: var(--ds-ok);   color: var(--ds-ok); }
.ds-dot--warn { background: var(--ds-warn); color: var(--ds-warn); }
.ds-dot--crit { background: var(--ds-crit); color: var(--ds-crit); }
.ds-dot--idle { background: var(--ds-idle); color: var(--ds-idle); }
.ds-dot--time { background: var(--ds-c-time); color: var(--ds-c-time); }
.ds-dot--vol  { background: var(--ds-c-vol);  color: var(--ds-c-vol); }
.ds-dot--qual { background: var(--ds-c-qual); color: var(--ds-c-qual); }

/* ───────────────────────── ИКОНКА-ЧИП КАТЕГОРИИ ──────────────────────── */
.ds-ico {
  width: calc(21px * var(--z));
  height: calc(21px * var(--z));
  border-radius: calc(6.5px * var(--z));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.ds-ico svg { width: calc(12.5px * var(--z)); height: calc(12.5px * var(--z)); }

.ds-ico--time  { background: color-mix(in srgb, var(--ds-c-time) 17%, transparent);  color: var(--ds-c-time); }
.ds-ico--vol   { background: color-mix(in srgb, var(--ds-c-vol) 17%, transparent);   color: var(--ds-c-vol); }
.ds-ico--money { background: color-mix(in srgb, var(--ds-c-money) 17%, transparent); color: var(--ds-c-money); }
.ds-ico--qual  { background: color-mix(in srgb, var(--ds-c-qual) 17%, transparent);  color: var(--ds-c-qual); }

/* ──────────────────────────── СПАРКЛАЙН ──────────────────────────────── */
.ds-spark {
  height: calc(17px * var(--z));
  display: flex;
  align-items: flex-end;
  gap: 2px;
}

.ds-spark i {
  flex: 1;
  border-radius: 1.5px;
  background: color-mix(in srgb, var(--ds-tx) 12%, transparent);
  display: block;
}

.ds-spark i.is-accent { background: color-mix(in srgb, var(--ds-c-time) 55%, transparent); }
.ds-spark i.is-last   { background: var(--ds-c-time); }

/* ───────────────────── СОСТОЯНИЕ «НЕТ ДАННЫХ» ────────────────────────── */
/* Отличается от нуля намеренно: пунктирная рамка, приглушённое значение,
   причина в подписи. Сегодня приложение вместо этого показывает выдуманные
   числа — например TCO «$0.001 / км» с расшифровкой «ГСМ $0.000 + ТО $0.001»,
   которая не сходится сама с собой. */
.ds-nodata {
  border-style: dashed;
  border-color: var(--ds-hair);
  box-shadow: none;
}

.ds-nodata .ds-value {
  font-size: var(--ds-f4);
  font-weight: 400;
  color: var(--ds-tx-3);
  letter-spacing: -0.01em;
}

/* ──────────────────────────── ТАБЛИЦЫ ────────────────────────────────── */
/* Липкая шапка работает только внутри прокручиваемого контейнера с высотой.
   Сейчас глобальное правило th{position:sticky} применено к таблицам,
   у обёртки которых нет max-height, поэтому шапка липнет к вьюпорту
   страницы и наезжает на соседние блоки. */
.ds-table-wrap {
  overflow-x: auto;
  overflow-y: auto;
  max-height: calc(340px * var(--z));
  border: 1px solid var(--ds-hair);
  border-radius: var(--ds-rad-in);
}

.ds-table-wrap table { width: 100%; border-collapse: collapse; font-size: var(--ds-f2); }

.ds-table-wrap thead th {
  position: sticky;
  top: 0;
  z-index: var(--ds-z-sticky);
  background: var(--ds-sunk);
  text-align: left;
  font-size: var(--ds-f1);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ds-tx-3);
  font-weight: 600;
  padding: var(--ds-s2) var(--ds-s3);
  border-bottom: 1px solid var(--ds-hair);
  white-space: nowrap;
}

.ds-table-wrap tbody td {
  padding: var(--ds-s2) var(--ds-s3);
  border-bottom: 1px solid var(--ds-hair-2);
  vertical-align: middle;
}

.ds-table-wrap tbody tr:last-child td { border-bottom: 0; }
.ds-table-wrap tbody tr { transition: background 0.16s ease; }
.ds-table-wrap tbody tr:hover { background: var(--ds-glass-2); }
.ds-table-wrap td.ds-right { text-align: right; }

/* ──────────────────────── ТАЧ-ТАРГЕТЫ ────────────────────────────────── */
/* На складских экранах работают стоя и в перчатках. Ниже 44 px опускаться
   нельзя. Сейчас базовая кнопка 36 px, мелкая 28 px, а мобильная — 40 px,
   то есть меньше планшетной. */
@media (pointer: coarse) {
  button,
  .ds-btn,
  a[role="button"],
  [tabindex]:not([tabindex="-1"]) {
    min-height: 44px;
    min-width: 44px;
  }
}

/* ══════════════════════ БОКОВАЯ НАВИГАЦИЯ ════════════════════════════ */
/* Заменяет горизонтальный ряд вкладок. Причины замены:
   — вкладок девять, при сужении окна они переносятся на вторую строку
     и прыгают, ломая позицию активного пункта;
   — в ряд не помещается ни счётчик проблем, ни группировка по смыслу;
   — эмодзи в подписях («🚚 Диспетчер-Логист») разъезжаются между ОС.

   DOM не перестраивается: <nav id="appNav"> остаётся на месте и просто
   становится фиксированной колонкой слева, а логотип переезжает в неё
   из шапки. Шапка и контент сдвигаются вправо на ширину колонки. */

:root { --ds-side-w: calc(186px * var(--z)); }

/* nav.ds-side, а не просто .ds-side: в style.css есть правило .app-nav
   с position:sticky и той же специфичностью, а подключается он позже —
   при равном весе побеждает последний. Селектор по тегу перевешивает. */
nav.ds-side {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--ds-side-w, 210px);
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--ds-s4) var(--ds-s2);
  background: var(--ds-panel);
  border-right: 1px solid var(--ds-hair);
  z-index: var(--ds-z-sticky);
  overflow-y: auto;
  /* Строго hidden: длинный пункт («Дашборд руководителя») иначе распирает
     колонку на десяток пикселей и внизу появляется горизонтальный
     скроллбар — в текущей теме он ещё и красный. Подпись сжимается
     многоточием, см. .ds-nav-label ниже. */
  overflow-x: hidden;
  overscroll-behavior: contain;
}

:root[data-theme="corporate"] nav.ds-side {
  background: var(--ds-glass);
  -webkit-backdrop-filter: blur(30px) saturate(190%);
  backdrop-filter: blur(30px) saturate(190%);
}

/* Сдвиг остального макета. Класс вешается на body, когда колонка показана,
   чтобы на экране входа (навигации ещё нет) ничего не смещалось. */
.ds-has-side header,
.ds-has-side main,
.ds-has-side #offlineBanner,
.ds-has-side #roleImpersonateBanner {
  padding-left: calc(var(--ds-side-w, 210px) + var(--ds-s4));
}

/* Логотип теперь в колонке — в шапке он дублировался бы. */
.ds-has-side header .brand { display: none; }

/* ── Шапка колонки: логотип и название ── */
.ds-side-brand {
  display: flex;
  align-items: center;
  gap: var(--ds-s2);
  padding: 2px var(--ds-s2) var(--ds-s4);
}

.ds-side-brand img {
  width: calc(24px * var(--z));
  height: calc(24px * var(--z));
  border-radius: calc(6px * var(--z));
  object-fit: cover;
  flex: none;
  box-shadow: 0 2px 8px -2px color-mix(in srgb, var(--ds-brand) 70%, transparent);
  transition: transform 0.3s cubic-bezier(0.2, 0.7, 0.2, 1);
}

nav.ds-side:hover .ds-side-brand img { transform: rotate(-6deg) scale(1.06); }

.ds-side-brand b {
  font-size: var(--ds-f4);
  font-weight: 600;
  letter-spacing: -0.022em;
  color: var(--ds-tx);
}

/* ── Подпись группы ── */
.ds-nav-group {
  font-size: var(--ds-f1);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ds-tx-3);
  font-weight: 600;
  padding: var(--ds-s3) calc(var(--ds-s2) - 1px) var(--ds-s1);
}

/* ── Пункт навигации ── */
nav.ds-side a.ds-nav-item {
  display: flex;
  align-items: center;
  gap: calc(9px * var(--z));
  padding: calc(6.5px * var(--z)) calc(9px * var(--z));
  border-radius: var(--ds-rad-sm);
  color: var(--ds-tx-2);
  font-size: var(--ds-f3);
  letter-spacing: -0.008em;
  text-decoration: none;
  border: 1px solid transparent;
  /* min-width:0 обязателен: без него флекс-элемент отказывается сжиматься
     ниже ширины содержимого, и многоточие в подписи не срабатывает. */
  min-width: 0;
  transition: background 0.18s ease, color 0.18s ease, transform 0.18s ease;
}

nav.ds-side a.ds-nav-item svg {
  width: calc(15px * var(--z));
  height: calc(15px * var(--z));
  flex: none;
  opacity: 0.85;
  transition: opacity 0.18s ease, color 0.18s ease;
}

nav.ds-side a.ds-nav-item span.ds-nav-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

nav.ds-side a.ds-nav-item:hover {
  background: var(--ds-glass-2);
  color: var(--ds-tx);
  transform: translateX(2px);
}

nav.ds-side a.ds-nav-item:hover svg { opacity: 1; }

/* Активный пункт — одно из трёх мест, где живёт фирменный красный.
   Красится только иконка: заливать весь пункт брендом значит потерять
   различимость между «выбрано» и «требует внимания». */
/* Фон активного пункта — утопленная поверхность, а не стекло: в светлой
   теме --ds-glass-2 это белый с прозрачностью 0.55, и на белой колонке он
   не виден вовсе. --ds-sunk даёт видимую подложку во всех трёх темах. */
nav.ds-side a.ds-nav-item.active {
  color: var(--ds-tx);
  font-weight: 600;
  background: var(--ds-sunk);
  border-color: var(--ds-hair-2);
}

nav.ds-side a.ds-nav-item.active svg { color: var(--ds-brand); opacity: 1; }

/* ══════════════════════════════════════════════════════════════════
   Свёрнутая колонка: остаются одни пиктограммы.

   Зачем. Панель занимает 186px постоянной ширины. На 1366×768 — а это
   обязательный минимум выживания — таблицы рейсов из-за этого сжимаются
   и уезжают вбок. Пользователь, который знает разделы наизусть, подписи
   не читает, но платит за них шириной каждую смену.

   Вся ширина макета уже выражена через --ds-side-w, включая сдвиг шапки и
   контента, поэтому сворачивание — это одна переопределённая переменная,
   а не вторая раскладка.
   ══════════════════════════════════════════════════════════════════ */
:root[data-side="svernuta"] { --ds-side-w: calc(56px * var(--z)); }

/* Ширина анимируется, но только если пользователь не просил обратного. */
@media (prefers-reduced-motion: no-preference) {
  nav.ds-side,
  .ds-has-side header,
  .ds-has-side main,
  .ds-has-side #offlineBanner,
  .ds-has-side #roleImpersonateBanner {
    transition: width 0.22s cubic-bezier(0.2, 0.7, 0.2, 1),
                padding-left 0.22s cubic-bezier(0.2, 0.7, 0.2, 1);
  }
}

/* Кнопка сворачивания живёт в шапке колонки и видна в обоих состояниях:
   иначе развернуть панель обратно было бы нечем. */
.ds-side-svernut {
  width: 28px;
  height: 28px;
  flex: none;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--ds-hair);
  border-radius: var(--ds-rad-sm);
  background: transparent;
  color: var(--ds-tx-2);
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}

.ds-side-svernut:hover { background: var(--ds-glass-2); color: var(--ds-tx); }
.ds-side-svernut svg { width: 14px; height: 14px; }
/* Стрелка разворачивается вместе с панелью — направление подсказывает,
   что произойдёт по нажатию. */
:root[data-side="svernuta"] .ds-side-svernut svg { transform: scaleX(-1); }

/* В свёрнутом виде прячем всё, кроме пиктограмм. */
:root[data-side="svernuta"] .ds-nav-label,
:root[data-side="svernuta"] .ds-nav-group,
:root[data-side="svernuta"] .ds-side-brand b { display: none; }

:root[data-side="svernuta"] .ds-side-brand {
  flex-direction: column;
  gap: var(--ds-s2);
  padding-left: 0;
  padding-right: 0;
}

:root[data-side="svernuta"] .ds-side-brand img { margin: 0 auto; }
:root[data-side="svernuta"] .ds-side-svernut { margin: 0 auto; }

:root[data-side="svernuta"] nav.ds-side a.ds-nav-item {
  justify-content: center;
  gap: 0;
  padding-left: 0;
  padding-right: 0;
}

/* Сдвиг вправо при наведении в узкой колонке выталкивал бы иконку за край. */
:root[data-side="svernuta"] nav.ds-side a.ds-nav-item:hover { transform: none; }

/* Счётчик проблем сжимается в точку: число в 56 пикселей не влезает, но
   потерять сам признак «здесь требуется внимание» нельзя — ради него
   счётчик и заведён. Подпись с числом остаётся в title пункта. */
:root[data-side="svernuta"] nav.ds-side a.ds-nav-item { position: relative; }

:root[data-side="svernuta"] .ds-nav-badge {
  position: absolute;
  top: calc(4px * var(--z));
  right: calc(8px * var(--z));
  margin: 0;
  padding: 0;
  width: calc(7px * var(--z));
  height: calc(7px * var(--z));
  border-radius: 50%;
  background: var(--ds-crit);
  color: transparent;
  overflow: hidden;
  text-indent: -99px;
}

/* Счётчик проблем на пункте: «Автопарк 4», «Складская логистика 14». */
.ds-nav-badge {
  margin-left: auto;
  font-size: var(--ds-f1);
  font-weight: 600;
  padding: 1.5px 6px;
  border-radius: 20px;
  background: color-mix(in srgb, var(--ds-crit) 18%, transparent);
  color: var(--ds-crit);
  flex: none;
}

/* ── Подвал колонки: кто вошёл ── */
.ds-side-foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: var(--ds-s2);
  padding: calc(11px * var(--z)) calc(7px * var(--z)) 0;
  border-top: 1px solid var(--ds-hair-2);
}

.ds-side-foot .ds-av {
  width: calc(22px * var(--z));
  height: calc(22px * var(--z));
  border-radius: 50%;
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair-2);
  flex: none;
  /* Пиктограмма внутри кружка: пустой круг читается как неподгрузившаяся
     картинка, а не как аватар. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  color: var(--ds-tx-2);
}

.ds-side-foot .ds-av svg {
  width: calc(13px * var(--z));
  height: calc(13px * var(--z));
}

/* Водяной знак разработчика. Приглушённый и мелкий: это подпись под
   работой, а не элемент управления, и внимание забирать не должна. */
.ds-side-znak {
  /* [FIX 26.09.2026] Раньше "прилипание" ко дну сайдбара обеспечивал
     соседний .ds-side-foot — его убрали (переехал в шапку), а margin-top:
     auto забыли перенести сюда. Без него подпись поднималась сразу под
     последний пункт меню, а не оставалась внизу колонки. */
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: calc(5px * var(--z));
  padding: calc(6px * var(--z)) calc(7px * var(--z)) calc(10px * var(--z));
  border-top: 1px solid var(--ds-hair-2);
  font-size: var(--ds-f1);
  line-height: 1.3;
  color: var(--ds-tx-3);
  opacity: 0.75;
  min-width: 0;
}

.ds-side-znak svg {
  width: calc(11px * var(--z));
  height: calc(11px * var(--z));
  flex: none;
}

.ds-znak-foto {
  width: calc(28px * var(--z));
  height: calc(28px * var(--z));
  border-radius: 50%;
  object-fit: cover;
  flex: none;
  border: 1px solid var(--ds-hair-2);
  cursor: pointer;
}

.znak-foto-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.75);
  z-index: 10000;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.znak-foto-overlay img {
  max-width: min(80vw, 420px);
  max-height: 80vh;
  border-radius: 12px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
}

.ds-side-znak span {
  min-width: 0;
  white-space: normal;
  overflow: visible;
  text-overflow: unset;
  line-height: 1.25;
}

/* В свёрнутой колонке остаётся один значок — подпись в 56 пикселей не
   помещается, а полный текст доступен подсказкой при наведении. */
:root[data-side="svernuta"] .ds-side-znak {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
}

:root[data-side="svernuta"] .ds-side-znak span { display: none; }

.ds-side-foot .ds-who {
  font-size: var(--ds-f2);
  line-height: 1.3;
  min-width: 0;
  flex: 1 1 auto;
  color: var(--ds-tx);
  /* ФИО оператора бывает длиннее колонки — обрезаем, а не распираем. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ds-side-foot .ds-who i {
  display: block;
  font-style: normal;
  color: var(--ds-tx-3);
  font-size: var(--ds-f1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Узкий экран: колонка уезжает вниз горизонтальной лентой ──
   На планшете и телефоне фиксированная колонка съедает половину ширины,
   поэтому там она превращается в прокручиваемую ленту под шапкой. */
@media (max-width: 860px) {
  nav.ds-side {
    position: static;
    width: auto;
    flex-direction: row;
    gap: var(--ds-s1);
    overflow-x: auto;
    overflow-y: hidden;
    border-right: 0;
    border-bottom: 1px solid var(--ds-hair);
    padding: var(--ds-s2) var(--ds-s3);
  }

  .ds-has-side header,
  .ds-has-side main,
  .ds-has-side #offlineBanner,
  .ds-has-side #roleImpersonateBanner { padding-left: 0; }

  .ds-has-side header .brand { display: flex; }
  .ds-side-brand,
  .ds-side-foot,
  .ds-nav-group { display: none; }

  nav.ds-side a.ds-nav-item { min-height: 44px; }
  nav.ds-side a.ds-nav-item:hover { transform: none; }
}

/* ════════════════════════════ ШАПКА ══════════════════════════════════ */
/* Фирменный красный в шапке не живёт: он зарезервирован за логотипом,
   активным пунктом навигации и главной кнопкой действия экрана. Сейчас в
   красный выкрашены круглые иконки темы и полноэкранного режима — из-за
   этого цвет перестал означать «здесь важное». */

/* Сокращённую запись padding здесь использовать нельзя: она обнулила бы
   padding-left, которым шапка сдвигается из-под фиксированной колонки,
   и переключатель роли уезжал под неё. Задаём стороны по отдельности. */
.ds-has-side header {
  background: var(--ds-panel);
  border-bottom: 1px solid var(--ds-hair);
  padding-top: var(--ds-s2);
  padding-bottom: var(--ds-s2);
  padding-right: var(--ds-s4);
  gap: var(--ds-s2);
}

:root[data-theme="corporate"] .ds-has-side header {
  background: var(--ds-glass);
  -webkit-backdrop-filter: blur(30px) saturate(190%);
  backdrop-filter: blur(30px) saturate(190%);
}

/* Круглые кнопки шапки: нейтральная поверхность вместо заливки брендом. */
.ds-has-side header .header-icon-btn {
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  color: var(--ds-tx-2);
  border-radius: var(--ds-rad-sm);
  width: auto;
  min-width: calc(34px * var(--z));
  height: calc(34px * var(--z));
  padding: 0 calc(9px * var(--z));
  box-shadow: none;
  transition: transform 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.ds-has-side header .header-icon-btn:hover {
  transform: translateY(-1px);
  border-color: var(--ds-tx-3);
  color: var(--ds-tx);
}

.ds-has-side header .header-icon-btn svg {
  width: calc(17px * var(--z));
  height: calc(17px * var(--z));
}

/* Выход — не разрушающее действие, красным его красить незачем. */
.ds-has-side header #logoutBtn {
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  color: var(--ds-tx-2);
  border-radius: var(--ds-rad-sm);
  font-size: var(--ds-f3);
  font-weight: 600;
  height: calc(34px * var(--z));
  padding: 0 calc(14px * var(--z));
  box-shadow: none;
  margin-left: var(--ds-s3);
}

.ds-has-side header #logoutBtn:hover {
  border-color: var(--ds-crit);
  /* [FIX FE-15] Текстом — тёмный красный: #E5484D на светлой шапке даёт
     3.96:1, это ниже нормы 4.5:1 для мелкого текста. */
  color: var(--ds-crit-text, #B8141A);
}

/* Кто вошёл — в шапке вторичен: то же самое уже стоит в подвале колонки. */
.ds-has-side header #whoami {
  font-size: var(--ds-f3);
  color: var(--ds-tx-3);
}

/* Переключатель роли и «Переобновить данные» — на шкале и в нейтрали. */
.ds-has-side header #roleSwitcherContainer {
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  border-radius: var(--ds-rad-sm);
  padding: calc(3px * var(--z)) calc(9px * var(--z));
}

.ds-has-side header #roleSwitcherContainer > span {
  font-size: var(--ds-f2);
  color: var(--ds-tx-3);
  font-weight: 600;
}

.ds-has-side header #roleViewSelect {
  background: transparent;
  border: 0;
  color: var(--ds-tx);
  font-size: var(--ds-f3);
  font-weight: 600;
  padding: calc(4px * var(--z)) calc(4px * var(--z));
}

.ds-has-side header #resyncBtn {
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  color: var(--ds-tx-2);
  border-radius: var(--ds-rad-sm);
  font-size: var(--ds-f3);
  height: calc(34px * var(--z));
}

.ds-has-side header #resyncBtn:hover {
  border-color: var(--ds-tx-3);
  color: var(--ds-tx);
}

/* ═══════════ РЕГЛАМЕНТ SLA ═══════════════════════════════════════════ */
/* Экран живёт на собственной таблице стилей sla.css в 1439 строк, где нет
   ни одного токена — цвета и размеры заданы числами. Выдаём материал и
   шкалу по классам, не трогая сам файл. */

#sec-sla .sla-kpi-card {
  background: var(--ds-glass);
  -webkit-backdrop-filter: blur(30px) saturate(190%);
  backdrop-filter: blur(30px) saturate(190%);
  border: 1px solid var(--ds-hair);
  border-radius: var(--ds-rad-in);
  box-shadow: var(--ds-sh), inset 0 1px 0 var(--ds-spec);
  transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 0.22s ease;
}

#sec-sla .sla-kpi-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--ds-sh-hi), inset 0 1px 0 var(--ds-spec);
}

/* «Обновить факт» — вспомогательное действие, перечитать показатели.
   Класс называется sla-btn-primary, но главным действием этого экрана
   он не является: экран читают, а не редактируют. */
#sec-sla .sla-btn-primary {
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  color: var(--ds-tx-2);
  box-shadow: none;
  transition: transform 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

#sec-sla .sla-btn-primary:hover {
  transform: translateY(-1px);
  border-color: var(--ds-tx-3);
  color: var(--ds-tx);
}

/* Фильтр по зоне ответственности: выбранный — заливкой цвета текста. */
#sec-sla .sla-tab-pill.active {
  background: var(--ds-tx);
  border-color: var(--ds-tx);
  color: var(--ds-bg);
  font-weight: 600;
  box-shadow: none;
}

/* Счётчик внутри выбранного фильтра. В sla.css ему прописан белый текст, и
   на светлой заливке тёмной темы получалось 1.10:1 — цифра просто исчезала.
   Цвет наследуется от самой плашки, чтобы правило работало в любой теме. */
#sec-sla .sla-tab-pill.active .sla-tab-count {
  background: color-mix(in srgb, var(--ds-bg) 18%, transparent);
  color: inherit;
}

#sec-sla table tbody tr { transition: background 0.16s ease; }
#sec-sla table tbody tr:hover { background: var(--ds-glass-2); }

/* ═══════════ НАСТРОЙКИ ═══════════════════════════════════════════════ */
/* Активная вкладка помечается отсутствием класса: showTab() в settings.js
   ставит неактивным className="secondary", а активной — пустую строку,
   из-за чего та получает глобальный стиль кнопки и заливается брендом.
   Красный здесь не к месту: вкладка это навигация, а не действие.
   Главным действием остаётся «Добавить» в форме — одновременно на экране
   видна ровно одна такая кнопка, и её мы не трогаем. */

#sec-settings .settings-tabs button:not(.secondary) {
  background: var(--ds-tx);
  border-color: var(--ds-tx);
  color: var(--ds-bg);
  font-weight: 600;
  box-shadow: none;
}

#sec-settings .settings-tabs button.secondary {
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  color: var(--ds-tx-2);
  box-shadow: none;
  transition: border-color 0.18s ease, color 0.18s ease;
}

#sec-settings .settings-tabs button.secondary:hover {
  border-color: var(--ds-tx-3);
  color: var(--ds-tx);
}

#sec-settings .card {
  background: var(--ds-glass);
  -webkit-backdrop-filter: blur(30px) saturate(190%);
  backdrop-filter: blur(30px) saturate(190%);
  border: 1px solid var(--ds-hair);
  border-radius: var(--ds-rad-in);
  box-shadow: var(--ds-sh), inset 0 1px 0 var(--ds-spec);
}

#sec-settings table tbody tr { transition: background 0.16s ease; }
#sec-settings table tbody tr:hover { background: var(--ds-glass-2); }

/* ═══════════ РАЗБОР РЕЙСА ════════════════════════════════════════════ */
/* Экран и так компактный — 646 px. Красная кнопка одна, «Найти», и это
   действительно главное действие: с неё экран начинается. Добавляем
   только отклик на наведение, чтобы совпадал с остальными. */

#sec-investigation .card,
#sec-investigation .investigation-dossier {
  background: var(--ds-glass);
  -webkit-backdrop-filter: blur(30px) saturate(190%);
  backdrop-filter: blur(30px) saturate(190%);
  border: 1px solid var(--ds-hair);
  border-radius: var(--ds-rad-in);
  box-shadow: var(--ds-sh), inset 0 1px 0 var(--ds-spec);
}

#sec-investigation table tbody tr { transition: background 0.16s ease; }
#sec-investigation table tbody tr:hover { background: var(--ds-glass-2); }

#sec-investigation .investigation-btn {
  transition: transform 0.18s ease, border-color 0.18s ease;
}

#sec-investigation .investigation-btn:hover { transform: translateY(-1px); }

@media (prefers-reduced-motion: reduce) {
  #sec-sla .sla-kpi-card,
  #sec-sla .sla-btn-primary,
  #sec-investigation .investigation-btn { transition: none; }
  #sec-sla .sla-kpi-card:hover,
  #sec-sla .sla-btn-primary:hover,
  #sec-investigation .investigation-btn:hover { transform: none; }
}

@media (prefers-reduced-transparency: reduce) {
  #sec-sla .sla-kpi-card,
  #sec-settings .card,
  #sec-investigation .card {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: var(--ds-panel);
  }
}

/* ═══════════ СКЛАДСКАЯ ЛОГИСТИКА ═════════════════════════════════════ */
/* Плитки этого экрана носят те же классы kpi-card-unified, что и плитки
   дашборда, но строит их Vue, а не tile() из dashboard.js — поэтому классы
   материала (.ds-glass, .ds-lift) на них не попадают. Выдаём материал по
   классу, чтобы экран не отличался от уже переведённых.

   Селектор с идентификатором секции весит 1-1-0 и перебивает и scoped-стили
   компонента, и warehouse.css. */

#sec-warehouse-head .kpi-card-unified {
  background: var(--ds-glass);
  -webkit-backdrop-filter: blur(30px) saturate(190%);
  backdrop-filter: blur(30px) saturate(190%);
  border: 1px solid var(--ds-hair);
  border-radius: var(--ds-rad-in);
  box-shadow: var(--ds-sh), inset 0 1px 0 var(--ds-spec);
  transition:
    transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1),
    box-shadow 0.22s ease;
  will-change: transform;
}

#sec-warehouse-head .kpi-card-unified:hover {
  transform: translateY(-3px);
  box-shadow: var(--ds-sh-hi), inset 0 1px 0 var(--ds-spec);
}

/* Кегли — из шкалы. Подпись прописными, значение крупное. */
#sec-warehouse-head .kpi-card-title {
  font-size: var(--ds-f1);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ds-tx-3);
}

#sec-warehouse-head .kpi-card-value {
  font-size: var(--ds-f6);
  font-weight: 650;
  letter-spacing: -0.032em;
  line-height: 1;
  color: var(--ds-tx);
}

/* Состояние «нет данных» отличается от нуля: пунктир и приглушённое
   значение вместо крупного числа. */
#sec-warehouse-head .kpi-card-unified.is-nodata {
  border-style: dashed;
  border-color: var(--ds-hair);
  box-shadow: none;
}

#sec-warehouse-head .kpi-card-unified.is-nodata .kpi-card-value {
  font-size: var(--ds-f4);
  font-weight: 400;
  color: var(--ds-tx-3);
  letter-spacing: -0.01em;
}

/* Цветная кромка по состоянию — слева, а не заливкой всей плитки:
   залитая карточка спорит за внимание с числом внутри себя. */
#sec-warehouse-head .kpi-card-unified.is-green { box-shadow: var(--ds-sh), inset 3px 0 0 var(--ds-ok), inset 0 1px 0 var(--ds-spec); }
#sec-warehouse-head .kpi-card-unified.is-amber { box-shadow: var(--ds-sh), inset 3px 0 0 var(--ds-warn), inset 0 1px 0 var(--ds-spec); }
#sec-warehouse-head .kpi-card-unified.is-red   { box-shadow: var(--ds-sh), inset 3px 0 0 var(--ds-crit), inset 0 1px 0 var(--ds-spec); }

#sec-warehouse-head .kpi-card-unified.is-green:hover { box-shadow: var(--ds-sh-hi), inset 3px 0 0 var(--ds-ok), inset 0 1px 0 var(--ds-spec); }
#sec-warehouse-head .kpi-card-unified.is-amber:hover { box-shadow: var(--ds-sh-hi), inset 3px 0 0 var(--ds-warn), inset 0 1px 0 var(--ds-spec); }
#sec-warehouse-head .kpi-card-unified.is-red:hover   { box-shadow: var(--ds-sh-hi), inset 3px 0 0 var(--ds-crit), inset 0 1px 0 var(--ds-spec); }

/* Карточки очереди и строки таблиц — отклик на наведение, как везде. */
#sec-warehouse-head .wh-kpi-block,
#sec-warehouse-head .wh-queue-card {
  transition: transform 0.2s cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 0.2s ease;
}

#sec-warehouse-head .wh-kpi-block:hover,
#sec-warehouse-head .wh-queue-card:hover {
  transform: translateX(2px);
  box-shadow: var(--ds-sh-hi);
}

#sec-warehouse-head table tbody tr { transition: background 0.16s ease; }
#sec-warehouse-head table tbody tr:hover { background: var(--ds-glass-2); }

@media (prefers-reduced-motion: reduce) {
  #sec-warehouse-head .kpi-card-unified,
  #sec-warehouse-head .wh-kpi-block,
  #sec-warehouse-head .wh-queue-card { transition: none; }
  #sec-warehouse-head .kpi-card-unified:hover,
  #sec-warehouse-head .wh-kpi-block:hover,
  #sec-warehouse-head .wh-queue-card:hover { transform: none; }
}

@media (prefers-reduced-transparency: reduce) {
  #sec-warehouse-head .kpi-card-unified {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: var(--ds-panel);
  }
}

/* ═══════════ ВКЛАДКИ ЭКРАНА «АВТОПАРК И ТО» ══════════════════════════ */
/* Разметку групп проставляет static/js/fleet-tabs.js. Видимость решается
   здесь, а не в скрипте: при перерисовке Vue атрибуты переставляются
   заново, и состояние вкладки не теряется. */

.fleet-tabbar {
  display: flex;
  gap: 2px;
  flex-wrap: wrap;
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  border-radius: var(--ds-rad-sm);
  padding: 3px;
  margin-bottom: var(--ds-s4);
  width: fit-content;
  max-width: 100%;
}

.fleet-tab {
  font: inherit;
  font-size: var(--ds-f3);
  font-weight: 600;
  border: 0;
  background: transparent;
  color: var(--ds-tx-2);
  padding: calc(7px * var(--z)) calc(13px * var(--z));
  border-radius: calc(6px * var(--z));
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.18s ease, color 0.18s ease;
}

/* [FIX ВИЗ-16] Своя заливка наведения обязательна: без неё вкладку подхватывает
   глобальное `button:hover { background: var(--brand-fill-dark) }` из style.css —
   и тёмный текст вкладки оказывается на тёмно-красном (2.95:1 при норме 4.5:1).
   Раньше это не всплывало: проверка под курсором смотрит только первые 40 кнопок
   экрана, а вкладки автопарка идут дальше по разметке. */
.fleet-tab:hover {
  background: var(--ds-bg);
  color: var(--ds-tx);
}

/* Активная вкладка — тёмной заливкой, не фирменным красным: красный на
   этом экране принадлежит главной кнопке действия, а не навигации. */
.fleet-tab.active {
  background: var(--ds-tx);
  color: var(--ds-bg);
}

.fleet-tab:focus-visible {
  outline: 2px solid var(--ds-c-time);
  outline-offset: 2px;
}

/* Скрываем блоки, не относящиеся к выбранной вкладке. Группа «always»
   (плавающий помощник) видна всегда. Блок без разметки тоже остаётся
   видимым — чтобы правка шаблона не спрятала контент молча. */
/* Одно правило на вкладку: прячем всё, кроме её группы и «always».
   Через пару «скрыть всё + показать нужное» не получится — правило
   скрытия с :not() весит больше правила показа и побеждает независимо
   от порядка, из-за чего пустым оказывается любой раздел. */
#sec-fleet[data-fleet-tab="overview"] .fleet-tabs-host > [data-fleet-group]:not([data-fleet-group="overview"]):not([data-fleet-group="always"]),
#sec-fleet[data-fleet-tab="park"]     .fleet-tabs-host > [data-fleet-group]:not([data-fleet-group="park"]):not([data-fleet-group="always"]),
#sec-fleet[data-fleet-tab="repairs"]  .fleet-tabs-host > [data-fleet-group]:not([data-fleet-group="repairs"]):not([data-fleet-group="always"]),
#sec-fleet[data-fleet-tab="fuel"]     .fleet-tabs-host > [data-fleet-group]:not([data-fleet-group="fuel"]):not([data-fleet-group="always"]),
#sec-fleet[data-fleet-tab="expenses"] .fleet-tabs-host > [data-fleet-group]:not([data-fleet-group="expenses"]):not([data-fleet-group="always"]),
#sec-fleet[data-fleet-tab="forecast"] .fleet-tabs-host > [data-fleet-group]:not([data-fleet-group="forecast"]):not([data-fleet-group="always"]) {
  display: none;
}

/* ══════════════ КНОПКИ ВНУТРИ VUE-БАНДЛОВ ════════════════════════════ */
/* Стили этих кнопок лежат в scoped-CSS компонентов (селекторы вида
   .map-btn[data-v-7ec02dc7], вес 0-2-0). Перекрываем селектором с
   идентификатором секции — он весит 1-1-0 и выигрывает, поэтому
   пересобирать бандлы ради цвета не требуется.

   Правило: фирменный красный на экране остаётся ровно у одной кнопки —
   главного действия. У диспетчера это «Создать рейс». «Центр», «Обновить»,
   «Легенда», спутник и полноэкранный режим — вспомогательные, они не
   должны кричать громче неё. */

#sec-dispatcher .map-btn,
#sec-warehouse-head .map-btn,
#sec-fleet .map-btn,
#sec-investigation .map-btn {
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  color: var(--ds-tx-2);
  box-shadow: none;
  transition: transform 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

#sec-dispatcher .map-btn:hover,
#sec-warehouse-head .map-btn:hover,
#sec-fleet .map-btn:hover,
#sec-investigation .map-btn:hover {
  transform: translateY(-1px);
  border-color: var(--ds-tx-3);
  color: var(--ds-tx);
}

/* Кнопка закрытия панели легенды. Своего фона у неё нет — только утилиты
   Tailwind для цвета текста, а заливку она получает от глобального правила
   button в style.css. Закрытие панели не действие, требующее внимания. */
#sec-dispatcher button[class*="text-[var(--muted)]"] {
  background: transparent;
  border: 0;
  box-shadow: none;
  color: var(--ds-tx-3);
}

#sec-dispatcher button[class*="text-[var(--muted)]"]:hover {
  background: var(--ds-sunk);
  color: var(--ds-tx);
}

/* Заголовочный блок складского экрана был смещён к центру карточки, тогда
   как весь остальной интерфейс выровнен по левому краю — взгляд каждый раз
   перескакивал. Прижимаем к левому краю и снимаем возможное центрирование
   на любом из уровней вложенности. */
#sec-sklad1 .wh-header,
#sec-sklad2 .wh-header,
#sec-sklad1 .wh-header-main,
#sec-sklad2 .wh-header-main,
#sec-sklad1 .wh-title-group,
#sec-sklad2 .wh-title-group,
#sec-sklad1 .warehouse-terminal-container,
#sec-sklad2 .warehouse-terminal-container {
  justify-content: flex-start;
  align-items: flex-start;
  text-align: left;
  margin-left: 0;
  margin-right: 0;
}

/* [FIX] align-items:flex-start на .warehouse-terminal-container выше был
   нужен только для заголовка, но как побочный эффект убрал растяжение
   (stretch по умолчанию) у ВСЕХ прямых потомков контейнера — в том числе
   у блока KPI-карточек .wh-kpi-block. Итог: те же карточки
   (.kpi-card-unified в .wh-kgrid-primary/.wh-kgrid-secondary), что на
   экране "Начальник складской логистики" растягиваются на всю ширину
   (480/282px), на #sec-sklad1/#sec-sklad2 сжимались по контенту до
   382/224px — расхождение шириной между одинаковыми по вёрстке
   складскими экранами. Возвращаем растяжение только этому блоку, не
   трогая выравнивание заголовка. */
#sec-sklad1 .wh-kpi-block,
#sec-sklad2 .wh-kpi-block {
  align-self: stretch;
}

/* Левый внутренний отступ у .wh-header был 203px — из-за него весь
   заголовочный блок выглядел смещённым к центру карточки, хотя формально
   был выровнен по левому краю. Приводим к шкале отступов. */
#sec-sklad1 .wh-header,
#sec-sklad2 .wh-header {
  flex-wrap: wrap;
  gap: var(--ds-s3);
  padding-left: var(--ds-s4);
  padding-right: var(--ds-s4);
}

/* ── Складские экраны ──
   «Обновить» — вспомогательное действие, перечитать данные. Красной она
   быть не должна: на этих экранах главное действие — «Ручной учёт».
   «Сегодня» — тоже вспомогательная, сброс даты на текущую. */
#sec-sklad1 .wh-refresh-btn,
#sec-sklad2 .wh-refresh-btn,
#sec-sklad1 .wh-btn-today,
#sec-sklad2 .wh-btn-today,
#sec-warehouse-head .wh-refresh-btn,
#sec-warehouse-head .wh-btn-today {
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  color: var(--ds-tx-2);
  box-shadow: none;
  transition: transform 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

#sec-sklad1 .wh-refresh-btn:hover,
#sec-sklad2 .wh-refresh-btn:hover,
#sec-sklad1 .wh-btn-today:hover,
#sec-sklad2 .wh-btn-today:hover,
#sec-warehouse-head .wh-refresh-btn:hover,
#sec-warehouse-head .wh-btn-today:hover {
  transform: translateY(-1px);
  border-color: var(--ds-tx-3);
  color: var(--ds-tx);
}

/* Класс wh-action-btn носят и главная кнопка «Ручной учёт», и вторичные
   вроде «Посмотреть очередь рамп» в пустом состоянии. Красным заливаем
   только ту, что стоит в панели действий экрана; остальные нейтральны. */
#sec-sklad1 .wh-action-btn,
#sec-sklad2 .wh-action-btn {
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  color: var(--ds-tx-2);
  box-shadow: none;
}

#sec-sklad1 .wh-action-btn:hover,
#sec-sklad2 .wh-action-btn:hover {
  border-color: var(--ds-tx-3);
  color: var(--ds-tx);
}

#sec-sklad1 .wh-header .wh-action-btn,
#sec-sklad2 .wh-header .wh-action-btn,
#sec-sklad1 .wh-databar .wh-action-btn,
#sec-sklad2 .wh-databar .wh-action-btn {
  /* Заливка под белым текстом берётся из --brand-fill, а не из --ds-brand:
     последний в тёмных темах поднят до #FF4D54 ради читаемости его самого
     как текста, и белым по нему выходило 3.26:1. */
  background: var(--brand-fill);
  border-color: transparent;
  color: #fff;
  font-weight: 600;
  box-shadow: 0 2px 10px -3px var(--ds-brand);
}

/* Вкладки реестра складского экрана: активная — тёмной заливкой. */
#sec-sklad1 .sklad-tab-btn.active,
#sec-sklad2 .sklad-tab-btn.active {
  background: var(--ds-tx);
  border-color: var(--ds-tx);
  color: var(--ds-bg);
  font-weight: 600;
  box-shadow: none;
}

/* Активная вкладка реестра: тёмная заливка вместо фирменной — красный
   в этом месте спорил бы с главной кнопкой действия. */
#sec-sklad1 .wh-databar-btn.active,
#sec-sklad2 .wh-databar-btn.active,
#sec-warehouse-head .wh-databar-btn.active,
#sec-sklad1 .analytics-tab-btn.active,
#sec-sklad2 .analytics-tab-btn.active {
  background: var(--ds-tx);
  border-color: var(--ds-tx);
  color: var(--ds-bg);
  font-weight: 600;
  box-shadow: none;
}

/* Фильтр по статусу рейсов: выбранный отмечается тёмной заливкой, а не
   фирменным красным — иначе он спорит с кнопкой создания рейса. */
#sec-dispatcher .kpi-filter-chip {
  background: var(--ds-sunk);
  border: 1px solid var(--ds-hair);
  color: var(--ds-tx-2);
  box-shadow: none;
}

#sec-dispatcher .kpi-filter-chip.active {
  background: var(--ds-tx);
  border-color: var(--ds-tx);
  color: var(--ds-bg);
  font-weight: 600;
}

/* ════════════════════ KPI-ПЛИТКА ДАШБОРДА ════════════════════════════ */
/* Плитки собирает tile() в static/js/dashboard.js. Класс kpi-card-unified
   сохранён (на него завязаны настройки видимости виджетов), поэтому правила
   ниже адресуют его в паре с .ds-glass — так они перебивают старые из
   style.css и warehouse.css, не ломая экраны, которые ещё не переехали. */

.kpi-card-unified.ds-glass {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--ds-s2);
  padding: calc(11px * var(--z)) calc(12px * var(--z));
  min-height: calc(96px * var(--z));
}

/* Шапка плитки: иконка-чип, затем подпись. Раньше иконка стояла справа
   и растаскивала взгляд — теперь она якорь строки, как в скетче. */
.kpi-card-unified.ds-glass .kpi-card-head {
  display: flex;
  align-items: center;
  gap: calc(7px * var(--z));
  margin: 0;
}

/* Кегль задан здесь же: .kpi-card-title из style.css весит столько же
   (один класс) и подключается позже, поэтому класс .ds-f1 сам по себе
   проигрывает и подпись оставалась 13px вместо 8.5px. */
.kpi-card-unified.ds-glass .kpi-card-title {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--ds-tx-3);
  font-size: var(--ds-f1);
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  gap: calc(5px * var(--z));
}

/* Иконка-чип: размер и фон задаёт .ds-ico, здесь только снимаем старые
   правила .kpi-card-icon из style.css, где она была просто цветным svg. */
/* Фон здесь НЕ задаётся: его ставят категорийные классы .ds-ico--time и
   прочие. Раньше тут стоял background:transparent, и он их гасил — чип
   оставался бесцветным, а цвет категории не считывался. */
.kpi-card-unified.ds-glass .kpi-card-icon.ds-ico {
  margin: 0;
  padding: 0;
}

.kpi-card-unified.ds-glass .kpi-card-icon svg {
  width: calc(12.5px * var(--z));
  height: calc(12.5px * var(--z));
}

/* Размер задан здесь, а не только классом .ds-f6: у .kpi-card-value из
   style.css та же специфичность (один класс), а файл подключается позже —
   при равном весе он бы победил и вернул кегль 30px. */
.kpi-card-unified.ds-glass .kpi-card-value {
  color: var(--ds-tx);
  margin: 0;
  font-size: var(--ds-f6);
  font-weight: 650;
  letter-spacing: -0.032em;
  line-height: 1;
}

.kpi-card-unified.ds-glass .kpi-card-value.ds-value {
  font-size: var(--ds-f4);
  font-weight: 400;
  color: var(--ds-tx-3);
  letter-spacing: -0.01em;
}

.kpi-card-unified.ds-glass .kpi-card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(6px * var(--z));
  font-size: var(--ds-f2);
  color: var(--ds-tx-2);
  margin: 0;
}

.kpi-card-unified.ds-glass .kpi-card-footer .cov {
  min-width: 0;
  flex: 1 1 auto;
}

/* Значок «i» с формулой. Должен стоять на КАЖДОЙ плитке: сегодня у нижнего
   блока из ~12 плиток его нет ни у одной. */
.kpi-card-unified.ds-glass .kpi-info-icon {
  width: calc(13px * var(--z));
  height: calc(13px * var(--z));
  border-radius: 50%;
  border: 1px solid var(--ds-hair);
  color: var(--ds-tx-3);
  font-size: calc(8.5px * var(--z));
  line-height: calc(11px * var(--z));
  text-align: center;
  flex: none;
  cursor: help;
  transition: color 0.18s ease, border-color 0.18s ease;
}

.kpi-card-unified.ds-glass:hover .kpi-info-icon {
  color: var(--ds-c-time);
  border-color: var(--ds-c-time);
}

/* Цветная левая кромка по состоянию — вместо заливки всей карточки:
   залитая плитка конкурирует за внимание с числом внутри неё. */
.kpi-card-unified.ds-glass.is-green { box-shadow: var(--ds-sh), inset 3px 0 0 var(--ds-ok), inset 0 1px 0 var(--ds-spec); }
.kpi-card-unified.ds-glass.is-amber { box-shadow: var(--ds-sh), inset 3px 0 0 var(--ds-warn), inset 0 1px 0 var(--ds-spec); }
.kpi-card-unified.ds-glass.is-red   { box-shadow: var(--ds-sh), inset 3px 0 0 var(--ds-crit), inset 0 1px 0 var(--ds-spec); }
.kpi-card-unified.ds-glass.is-nodata { box-shadow: none; }

.kpi-card-unified.ds-glass.is-green:hover { box-shadow: var(--ds-sh-hi), inset 3px 0 0 var(--ds-ok), inset 0 1px 0 var(--ds-spec); }
.kpi-card-unified.ds-glass.is-amber:hover { box-shadow: var(--ds-sh-hi), inset 3px 0 0 var(--ds-warn), inset 0 1px 0 var(--ds-spec); }
.kpi-card-unified.ds-glass.is-red:hover   { box-shadow: var(--ds-sh-hi), inset 3px 0 0 var(--ds-crit), inset 0 1px 0 var(--ds-spec); }

/* ─────────────── ЗАПРЕТ ГОРИЗОНТАЛЬНОГО СКРОЛЛА ─────────────────────── */
/* Страница никогда не едет вбок. Широкое содержимое прокручивается внутри
   своего контейнера (.ds-table-wrap), а не двигает весь макет.
   Важно: это не маскировка через overflow-x:hidden на main — та прячет
   симптом и делает часть колонок недостижимой. */
.ds-scope { max-width: 100%; min-width: 0; }
.ds-scope > * { min-width: 0; }

/* ── Панель выгрузки пробега из Wialon (static/js/wialon-mileage.js) ────────
   Вставляется скриптом оболочки в начало вкладки «Топливо и TCO». */
#sec-fleet .wm-panel {
  padding: var(--ds-s3) var(--ds-s4);
  border-radius: var(--ds-rad-in);
  margin-bottom: var(--ds-s3);
}
#sec-fleet .wm-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--ds-s3);
}
#sec-fleet .wm-title {
  font-size: var(--ds-f3);
  font-weight: 600;
  color: var(--ds-tx);
  margin-right: var(--ds-s2);
}
#sec-fleet .wm-lbl {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--ds-f2);
  color: var(--ds-tx-2);
}
#sec-fleet .wm-lbl input[type="date"] {
  font-size: var(--ds-f2);
  padding: 4px 8px;
  border-radius: var(--ds-rad-sm);
  border: 1px solid var(--ds-hair);
  background: var(--ds-sunk);
  color: var(--ds-tx);
}
#sec-fleet .wm-btn {
  font-size: var(--ds-f2);
  font-weight: 600;
  padding: 6px 14px;
  border-radius: var(--ds-rad-sm);
  border: 1px solid var(--ds-hair-2);
  background: var(--ds-sunk);
  color: var(--ds-tx);
  cursor: pointer;
}
#sec-fleet .wm-btn:hover:not(:disabled) { background: var(--ds-glass-2); }
/* Выгрузка идёт минуты — заблокированная кнопка должна читаться как занятая,
   иначе пользователь решит, что нажатие не сработало, и уйдёт со вкладки. */
#sec-fleet .wm-btn:disabled { opacity: .55; cursor: progress; }
#sec-fleet .wm-status { font-size: var(--ds-f2); color: var(--ds-tx-2); }
#sec-fleet .wm-info {
  margin-top: 6px;
  font-size: var(--ds-f2);
  color: var(--ds-tx-3);
  font-variant-numeric: tabular-nums;
}

/* ── Панель пакетной загрузки ведомостей (static/js/fuel-batch.js) ──────── */
#sec-fleet .fb-panel {
  padding: var(--ds-s3) var(--ds-s4);
  border-radius: var(--ds-rad-in);
  margin-bottom: var(--ds-s3);
}
#sec-fleet .fb-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--ds-s3);
}
#sec-fleet .fb-title {
  font-size: var(--ds-f3);
  font-weight: 600;
  color: var(--ds-tx);
  margin-right: var(--ds-s2);
}
#sec-fleet .fb-lbl {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--ds-f2);
  color: var(--ds-tx-2);
}
#sec-fleet .fb-lbl input[type="month"] {
  font-size: var(--ds-f2);
  padding: 4px 8px;
  border-radius: var(--ds-rad-sm);
  border: 1px solid var(--ds-hair);
  background: var(--ds-sunk);
  color: var(--ds-tx);
}
#sec-fleet .fb-btn {
  font-size: var(--ds-f2);
  font-weight: 600;
  padding: 6px 14px;
  border-radius: var(--ds-rad-sm);
  border: 1px solid var(--ds-hair-2);
  background: var(--ds-sunk);
  color: var(--ds-tx);
  cursor: pointer;
}
#sec-fleet .fb-btn:hover:not(:disabled) { background: var(--ds-glass-2); }
#sec-fleet .fb-btn:disabled { opacity: .55; cursor: not-allowed; }
/* Загрузка идёт минутами — кнопка в работе должна читаться как занятая. */
#sec-fleet .fb-btn-go:disabled { cursor: progress; }
#sec-fleet .fb-hint {
  margin-top: 6px;
  font-size: var(--ds-f1);
  color: var(--ds-tx-3);
}
#sec-fleet .fb-progress {
  margin-top: 6px;
  font-size: var(--ds-f2);
  color: var(--ds-tx-2);
  font-variant-numeric: tabular-nums;
}
/* Журнал ограничен по высоте: при 70 файлах он иначе растягивает страницу
   на несколько экранов и прячет остальную вкладку. */
#sec-fleet .fb-log {
  margin-top: 6px;
  max-height: 190px;
  overflow-y: auto;
  font-size: var(--ds-f1);
  line-height: 1.5;
}
#sec-fleet .fb-line { color: var(--ds-tx-3); }
#sec-fleet .fb-line.fb-ok { color: var(--ds-ok); }
#sec-fleet .fb-line.fb-dubl { color: var(--ds-warn); }
#sec-fleet .fb-line.fb-err { color: var(--ds-crit); }

/* ── Вкладка «Виды топлива» в Настройках ────────────────────────────────── */
#secTipyTopliva .tt-hint {
  font-size: var(--ds-f2);
  color: var(--ds-tx-3);
  max-width: 70ch;
  margin-bottom: var(--ds-s3);
}
#secTipyTopliva .tt-form,
#secTipyTopliva .tt-massovo {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--ds-s3);
  margin-bottom: var(--ds-s4);
}
#secTipyTopliva .tt-massovo { display: block; }
#secTipyTopliva .tt-massovo label { margin-right: var(--ds-s3); }
#secTipyTopliva label {
  display: inline-flex;
  flex-direction: column;
  gap: 4px;
  font-size: var(--ds-f2);
  color: var(--ds-tx-2);
}
#secTipyTopliva label.tt-chk { flex-direction: row; align-items: center; gap: 6px; }
#secTipyTopliva .tt-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--ds-f2);
  margin-bottom: var(--ds-s4);
}
#secTipyTopliva .tt-table th {
  text-align: left;
  font-weight: 600;
  color: var(--ds-tx-2);
  border-bottom: 1px solid var(--ds-hair);
  padding: 6px 10px;
}
#secTipyTopliva .tt-table td {
  padding: 6px 10px;
  border-bottom: 1px solid var(--ds-hair);
  font-variant-numeric: tabular-nums;
}
/* Архивный вид остаётся в списке приглушённым: скрыть его совсем — значит
   потерять историю, по которой заведены старые машины. */
#secTipyTopliva .tt-table tr.tt-archived td { opacity: .5; }
#secTipyTopliva .tt-status { font-size: var(--ds-f2); color: var(--ds-tx-2); }

/* Акцент на экране один: массовый перевод меняет вид топлива у всего парка,
   добавление вида в справочник — рядовое действие. */
#secTipyTopliva .tt-form #tt_save {
  background: var(--ds-sunk);
  color: var(--ds-tx);
  border: 1px solid var(--ds-hair-2);
}
#secTipyTopliva .tt-form #tt_save:hover { background: var(--ds-glass-2); }

/* Неподтверждённая норма — та, что унаследована из умолчания схемы, а не
   названа человеком. Перерасход считается именно от неё, поэтому разница
   между «согласовано» и «досталось по наследству» должна быть видна. */
#secTipyTopliva .tt-table tr.nr-ne-podtverzhdena td { color: var(--ds-warn); }
#secTipyTopliva .tt-razdel {
  margin-top: var(--ds-s5);
  padding-top: var(--ds-s4);
  border-top: 1px solid var(--ds-hair);
}

/* «Сохранить умолчание» — рядовое сохранение одного числа. Акцент оставлен
   двум массовым операциям ниже: они меняют данные у полусотни машин. */
#secTipyTopliva #nr_default_save {
  background: var(--ds-sunk);
  color: var(--ds-tx);
  border: 1px solid var(--ds-hair-2);
}
#secTipyTopliva #nr_default_save:hover { background: var(--ds-glass-2); }

/* ── Совместимость: имена токенов из старых таблиц стилей ──────────────────
   Пункт D-2 плана. Эти имена используются в style.css, sla.css и в собранных
   бандлах static/dist/, но нигде не объявлены. Пустой токен не даёт ошибки:
   правило просто отбрасывается — скругление не применяется, граница становится
   невидимой, hover перестаёт работать. Найти это на глаз нельзя, харнесс
   приёмки нашёл сразу.

   Бандлы по плану не пересобираем (собранное рассинхронизировано с исходниками),
   поэтому имена сопоставляются здесь. Заодно видно, что чему соответствует —
   при будущем переносе стилей в дизайн-систему это готовая таблица перехода. */
:root {
  --accent: var(--ds-brand);
  --accent-ui-subtle: var(--ds-sunk);

  --border-subtle: var(--ds-hair);
  --border-strong: var(--ds-hair-2);

  --bg: var(--ds-bg);
  --paper-soft: var(--ds-panel);
  --surface-hover: var(--ds-glass-2);

  --ink-main: var(--ds-tx);

  --status-red-border: var(--ds-crit);
  --status-green-border: var(--ds-ok);
  --status-amber-border: var(--ds-warn);
}

/* ── Контраст цветных плашек складского экрана (D-28) ──────────────────────
   Голубой #06B6D4 давал 2.43:1 на плашке очереди и 2.23:1 в заголовке колонки,
   фиолетовый #8B5CF6 — 3.89:1 на метке склада. Норма для мелкого текста 4.5:1.

   Оттенок сохранён, изменена только светлота: колонки очереди остаются
   различимыми по цвету, но подписи читаются.

   Значения взяты с запасом (5.0:1 на белом): плашки имеют слабую
   заливку собственным цветом, и расчёт впритык на чистом белом
   давал на реальном фоне 4.27-4.32 вместо нужных 4.5.

   Правится отсюда, а не в исходнике компонента: стили лежат в собранном
   бандле static/dist/, который по плану не пересобираем. Селектор по id
   секции перекрывает класс бандла по специфичности.

   Первая попытка целилась в инлайновый стиль ([style*="6, 182, 212"]) и не
   работала: цвет задаётся классом. Проверка в браузере это показала сразу. */
#sec-warehouse-head .wh-q-pill.wh-q-site,
#sec-warehouse-head .wh-q-head-site .wh-head-title {
  color: #03798E;
}

#sec-warehouse-head .wh-site-tag-purple {
  color: #7E53DF;
}

/* Те же две метки в тёмных темах: подобранные под белый фон #03798E и
   #7E53DF на антраците дают 3.65:1 и 3.71:1. Оттенок сохранён, светлота
   поднята до прохождения нормы на --paper тёмной темы. */
:root[data-theme="dark"] #sec-warehouse-head .wh-q-pill.wh-q-site,
:root[data-theme="dark"] #sec-warehouse-head .wh-q-head-site .wh-head-title,
:root[data-theme="graphite"] #sec-warehouse-head .wh-q-pill.wh-q-site,
:root[data-theme="graphite"] #sec-warehouse-head .wh-q-head-site .wh-head-title,
:root[data-theme="corporate"] #sec-warehouse-head .wh-q-pill.wh-q-site,
:root[data-theme="corporate"] #sec-warehouse-head .wh-q-head-site .wh-head-title {
  color: #4FC3D9;
}

:root[data-theme="dark"] #sec-warehouse-head .wh-site-tag-purple,
:root[data-theme="graphite"] #sec-warehouse-head .wh-site-tag-purple,
:root[data-theme="corporate"] #sec-warehouse-head .wh-site-tag-purple {
  color: #B79BF0;
}

/* Перекрытие утилит Tailwind отсюда убрано.

   Оно появилось, когда бандлы не пересобирались и правило !important было
   единственным способом дотянуться до их размеров. Теперь шкала задана в
   самом Tailwind через @theme в frontend/src/shared/style.css, и два
   источника правды расходились: здесь text-xs равнялся 10px, в @theme —
   11.5px, а побеждал !important. */

/* Кнопки масштаба карты: 22px мимо шкалы. Уменьшать сильно нельзя — по ним
   попадают пальцем, поэтому берём верхнюю ступень. */
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
  font-size: var(--ds-f6) !important;
}

/* ── Подписи меток на карте (D-12) ─────────────────────────────────────────
   Название точки длиннее плашки и обрезалось без всякого указания:
   «Пункт загрузки обратки (Север, Самарканд)» превращалось в огрызок, и
   понять, что обрезано, было нельзя. Многоточие показывает, что текст
   продолжается, а предельная ширина не даёт плашке закрыть пол-карты. */
.wh-marker-badge {
  max-width: calc(180px * var(--z));
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Иконка внутри строки текста (D-15) ────────────────────────────────────
   Заменяет эмодзи в подписях кнопок и заголовках. Размер задан в единицах
   шрифта, а не в пикселях: иконка растёт и уменьшается вместе с текстом,
   рядом с которым стоит, и не требует отдельной правки при смене ступени
   типографической шкалы.

   currentColor — чтобы иконка перекрашивалась вместе с текстом: в кнопке с
   красной подписью она красная, в приглушённой строке приглушённая. Эмодзи
   так не умеет, он всегда одного цвета и зависит от шрифта системы. */
.ds-ico-inline {
  width: 1.15em;
  height: 1.15em;
  vertical-align: -0.18em;
  flex: none;
  color: currentColor;
  /* Обводка задаётся в символе спрайта; здесь только размер и цвет. */
}

/* ── Подсказка показателя: сброс наследованных прописных ───────────────────
   Значок ⓘ находится внутри подписи карточки, а у неё text-transform:
   uppercase — свойство наследуемое, поэтому всплывающая подсказка получала
   прописные вместе с ним. Определение показателя — это связное предложение на
   несколько строк, и капслоком оно читается тяжело: глаз теряет границы слов,
   потому что исчезают выносные элементы букв.

   Прописные оставлены только служебным подписям «Норматив DEYA» и «Единица
   измерения» — они короткие и работают как заголовки строк. */
[class*="kpi-tooltip"] {
  text-transform: none;
  letter-spacing: normal;
}

.kpi-tooltip-unit > span:first-child,
.kpi-tooltip-target > span:first-child {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: var(--ds-f1);
}


/* Размеры шрифта из чужих таблиц стилей.

   Leaflet задаёт .leaflet-container { font-size: var(--ds-f3) } и этот размер
   наследуют все подписи маркеров и кнопки управления картой. Своего 12px в
   проекте не осталось ни одного, а приёмка показывала его на двух экранах —
   источник был именно здесь. */
/* Селектор с body намеренно: leaflet.css подключён ПОСЛЕ этого файла, и при
   равной силе побеждал бы он. Поднимать порядок подключения рискованнее —
   тогда наши правила начнут перекрывать чужие в других местах. */
body .leaflet-container,
body .leaflet-container .leaflet-control,
body .leaflet-popup-content {
  font-size: var(--ds-f3);
}

/* ── Экран водителя (P4-9) ────────────────────────────────────────────────
   Единственный экран, который заведомо открывают с телефона в кабине. Размеры
   кнопок здесь больше общих: 48px против 36px в системе — это не прихоть, а
   нижняя граница попадания пальцем, и на 390px именно по ним и жмут.

   Один столбец на любой ширине: на десктопе экран смотрит диспетчер через
   «вид роли», и растягивать карточки рейса на 1920px незачем — читать их
   всё равно сверху вниз. */
.drv-root {
  max-width: 640px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.drv-msg {
  padding: 10px 12px;
  border-radius: 10px;
  font-size: var(--ds-f3);
  line-height: 1.4;
}
.drv-msg--ok {
  background: var(--status-green-bg);
  color: var(--status-green);
  border: 1px solid var(--status-green);
}
.drv-msg--warn {
  background: var(--status-amber-bg);
  color: var(--status-amber);
  border: 1px solid var(--status-amber);
}
.drv-msg--error {
  background: var(--status-red-bg);
  color: var(--status-red);
  border: 1px solid var(--status-red);
}

.drv-shapka {
  padding: 12px 14px;
  border-radius: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
}
.drv-fio {
  font-size: var(--ds-f5);
  font-weight: 700;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 8px;
}
.drv-pod {
  font-size: var(--ds-f3);
  color: var(--ink-soft);
  margin-top: 2px;
}

.drv-telo {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.drv-pusto {
  padding: 18px 14px;
  border-radius: 14px;
  background: var(--surface);
  border: 1px dashed var(--border);
  color: var(--ink-soft);
  font-size: var(--ds-f3);
  line-height: 1.5;
}

.drv-reis {
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.drv-reis-shapka {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.drv-reis-nomer {
  font-size: var(--ds-f4);
  font-weight: 700;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 8px;
}
.drv-reis-data {
  font-size: var(--ds-f3);
  color: var(--ink-soft);
}

.drv-marshrut {
  font-size: var(--ds-f3);
  color: var(--ink);
  /* Названия точек длинные, а экран узкий: переносим по словам, а не режем
     многоточием — водителю нужно название целиком, чтобы не уехать не туда. */
  overflow-wrap: anywhere;
  line-height: 1.5;
}
.drv-strelka { color: var(--ink-soft); }

.drv-etap {
  border: 1px solid var(--border);
  border-left: 3px solid var(--status-gray);
  border-radius: 11px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--paper);
}
.drv-etap-imya {
  font-size: var(--ds-f3);
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.drv-etap-fakty {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  font-size: var(--ds-f3);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.drv-etap-fakty b { color: var(--ink); }

.drv-knopki {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.drv-knopka {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  padding: 0 16px;
  border-radius: 12px;
  border: none;
  cursor: pointer;
  font-size: var(--ds-f4);
  font-weight: 700;
  background: var(--brand-fill);
  color: #fff;
  width: 100%;
}
.drv-knopka:disabled {
  opacity: 0.6;
  cursor: default;
}
.drv-knopka:focus-visible {
  outline: 3px solid var(--focus-ring-ui);
  outline-offset: 2px;
}
/* Убытие — второе действие на этапе, и оно не должно спорить по весу с
   прибытием: заливка снимается, остаётся контур. */
.drv-knopka--vtor {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--border);
}
.drv-knopka--foto {
  background: var(--surface-sunken);
  color: var(--ink);
  border: 1px dashed var(--border);
  position: relative;
}

/* Поле выбора файла скрыто визуально, но остаётся в потоке и доступно с
   клавиатуры: display:none выключил бы его и для программ чтения с экрана. */
.drv-file {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.drv-foto {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.drv-foto-spisok {
  font-size: var(--ds-f2);
  color: var(--muted);
}

/* ── Шапка на телефоне ────────────────────────────────────────────────────
   Правая группа шапки не помещалась в 390px и выдавливала страницу вбок на
   26px: подпись «Переобновить данные» 91px, ФИО оператора 136px, «Выйти» 66px
   плюс три кнопки-иконки. На десктопе всё это уместно, на телефоне — нет.

   ФИО скрывается, а не сокращается: оно уже показано в подвале боковой панели,
   и второй раз в шапке телефона ему места нет. Подпись кнопки обновления
   убирается, остаётся сама пиктограмма с доступным именем в aria-label. */
@media (max-width: 480px) {
  header > div {
    flex-wrap: wrap;
    min-width: 0;
  }

  #whoami {
    display: none;
  }

  #resyncBtn span {
    display: none;
  }

  #logoutBtn {
    margin-left: 0;
  }

  /* Переключатель роли — инструмент администратора, в кабине он не нужен и
     занимает половину ширины. */
  #roleSwitcherContainer {
    display: none !important;
  }
}

/* ── Нормативы и правила (P2-10) ──────────────────────────────────────────
   Экран, где операционный директор меняет числа, по которым система судит о
   работе. Плотность важнее красоты: нормативов двадцать, и листать их с
   воздухом между строками неудобно. */
.pravila-gruppa {
  margin-bottom: 18px;
}

/* Кнопка-обёртка вокруг бейджа: сама она невидима, показывает бейдж.
   В style.css есть глобальные правила button и button:hover, которые
   закрашивают ЛЮБУЮ кнопку фирменным красным и делают текст белым. Для
   кнопки-обёртки это означало, что при наведении зелёный бейдж «100»
   превращался в красную плашку с белыми цифрами: оценка «отлично»
   выглядела аварией ровно в тот момент, когда на неё наводят мышь, чтобы
   прочитать. Класс объявлен здесь, а не в Tailwind-утилитах бандла:
   у глобального правила по тегу тот же вес, и побеждает подключённый позже.

   !important нужен по той же причине: у button:hover вес выше, чем у
   одиночного класса, и без него правило не применится. */
.btn-driving-quality,
.btn-driving-quality:hover,
.btn-driving-quality:focus,
.btn-driving-quality:active {
  background: transparent !important;
  background-image: none !important;
  color: inherit !important;
  border: 0;
  padding: 0;
  box-shadow: none;
}

/* ── Регламент ТО: машина и её виды обслуживания ──
   Список на полсотни машин: развёрнутыми держим только те, с которыми
   работают, остальное — одна строка на машину. */
.reglament-poisk { margin-bottom: 12px; }
.reglament-poisk input { width: 100%; max-width: 420px; }

.reglament-avto {
  border: 1px solid var(--border);
  border-radius: 10px;
  margin-bottom: 8px;
  background: var(--surface);
}

.reglament-avto > summary {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
  padding: 10px 12px;
  cursor: pointer;
  list-style: none;
}

.reglament-avto > summary::-webkit-details-marker { display: none; }

.reglament-gosnomer {
  font-family: var(--font-data, monospace);
  font-weight: 700;
  font-size: var(--ds-f4);
  color: var(--ink);
}

.reglament-marka { font-size: var(--ds-f3); color: var(--ink-soft); }

.reglament-odo {
  font-size: var(--ds-f2);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.reglament-blizhayshee {
  font-size: var(--ds-f2);
  color: var(--ink-soft);
  margin-left: auto;
}

/* Признак «свой регламент» — единственная метка, ради которой список и
   листают: она отвечает на вопрос «эту машину уже развели или она идёт по
   модели». */
.reglament-priznak {
  font-size: var(--ds-f1);
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 20px;
  background: var(--accent-ui-subtle);
  color: var(--accent-ui);
}

.reglament-telo { padding: 0 12px 12px; }

.reglament-vid {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 8px;
}

.reglament-vid-shapka {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 6px;
}

.reglament-kod {
  font-family: var(--font-data, monospace);
  font-weight: 700;
  font-size: var(--ds-f2);
  color: var(--ink);
}

.reglament-istochnik {
  font-size: var(--ds-f1);
  color: var(--muted);
  padding: 2px 8px;
  border-radius: 20px;
  border: 1px solid var(--border);
}

.reglament-istochnik.svoy {
  color: var(--accent-ui);
  border-color: var(--accent-ui);
}

.reglament-vernut, .reglament-istoriya {
  font-size: var(--ds-f1);
  padding: 2px 9px;
  margin-left: auto;
}

.reglament-istoriya { margin-left: 0; }

.reglament-vid .pravilo {
  grid-template-columns: minmax(150px, 220px) minmax(0, 1fr);
}

.reglament-vid .pravilo:last-of-type { border-bottom: 0; }
.reglament-vid .pravilo-upravlenie { width: 100%; }

.reglament-vid .pravilo-pole {
  width: 100%;
  font-variant-numeric: tabular-nums;
}

.reglament-vid textarea.pravilo-pole {
  min-height: 52px;
  resize: vertical;
  font-variant-numeric: normal;
}

.reglament-dobavit { font-size: var(--ds-f2); }

/* Пробег последнего ТО — отдельным блоком: он относится к машине, а не к её
   регламенту, и сохраняется другим запросом. */
.reglament-posledneye {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
}

.reglament-posledneye-podpis {
  font-size: var(--ds-f2);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 4px;
}

.reglament-posledneye-ryad {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.reglament-posledneye-ryad .pravilo-pole {
  flex: none;
  width: 150px;
}

.reglament-net-dannyh {
  font-size: var(--ds-f2);
  /* [FIX FE-15] Раньше здесь стоял --ds-warn с запасным #92400e: запасное
     значение и было выбрано ради контраста, но токен его перебивал, и текст
     получался янтарным (#D97706) — 3.19:1 на белом. Теперь текстовый токен. */
  color: var(--ds-warn-text, #92400e);
}

.reglament-sleduyushchee {
  font-size: var(--ds-f2);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

.reglament-zhurnal {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: var(--ds-f1);
  color: var(--ink-soft);
  display: grid;
  gap: 3px;
  overflow-wrap: anywhere;
}

/* ── Карточка норматива регламента SLA ──
   Значения здесь текстовые и длинные («Допустимое опоздание к дилеру:
   ≤ 15 минут»), а не числа в 140 пикселей, как у остальных нормативов,
   поэтому поле растягивается на всю доступную ширину. */
.sla-normativ-karta {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 10px;
  background: var(--surface);
}

.sla-normativ-shapka {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}

.sla-normativ-kod {
  font-family: var(--font-data, monospace);
  font-size: var(--ds-f2);
  font-weight: 700;
  color: var(--accent-ui);
  background: var(--accent-ui-subtle);
  padding: 2px 8px;
  border-radius: 6px;
  flex: none;
}

.sla-normativ-nazvanie {
  font-size: var(--ds-f4);
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}

/* Формула показана, но не редактируется: она описывает то, что считает код. */
.sla-normativ-formula {
  font-family: var(--font-data, monospace);
  font-size: var(--ds-f2);
  color: var(--ink-soft);
  background: var(--surface-sunken);
  border: 1px dashed var(--border);
  border-radius: 6px;
  padding: 5px 9px;
  margin-bottom: 8px;
  overflow-wrap: anywhere;
}

.sla-normativ-karta .pravilo {
  grid-template-columns: minmax(150px, 200px) minmax(0, 1fr);
}

.sla-normativ-karta .pravilo:last-of-type { border-bottom: 0; }

.sla-normativ-karta .pravilo-upravlenie { width: 100%; }

.sla-normativ-karta .pravilo-pole {
  width: 100%;
  font-variant-numeric: normal;
}

.sla-normativ-istoriya {
  font-size: var(--ds-f2);
  padding: 3px 10px;
  margin-top: 8px;
}

.sla-normativ-zhurnal {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: var(--ds-f2);
  color: var(--ink-soft);
  display: grid;
  gap: 3px;
  overflow-wrap: anywhere;
}

.pravila-gruppa h3 {
  margin: 0 0 8px;
  font-size: var(--ds-f4);
  font-weight: 700;
  color: var(--ink);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}

.pravilo {
  display: grid;
  grid-template-columns: minmax(180px, 1fr) auto;
  grid-template-areas:
    "podpis upravlenie"
    "opisanie opisanie"
    "zhurnal zhurnal";
  gap: 4px 12px;
  align-items: center;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}

.pravilo-podpis {
  grid-area: podpis;
  font-size: var(--ds-f3);
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.pravilo-upravlenie {
  grid-area: upravlenie;
  display: flex;
  align-items: center;
  gap: 8px;
}

.pravilo-pole {
  width: 140px;
  font-variant-numeric: tabular-nums;
}

.pravilo-pole[type="checkbox"] {
  width: auto;
}

.pravilo-edinica {
  font-size: var(--ds-f2);
  color: var(--muted);
  min-width: 70px;
}

.pravilo-istoriya {
  font-size: var(--ds-f2);
  padding: 3px 10px;
}

/* Описание объясняет, на что влияет число. Без него правка норматива —
   гадание: по названию «Допуск задержки: критично» не видно, что от него
   зависит красный светофор на четырёх экранах. */
.pravilo-opisanie {
  grid-area: opisanie;
  font-size: var(--ds-f2);
  color: var(--ink-soft);
  line-height: 1.45;
}

.pravilo-zhurnal {
  grid-area: zhurnal;
  margin-top: 4px;
  padding: 8px 10px;
  border-radius: 8px;
  background: var(--surface-sunken);
  font-size: var(--ds-f2);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

/* Полоса режима просмотра роли (P3-7).

   Стоит поверх всего и намеренно заметна: администратор в этом режиме видит
   чужое рабочее место, и забыть об этом легко — а дальше он решит, что у него
   пропали права. */
.prosmotr-polosa {
  position: sticky;
  top: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 8px 16px;
  background: var(--status-amber-bg);
  color: var(--status-amber);
  border-bottom: 1px solid var(--status-amber);
  font-size: var(--ds-f3);
  font-weight: 600;
  text-align: center;
}

.prosmotr-polosa button {
  background: var(--status-amber);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 4px 12px;
  font-size: var(--ds-f3);
  font-weight: 700;
  cursor: pointer;
}


/* Нормативы плитками.

   Раньше каждый параметр занимал строку во всю ширину экрана: подпись слева,
   поле ввода справа, между ними полоса пустоты. Двадцать два норматива
   превращались в длинную ленту, по которой приходилось прокручивать, чтобы
   найти один допуск.

   Ширина плитки 300 px — минимум, при котором помещается поле на четыре-пять
   цифр с единицей измерения и кнопкой истории. */
.pravila-setka {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 10px;
  align-items: start;
}

.pravila-setka .pravilo {
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "podpis podpis"
    "upravlenie upravlenie"
    "opisanie opisanie"
    "zhurnal zhurnal";
  gap: 6px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 8px);
  background: var(--surface);
  align-items: start;
  min-height: 0;
}

/* Поле занимает ширину плитки: фиксированные 140 px оставляли справа дыру,
   ради которой плитки и затевались. */
.pravila-setka .pravilo-upravlenie {
  width: 100%;
}

.pravila-setka .pravilo-pole {
  width: 100%;
  min-width: 0;
}

.pravila-setka .pravilo-pole[type="checkbox"] {
  width: auto;
}

.pravila-setka .pravilo-edinica {
  min-width: 0;
  /* [FIX FE-15] Было `white-space: nowrap` без многоточия: в узкой колонке
     подпись единицы («мин») обрезалась без всякого признака обрезки — приёмка
     нашла три таких места. Пусть переносится: подпись короткая. */
  overflow-wrap: anywhere;
}

/* Описание — мелким и в три строки с обрезкой: оно объясняет смысл, но не
   должно растягивать плитку вдвое против соседней. */
.pravila-setka .pravilo-opisanie {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
