/* TE-5 design system — Путевые листы Трансэнерго.
   Извлечено из дизайн-прототипов TE-5 (*.dc.html). Шрифты — системный стек
   (CSP блокирует внешние CDN; IBM Plex заменён метрически близкими). */

/* 🛑 Числа рядом с токенами — не украшение: их пересчитывает и пинит
   `tests/app/test_console_contrast_gate.py`. Правишь цвет — прогони гейт, он
   считает отношения к КАЖДОЙ поверхности, на которой цвет лежит. */

/* 🛑 `hidden` обязан прятать ЧТО УГОДНО, и это правило корневое, а не ещё одна заплатка.
   Браузерное `[hidden] { display: none }` весит столько же, сколько класс, и проигрывает
   ему порядком каскада (UA-стили объявлены раньше авторских). Поэтому `node.hidden = true`
   на любом `.te5-*` с собственным `display` не прячет ничего. Класс лечили ТОЧЕЧНО трижды
   (`.te5-check`, `.te5-mobile-menu`, `.te5-viewas__menu`) — и он возвращался на следующем
   компоненте: 02.09.2026 кнопка «Поменять местами» в карточке смены показывалась сразу,
   до отказа «водитель занят», предлагая обмен там, где меняться не с кем. `!important`
   здесь не грубость, а единственный способ победить каскад, не перечисляя классы:
   перечисление у́же предмета по построению — следующий компонент в него не попадёт.
   Пин — `tests/app/test_console_ui_kit.py::test_hidden_attribute_beats_every_component_display`. */
[hidden] { display: none !important; }

:root {
  --te5-bg: #ecebe7;                 /* тёплая нейтраль, общая с экраном водителя */
  --te5-text: #1a1e26;
  --te5-text-2: #3f4855;             /* выровнено: ступени были 2.40 и 1.30, стали 1.80 и 1.72 */
  --te5-muted: #636b78;              /* было #8b94a3 — 2.68 на полотне, ниже порога 4.5 */
  --te5-primary: #1d63b5;
  /* 🛑 Цвет надписи НА основном фоне — пара к нему. Пока он писался литералом
     `#fff` по месту, каждое новое место с синим фоном повторяло ошибку: в тёмной
     теме `--te5-primary` СВЕТЛЫЙ, и белое ложилось на светло-голубое. Замер
     24.08.2026 на переключателе «Списком | На карте»: контраст 1.95 при норме 4.5. */
  --te5-on-primary: #ffffff;
  --te5-primary-hover: #17539a;
  --te5-primary-bg: #e8f0fa;
  --te5-primary-ln: #b9d2ee;
  --te5-card: #fffefb;
  /* Подсветка совпадений поиска (TE-307). */
  --te5-mark-bg: #DBEAFE;
  --te5-surface: #fffefb;
  --te5-surface-raised: #ffffff;
  --te5-border: #d6d5cf;
  --te5-border-2: #e3e2dc;
  --te5-line: #d6d5cf;
  --te5-row-ln: #eeede7;
  --te5-row-hover: #f6f5f0;
  --te5-hover-bg: #f4f3ee;
  --te5-input-ln: #7e8695;           /* было #c8cdd6 — 1.4, а это «UI component»: порог 3.0 */
  --te5-ok: #177a43;                 /* было #1c8a4d — 3.84 на полотне */
  --te5-ok-bg: #e6f4ec;
  --te5-ok-ln: #b9e0c9;
  --te5-warn: #8a5f0c;               /* было #9a6a0e — 4.14 на полотне */
  --te5-warn-bg: #fbf2db;
  --te5-warn-ln: #ecd8a3;
  --te5-bad: #c0392f;
  --te5-bad-bg: #fae9e7;
  --te5-bad-ln: #eec3bd;
  --te5-open: #5b6472;
  /* Тоны значков набора (`TE5.ICON_TONES`, класс `te5-icon--tone-*`): цвет по смыслу, как у
     прежних эмодзи. Порог — 3.0 к карточке и холсту (WCAG 1.4.11, это графика, не текст);
     гейт `test_console_icons.py::test_icon_tones_read_on_every_surface`. С 28.09 вечера
     (сплошная заливка силуэтов) тона ярче текстовых на ступень — j по кадру светлой темы:
     «чё они такие тёмные»; порог 3.0 к холсту, карточке и чипу #dde4ee держится. */
  --te5-ico-blue: #2a72d4;
  --te5-ico-green: #1e8f50;
  --te5-ico-amber: #c46a0f;
  --te5-ico-red: #d1463a;
  --te5-ico-violet: #7a5fd6;
  --te5-ico-teal: #128a80;
  --te5-ico-slate: #687384;
  /* Те же тоны на СИНЕЙ или ЗЕЛЁНОЙ заливке (чип плитки водителя, кнопка подтверждения):
     светлые пастели, не зависят от темы — заливка в обеих темах насыщенная. Синий и серый
     на заливке не нужны — там значок остаётся белым (`currentColor`). */
  --te5-ico-green-fill: #7ee8a2;
  --te5-ico-amber-fill: #ffd166;
  --te5-ico-red-fill: #ffc1ba;
  --te5-ico-violet-fill: #d6c8ff;
  --te5-ico-teal-fill: #7ff0dc;
  /* Кнопка темы — вариант B прототипа (j 28.09.2026): подложка цветом показанного значка,
     без рамки. Днём кнопка показывает луну (лиловая подложка), ночью солнце (янтарная) —
     токен один, значение по теме. `-strong` — наведение и нажатие. Контраст значка к
     подложке пинит `test_console_icons.py::test_the_theme_button_tint_carries_its_icon`. */
  --te5-toggle-bg: #ece8fb;
  --te5-toggle-bg-strong: #dfd8f8;
  --te5-open-bg: #eceef2;
  --te5-open-ln: #d4d9e0;
  --te5-success: var(--te5-ok);
  --te5-success-bg: var(--te5-ok-bg);
  --te5-success-ln: var(--te5-ok-ln);
  --te5-warning: var(--te5-warn);
  --te5-warning-bg: var(--te5-warn-bg);
  --te5-warning-ln: var(--te5-warn-ln);
  --te5-danger: var(--te5-bad);
  --te5-danger-bg: var(--te5-bad-bg);
  --te5-danger-ln: var(--te5-bad-ln);
  --te5-info: var(--te5-primary);
  --te5-info-bg: var(--te5-primary-bg);
  --te5-info-ln: var(--te5-primary-ln);
  --te5-neutral: var(--te5-open);
  --te5-neutral-bg: var(--te5-open-bg);
  --te5-neutral-ln: var(--te5-open-ln);
  --te5-toast-bg: #232936;      /* тёмная плашка на светлом полотне — 12.2 */
  --te5-shadow-sm: 0 1px 4px rgba(20, 28, 42, .10);
  --te5-shadow: 0 6px 24px rgba(20, 28, 42, .12);
  --te5-shadow-md: 0 6px 24px rgba(20, 28, 42, .12);
  --te5-shadow-float: 0 10px 32px rgba(20, 28, 42, .20);
  /* Шкала интервалов между управляющими элементами. Заведена по замечанию 29.08.2026
     «кнопки приплюснуты, задай расстояние в одном месте»: до неё каждый ряд действий
     держал своё число, и они разъезжались молча. Правишь ряд кнопок — бери токен,
     а не литерал. Значения не цветовые, поэтому в тёмных ветках не переопределяются. */
  --te5-gap-tight: 8px;
  --te5-gap-controls: 12px;
  --te5-gap-group: 20px;
  --te5-radius-control: 6px;
  --te5-radius-card: 8px;
  --te5-radius-panel: 10px;
  --te5-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --te5-mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  /* 🛑 `light dark`, а не `light`. Одно слово здесь — это разрешение системе красить
     нас САМОЙ: браузер читает `light` как «сайт умеет только светлое», видит систему в
     тёмном режиме и включает собственное принудительное затемнение поверх нашей светлой
     темы, тогда как выверенная тёмная простаивает. Замер кадра входа с телефона
     водителя 09.08.2026: полотно #1e1c18 вместо #ecebe7, «Войти» с насыщенностью 100 %,
     карточка от полотна отличается на 1.03 (у нас 1.63) — то есть цвета не наши.
     Тёмные ветки ниже остаются `dark`: там объявление про элементы браузера. */
  color-scheme: light dark;
}

/* 🛑 ТЕ ЖЕ алиасы ещё раз, на `body.te5` — и это не дубль, а единственный способ
   довезти их до водителя в СВЕТЛОЙ теме.

   Семантические имена выше — АЛИАСЫ (`--te5-success: var(--te5-ok)`), а `var()`
   в алиасе резолвится ТАМ, ГДЕ АЛИАС ОБЪЯВЛЕН. Блок выше объявлен на `:root`, то
   есть на `html`. `driver.css` перекрывает старые токены на своём
   `body.te5-driver-redesign`, но про это перекрытие `html` ничего не знает —
   поэтому к водителю `--te5-success` приходил унаследованным сверху, с КОНСОЛЬНЫМ
   значением, и `.te5-banner--*` красились палитрой диспетчерской (замер 31.08.2026:
   `danger` `#c0392f` вместо водительского `#d94444`, `info` `#1d63b5` вместо
   `#075cff`, рамка `chip--success` консольная).

   Тёмная тема не страдала СЛУЧАЙНО: её блоки ниже перечисляют ещё и `body.te5`,
   поэтому там алиас пересчитывается на том же элементе, где `driver.css` кладёт
   своё значение. Здесь дописываем недостающую половину.

   Регрессию внёс `f0162a47` — коммит, заведший семантический слой; до него правила
   ссылались на старые имена напрямую, и цвет был водительским в обеих темах.

   🛑 Разворот направления (`--te5-ok := var(--te5-success)`) дефект НЕ лечит:
   перекрытие всё равно на body, а чтение на html. Замерено инъекцией — тот же
   результат побайтово.

   Консоли этот блок ничего не меняет: у неё перекрытия старых токенов нет, значит
   алиас берёт те же значения, что и на `:root`.
   Пин — `tests/app/test_status_token_aliases_reach_the_driver.py`. */
body.te5 {
  --te5-success: var(--te5-ok);
  --te5-success-bg: var(--te5-ok-bg);
  --te5-success-ln: var(--te5-ok-ln);
  --te5-warning: var(--te5-warn);
  --te5-warning-bg: var(--te5-warn-bg);
  --te5-warning-ln: var(--te5-warn-ln);
  --te5-danger: var(--te5-bad);
  --te5-danger-bg: var(--te5-bad-bg);
  --te5-danger-ln: var(--te5-bad-ln);
  --te5-info: var(--te5-primary);
  --te5-info-bg: var(--te5-primary-bg);
  --te5-info-ln: var(--te5-primary-ln);
  --te5-neutral: var(--te5-open);
  --te5-neutral-bg: var(--te5-open-bg);
  --te5-neutral-ln: var(--te5-open-ln);
}

/* ----- Тёмная тема -----
   Палитра переопределяет те же --te5-* переменные, поэтому работает на ВСЕХ
   экранах (единый te5.css). Применяется: системно по умолчанию (если юзер не
   выбрал вручную) ИЛИ принудительно через data-theme на <html> (theme.js). */
/* 🛑 ДВЕ ветки доставки тёмной темы, и они обязаны совпадать ПОТОКЕННО: `data-theme`
   ставит `theme.js` только после нажатия тумблера, а большинство живёт в системной
   ветке ниже. Тождество пинит `test_both_dark_delivery_paths_declare_the_same_palette`
   — у водителя расхождение уже роняло контраст до 2.64 при пороге 4.5.
   Полотно поднято #13161c → #1b2027 (+77 % яркости), карточка #1c222b → #384352 —
   ТА ЖЕ, что у водителя: перепад карточка/полотно 1.13 → 1.63, поверхности двух
   приложений совпадают. Решение владельца 08.08 («хочу как у водителя, чтоб едино
   было») принято после того, как цена названа вслух: на светлой карточке диапазон
   для трёх ступеней текста у́же, шаг иерархии падает 1.72 → ~1.37. Промежуточный
   вариант #303947 (перепад 1.40), стоявший здесь несколько часов, ОТМЕНЁН — не
   возвращать. Тексты пересобраны под новую карточку: #eef3fb / #c8d2e4 / #aab4c6. */
:root[data-theme="dark"],
:root[data-theme="dark"] body.te5 {
  --te5-bg: #1b2027;
  --te5-text: #eef3fb;
  --te5-text-2: #c8d2e4;
  --te5-muted: #aab4c6;
  --te5-primary: #9fb8d8;
  --te5-on-primary: #10151d;
  --te5-primary-hover: #b0c5df;
  --te5-primary-bg: #344659;
  --te5-primary-ln: #637b99;
  --te5-card: #384352;
  --te5-mark-bg: #BFDBFE;
  --te5-mark-text: #172033;
  --te5-surface: #384352;
  --te5-surface-raised: #424e5f;
  --te5-border: #525f72;
  --te5-border-2: #4b5768;
  --te5-line: #525f72;
  --te5-row-ln: #4b5768;
  --te5-row-hover: #414d5e;
  --te5-hover-bg: #434f61;
  --te5-input-ln: #8090a6;
  --te5-ok: #5ed08a;
  --te5-ok-bg: #28503a;
  --te5-ok-ln: #3a6b4d;
  --te5-warn: #e2b64f;
  --te5-warn-bg: #4a3d20;
  --te5-warn-ln: #66552e;
  --te5-bad: #f5978f;
  --te5-bad-bg: #4e2f2b;
  --te5-bad-ln: #6d4038;
  --te5-open: #c1c7d1;
  --te5-ico-blue: #8ab5f0;
  --te5-ico-green: #5ed08a;
  --te5-ico-amber: #f0bd51;
  --te5-ico-red: #f5978f;
  --te5-ico-violet: #b39dfa;
  --te5-ico-teal: #5eead4;
  --te5-ico-slate: #c1c7d1;
  --te5-toggle-bg: #4a3d20;
  --te5-toggle-bg-strong: #5b4b27;
  --te5-open-bg: #454f60;
  --te5-open-ln: #5a6879;
  --te5-success: var(--te5-ok);
  --te5-success-bg: var(--te5-ok-bg);
  --te5-success-ln: var(--te5-ok-ln);
  --te5-warning: var(--te5-warn);
  --te5-warning-bg: var(--te5-warn-bg);
  --te5-warning-ln: var(--te5-warn-ln);
  --te5-danger: var(--te5-bad);
  --te5-danger-bg: var(--te5-bad-bg);
  --te5-danger-ln: var(--te5-bad-ln);
  --te5-info: var(--te5-primary);
  --te5-info-bg: var(--te5-primary-bg);
  --te5-info-ln: var(--te5-primary-ln);
  --te5-neutral: var(--te5-open);
  --te5-neutral-bg: var(--te5-open-bg);
  --te5-neutral-ln: var(--te5-open-ln);
  --te5-toast-bg: #5a6879;
  --te5-shadow-sm: 0 1px 4px rgba(0, 0, 0, .22);
  --te5-shadow: 0 8px 24px rgba(0, 0, 0, .24);
  --te5-shadow-md: 0 8px 24px rgba(0, 0, 0, .24);
  --te5-shadow-float: 0 14px 36px rgba(0, 0, 0, .32);
  --te5-radius-control: 6px;
  --te5-radius-card: 8px;
  --te5-radius-panel: 10px;
  color-scheme: dark;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]),
  :root:not([data-theme="light"]) body.te5 {
    /* ОСНОВНОЙ путь доставки тёмной темы — значения обязаны совпадать с ветвью
       `[data-theme="dark"]` выше токен-в-токен (пинится тестом). */
    --te5-bg: #1b2027;
    --te5-text: #eef3fb;
    --te5-text-2: #c8d2e4;
    --te5-muted: #aab4c6;
    --te5-primary: #9fb8d8;
    --te5-on-primary: #10151d;
    --te5-primary-hover: #b0c5df;
    --te5-primary-bg: #344659;
    --te5-primary-ln: #637b99;
    --te5-card: #384352;
    --te5-mark-bg: #BFDBFE;
    --te5-mark-text: #172033;
    --te5-surface: #384352;
    --te5-surface-raised: #424e5f;
    --te5-border: #525f72;
    --te5-border-2: #4b5768;
    --te5-line: #525f72;
    --te5-row-ln: #4b5768;
    --te5-row-hover: #414d5e;
    --te5-hover-bg: #434f61;
    --te5-input-ln: #8090a6;
    --te5-ok: #5ed08a;
    --te5-ok-bg: #28503a;
    --te5-ok-ln: #3a6b4d;
    --te5-warn: #e2b64f;
    --te5-warn-bg: #4a3d20;
    --te5-warn-ln: #66552e;
    --te5-bad: #f5978f;
    --te5-bad-bg: #4e2f2b;
    --te5-bad-ln: #6d4038;
    --te5-open: #c1c7d1;
    --te5-ico-blue: #8ab5f0;
    --te5-ico-green: #5ed08a;
    --te5-ico-amber: #f0bd51;
    --te5-ico-red: #f5978f;
    --te5-ico-violet: #b39dfa;
    --te5-ico-teal: #5eead4;
    --te5-ico-slate: #c1c7d1;
    --te5-toggle-bg: #4a3d20;
    --te5-toggle-bg-strong: #5b4b27;
    --te5-open-bg: #454f60;
    --te5-open-ln: #5a6879;
    --te5-success: var(--te5-ok);
    --te5-success-bg: var(--te5-ok-bg);
    --te5-success-ln: var(--te5-ok-ln);
    --te5-warning: var(--te5-warn);
    --te5-warning-bg: var(--te5-warn-bg);
    --te5-warning-ln: var(--te5-warn-ln);
    --te5-danger: var(--te5-bad);
    --te5-danger-bg: var(--te5-bad-bg);
    --te5-danger-ln: var(--te5-bad-ln);
    --te5-info: var(--te5-primary);
    --te5-info-bg: var(--te5-primary-bg);
    --te5-info-ln: var(--te5-primary-ln);
    --te5-neutral: var(--te5-open);
    --te5-neutral-bg: var(--te5-open-bg);
    --te5-neutral-ln: var(--te5-open-ln);
    --te5-toast-bg: #5a6879;
    --te5-shadow-sm: 0 1px 4px rgba(0, 0, 0, .22);
    --te5-shadow: 0 8px 24px rgba(0, 0, 0, .24);
    --te5-shadow-md: 0 8px 24px rgba(0, 0, 0, .24);
    --te5-shadow-float: 0 14px 36px rgba(0, 0, 0, .32);
    --te5-radius-control: 6px;
    --te5-radius-card: 8px;
    --te5-radius-panel: 10px;
    color-scheme: dark;
  }
}

/* Плавающая кнопка переключения темы (theme.js вставляет в body) */
.te5-theme-toggle {
  position: fixed;
  top: 12px;
  right: 12px;
  z-index: 9999;
  width: 38px;
  height: 38px;
  padding: 0;
  border-radius: 10px; /* квадратные углы везде (правка j 02.07) — не круг */
  /* Вариант B (j 28.09.2026): подложка цветом значка. Рамка — та же, что у соседей по строке
     (колокольчик `.te5-header-notifications`): j по кадру прода — «она тоже должна быть
     выделена цветом границ, как и остальные». */
  border: 1px solid var(--te5-input-ln);
  background: var(--te5-toggle-bg);
  color: var(--te5-text);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  transition: background 0.15s, border-color 0.15s;
}
.te5-header-notifications:hover { border-color: var(--te5-primary); }
.te5-theme-toggle:hover, .te5-theme-toggle:active { border-color: var(--te5-primary); background: var(--te5-toggle-bg-strong); }
.te5-theme-toggle--inline {
  position: static;
  z-index: auto;
  box-shadow: none;
  flex: 0 0 auto;
}
.te5-header-notifications {
  width: 38px; height: 38px;
  border: 1px solid var(--te5-input-ln);
  border-radius: 10px;
  background: var(--te5-card);
  color: var(--te5-text);
  font: inherit;
  font-size: 18px;
  font-weight: 800;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.te5-header-notifications.has-new::after {
  content: "";
  position: absolute;
  top: 6px; right: 6px;
  width: 8px; height: 8px;
  border-radius: 999px;
  background: var(--te5-primary);
  box-shadow: 0 0 0 2px var(--te5-card);
}
[data-open-driver-chats].has-new::after { display: none; }
.te5-header-badge {
  position: absolute;
  top: -5px;
  right: -7px;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border: 2px solid var(--te5-card);
  border-radius: 999px;
  background: var(--te5-primary);
  color: var(--te5-on-primary);
  font-size: 10px;
  font-weight: 800;
  line-height: 14px;
  text-align: center;
}

* { box-sizing: border-box; }

/* E1 (j 02.07): фон html = фон темы → на PWA (iOS standalone) зона overscroll/safe-area (сверху за
   вырезом, снизу при оттяжке) показывает серый/тёмный фон страницы, а не синий (theme-color). */
html { background: var(--te5-bg); }

body.te5 {
  margin: 0;
  background: var(--te5-bg);
  color: var(--te5-text);
  font-family: var(--te5-font);
  font-size: 14px;
  /* dvh не реагирует на показ/скрытие URL-бара на мобиле → нет reflow-jank на скролле
     (100vh пересчитывался каждый кадр). 100vh — фолбэк для старых движков. */
  min-height: 100vh;
  min-height: 100dvh;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* ===== Десктопный масштаб КОНСОЛИ (правка владельца 04.08) =====
   Жалоба: «не видно ни черта, кроме кнопки Выйти и бургера». База te5.css —
   14px, и она ОБЩАЯ для консоли и водителя, поэтому поднимать её глобально
   нельзя: у водителя свой ×1.5 (`.te5-driver-scale`) считается от неё, и
   базовый бамп дал бы гигантизм на телефоне.

   🛑 Кегли в te5.css заданы АБСОЛЮТНЫМИ px и от базового не наследуются —
   поднять один `body.te5` мало, элементы остались бы прежними. Поэтому ниже
   перечислены именно те, что диспетчер читает: таблицы, кнопки, поля, чипы,
   подписи, заголовки. Всё под `:not()` по driver-маркерам — экран водителя
   этот блок не касается ни в одном состоянии. */
@media (min-width: 1024px) {
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) { font-size: 16px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-table { font-size: 15px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-table th { font-size: 13px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-btn { font-size: 15px; padding: 9px 15px; }
  /* 🛑 `textarea` исключена из правила ВЫСОТЫ: она тянется по `rows`, и общая
     `height` схлопывала поле разнарядки с двенадцати строк до трёх — правило
     масштаба било по одной оси и задело чужую. Кегль ей нужен, высота — нет. */
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-input:not(textarea),
  /* 🛑 Кнопка селектора с поиском СТОИТ НА МЕСТЕ нативного контрола, значит десктопный
     масштаб обязан задевать и её. Живой замер 04.09.2026 на 1440px: сосед вырос до 40px,
     кнопка осталась 38px — ряд формы «прыгал» по высоте. На 360px расхождения нет вовсе,
     поэтому узкий прогон это не показывал. */
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-esel__button,
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-select { font-size: 15px; height: 40px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) textarea.te5-input { font-size: 15px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-sub { font-size: 13.5px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-chip { font-size: 13.5px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-pagehead h1 { font-size: 25px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-pagehead__sub { font-size: 15px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-card__title { font-size: 17px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-field > span { font-size: 14px; }
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-nav a,
  body.te5:not(.te5-driver-scale):not(.te5-driver-access):not(.te5-driver-redesign) .te5-nav__skel { font-size: 15px; }
}

/* Экран разнарядки — САМАЯ широкая таблица консоли: одиннадцать колонок, из них
   четыре с выпадающими списками. 🛑 Ему нужны СВОИ, более узкие отступы, иначе
   правый край (телефон и примечание) уезжает за экран — жалоба владельца
   «не видно всё до конца». Общие отступы консоли при этом не трогаем: там
   таблицы на четыре колонки, и ужимать их не за что. */
body.te5-order .te5-main { max-width: 1680px; padding: 18px 14px; }
body.te5-order .te5-table th,
body.te5-order .te5-table td { padding-left: 8px; padding-right: 8px; }
body.te5-order .te5-table td { padding-top: 8px; padding-bottom: 8px; vertical-align: top; }
body.te5-order .te5-select,
body.te5-order .te5-input:not(textarea) { padding: 0 8px; }
/* Разнарядку вставляют целиком: тридцать строк. Поле на три строки заставляет
   диспетчера скроллить в поле, чтобы понять, что он вообще вставил. */
body.te5-order #orderText { min-height: 300px; }
body.te5-order .te5-order-result-head { margin-top: 20px; }
/* Примечание — самая длинная колонка и самая необязательная: показываем начало,
   полный текст остаётся в «Оригинале». */
/* Примечание переносится по строкам: в нём подробности рейса (второй адрес,
   груз), и обрезка прятала именно то, ради чего колонку и заводили. */
body.te5-order .te5-table td.te5-order-note { white-space: normal; word-break: break-word; }
/* 🛑 Одиннадцать колонок в одну ширину экрана влезают только при ЗАДАННЫХ
   долях: с `auto` браузер отдаёт место самой длинной ячейке (примечанию), и
   правый край — статус с кнопкой — уезжает за экран. Проценты в сумме 100,
   поэтому горизонтального скролла нет ни на одном мониторе от 1280. */
body.te5-order .te5-table { table-layout: fixed; font-size: 12.5px; }
body.te5-order .te5-table th:nth-child(1),
body.te5-order .te5-table td:nth-child(1) { width: 2%; }
body.te5-order .te5-table th:nth-child(2),
body.te5-order .te5-table td:nth-child(2) { width: 9.5%; }
body.te5-order .te5-table th:nth-child(3),
body.te5-order .te5-table td:nth-child(3) { width: 7%; }
body.te5-order .te5-table th:nth-child(4),
body.te5-order .te5-table td:nth-child(4) { width: 19%; }
body.te5-order .te5-table th:nth-child(5),
body.te5-order .te5-table td:nth-child(5) { width: 8%; }
body.te5-order .te5-table th:nth-child(6),
body.te5-order .te5-table td:nth-child(6) { width: 14%; }
body.te5-order .te5-table th:nth-child(7),
body.te5-order .te5-table td:nth-child(7) { width: 11%; }
body.te5-order .te5-table th:nth-child(8),
body.te5-order .te5-table td:nth-child(8) { width: 17%; }
body.te5-order .te5-table th:nth-child(9),
body.te5-order .te5-table td:nth-child(9) { width: 8.5%; }
body.te5-order .te5-table th:nth-child(10),
body.te5-order .te5-table td:nth-child(10) { width: 3.5%; }
/* Контролы тянутся по своей ячейке, а не распирают её изнутри. */
body.te5-order .te5-select,
body.te5-order .te5-input { width: 100%; min-width: 0; font-size: 12.5px; }
body.te5-order .te5-order-time { width: 100%; }
body.te5-order .te5-btn { font-size: 12px; padding: 5px 7px; }
/* Поле объекта и кнопки «завести/править» — одной строкой. */
body.te5-order .te5-order-objectcell { display: flex; align-items: center; gap: 6px; }
body.te5-order .te5-order-objectcell .te5-select { flex: 1 1 auto; min-width: 0; }
body.te5-order .te5-order-objectcell__tools { display: inline-flex; gap: 4px; flex: none; }
body.te5-order .te5-chip { font-size: 12px; padding: 3px 7px; }
/* 🛑 Статус — КВАДРАТНЫЙ бейдж со скруглением кнопки (6px), не «таблетка»:
   правка владельца 04.08. Свой цвет на каждую ситуацию — одним жёлтым были
   покрашены и «нет водителя» (чинится выбором в строке), и «машины нет в
   справочнике» (её вообще не существует), а это решения разной цены. */
body.te5-order .te5-order-badge {
  border-radius: 6px; justify-content: center; width: 100%;
  color: var(--badge-fg); background: var(--badge-bg); border-color: var(--badge-ln);
}
body.te5-order .te5-order-badge--ready     { --badge-fg: var(--te5-success); --badge-bg: var(--te5-success-bg); --badge-ln: var(--te5-success-ln); }
body.te5-order .te5-order-badge--nodriver  { --badge-fg: var(--te5-warning); --badge-bg: var(--te5-warning-bg); --badge-ln: var(--te5-warning-ln); }
body.te5-order .te5-order-badge--novehicle { --badge-fg: var(--te5-danger);  --badge-bg: var(--te5-danger-bg);  --badge-ln: var(--te5-danger-ln); }
body.te5-order .te5-order-badge--exists    { --badge-fg: var(--te5-info); --badge-bg: var(--te5-info-bg); --badge-ln: var(--te5-info-ln); }
body.te5-order .te5-order-badge--ambiguous { --badge-fg: #6d28d9; --badge-bg: #efe9fd; --badge-ln: #d6c8f7; }
body.te5-order .te5-order-badge--nocustomer{ --badge-fg: #a1490b; --badge-bg: #fdeee1; --badge-ln: #f3d2b6; }
body.te5-order .te5-order-badge--nodate    { --badge-fg: #0e6f7f; --badge-bg: #e2f4f7; --badge-ln: #bde0e7; }
body.te5-order .te5-order-badge--dup       { --badge-fg: #a51b57; --badge-bg: #fce8f0; --badge-ln: #f5c6da; }
body.te5-order .te5-order-badge--other     { --badge-fg: var(--te5-open); --badge-bg: var(--te5-open-bg); --badge-ln: var(--te5-open-ln); }
/* 🛑 Тёмная тема — ОБЕ ветки: `data-theme` ставит тумблер, а основная у
   большинства — системная. Правишь один блок — правь второй. */
:root[data-theme="dark"] body.te5-order .te5-order-badge--ambiguous  { --badge-fg: #c4a7fb; --badge-bg: #2b2440; --badge-ln: #45386b; }
:root[data-theme="dark"] body.te5-order .te5-order-badge--nocustomer { --badge-fg: #f0a978; --badge-bg: #3a2a1e; --badge-ln: #5e4530; }
:root[data-theme="dark"] body.te5-order .te5-order-badge--nodate     { --badge-fg: #79c8d6; --badge-bg: #1e3339; --badge-ln: #2f5058; }
:root[data-theme="dark"] body.te5-order .te5-order-badge--dup        { --badge-fg: #f08cb4; --badge-bg: #3a2029; --badge-ln: #5d3444; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) body.te5-order .te5-order-badge--ambiguous  { --badge-fg: #c4a7fb; --badge-bg: #2b2440; --badge-ln: #45386b; }
  :root:not([data-theme="light"]) body.te5-order .te5-order-badge--nocustomer { --badge-fg: #f0a978; --badge-bg: #3a2a1e; --badge-ln: #5e4530; }
  :root:not([data-theme="light"]) body.te5-order .te5-order-badge--nodate     { --badge-fg: #79c8d6; --badge-bg: #1e3339; --badge-ln: #2f5058; }
  :root:not([data-theme="light"]) body.te5-order .te5-order-badge--dup        { --badge-fg: #f08cb4; --badge-bg: #3a2029; --badge-ln: #5d3444; }
}
/* Телефон — по нему звонят прямо со строки: синим и жирным, а не серым мелким. */
body.te5-order .te5-order-phone { color: var(--te5-primary); font-weight: 700; white-space: nowrap; }
/* Указания на смену — читаются как список требований, а не как абзац текста. */
body.te5-order .te5-order-standing { margin: 0; padding-left: 20px; line-height: 1.7; font-weight: 600; }
/* Предупреждение «уведомление некуда доставить» — тон предостережения, не ошибки:
   смены созданы корректно, но водитель о них не узнает сам. */
body.te5-order .te5-order-unreachable {
  margin-top: 10px; padding: 10px 12px; border-radius: 8px;
  color: var(--te5-warning); background: var(--te5-warning-bg); border: 1px solid var(--te5-warning-ln);
}
body.te5-order .te5-order-unreachable ul { margin: 6px 0 0; padding-left: 20px; line-height: 1.6; }
/* Телефон — цифры, перенос по месту, а не в одну длинную строку. */
body.te5-order .te5-table td:nth-child(7) { word-break: break-word; }

@keyframes te5pulse { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
@keyframes te5spin { to { transform: rotate(360deg); } }

/* ---------- layout ---------- */

.te5-shell { min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; }

.te5-header {
  position: sticky; top: 0; z-index: 30;
}
/* 🛑 На страницах консоли шапка лежит в обёртке `<div id="te5-header">` высотой в саму
   себя — `sticky` у `.te5-header` там некуда прилипать, и шапка уезжала при прокрутке.
   Липкой объявлена сама обёртка (решение владельца 15.09.2026: «везде, на всех страницах»).
   `display: contents` не годится: у обёртки нулевой `getBoundingClientRect`, а её берут по
   id `te5.js`/`te5-owner.js`. Пин — `test_console_nav_under_header.py`. */
#te5-header {
  position: sticky; top: 0; z-index: 30;
}
/* 🛑 Фон шапки — ОТДЕЛЬНЫЙ слой, а не заливка самого блока. Так панель навигации
   выезжает ИЗ-ПОД полосы (правка владельца 08.08.2026 по кадру прода: «чтоб не
   наслаивалось сверху на навбар, а как бы из-под него вылезало»). Заливкой блока
   этого добиться нельзя: `.te5-nav` — потомок `.te5-header__inner`, а фон родителя
   по построению всегда ниже потомка. Порядок слоёв пинит
   `test_console_nav_under_header.py`. */
.te5-header::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--te5-card);
  border-bottom: 1px solid var(--te5-border);
  pointer-events: none;
}
/* 🛑 У самого `inner` z-index быть НЕ ДОЛЖНО: он создал бы контекст наложения, внутри
   которого панель физически не может уйти ниже подложки шапки — та лежит снаружи.
   Поэтому слой поднимают ДЕТИ, а не контейнер. */
.te5-header__inner {
  max-width: 1280px; margin: 0 auto; padding: 6px 24px; min-height: 44px;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  position: relative;
}
.te5-header__inner > * { position: relative; z-index: 2; }
.te5-logo { display: flex; align-items: center; gap: 10px; margin-right: 6px; text-decoration: none; color: inherit; }

/* Логотип-плашка — theme-aware, КОНТРАСТ с фоном: светлая тема → тёмный тайл +
   белый глиф; тёмная тема → светлый тайл + тёмный глиф (синий акцент на обеих). */
:root { --te5-logo-bg: #0d0d0d; --te5-logo-img: url("/icons/bit-glyph.svg"); --te5-logo-ring: inset 0 0 0 1px rgba(255, 255, 255, .10); }
:root[data-theme="dark"] { --te5-logo-bg: #eef1f5; --te5-logo-img: url("/icons/bit-glyph-ink.svg"); --te5-logo-ring: inset 0 0 0 1px rgba(13, 16, 20, .12); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --te5-logo-bg: #eef1f5; --te5-logo-img: url("/icons/bit-glyph-ink.svg"); --te5-logo-ring: inset 0 0 0 1px rgba(13, 16, 20, .12); }
}

/* Общий вид всех bit-плашек (тема — через --te5-logo-*); каждый селектор ниже
   задаёт только свой размер/радиус. Новая плашка: добавить класс сюда — тему
   и глиф получит бесплатно. */
.te5-logo__mark, .te5-login__mark, .te5-mobile-head__mark {
  flex: 0 0 auto;
  background-color: var(--te5-logo-bg); background-image: var(--te5-logo-img);
  background-repeat: no-repeat; background-position: center; background-size: 62%;
  box-shadow: var(--te5-logo-ring);
}
.te5-logo__mark { width: 30px; height: 30px; border-radius: 7px; }
.te5-logo__name { font-weight: 800; font-size: 17px; letter-spacing: -.01em; white-space: nowrap; }

.te5-nav { display: flex; gap: 4px; flex: 1; flex-wrap: wrap; }
.te5-nav a, .te5-nav__logout button {
  font: inherit; font-size: 13.5px; color: var(--te5-text-2); text-decoration: none;
  border: none; border-radius: 6px; padding: 8px 13px; cursor: pointer; background: none; white-space: nowrap;
}
.te5-nav a:hover, .te5-nav__logout button:hover { background: var(--te5-row-ln); }
/* Скелетон навигации до ответа app-config и whoami (`TE5.renderHeader`, класс
   `te5-nav-pending` ставит `mountHeader`). Плашка той же геометрии, что ссылка: её
   прозрачный текст «Путевые листы» задаёт ширину, жирность — как у активного пункта
   на борде. Строку не переносим — лишняя плашка обрезается, а не уводит шапку во
   вторую строку, пока идёт загрузка. */
.te5-nav__skel {
  font-size: 13.5px; font-weight: 600; padding: 8px 13px; border-radius: 6px; white-space: nowrap;
  color: transparent; background: var(--te5-border-2); animation: te5pulse 1.2s ease-in-out infinite;
  user-select: none; pointer-events: none;
}
:root:not(.te5-nav-pending) .te5-nav__skel { display: none; }
.te5-nav-pending .te5-nav { flex-wrap: nowrap; overflow: hidden; }
.te5-nav-pending .te5-nav > a { display: none !important; }
.te5-nav a.is-active { background: var(--te5-primary-bg); color: var(--te5-primary); font-weight: 600; }
/* Счётчик заявок у «Справочников». Цвет — акцент (`--te5-primary`), а НЕ `--te5-primary-bg`:
   тот является ФОНОМ чипа и к карточке даёт 1.14 при пороге 3.0 — ровно та ошибка, что
   гасила обводку фокуса кнопки «Скопировать» (09.08). Фон значка приглушённый, текст
   акцентный: на нём и держится читаемость в обеих темах. */
/* Колонка действий в таблице: три кнопки в ряд не переносим — перенос делает строку
   двухэтажной и ломает ритм списка. */
.te5-nowrap { white-space: nowrap; }
.te5-nav__count {
  display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 999px;
  background: var(--te5-primary-bg); color: var(--te5-primary);
  font-size: 12px; font-weight: 700; line-height: 1.5;
}

.te5-burger {
  display: none;
  width: 38px;
  height: 38px;
  padding: 0;
  margin-left: 2px;
  border: 1px solid var(--te5-border);
  border-radius: 8px;
  background: var(--te5-card);
  color: var(--te5-text);
  font-size: 21px;
  line-height: 1;
  cursor: pointer;
  align-items: center;
  justify-content: center;
}
.te5-burger:hover { border-color: var(--te5-primary); }
.te5-nav__logout { display: none; }
.te5-nav__logout { margin: 6px 0 0; padding: 0; }
.te5-nav__logout button {
  width: 100%;
  text-align: left;
  color: var(--te5-bad);
  border: 1px solid var(--te5-bad-ln);
  background: var(--te5-bad-bg);
}
.te5-nav__logout button:hover {
  color: var(--te5-bad);
  border-color: var(--te5-bad-ln);
  background: var(--te5-bad-bg);
}

.te5-header__right { display: flex; align-items: center; gap: 12px; }
.te5-header__user { font-size: 13px; color: var(--te5-text-2); }
.te5-header__right .te5-btn {
  background: var(--te5-card);
  color: var(--te5-text);
  border-color: var(--te5-input-ln);
}
.te5-header__right .te5-btn:hover {
  background: var(--te5-hover-bg);
  color: var(--te5-text);
  border-color: var(--te5-input-ln);
}

.te5-push-toggle {
  width: 38px;
  height: 38px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--te5-border);
  background: var(--te5-card);
  color: var(--te5-text);
  font: inherit;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.te5-push-toggle:hover {
  background: var(--te5-hover-bg);
  border-color: var(--te5-primary);
}
.te5-push-toggle.is-busy {
  color: var(--te5-warn);
  border-color: var(--te5-warn-ln);
  background: var(--te5-warn-bg);
}
.te5-push-toggle.is-error {
  color: var(--te5-bad);
  border-color: var(--te5-bad-ln);
  background: var(--te5-bad-bg);
}
.te5-push-toggle__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.te5-main { max-width: 1280px; margin: 0 auto; padding: 24px; width: 100%; flex: 1; }

.te5-pagehead { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 18px; flex-wrap: wrap; }
.te5-pagehead h1 { margin: 0; font-size: 21px; font-weight: 700; }
.te5-pagehead__sub { font-size: 13px; color: var(--te5-muted); margin-top: 3px; }
.te5-pagehead__actions { display: flex; gap: 10px; flex-wrap: wrap; }
/* Липкая шапка страницы — класс ставит `TE5.stickHead` (shared/ui.js), он же меряет `top`
   по шапке консоли. Борд «Путевые листы» с 14.09, страницы создания с 28.09 (j). Фон и линия —
   чтобы список не просвечивал; отрицательные поля — во всю ширину `.te5-main`.
   🛑 Верхнее поле тоже отрицательное — ровно поле `.te5-main` (24px; до 900px — 16px, у
   разнарядки 18/14): иначе в покое от шапки консоли до заголовка ложились поле страницы плюс
   своё, а при прилипании только своё (j 15.09: «в самый верх проскроллил — огромный зазор»).
   Меняешь поля `.te5-main` — правь и здесь. Ставится и на обёртку вокруг `.te5-pagehead`
   (борд), и на саму `.te5-pagehead` (страницы создания): у самой шапки правило ниже
   перебивает её `margin-bottom` той же специфичностью — порядок несущий. */
.te5-pagehead-stick {
  position: sticky; top: 0; z-index: 20; /* ниже шапки консоли (30), выше карточек */
  margin: -24px -24px 18px; padding: 12px 24px; background: var(--te5-bg);
}
/* Линия под блоком — во всю ширину окна, а не `.te5-main` (j 15.09): псевдоэлемент от края
   до края окна. Перелива нет, потому что `overflow-x: hidden` у `body.te5` уходит на viewport —
   у `html` overflow не задан; задашь `html { overflow… }` — перелив вернётся, стенд это меряет. */
.te5-pagehead-stick::after {
  content: ""; position: absolute; left: calc(50% - 50vw); right: calc(50% - 50vw); bottom: -1px; height: 1px;
  background: var(--te5-border); pointer-events: none;
}
.te5-pagehead-stick > .te5-pagehead { margin-bottom: 0; }
body.te5-order .te5-pagehead-stick { margin: -18px -14px 18px; padding-inline: 14px; }

/* Переключатель ВИДА одного экрана (диспетчерская: списком / на карте).
   Это не навигация по разделам — раздел один, меняется только взгляд, поэтому
   переключатель живёт на странице, а не в шапке. */
.te5-modeswitch { display: inline-flex; gap: 2px; margin: -6px 0 18px; padding: 3px; border: 1px solid var(--te5-border); border-radius: var(--te5-radius-panel); background: var(--te5-surface); }
.te5-modeswitch a {
  padding: 7px 16px; border-radius: var(--te5-radius-control); font-size: 14px; font-weight: 600;
  color: var(--te5-text-2); text-decoration: none; white-space: nowrap;
}
.te5-modeswitch a:hover { background: var(--te5-hover-bg); color: var(--te5-text); }
/* Сегмент внутри шапки страницы (борд, страницы создания): отступы задаёт сама шапка, а сам
   он прижат к низу шапки и ростом с поле кита (38px) — иначе стоит не на одной линии с полями
   и кнопками справа (j 28.09: «Список | Карта не на одной линии, как кнопка»). Радиус и рост —
   как у кнопок той же строки (j 28.09 ночь: «скругления не те, что у нас, и высота не как у
   кнопок»), но внутри — таблетка в рамке, а не сплошная заливка до краёв (j 28.09 день: «мне
   нравилось, что они будто не полностью закрашивались»): подложка 3px, активная ссылка —
   скруглённая таблетка на 2px меньше радиуса рамки. Кегль и боковые отступы — от
   `.te5-modeswitch a`. */
.te5-pagehead .te5-pagehead__view {
  margin: 0; align-self: flex-end; height: 38px; box-sizing: border-box;
  padding: 3px; gap: 2px; border-radius: var(--te5-radius-control); overflow: hidden;
}
.te5-pagehead .te5-pagehead__view a {
  display: inline-flex; align-items: center; height: 100%; padding-top: 0; padding-bottom: 0;
  border-radius: calc(var(--te5-radius-control) - 2px);
}
/* Карта: сегмент в строке заголовка рядом с ним, кнопки действий — у правого края (j 28.09:
   «на карте оно всё ещё на следующей строке, а не на той же, что и название»). Распор держит
   блок действий, поэтому заголовок и сегмент стоят рядом с общим зазором шапки. */
.te5-pagehead .te5-pagehead__view + .te5-pagehead__actions { margin-left: auto; }
.te5-modeswitch a.is-active { background: var(--te5-primary); color: var(--te5-on-primary); }

/* Кнопка, выглядящая ссылкой: действие внутри строки таблицы, где полноценная
   кнопка распирала бы колонку. */
.te5-linkbtn {
  border: 0; background: none; padding: 0; font: inherit; font-size: inherit;
  color: var(--te5-primary); text-decoration: underline; cursor: pointer;
}
.te5-linkbtn:hover { text-decoration: none; }
.te5-linkbtn[disabled] { opacity: .5; cursor: default; }

/* ---------- cards / tables ---------- */

.te5-card { background: var(--te5-surface); border: 1px solid var(--te5-border); border-radius: var(--te5-radius-card); overflow: hidden; }
.te5-card,
.te5-cols > * { min-width: 0; }
.te5-card--mt { margin-top: 16px; }
.te5-card__head {
  padding: 12px 16px; border-bottom: 1px solid var(--te5-border);
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
}
.te5-card__title { font-weight: 600; font-size: 13.5px; }
.te5-card__body { padding: 16px; }

/* ---------- TE5 console kit helpers ---------- */

.te5-surface-raised {
  background: var(--te5-surface-raised);
  border-color: var(--te5-border);
  box-shadow: var(--te5-shadow-sm);
}
.te5-filter-panel {
  overflow: visible;
  position: relative;
  z-index: 10;
  box-shadow: var(--te5-shadow-sm);
}
.te5-actionbar {
  box-shadow: var(--te5-shadow-float);
}
.te5-menu {
  position: relative;
}
.te5-menu__summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.te5-menu__summary::-webkit-details-marker { display: none; }
.te5-menu__panel {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  min-width: 100%;
  padding: 8px;
  border: 1px solid var(--te5-border);
  border-radius: var(--te5-radius-card);
  background: var(--te5-surface-raised);
  box-shadow: var(--te5-shadow-md);
  display: grid;
  gap: 6px;
}
/* Стрелка меню рисуется двумя границами, а не символом «⌄»: у знака нет ни толщины, ни
   поворота, и в шрифте интерфейса он выходит тонким и мелким (кадр владельца 08.09.2026).
   Полупрозрачность — чтобы указатель не спорил с подписью кнопки, а поворот показывает
   состояние: вниз — закрыто, вверх — открыто. */
.te5-menu__caret {
  width: 7px;
  height: 7px;
  flex: none;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  border-radius: 1px;
  opacity: .55;
  transform: translateY(-2px) rotate(45deg);
  transition: transform .15s ease;
}
.te5-menu[open] > .te5-menu__summary .te5-menu__caret {
  transform: translateY(1px) rotate(-135deg);
}
@media (prefers-reduced-motion: reduce) {
  .te5-menu__caret { transition: none; }
}
.te5-menu__check {
  display: flex;
  gap: 8px;
  align-items: center;
  white-space: nowrap;
}
.te5-menu__check input { width: 16px; height: 16px; flex: 0 0 auto; }
.te5-stack { display: grid; gap: 12px; }
.te5-stack--sm { gap: 8px; }
.te5-stack--xs { gap: 4px; }
.te5-row { display: flex; align-items: center; gap: 10px; }
.te5-row--wrap { flex-wrap: wrap; }
.te5-row--end { justify-content: flex-end; }
.te5-row--between { justify-content: space-between; }
.te5-row--baseline { align-items: baseline; }
.te5-actions-row { display: flex; align-items: center; flex-wrap: wrap; gap: var(--te5-gap-controls); margin-top: 14px; }
.te5-actions-row--block { margin: 16px 0 8px; }
.te5-section-title { margin: 0 0 4px; font-size: 16px; font-weight: 700; }
.te5-section-sub { margin-bottom: 12px; }
.te5-muted,
.te5-cell-muted { color: var(--te5-muted); }
.te5-num { font-variant-numeric: tabular-nums; text-align: right; }
.te5-cell-right { text-align: right; }
.te5-ml-auto { margin-left: auto; }
.te5-skel + .te5-skel { margin-top: 8px; }
.te5-skel--gap { margin-top: 12px; }
.te5-skel--tail { margin-bottom: 12px; }
.te5-form-stack { display: flex; flex-direction: column; gap: 12px; }
.te5-form-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.te5-field--mt { margin-top: 12px; }
.te5-field--mt-sm { margin-top: 10px; }
.te5-field--narrow { max-width: 260px; }
.te5-search-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: end; }
.te5-search-row .te5-input { flex: 1 1 280px; max-width: 420px; min-width: 0; }
.te5-search-row .te5-select { flex: 1 1 190px; max-width: 280px; min-width: 0; }
.te5-filter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; align-items: end; }
.te5-filter-grid--wide { grid-template-columns: minmax(220px, 1fr) minmax(180px, 240px) minmax(260px, 1.5fr); }
.te5-lockbox {
  background: var(--te5-row-ln);
  border: 1px solid var(--te5-border-2);
  border-radius: var(--te5-radius-card);
  padding: 10px 12px;
  margin-bottom: 14px;
}
.te5-lockbox__hint { font-size: 11px; color: var(--te5-muted); margin-top: 7px; }
.te5-copy-value { font-size: 16px; }
.te5-copy-secret { font-size: 20px; }
.te5-form-note { font-size: 13.5px; line-height: 1.5; margin: 0; }
.te5-form-note--center { font-size: 14px; margin: 0 0 14px; text-align: center; }
.te5-modal__title--center { text-align: center; }
.te5-qr-wrap { display: flex; justify-content: center; margin-bottom: 14px; }
.te5-qr-img {
  width: min(82vw, 340px);
  height: min(82vw, 340px);
  aspect-ratio: 1;
  image-rendering: pixelated;
  border: 1px solid var(--te5-border);
  border-radius: var(--te5-radius-card);
}
.te5-admin-id-grid { display: grid; gap: 8px; }
.te5-admin-id-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.te5-admin-id-label { font-size: 12px; font-weight: 600; color: var(--te5-text-2); }

/* ── Складная полоска со сводкой (W4) ──────────────────────────────────────
   Свёрнутый блок обязан продолжать отвечать на вопрос, ради которого его открывали,
   поэтому итог живёт в самой полоске, а не только внутри. Разметку даёт `TE5.fold`. */
.te5-fold {
  border: 1px solid var(--te5-border);
  border-radius: 8px;
  overflow: hidden;
  background: var(--te5-card);
}
.te5-fold__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  cursor: pointer;
  font-weight: 600;
  font-size: 13.5px;
  list-style: none;  /* Safari рисует свой треугольник мимо нашей раскладки */
}
.te5-fold__bar::-webkit-details-marker { display: none; }
.te5-fold[open] > .te5-fold__bar { border-bottom: 1px solid var(--te5-border); }
/* 🛑 Порядок сжатия задаём явно, иначе на узком экране первым ломается ЗАГОЛОВОК.
   Замер 09.08 на 390px: «Отчёт о создании смен» переносился на три строки, полоска
   вырастала 40 → 73px и переставала быть полоской — при том что сводка рядом честно
   сжималась многоточием. Заголовок сжимается последним (shrink 1), сводка первой (999). */
.te5-fold__label {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Сводка сжимается и обрезается многоточием; счётчик рядом — никогда.
   Держать их одним узлом нельзя: цифра внутри обрезаемого блока уезжает под обрез. */
.te5-fold__peek {
  margin-left: auto;
  flex: 0 999 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--te5-muted);
  font-weight: 400;
}
.te5-fold__count {
  flex: none;
  min-width: 22px;
  padding: 0 7px;
  border-radius: 999px;
  background: var(--te5-warning-bg);
  color: var(--te5-warning);
  font-size: 12px;
  font-weight: 700;
  text-align: center;
}
/* Шеврон рисуем сами: `content` с символом зависит от шрифта системы,
   а рамка из бордеров одинакова везде и поворачивается без перерисовки текста. */
.te5-fold__chev {
  flex: none;
  width: 8px;
  height: 8px;
  margin-left: 2px;
  border-right: 2px solid var(--te5-muted);
  border-bottom: 2px solid var(--te5-muted);
  /* 🛑 Поворот квадрата смещает его ВИДИМЫЙ центр: у «вниз» тяжёлый угол внизу, у «вверх»
     наверху, и одинаковый `translate` для обоих состояний уводит стрелку из середины
     полоски (живой замер 09.08: в свёрнутом виде она висела в правом верхнем углу).
     Поэтому компенсация РАЗНАЯ и подобрана замером, а не на глаз. */
  transform: translateY(-2px) rotate(45deg);
  transition: transform 150ms ease;
}
.te5-fold[open] > .te5-fold__bar .te5-fold__chev { transform: translateY(2px) rotate(-135deg); }
.te5-fold__body { padding: 14px 16px; }
/* Тон исхода живёт на обёртке: сама полоска остаётся нейтральной, иначе
   зелёная заливка на весь блок перекрикивает содержимое. */
.te5-fold-wrap--success > .te5-fold { border-color: var(--te5-success-ln); }
.te5-fold-wrap--warning > .te5-fold { border-color: var(--te5-warning-ln); }
/* Обязательное действие живёт СНАРУЖИ складного блока — свернув отчёт однажды, диспетчер
   не должен потерять следующий шаг (складка помнит себя между заходами). */
.te5-fold-wrap__cta { margin-top: 12px; }
@media (prefers-reduced-motion: reduce) {
  .te5-fold__chev { transition: none; }
}

.te5-table { width: 100%; border-collapse: collapse; font-size: 13px; background: var(--te5-surface); }
.te5-table th {
  text-align: left; padding: 8px 16px; font-size: 11px; font-weight: 700; color: var(--te5-muted);
  text-transform: uppercase; letter-spacing: .4px; border-bottom: 1px solid var(--te5-border-2); white-space: nowrap;
  background: var(--te5-surface-raised);
}
.te5-table td { padding: 11px 16px; border-bottom: 1px solid var(--te5-row-ln); vertical-align: middle; }
.te5-table tr:last-child td { border-bottom: none; }
.te5-table tr.is-clickable { cursor: pointer; }
.te5-table tbody tr:hover td,
.te5-table tr.is-clickable:hover td { background: var(--te5-row-hover); }
.te5-table td[colspan] { background: var(--te5-surface); }
.te5-table .num { font-family: var(--te5-mono); }
.te5-table-scroll {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: var(--te5-input-ln) transparent;
}
.te5-table-scroll .te5-table { min-width: 760px; }
.te5-table-scroll--compact .te5-table { min-width: 0; }
.te5-route-object-cell {
  display: grid; grid-template-columns: minmax(0, 1fr) 110px;
  gap: 8px; align-items: center;
}
.te5-route-object-cell .te5-esel--address { width: 100%; max-width: 320px; min-width: 0; }
@media (max-width: 640px) {
  .te5-table-scroll.te5-route-table .te5-table { min-width: 0; table-layout: fixed; }
  .te5-route-table .te5-table th,
  .te5-route-table .te5-table td { padding-left: 4px; padding-right: 4px; }
  .te5-route-table .te5-table th:first-child { width: 28px; }
  .te5-route-table .te5-table th:nth-child(3) { width: 68px; }
  .te5-route-table .te5-table th:last-child { width: 88px; }
  .te5-route-object-cell { grid-template-columns: 1fr; }
  .te5-route-table [data-route-cancel] {
    width: 100%; min-width: 0; padding-left: 6px; padding-right: 6px; font-size: 13px;
  }
}

/* ---------- owner equipment PWA ---------- */

body.te5-owner,
body.te5-owner button,
body.te5-owner input,
body.te5-owner select,
body.te5-owner textarea,
body.te5-owner a {
  font-size: 16px;
}
body.te5-owner .te5-owner-table--registry { table-layout: fixed; }
body.te5-owner .te5-owner-table--feed { table-layout: auto; }
body.te5-owner .te5-owner-controls { align-items: flex-end; gap: 12px; }
body.te5-owner .te5-owner-actions { gap: 8px; }
body.te5-owner .te5-owner-actions [role="group"] {
  display: inline-flex;
  gap: var(--te5-gap-tight);
}
/* Шапка экрана — ОДНА строка: название, вкладки, действия. 🛑 Ряд держит общая нижняя
   линия, и подчёркивание активной вкладки ложится ПОВЕРХ неё (`margin-bottom: -1px`).
   Без этой линии вкладки висели в воздухе и не читались одним рядом с заголовком —
   замечание Серёжи 01.09.2026: «не очень ровно». Высоту ряда задаёт САМЫЙ высокий
   элемент (кнопки 38px), поэтому заголовок и действия центрируются по нему сами, а
   вкладки прижимаются к линии — им нужен низ, а не центр. */
body.te5-owner .te5-owner-pagehead {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: 4px var(--te5-gap-group);
  margin-bottom: 18px;
  border-bottom: 1px solid var(--te5-row-ln);
}
body.te5-owner .te5-owner-pagehead > h1 {
  align-self: center;
  padding-bottom: 10px;
}
body.te5-owner .te5-owner-tabs {
  flex: 1 1 auto;
  align-items: flex-end;
  gap: 2px;
  margin-bottom: 0;
  overflow: visible;
}
/* 🛑 Подчёркнутые вкладки — ОБЩИЙ компонент кита, а не украшение одного экрана.
   Учёт техники и кабинет заказчика рисуют одну и ту же вещь; пока правила жили под
   `body.te5-owner`, кабинет переизобретал их своим `.cab-tab` и выглядел чужим
   приложением (замечание владельца 02.09.2026). Правила перенесены СЮДА дословно —
   вид учёта техники не менялся, к его `nav` добавлен этот класс. */
.te5-tabs.te5-tabs--underline [role="tab"] {
  min-height: 38px;
  margin-bottom: -1px;
  padding: 0 14px;
  border: 0;
  border-bottom: 3px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--te5-text-2);
}
.te5-tabs.te5-tabs--underline [role="tab"]:hover {
  background: transparent;
  border-bottom-color: var(--te5-row-ln);
  color: var(--te5-text);
}
.te5-tabs.te5-tabs--underline [role="tab"][aria-selected="true"] {
  border-bottom-color: var(--te5-primary);
  background: transparent;
  color: var(--te5-primary);
}
/* 🛑 Обе кнопки ряда приводятся к ОДНОЙ высоте явно: квадратная иконка задана в 38px
   жёстко, а у текстовой высота набегает из паддингов и кегля — совпадали они случайно
   и разъехались бы от любой правки шрифта. */
body.te5-owner .te5-owner-pagehead__actions {
  display: flex;
  align-self: center;
  align-items: center;
  flex: none;
  gap: var(--te5-gap-tight);
  margin-left: auto;
  padding-bottom: 8px;
}
body.te5-owner .te5-owner-pagehead__actions > * {
  min-height: 38px;
  box-sizing: border-box;
}
body.te5-owner .te5-owner-pagehead__actions .te5-btn { font-size: 16px; }
/* Действия «Парка» (меню документов + Диадок) — один элемент ряда, чтобы прятаться и
   переноситься целиком: у «Фитингов» и «ГНБ» реестра нет, и ни один из них не применим.
   🛑 Своё правило для `[hidden]` обязательно: собственный `display` перебил бы браузерное
   правило скрытия, и `hidden` на этом узле не сработал бы вовсе (общий `!important` в
   шапке файла держит только те узлы, у кого своего `display` нет). */
body.te5-owner .te5-owner-park-actions {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--te5-gap-tight);
}
body.te5-owner .te5-owner-park-actions[hidden] { display: none; }
/* Меню «Действия»: панель выпадает ВЛЕВО от кнопки (`right: 0`) — ряд шапки прижат к правому
   краю страницы, и панель, выровненная по левому краю кнопки, уезжала бы за экран. */
body.te5-owner .te5-owner-docs-menu .te5-menu__panel {
  left: auto;
  right: 0;
  min-width: 220px;
}
body.te5-owner .te5-owner-docs-menu .te5-owner-doc {
  justify-content: flex-start;
  white-space: nowrap;
}
body.te5-owner dialog.te5-modal-backdrop .te5-modal__scroll { padding-top: 0; }
body.te5-owner .te5-owner-hours-warning {
  position: sticky;
  top: 0;
  z-index: 2;
  margin: 0 0 14px;
  font-size: 16px;
}
body.te5-owner .te5-owner-form-error {
  flex: 1 1 240px;
  margin: 0;
  font-size: 16px;
}
body.te5-owner .te5-owner-table--feed { min-width: 1120px; }
/* Номер машины — НАСТОЯЩАЯ кнопка. Отдельной колонки с карандашом больше нет (правка
   Егора 01.09.2026: «клик по всей строке»), но клавиатурному входу в правку надо где-то
   жить: `tabindex`/`role` на самом `<tr>` перебивают роль строки таблицы и отнимают у
   скринридера навигацию по десяти колонкам. Кнопка выглядит ровно как значение ячейки,
   поэтому колонку не расширяет и вторым элементом управления не читается. */
body.te5-owner .te5-owner-rowbtn {
  appearance: none;
  border: 0;
  margin: 0;
  padding: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
body.te5-owner .te5-owner-rowbtn:hover { text-decoration: underline; }
body.te5-owner .te5-owner-rowbtn:focus-visible {
  outline: 2px solid var(--te5-primary);
  outline-offset: 2px;
  border-radius: 4px;
}
body.te5-owner .te5-owner-table td[data-owner-select-cell] {
  text-align: center;
}
body.te5-owner :is([data-owner-select-all], [data-owner-select], #ownerShowDeleted) {
  width: 22px;
  height: 22px;
  accent-color: var(--te5-primary);
}
/* Липкой правой колонки больше нет вместе с карандашом: липнуть нечему, а «отклеенный
   слэб» (баг TE-224) вместе с ней перестал быть возможным. */
body.te5-owner .te5-owner-table tr[data-registry-row] { cursor: pointer; }
body.te5-owner .te5-owner-table tr[data-registry-row]:hover td {
  background: var(--te5-row-hover);
}
/* 🛑 Правила `:focus-visible` у самой строки здесь НЕТ намеренно: строка не получает
   ни `tabindex`, ни `role="button"` (иначе скринридер теряет структуру таблицы), значит
   сфокусировать её нельзя и обводка была бы мёртвым кодом. Клавиатурный фокус живёт на
   кнопке в ячейке номера — её обводку рисует `.te5-owner-rowbtn:focus-visible`. */
body.te5-owner .te5-owner-table input[type="number"] {
  font-variant-numeric: tabular-nums;
  text-align: right;
}
/* Строка с расхождением (правка ≠ системный факт): короткий бейдж-чип живёт В ПЕРВОЙ
   ячейке той же строки (JS, рядом с датой), полная формулировка — в title (tooltip).
   Рамка здесь — только доп. подсказка, НЕ единственный носитель смысла (текст+глиф остаются
   у бейджа). Линия обводки WCAG-порога не имеет (claude-config: «границы поля — 3.0,
   линии строк — без порога»), поэтому фон/текст ячеек трогать не нужно. */
body.te5-owner .te5-owner-table tr.te5-owner-conflict-row td[data-owner-field="work_date"] {
  box-shadow: inset 3px 0 0 var(--te5-warn-ln);
}
body.te5-owner .te5-owner-table tr.te5-owner-deleted-row td[data-owner-field] {
  color: var(--te5-text-2);
}
body.te5-owner .te5-owner-table tr.te5-owner-deleted-row td[data-owner-field="work_date"] {
  box-shadow: inset 3px 0 0 var(--te5-border-2);
}
body.te5-owner .te5-owner-table td[data-owner-field] .te5-chip {
  margin-right: 8px;
}
/* 🛑 Зазор нужен чипу, ЗА КОТОРЫМ что-то стоит: бейджи «⚠ конфликт»/«⊘ Убрана» живут в
   ячейке даты перед самой датой, и без него они слипались бы с ней. Чипу-последышу зазор
   отдавать некуда — он превращается в 8px мёртвого поля, за которые платит ВСЯ колонка.
   Замер стенда 08.09.2026: бейдж «○ Ожидает часов» — 137px, самое широкое неразрезаемое
   содержимое таблицы; с хвостом 145px, и в колонку статуса он не влезал, из-за чего вся
   таблица получала горизонтальную полосу — под всей страницей, ради пустоты.
   🛑 Адресуем ЯЧЕЙКУ СТАТУСА, а не `:last-child`. Селектор `:last-child` считает только
   элементы и текстовых узлов не видит, а дата печатается голым текстом ПОСЛЕ бейджей
   (`te5-owner.js`: `deletedBadge + conflictBadge + reviewBadge + cellHtml(...)`). Через
   `:last-child` под правило попадал бы и последний бейдж перед датой — он слипся бы с ней,
   то есть правило отняло бы ровно тот зазор, ради которого оставлено (находка codex 08.09.2026). */
body.te5-owner .te5-owner-table td[data-owner-field="status"] .te5-chip {
  margin-right: 0;
}
/* 🛑 Числовые колонки — по ПРАВОМУ краю и моноширинными цифрами. Слева разряды не
   выстраиваются в столбик, и «48 125,00» против «4 375,00» глазом не сравнить; плюс
   левое выравнивание придвигало сумму вплотную к соседней, и две читались одним
   числом (снимок стенда 01.09.2026). Заголовок выравниваем ТЕМ ЖЕ правилом, иначе
   подпись уезжает от своего столбца цифр. */
/* 🛑 Свободный текст режется многоточием, а НЕ переносится. При `table-layout: fixed`
   одно длинное слово («Каналопромывка») не переносится в принципе и вылезает поверх
   соседней колонки — на снимке стенда 01.09.2026 название техники наехало на часы.
   Перенос сюда не годится: строки станут разной высоты от одного редкого значения,
   а «АО Дорстрой» в две строки уже забраковали. Полное значение живёт в `title`. */
body.te5-owner .te5-owner-table td:is([data-owner-field="customer"],
  [data-owner-field="equipment_type"], [data-owner-field="note"]) {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.te5-owner .te5-owner-table :is(td, th):is([data-owner-field="hours"],
  [data-owner-field="extra_trips"], [data-owner-field="rate"],
  [data-owner-field="potential"], [data-owner-field="revenue"]) {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
body.te5-owner .te5-owner-table th:is([data-owner-field="hours"],
  [data-owner-field="extra_trips"], [data-owner-field="rate"],
  [data-owner-field="potential"], [data-owner-field="revenue"]) .te5-owner-th__btn {
  width: 100%;
  justify-content: flex-end;
}
/* 🛑 Бейдж статуса НЕ переносится: «Нет водителя» в две строки ломал ритм таблицы
   (замечание Егора 01.09.2026). Место под него освободила снятая колонка действий —
   колонка статуса выросла с 9% до 13% в `colgroup`. */
body.te5-owner .te5-owner-status {
  font-size: 16px;
  white-space: nowrap;
}

/* ── /console/owner: сводка периода ───────────────────────────────────────────
   Фильтр периода стоит выше сводки по прямому решению тимлида 01.09.2026:
   сначала задают границы вопроса, затем читают ответ. Сводка остаётся mobile-first.
   🛑 Ни одного нового токена и ни одного зашитого hex: цвет полос берётся только
   из `--te5-ok`, `--te5-open` и `--te5-row-ln`, а они переопределены во всех темах.
   Литерал молча выпал бы из тёмной темы и из гейта контраста.
   🛑 Синий акцент здесь не используем НАМЕРЕННО: он у нас означает ДЕЙСТВИЕ,
   а полосы — данные.
   🛑 А вот прежний запрет на цвета состояний СНЯТ 01.09.2026 (Егор просил цвет):
   строки разбора недобора — это те же самые статусы, что в таблице, и там они уже
   янтарные. Нейтральный серый разводил одно и то же понятие по двум видам, и человек
   не связывал полоску с бейджем. Возвращать серый — только вместе с бейджами. */
/* ── Фильтр периода: быстрые кнопки + компактный диапазон ─────────────────────
   Подписи «С»/«По» сняты (тире между полями читается само), поля получили ЯВНУЮ
   ширину. 🛑 Явная ширина не косметика: `<input type="date">` — самый
   платформозависимый контрол, его собственная ширина в Chrome под macOS и под
   Linux разная, и раскладка, положившаяся на неё, разъезжается между машинами. */
body.te5-owner .te5-owner-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--te5-gap-controls) var(--te5-gap-group);
}
/* Поле, ставшее обязательным ПРЯМО СЕЙЧАС: тронули «Часы» — «Примечание» подсвечивается.
   Рамкой, а не цветом текста: порог для границы поля ввода 3.0, для текста 4.5, и
   предупреждающий тон на эту роль по тексту не проходит (`test_console_contrast_gate`). */
.te5-input--needed { border-color: var(--te5-warning-ln); box-shadow: 0 0 0 2px var(--te5-warning-bg); }
/* Поле, чьё значение НЕ ПРОШЛО проверку (ИНН с неверной контрольной цифрой, заглушка из
   нулей). Тем же приёмом, что и `--needed`: рамкой, а не цветом текста — у границы поля
   ввода порог контраста 3.0, у текста 4.5, и красный тон на текст поля не проходит. */
.te5-input--wrong { border-color: var(--te5-bad-ln); box-shadow: 0 0 0 2px var(--te5-bad-bg); }

/* ---------- сортировка реестра (TE-224) ---------- */
/* Переключатель — единственный способ сортировать с телефона: ниже 900px `thead` скрыт
   целиком, заголовков там нет вовсе.
   🛑 Стоит СВОИМ блоком между сводкой и списком, а не рядом внутри карточки фильтров
   (решение владельца 02.09.2026): там он был третьим рядом и отжимал сводку с таблицей
   на второй экран телефона. `flex: 1 1 100%` снят вместе с переездом — растягиваться
   больше не в чем, блок и так во всю ширину. */
body.te5-owner .te5-owner-sort {
  display: flex; align-items: center; gap: var(--te5-gap-tight); min-width: 0;
  margin: 0 0 12px;
}
body.te5-owner .te5-owner-sort__label { flex: none; font-size: 16px; color: var(--te5-text-2); }
body.te5-owner .te5-owner-sort__section, body.te5-owner .te5-owner-sort__count { display: none; }
/* 🛑 44px — тап-цель, а не декор: это единственный способ сортировать касанием (шапка
   таблицы в «Плашках» скрыта). Замер 02.09.2026 — общий `.te5-select` давал 38px. */
body.te5-owner .te5-owner-sort__select { flex: 1 1 auto; min-width: 0; min-height: 44px; }
body.te5-owner .te5-owner-show-deleted {
  display: inline-flex; align-items: center; gap: 8px; min-height: 34px;
  color: var(--te5-text-2); font-size: 16px;
}
@media (min-width: 1024px) { body.te5-owner .te5-owner-sort__select { max-width: 340px; } }

/* 🛑 Порог 769px — ровно тот, ниже которого `thead` таблицы скрыт целиком (см. блок
   `@media (max-width: 768px)`). Выше него сортируют заголовки-кнопки, и переключатель
   становится вторым контролом на то же действие — владелец 08.09.2026 попросил его убрать
   именно поэтому. Из разметки он НЕ удалён: ниже порога он единственный способ сортировать
   касанием. */
@media (min-width: 769px) {
  body.te5-owner .te5-owner-sort__label[for="ownerSort"],
  body.te5-owner .te5-owner-sort__select#ownerSort { display: none; }
  /* «Записей: N» и «+ Добавить строку» стоят ПАРОЙ у правого края (решение владельца
     08.09.2026). 🛑 Распор держит только счётчик: два `margin-left: auto` в одной флекс-строке
     делят свободное место ПОПОЛАМ, и счётчик повисал посреди ряда — ровно на это владелец и
     показал. `order` вместо перестановки в разметке: на телефоне кнопка остаётся первой, а её
     положение там пинится отдельным сценарием фикс-панели. */
  body.te5-owner .te5-owner-actions__bar [data-registry-add] { order: 99; margin-left: 0; }
  body.te5-owner .te5-owner-count { order: 98; }
  /* 🛑 Поля ячеек реестра — 10px, а не общие 16px кита, и это арифметика, а не вкус.
     Ширина таблицы упёрта в `.te5-main` (max-width 1280px минус поля 24px = 1230px) и от
     монитора НЕ зависит; колонок после «Доп. рейса» стало двенадцать, то есть 32px полей
     на ячейку — это 384px, треть всей строки, отданная пустоте.
     Замер стенда 08.09.2026 ДО правки (1440px, реальные данные парка): подпись «Доп. рейс»
     занимает 62.6px при 22.8px свободного места в кнопке-заголовке, и 23.8px из неё
     ВЫЛЕЗАЕТ за границу своей ячейки. Видно это потому, что в таблице сначала рисуются
     фоны ВСЕХ ячеек и только потом их содержимое: чужой текст ложится поверх соседа, и две
     подписи читаются одной кашей. Тем же способом «Часы» наезжали на «Технику» на 6.8px.
     🛑 Поле заголовка и поле ячейки обязаны быть РАВНЫ: подпись стоит над своим столбцом
     значений, и разные поля увели бы её от него ровно на разницу. Правится ПАРОЙ.
     Приём в ките не новый: телефонная «Таблица» ужимает кнопку-заголовка до 12px по этой
     же причине («треки узкие, 16px с двух сторон съедали подпись»), консоль заявок —
     до 8px (`body.te5-order .te5-table`). Ниже 769px правило не действует намеренно:
     там у обоих режимов своя геометрия и свои замеры. */
  body.te5-owner .te5-owner-table--registry :is(th, td) {
    padding-left: 10px;
    padding-right: 10px;
  }
  body.te5-owner .te5-owner-table--registry .te5-owner-th__btn {
    padding-left: 10px;
    padding-right: 10px;
  }
}

/* Заголовок-кнопка. Отступы держит кнопка, а не ячейка: иначе область нажатия меньше
   видимого заголовка, и промах по краю выглядит как «сортировка не работает». */
body.te5-owner .te5-owner-table th.te5-owner-th { padding: 0; }
body.te5-owner .te5-owner-th__btn {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  width: 100%; padding: 8px 16px; border: 0; border-bottom: 2px solid transparent;
  background: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
body.te5-owner .te5-owner-th__btn:hover { background: var(--te5-row-hover); }
/* Каретка ПАРНАЯ и в покое (`⇅`): без неё ничем не показано, что заголовок нажимаем. */
body.te5-owner .te5-owner-th__glyph { flex: none; font-size: 16px; opacity: .5; }
/* 🛑 Активная колонка помечена ТРЕМЯ носителями, и это не украшение. Одной заливки НЕ
   ХВАТАЕТ: в тёмной теме `--te5-primary-bg` (#344659) на шапке `--te5-surface-raised`
   (#424e5f) даёт контраст 1.15 при пороге 3.0 для графики — признака не видно вовсе.
   Линия акцентом на той же шапке даёт 4.15 и держит признак там, где заливка пропала.
   🛑 Подпись НЕ красим `--te5-primary`: на шапке это 4.15 при пороге 4.5 для ТЕКСТА,
   то есть провал `test_console_contrast_gate`. Акцент живёт на линии и каретке. */
body.te5-owner .te5-owner-th--sorted .te5-owner-th__btn {
  background: var(--te5-primary-bg); border-bottom-color: var(--te5-primary);
}
body.te5-owner .te5-owner-th--sorted .te5-owner-th__glyph { opacity: 1; }

body.te5-owner .te5-owner-presets { display: flex; flex-wrap: wrap; gap: var(--te5-gap-tight); }
body.te5-owner .te5-owner-range {
  display: flex;
  align-items: center;
  gap: var(--te5-gap-tight);
  flex-wrap: wrap;
}
body.te5-owner .te5-owner-range__input { width: 168px; flex: none; }
body.te5-owner .te5-owner-range__dash { color: var(--te5-muted); }
body.te5-owner #ownerApply { margin-left: auto; }

body.te5-owner .te5-owner-pager {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: center;
  gap: var(--te5-gap-tight);
  padding: 14px 16px;
  border-top: 1px solid var(--te5-row-ln);
  overflow-x: auto;
}
body.te5-owner .te5-owner-pager__size {
  width: auto;
  min-width: 60px;
  font-size: 16px;
}
body.te5-owner .te5-owner-pager .te5-btn {
  flex: 0 0 36px;
  width: 36px;
  min-width: 36px;
  padding: 0;
}
body.te5-owner .te5-owner-pager__label {
  font-size: 16px;
  color: var(--te5-text-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
body.te5-owner .te5-owner-count { margin-left: auto; }

/* Таблица лежит в карточке, как и фильтр: голое полотно посреди страницы читалось
   как «что-то не догрузилось». Прокрутка остаётся у внутреннего контейнера. */
body.te5-owner .te5-owner-tablecard { padding: 0; overflow: hidden; }
/* На «Парке» между фильтром и таблицей стоит ряд действий и зазор даёт он. У фидов ряда
   нет, и две карточки склеивались в одну с разорванной рамкой. */
body.te5-owner .te5-filter-panel + .te5-owner-tablecard { margin-top: var(--te5-gap-group); }


/* 🛑 Вертикальный ритм тела задаётся ОДНИМ правилом, а не каждым блоком по-своему: до
   08.09.2026 зазоры были 12/14/16 вперемешку, и карточки читались слипшимися (кадры
   владельца). Селектор с id перебивает частные `margin-bottom` соседей намеренно — один
   источник ритма вместо шести; действует на всех трёх вкладках, включая «Фитинги» и «ГНБ».
   Схлопывание с `margin-top` соседа (`.te5-actions-row--block`) оставляет те же 20px. */
body.te5-owner #ownerBody > * { margin-bottom: var(--te5-gap-group); }
body.te5-owner #ownerBody > *:last-child { margin-bottom: 0; }

body.te5-owner .te5-owner-summary { margin-bottom: 12px; }
body.te5-owner .te5-owner-summary__head {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 10px;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.35;
  color: var(--te5-text-2);
}
body.te5-owner .te5-owner-summary__money {
  font-size: 30px;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--te5-text);
  font-variant-numeric: tabular-nums;
}
body.te5-owner .te5-owner-bar-row {
  display: flex;
  align-items: center;
  /* 🛑 Не меньше 16px: на 10px «37 %» читалось продолжением самой полосы, а это
     ДРУГАЯ величина — доля, а не деньги (замечание Серёжи 01.09.2026). */
  gap: 18px;
  margin-top: 14px;
}
body.te5-owner .te5-owner-bar {
  /* 🛑 Полоса УЖИМАЕТСЯ, потолок задаёт `max-width`. Прежние `flex: none` + фиксированные
     320px не влезали в свою колонку вместе с долей, и «37 %» наезжало на соседний блок
     (замечание Серёжи 01.09.2026). Ширина всё равно не зависит от содержимого — её
     держат `flex-basis` и потолок, а не длина текста внутри. */
  flex: 1 1 auto;
  max-width: 320px;
  min-width: 0;
  height: 16px;
  border-radius: 999px;
  background: var(--te5-row-ln);
  overflow: hidden;
}
body.te5-owner .te5-owner-bar__fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  /* 🛑 Градиента здесь НЕТ, и это отмена правки от 01.09.2026, а не забытый хвост:
     осветление токена белым даёт грязный оттенок (у янтарной полосы ниже вышло
     кофейно-коричневое), а полоса и так несёт ровно одну величину — второй тон ей
     нечего кодировать. Возвращать градиент — только вместе с ответом, ЧТО он значит. */
  background: var(--te5-ok);
}
body.te5-owner .te5-owner-bar-row__share {
  flex: none;
  font-size: 16px;
  font-weight: 700;
  color: var(--te5-text);
  font-variant-numeric: tabular-nums;
}
body.te5-owner .te5-owner-summary__sub {
  margin: 22px 0 10px;
  font-size: 16px;
  font-weight: 700;
  color: var(--te5-text);
}
body.te5-owner .te5-owner-summary__note {
  margin: 16px 0 0;
  font-size: 16px;
  color: var(--te5-text-2);
}
body.te5-owner .te5-owner-break {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 12px;
}
body.te5-owner .te5-owner-break__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 3px 10px;
}
body.te5-owner .te5-owner-break__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 16px;
  color: var(--te5-text-2);
}
body.te5-owner .te5-owner-break__value {
  font-size: 16px;
  font-weight: 600;
  color: var(--te5-text);
  font-variant-numeric: tabular-nums;
}
body.te5-owner .te5-owner-break__track {
  grid-column: 1 / -1;
  width: 100%;
  height: 12px;
  border-radius: 999px;
  background: var(--te5-row-ln);
  overflow: hidden;
}
body.te5-owner .te5-owner-break__fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  /* 🛑 Нейтральный `--te5-open`, а НЕ янтарь и не цвет состояния. Две причины, обе
     ловятся только глазами. Первая: #8a5f0c крупной заливкой читается коричневым, и
     такого пятна в интерфейсе нет больше нигде (замечание Серёжи 01.09.2026). Вторая
     важнее: ТЕМ ЖЕ классом красятся «Выручка по заказчикам» и «Часы по статусам», а
     выручка — не предупреждение. Красить эти полосы по смыслу можно только после того,
     как у каждого из трёх разборов появится свой класс. */
  background: var(--te5-open);
}
body.te5-owner .te5-owner-summary__meta {
  margin: 18px 0 0;
  font-size: 16px;
  color: var(--te5-muted);
  font-variant-numeric: tabular-nums;
}
/* Деньги и часы не переносим по словам: «5 250,00 ₽» ломалось на «5 250,00» и «₽»
   отдельной строкой, и колонка читалась как две. Таблица лежит в `te5-table-scroll`,
   так что лишняя ширина уходит в прокрутку, а не в обрезку. */
body.te5-owner .te5-owner-table td[data-owner-field="hours"],
body.te5-owner .te5-owner-table td[data-owner-field="rate"],
body.te5-owner .te5-owner-table td[data-owner-field="revenue"],
body.te5-owner .te5-owner-table td[data-owner-field="potential"] {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* На широком мониторе сводка раскладывается в две колонки: слева ответ (сколько
   заработано и какая это доля), справа разбор недобора. Одна колонка оставляла
   справа полэкрана пустоты и растягивала полосу на 1400px — растянутая дорожка
   перестаёт показывать долю формой. Блок скоупен `body.te5-owner`, поэтому
   выверенный масштаб водителя он не задевает. */
/* Разборы (недобор, заказчики, статусы) — одинаковые по устройству блоки, поэтому
   раскладываются автоматически: на телефоне столбиком, на мониторе в ряд, сколько
   поместится. Числа колонок нигде не зашито. */
body.te5-owner .te5-owner-summary__breaks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 4px var(--te5-gap-group);
  align-items: start;
}
body.te5-owner .te5-owner-summary__breaks > * { min-width: 0; }
body.te5-owner .te5-owner-summary__segments { display: none; }

@media (min-width: 1024px) {
  body.te5-owner .te5-owner-summary .te5-card__body {
    display: grid;
    grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
    grid-template-rows: auto auto 1fr;
    align-items: start;
    gap: 4px 48px;
    max-width: 1280px;
  }
  body.te5-owner .te5-owner-summary__head { grid-column: 1; grid-row: 1; }
  body.te5-owner .te5-owner-bar-row { grid-column: 1; grid-row: 2; }
  body.te5-owner .te5-owner-summary__meta { grid-column: 1; grid-row: 3; }
  body.te5-owner .te5-owner-summary__breaks { grid-column: 2; grid-row: 1 / span 3; }
}

.te5-reg { font-family: var(--te5-mono); font-weight: 600; font-size: 13px; }
/* Госномер в разнарядке — то, по чему диспетчер узнаёт машину: акцент и вес,
   чтобы он читался первым в строке (правка владельца 04.08). Кегль поднят
   с 13 до 15px: строк 28, и номер сканируют глазами сверху вниз. */
.te5-reg--accent { color: var(--te5-primary); font-weight: 700; font-size: 15px; letter-spacing: 0.02em; }
/* Буквенный хвост госномера — тот же вес, обычный цвет: акцент нужен цифрам,
   именно их диспетчер выхватывает глазом (правка владельца 04.08). */
.te5-reg--tail { color: var(--te5-text); font-weight: 700; font-size: 15px; letter-spacing: 0.02em; }
.te5-raw { white-space: pre-wrap; word-break: break-word; font-family: var(--te5-mono); font-size: 13px; margin: 0; }
/* Блоки разбора шли встык — тот же шаг, что между плашками и «Создать смены». */
#orderResult > .te5-card + .te5-card { margin-top: 16px; }
#orderResult > .te5-card:first-child { margin-top: 16px; }
.te5-sub { font-size: 11.5px; color: var(--te5-muted); }
/* Текст только для скринридера. `position: absolute` обязателен: узел бывает
   прямым ребёнком grid/flex-контейнера и иначе занял бы ячейку. */
.te5-visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------- chips ---------- */

.te5-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px; border-radius: 999px;
  font-size: 12px; font-weight: 600; white-space: nowrap;
  color: var(--te5-neutral); background: var(--te5-neutral-bg); border: 1px solid var(--te5-neutral-ln);
}
/* Чип с текстом ПРОИЗВОЛЬНОЙ длины (серверная причина отказа): базовый
   `white-space: nowrap` раздувал бы его auto-трек и выталкивал соседнюю кнопку
   за край карточки. Для коротких статусов модификатор не нужен. */
.te5-chip--wrap { white-space: normal; text-align: left; }
.te5-chip--success { color: var(--te5-success); background: var(--te5-success-bg); border-color: var(--te5-success-ln); }
.te5-chip--warning { color: var(--te5-warning); background: var(--te5-warning-bg); border-color: var(--te5-warning-ln); }
.te5-chip--danger { color: var(--te5-danger); background: var(--te5-danger-bg); border-color: var(--te5-danger-ln); }
.te5-chip--info { color: var(--te5-info); background: var(--te5-info-bg); border-color: var(--te5-info-ln); }
.te5-chip--neutral { color: var(--te5-neutral); background: var(--te5-neutral-bg); border-color: var(--te5-neutral-ln); }

/* ---------- регуляторный режим (TE-9 MVP v1) ----------
   Класс `no-epl` ставит JS на <html> по GET /api/v1/app-config
   (epl_regulatory_enabled=false). Прячет регуляторные хвосты (ЭПЛ-бейджи,
   колонку ЭПЛ, «Подписание», «Создать ЭПЛ-черновик»). Работает на <td>/<th>/
   <span>/<a>/<button>/<label> одинаково. !important — перебить inline-display. */
.no-epl .epl-only { display: none !important; }
/* Класс `no-admin` ставит JS по GET /console/whoami (is_admin=false / ошибка / до ответа).
   Прячет admin-only пункты навбара («Учёт техники»). Реальная защита — 403 на роуте. */
.no-admin .admin-only { display: none !important; }

/* ---------- buttons ---------- */

.te5-btn {
  font: inherit; font-size: 13.5px; font-weight: 600; background: var(--te5-card); color: var(--te5-text);
  border: 1px solid var(--te5-input-ln); border-radius: var(--te5-radius-control); padding: 9px 16px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; text-decoration: none; white-space: nowrap;
}
.te5-btn:hover { background: var(--te5-hover-bg); }
.te5-btn.is-active { background: var(--te5-primary-bg); color: var(--te5-primary); border-color: var(--te5-primary-ln); }
.te5-btn:disabled { opacity: .55; cursor: not-allowed; background: var(--te5-card); color: var(--te5-text-2); }
.te5-btn:disabled:hover { background: var(--te5-card); }
.te5-btn--primary { background: var(--te5-primary); color: var(--te5-on-primary); border-color: var(--te5-primary); }
.te5-btn--primary:hover { background: var(--te5-primary-hover); }
.te5-btn--danger { color: var(--te5-danger); border-color: var(--te5-danger-ln); }
.te5-btn--danger:hover { background: var(--te5-danger-bg); }
.te5-btn--success {
  color: var(--te5-success); border-color: var(--te5-success); background: var(--te5-success-bg);
}
.te5-btn--success:hover {
  background: var(--te5-success-bg); box-shadow: 0 0 0 3px var(--te5-success-ln);
}
/* Предупреждающая кнопка (сброс доступа водителя). 🛑 «Тусклой» её делал НЕ цвет
   текста, а ГРАНИЦА: `--te5-warn-ln` к карточке это 1.40 светлая / 1.39 тёмная при
   пороге 3.0 (WCAG 1.4.11) — обводки не было видно вовсе. Границу красит акцент
   (5.59 / 5.27), текст на заливке 5.06 / 5.58. Заливка `--te5-warn-bg` к карточке
   даёт всего 1.11 / 1.06 — она только тон, работу делает рамка.
   🛑 Подсветка при наведении — КОЛЬЦОМ, а не сменой фона: текст на `--te5-warn-ln`
   проваливается (4.01 светлая / 3.80 тёмная при пороге 4.5). */
.te5-btn--warning { color: var(--te5-warning); border-color: var(--te5-warning); background: var(--te5-warning-bg); }
.te5-btn--warning:hover { background: var(--te5-warning-bg); box-shadow: 0 0 0 3px var(--te5-warning-ln); }
.te5-btn--ghost { border: none; background: none; color: var(--te5-primary); padding: 6px 8px; }
.te5-btn--ghost:hover { background: var(--te5-primary-bg); }
.te5-btn--sm { padding: 5px 10px; font-size: 12.5px; }
/* Кнопка-стрелка «назад» слева от заголовка (карточка листа, 10.09.2026). Видимый квадрат
   небольшой, а цель нажатия расширена невидимым `::before` — тем же приёмом, что у значка
   подсказки `te5-hint`: уменьшая квадрат, его не трогать. Подпись живёт в `aria-label`,
   поэтому текста внутри нет и контраст меряется по самой стрелке. */
/* Кнопка-иконка кита — ОДИН вид на все случаи (решение владельца 10.09.2026:
   «обнови кит, чтоб единый стиль они все использовали»). Общее здесь — рамка,
   скругление, выравнивание и поведение при наведении; габарит и кегль у каждой
   свои: стрелка стоит в строке шапки, значок подсказки — в углу карточки.
   🛑 Правило объявлено ОДНИМ селектором намеренно: две похожие копии разъезжаются
   молча, и «единый стиль» перестаёт быть правдой при первой же правке одной из них. */
.te5-iconbtn,
.te5-hint__btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  flex: none;
  border: 1px solid var(--te5-border);
  border-radius: var(--te5-radius-panel, 8px);
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
}
/* Стрелка «назад» ростом с кнопку темы и «Выйти» — они стоят одной строкой, и
   30px рядом с их 38px читались как случайно уменьшенная кнопка. */
.te5-iconbtn {
  width: 38px;
  height: 38px;
  background: var(--te5-card);
  color: var(--te5-text);
  font-size: 17px;
}
/* 🛑 Цель нажатия задаётся ЧИСЛОМ, а не отрицательным `inset`: абсолютный потомок
   считает края от PADDING-box родителя, поэтому вычитание из порога даёт на два
   пикселя меньше — замер кита поймал это на живой странице. */
.te5-iconbtn::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}
.te5-iconbtn:hover,
.te5-hint__btn:hover { border-color: var(--te5-primary-ln); color: var(--te5-primary); }
/* 🛑 Своё правило для `[hidden]` обязательно: у обёртки нет своего `display`, но правило
   рядом может появиться, а браузерное `[hidden]` проигрывает любому классу с `display`. */
.te5-wip[hidden] { display: none !important; }
/* «Выйти» стоит вплотную к кнопке темы — это одна пара, а не две разные кнопки:
   габарит и скругление берутся от `.te5-theme-toggle` (38px / 10px). Кегль
   поднят с 12.5 до 15px: аудитория 40+, мелкая подпись в углу читается хуже
   всего. Подсветка при наведении — кольцом акцента, без смены фона. */
.te5-btn--logout {
  height: 38px;
  padding: 0 16px;
  border-radius: 10px;
  font-size: 15px;
  transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.te5-btn--logout:hover {
  border-color: var(--te5-primary);
  box-shadow: 0 0 0 3px var(--te5-primary-bg);
}
.te5-btn--block { width: 100%; min-height: 42px; }

.te5-spin {
  width: 14px; height: 14px; border: 2px solid rgba(255,255,255,.4); border-top-color: #fff;
  border-radius: 50%; display: inline-block; animation: te5spin .7s linear infinite;
}
.te5-btn:not(.te5-btn--primary) .te5-spin { border-color: rgba(29,99,181,.3); border-top-color: var(--te5-primary); }

/* ---------- forms ---------- */

.te5-field { display: flex; flex-direction: column; gap: 5px; }
.te5-field > span { font-size: 12px; font-weight: 600; color: var(--te5-text-2); }
.te5-input, .te5-select {
  height: 38px; border: 1px solid var(--te5-input-ln); border-radius: var(--te5-radius-control); padding: 0 12px;
  font: inherit; font-size: 14px; outline-color: var(--te5-primary); background: var(--te5-card); color: inherit; width: 100%;
}
.te5-input:hover, .te5-select:hover { background: var(--te5-hover-bg); }
.te5-input:focus, .te5-select:focus {
  background: var(--te5-card);
  border-color: var(--te5-primary);
  box-shadow: 0 0 0 2px var(--te5-primary-bg);
}
/* Chromium/Safari autofill иначе может выбелить поле в dark mode. */
.te5-input:-webkit-autofill {
  -webkit-text-fill-color: var(--te5-text);
  transition: background-color 9999s ease-out;
}
textarea.te5-input { height: auto; min-height: 72px; padding: 10px 12px; resize: vertical; }
.te5-form-row { display: flex; gap: 12px; flex-wrap: wrap; }
.te5-form-row .te5-field { flex: 1; min-width: 140px; }
/* Плотный ряд — для частей ОДНОГО реквизита, напечатанных на бланке в строку
   («Код 74 ЕЕ 200008»). Базовые 140px здесь не годятся: три поля по 140 не влезают в
   колонку ~340px и переносятся, разрывая номер по строкам. `min-width: 0` обязателен —
   без него flex-элемент не сжимается ниже своего min-content. */
.te5-form-row--tight { flex-wrap: nowrap; gap: 8px; }
.te5-form-row--tight .te5-field { flex: 1 1 0; min-width: 0; }
.te5-form-row--tight .te5-field--span2 { flex: 2 1 0; }

/* Набор галочек закрытого списка (категории самоходных машин). Метка кликабельна целиком —
   у неё `<label>` вокруг поля, поэтому попадать надо в текст, а не в квадратик 13px. */
.te5-checks { display: flex; flex-wrap: wrap; gap: 6px 14px; }
/* 🛑 Длинный список (объекты заказчика — замер на проде: 147 штук,
   4404px) прокручивается внутри себя, иначе он занимает 94% формы и хоронит поля
   над собой. Модификатором, а не всем группам: у категорий ВУ галочек девять,
   там прокрутка только мешала бы. */
.te5-checks--scroll {
  flex-direction: column;
  flex-wrap: nowrap;
  gap: 2px;
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--te5-border);
  border-radius: 8px;
  padding: 8px 10px;
}
.te5-checks--scroll .te5-check { padding: 2px 0; }
.te5-checks-search { margin-bottom: 6px; }
.te5-checks-empty { font-size: 12px; color: var(--te5-muted); padding: 4px 0; }
.te5-check {
  display: flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 13px; color: var(--te5-text); white-space: nowrap;
  /* Цель нажатия по вертикали — не меньше строки таблицы: диспетчер отмечает девять
     галочек подряд мышью, и промах стоит ему повторного прохода по бумажке. */
  min-height: 24px;
}
.te5-check input { accent-color: var(--te5-primary); }
/* 🛑 Авторский `display: flex` выше перебивает браузерное `[hidden]`, и строка,
   скрытая поиском, остаётся на экране: фильтр выглядит сломанным. */
.te5-check[hidden] { display: none; }

/* Горизонтальные табы справочников: одна строка на мобиле, без съезда второй
   строкой и без левого внутреннего скролла страницы. */
.te5-tabs {
  display: flex;
  gap: 6px;
  margin-bottom: 16px;
  flex-wrap: wrap;
  max-width: 100%;
}

/* ---------- states ---------- */

.te5-empty { padding: 56px 24px; text-align: center; }
.te5-empty__title { font-size: 15px; font-weight: 600; }
.te5-empty__text { font-size: 13px; color: var(--te5-muted); margin-top: 6px; line-height: 1.5; }

/* ---------- hint: значок «i» в углу карточки ---------- */
/* Решение владельца 03.09.2026: длинные пояснения на карточке прячутся за значком «i» в
   правом верхнем углу (как в «Журнале надзора»); тап по значку открывает окно, закрывают
   крестик в углу окна, тап по затемнению и Esc. Разметка и поведение —
   `frontend/scripts/te5-hint.js`: окно — нативный `<dialog>` через `showModal()` (top
   layer, `::backdrop`, ловушка фокуса от браузера), без `showModal` — атрибут `open`.
   Значок — скруглённый КВАДРАТ токеном кита, не кружок и не чип, буква прямая шрифтом
   страницы (по кадру с iPhone: «слишком большая» и курсив); видимый квадрат небольшой, а
   цель нажатия ≥44px даёт невидимый `::before` вокруг него. Крестик окна — тот же квадрат
   (`.te5-hint__btn--close`). На поверхности водителя/прораба `driver.css` подгоняет их
   под свои кнопки. */
.te5-hint-host { position: relative; }
/* Заголовок карточки не заезжает под значок; у центрированного пустого состояния отступ
   симметричный, иначе текст съедет с середины. */
.te5-hint-host > .te5-card__body > :first-child { padding-right: 44px; }

/* Строка «ключ — значение» в карточках прораба и заказчика (`customer.js::kv`).
   🛑 Здесь только ГРАНИЦА: отступы и высота строки заданы инлайном из JS, потому
   что на них завязаны поля круглых кнопок внутри строки. Последняя строка блока
   черты не несёт — под ней уже край карточки, и отделять ею нечего (TE-420). */
.te5-kv-row { border-bottom: 1px solid var(--te5-row-ln); }
.te5-kv-row:last-child { border-bottom: none; }
.te5-hint-host > .te5-card__head { padding-right: 54px; }
.te5-hint-host > .te5-empty { padding-left: 44px; padding-right: 44px; }
/* Без `z-index`: свой контекст наложения запер бы запасное окно (z 60) внутри карточки —
   под липкой шапкой водителя/прораба (z 5). Абсолютный блок и так рисуется над потоком
   карточки. */
.te5-hint { position: absolute; top: 12px; right: 12px; }
/* Вид и наведение берутся от общей кнопки-иконки (объявлена выше, рядом с
   `.te5-iconbtn`) — здесь только своё: мелкий квадрат угла карточки и кегль буквы. */
.te5-hint__btn {
  width: 28px; height: 28px;
  background: var(--te5-surface-raised); color: var(--te5-muted);
  font: inherit; font-size: 14px; font-weight: 700; font-style: normal;
}
/* Невидимая область нажатия: на экране квадрат мелкий, а палец попадает по расширению.
   🛑 Арифметика НЕ «28 + 2×8 = 44»: абсолютный потомок считает края от PADDING-box, и
   рамка 1px съедает два пикселя — замер попаданием 10.09.2026 дал здесь 42px. Нормы это
   не роняет: единственный потребитель значка (`customer.html`) идёт в полевой оболочке,
   где `driver.css` поднимает квадрат до 32px, то есть цель 46px. Уменьшишь квадрат или
   снимешь полевую оболочку — считай заново попаданием, а не вычитанием `inset`. */
.te5-hint__btn::before { content: ""; position: absolute; inset: -8px; }
/* Окно — `<dialog>` БЕЗ внутренних отступов (они на `.te5-hint__body`): тогда клик с
   `e.target === dialog` может прийти только с затемнения, и тап мимо окна закрывает его,
   не проваливаясь к элементу под пальцем. Скрыто, пока не открыто: `[open]` ставит
   `showModal()` либо запасной путь скрипта; `z-index` — для запасного пути без top layer.
   Свою обводку фокуса кнопкам не задаём — системная видна на карточке. (Слово-селектор
   фокуса в этот комментарий не писать: гейт фокуса читает CSS без вырезания комментариев.) */
.te5-hint__panel {
  position: fixed; inset: 0; margin: auto;
  width: min(420px, calc(100vw - 32px)); max-width: none; height: fit-content; max-height: 80vh; overflow: auto;
  padding: 0;
  border: 1px solid var(--te5-border); border-radius: var(--te5-radius-panel);
  background: var(--te5-surface-raised); color: var(--te5-text);
  box-shadow: var(--te5-shadow-float);
  font-size: 15px; line-height: 1.5; text-align: left;
  z-index: 60;
}
.te5-hint__panel:not([open]) { display: none; }
.te5-hint__panel[open] { display: block; }
.te5-hint__panel::backdrop { background: rgba(2, 7, 15, .45); }
.te5-hint__body { padding: 18px 20px; }
/* Тело окна получает начальный фокус вместо крестика (`te5-hint.js`): это контейнер, а не
   интерактив, и рисовать на нём кольцо незачем — на iPhone оно обводило крестик при каждом
   открытии (владелец 03.09.2026). Гашение законно только у контейнера; крестик и Tab по нему
   кольцо сохраняют. Допуск — `_OUTLINE_SUPPRESSION_ALLOWED` в контраст-гейте. */
.te5-hint__body:focus { outline: none; }
/* Крестик — в том же углу и того же вида, что значок «i» на карточке (владелец 03.09.2026). */
.te5-hint__btn--close { position: absolute; top: 12px; right: 12px; font-size: 18px; }
.te5-hint__title { margin: 0 0 8px; padding-right: 36px; font-size: 16px; font-weight: 700; }
.te5-hint__body p { margin: 0; }
.te5-hint__body p + p { margin-top: 8px; }
.te5-error { padding: 48px 24px; text-align: center; }
.te5-error__title { font-size: 15px; font-weight: 600; color: var(--te5-danger); }

.te5-skel { background: var(--te5-border-2); border-radius: 6px; animation: te5pulse 1.2s ease-in-out infinite; height: 36px; }
.te5-skel--sm { height: 14px; }

/* 🛑 «Уменьшить движение» — системная настройка, и включают её люди, которым от
   мигания физически плохо (вестибулярные расстройства, WCAG 2.3.3 / 2.2.2).
   В te5.css бесконечных анимаций две — скелетон и спиннер — и guard'а не было
   НИ ОДНОГО: водитель был защищён своим слоем (driver.css), а диспетчер нет.
   Анимации не выключаем совсем, а обездвиживаем: индикатор обязан остаться
   видимым, иначе «загружается» превратится в «пустой экран».
   Держим `1` итерацию, а не `none`: первый кадр отрисуется, движения не будет. */
@media (prefers-reduced-motion: reduce) {
  .te5-skel,
  .te5-nav__skel,
  .te5-spin {
    animation-duration: .01ms;
    animation-iteration-count: 1;
  }
}

.te5-banner { border-radius: var(--te5-radius-control); padding: 9px 12px; font-size: 13px; margin-bottom: 14px; line-height: 1.45; }
.te5-banner--danger { background: var(--te5-danger-bg); border: 1px solid var(--te5-danger-ln); color: var(--te5-danger); }
.te5-banner--warning { background: var(--te5-warning-bg); border: 1px solid var(--te5-warning-ln); color: var(--te5-warning); }
.te5-banner--success { background: var(--te5-success-bg); border: 1px solid var(--te5-success-ln); color: var(--te5-success); }
.te5-banner--info { background: var(--te5-info-bg); border: 1px solid var(--te5-info-ln); color: var(--te5-info); }

/* ---------- toasts ---------- */

.te5-toasts { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 100; display: flex; flex-direction: column; gap: 8px; align-items: center; pointer-events: none; }
/* Контейнер тостов поднят в top layer через popover (иначе он уходит под ::backdrop
   открытой модалки). UA даёт popover'у свою рамку, фон и раскладку по центру —
   гасим их и возвращаем нашу позицию у нижнего края. */
.te5-toasts:popover-open { inset: auto auto 20px 50%; margin: 0; border: 0; padding: 0; background: transparent; overflow: visible; }
/* 🛑 Тост — токен, а не хардкод: он отделялся от фона тем, что СВЕТЛЕЕ полотна,
   а после подъёма тёмного полотна (#13161c → #1b2027) прежний #232936 давал к нему
   1.12 — то есть тост переставал существовать как отдельная поверхность. */
.te5-toast {
  background: var(--te5-toast-bg); color: #fff; border-radius: var(--te5-radius-card); padding: 10px 18px; font-size: 13.5px;
  box-shadow: var(--te5-shadow-md); max-width: min(560px, 90vw);
}
.te5-toast--danger { background: var(--te5-bad); }

/* ---------- service-worker update banner ---------- */

/* 🛑 Плашка живёт ВНУТРИ липкой шапки (`#driverHead` / `.te5-header`), а не поверх
   экрана снизу — решение владельца 03.09.2026 (TE-313): внизу «её не видно». Внутри
   шапки она липнет вместе с навбаром и берёт его ширину; фон — синий кнопки, текст —
   цвет надписи на кнопке (пара уже под контраст-гейтом). `z-index` — над панелью меню,
   которая выезжает из-под шапки (у прораба 2, в консоли подложка `::after` на 1).
   Кнопки — свои, с панельным (квадратным) скруглением, а не мелкие чипы `te5-btn--sm`. */
.te5-sw-update {
  position: relative;
  z-index: 3;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 12px;
  min-height: 60px;
  /* Отступ снизу равен отступу сверху (владелец 03.09.2026): плашка стоит между шапкой и
     первой карточкой, и ей нужен воздух с обеих сторон. */
  margin: 10px 0;
  padding: 12px 16px;
  border-radius: 16px;
  background: var(--te5-primary);
  color: var(--te5-on-primary);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
}
/* Консоль: полоса на всю ширину шапки, без скругления и отступа; текст и кнопки
   выровнены по контенту шапки — `.te5-header__inner` это 1280px по центру с полями
   24px, поэтому боковое поле плашки = поле до контента + 24px (владелец 03.09.2026). */
.te5-header > .te5-sw-update { margin: 0; border-radius: 0; padding: 10px max(24px, calc((100% - 1280px) / 2 + 24px)); }
/* Запасной путь: страница без шапки — фиксируем СВЕРХУ, не снизу. */
.te5-sw-update--fixed {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9999;
  margin: 0;
  border-radius: 0;
  /* В PWA без адресной строки верх экрана занят статус-баром — отступ под него. */
  padding-top: calc(12px + env(safe-area-inset-top, 0px));
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
}
.te5-sw-update__text { flex: 1 1 auto; min-width: 0; }
/* Кнопки — одним рядом: на узком экране уходят на вторую строку ВМЕСТЕ, вправо. */
.te5-sw-update__actions { display: flex; gap: 8px; margin-left: auto; }
.te5-sw-update__btn {
  appearance: none;
  min-height: 44px;
  padding: 10px 16px;
  border: 2px solid var(--te5-on-primary);
  border-radius: var(--te5-radius-panel);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.te5-sw-update__btn--reload { background: var(--te5-on-primary); color: var(--te5-primary); }
.te5-sw-update__btn--later { background: transparent; color: var(--te5-on-primary); }
/* Свой индикатор фокуса на синей подложке — ДВОЙНОЕ кольцо (владелец 03.09.2026):
   внутреннее цветом карточки отделяет кнопку от синего, внешнее синим кнопки видно на
   любой карточке — так одно правило проходит и контраст-гейт (он мерит против фонов
   карточки и полотна), и глаз на самой плашке. */
.te5-sw-update__btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--te5-card), 0 0 0 5px var(--te5-primary); }

/* ---------- форма одной смены (TE-380, 28.09.2026) ---------- */
.te5-create { max-width: 900px; min-width: 0; }
.te5-create .te5-form-row + .te5-form-row { margin-top: 12px; }
.te5-create__when { align-items: end; }
.te5-create__when .te5-field { flex: 0 1 280px; }
.te5-create__period { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0; }
.te5-create__period .te5-btn { height: 38px; }
.te5-create__points { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.te5-create__point { align-items: end; }
.te5-create__point .te5-create__object { flex: 3 1 260px; }
.te5-create__point .te5-create__time { flex: 0 1 150px; }
.te5-create__remove { flex: none; height: 38px; }
.te5-create__add { margin-top: 10px; }
.te5-create__quick { margin-top: 14px; }
.te5-create__quick summary { color: var(--te5-primary); font-size: 13px; font-weight: 700; cursor: pointer; }
.te5-create__quick .te5-form-row { margin-top: 12px; align-items: end; }
.te5-create__actions { display: flex; align-items: center; gap: 12px; margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--te5-row-ln); }
.te5-create__result a { color: inherit; font-weight: 700; }
.te5-create :is(button, input, select, summary):focus-visible { outline: 2px solid var(--te5-primary); outline-offset: 2px; }

@media (max-width: 768px) {
  .te5-create__point .te5-create__object,
  .te5-create__point .te5-create__time { flex-basis: 100%; }
  .te5-create__remove { width: 100%; }
}

/* ---------- modal ---------- */

.te5-modal-backdrop {
  position: fixed; inset: 0; background: rgba(20,28,42,.45); z-index: 60;
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.te5-modal {
  background: var(--te5-card); border-radius: var(--te5-radius-panel); box-shadow: var(--te5-shadow-float);
  width: 440px; max-width: 100%; max-height: 90vh; overflow: auto; padding: 22px;
}
/* Широкая форма — под карточку водителя с двумя удостоверениями рядом (решение
   владельца 09.08.2026: колонки, а не переключатель). `max-width: 100%` наследуется
   от правила выше и обязан уцелеть: без него окно уедет за край телефона. */
.te5-modal--wide { width: 760px; }

/* ---------- колонки-секции внутри формы ---------- */

/* Два документа лежат рядом, потому что диспетчеру нужна плотность (`.impeccable.md`):
   переключатель прятал бы половину граф, а свернуть колонку нельзя — значит вопрос
   «когда истекает» отвечается без единого клика. */
.te5-form-groups { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 14px; }
.te5-form-group {
  border: 1px solid var(--te5-border-2); border-radius: 8px; padding: 12px;
  /* Длинная категория («A I, A II, A III, A IV») не имеет права распирать колонку:
     грид-ячейка по умолчанию `min-width: auto` и ниже min-content не сжимается. */
  min-width: 0;
}
.te5-form-group__head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px;
}
.te5-form-group__title { font-size: 12px; font-weight: 600; color: var(--te5-text-2); }
.te5-form-group__body { display: flex; flex-direction: column; gap: 10px; }

/* Колонки встают друг под друга, когда окно у́же самой формы. Медиа-запрос здесь честен
   (в отличие от строки автопарка, где мерить надо было контейнер): ширина модалки и есть
   ширина окна минус поля — `max-width: 100%` не даёт ей быть шире. */
@media (max-width: 820px) {
  .te5-form-groups { grid-template-columns: 1fr; }
}
/* Консольная модалка — нативный <dialog>: Esc, top layer, инертный фон и возврат
   фокуса даёт браузер (TE5.modal). Здесь только гасим UA-стили диалога (рамка,
   авторазмер, свой фон) и переносим затемнение в ::backdrop — остальное
   (position/inset/display:flex/padding) наследуется от правила выше.
   🛑 Правило `.te5-modal-backdrop` оставлено как есть: на нём живёт модалка
   водителя (`driver.js` рисует <div>, te5.js на driver.html не подключён). */
dialog.te5-modal-backdrop {
  width: 100%; max-width: none; height: 100%; max-height: none;
  margin: 0; border: 0; background: transparent; overflow: visible;
  /* 🛑 `color` тоже UA-стиль самого элемента (`CanvasText`), поэтому наследование
     от `body.te5` им перебито — без явного токена текст модалки красит браузер. */
  color: var(--te5-text);
}
/* 🛑 Браузерная обводка фокуса на СЛУЖЕБНЫХ контейнерах окна. `showModal()` без
   `autofocus` оставляет фокус на самом <dialog>, а `.te5-modal` Chrome делает
   фокусируемым сам: у него `overflow: auto`, то есть это скроллер, а скроллеры
   с версии 125 попадают в tab-порядок ради доступности. Обоим достаётся UA
   `outline: auto` — в тёмной теме белый, и владелец увидел его 07.08.2026 как
   толстую рамку вокруг карточки водителя. Гасим ТОЛЬКО контейнеры: у кнопок и
   полей внутри окна обводка остаётся (правило ниже), иначе окно станет
   непроходимым с клавиатуры. */
dialog.te5-modal-backdrop:focus,
dialog.te5-modal-backdrop:focus-visible,
dialog.te5-modal-backdrop .te5-modal:focus,
dialog.te5-modal-backdrop .te5-modal:focus-visible { outline: none; }
dialog.te5-modal-backdrop:not([open]) { display: none; }
dialog.te5-modal-backdrop::backdrop { background: rgba(20,28,42,.45); }
/* Скролл-лока не было ни у одной из шести прежних копий: фон уезжал под окном.
   🛑 Вместе с `scrollbar-gutter` ниже: без него лок убирает полосу прокрутки, и на
   Windows/Linux (там она классическая, ~15px) вся консоль дёргается вбок на каждое
   открытие и закрытие окна. Замер ревью: `clientWidth` 1425 → 1440. На macOS
   симптома нет по построению — проверять не на своей машине. */
body:has(dialog.te5-modal-backdrop[open]) { overflow: hidden; }
html { scrollbar-gutter: stable; }

.te5-modal__title { font-size: 16px; font-weight: 700; margin: 0 0 14px; }
.te5-modal__actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: flex-end; margin-top: 18px; }
.te5-modal__action-start { margin-right: auto; }

/* ---------- окно-форма: шапка и подвал ВНЕ прокрутки (`formModal`) ----------
   🛑 Всё в этом блоке заскоуплено на `dialog.te5-modal-backdrop`, и это не
   украшение селектора: модалка ВОДИТЕЛЯ — своя копия на `<div>` с тем же классом
   (`driver.js::openForm`), у неё другая поверхность (`--driver-surface`) и свой
   крестик в `driver.css`. Голое правило покрасило бы её полосы цветом консоли —
   тот же класс, что «перебил заливку, а цвет текста остался от прежнего фона».

   🛑 ЛИПКОСТЬ (`position: sticky`) здесь НЕ РАБОТАЕТ, и это проверено замером, а не
   рассуждением: sticky-элемент клампится своим содержащим блоком, то есть КОНТЕНТ-боксом
   скроллера — прижаться к кромке окна он не может, между ним и краем остаётся полоса
   padding'а (замер 09.08: ровно 22px, и в ней просвечивало уезжающее поле ввода).
   Отрицательный офсет `top: -22px` этого не лечит по той же причине — клип сильнее.
   Поэтому раскладка честная: окно — колонка, прокручивается только середина. */
dialog.te5-modal-backdrop .te5-modal--framed {
  display: flex; flex-direction: column; padding: 0; overflow: hidden;
}
dialog.te5-modal-backdrop .te5-modal--framed .te5-modal__scroll {
  flex: 1 1 auto; min-height: 0; overflow: auto; padding: 14px 22px;
}
/* Скроллером стала середина, значит в tab-порядок (Chrome 125+) попадает ОНА —
   гасим UA-обводку там же, где её гасят прочим служебным контейнерам окна. */
dialog.te5-modal-backdrop .te5-modal__scroll:focus,
dialog.te5-modal-backdrop .te5-modal__scroll:focus-visible { outline: none; }
/* 🛑 КОЛОНКА, а не строка. `display:flex` без направления выкладывал шапку в ряд, и
   подзаголовок («Иванов И. И.») уезжал ВБОК от заголовка, а крестик — он прижат
   `margin-left:auto` внутри `__headline` — садился между ними и наезжал на имя. Ровно то,
   от чего предостерегает комментарий у `.te5-modal__subtitle` ниже.
   `align-items` не задаём НАМЕРЕННО: в колонке `flex-start` сжал бы `__headline` до ширины
   текста, и `margin-left:auto` крестика упёрся бы не в край окна, а в конец заголовка —
   тот же дефект другим путём. Растяжка по умолчанию (`stretch`) и держит крестик в углу.
   `justify-content` тут больше не нужен: в колонке он развёл бы заголовок и имя записи
   по разным краям шапки. Отступ между строками даёт `margin-top` подзаголовка. */
dialog.te5-modal-backdrop .te5-modal__head {
  flex: none; display: flex; flex-direction: column; padding: 18px 22px 12px;
  background: var(--te5-card); border-bottom: 1px solid var(--te5-border);
}
dialog.te5-modal-backdrop .te5-modal__head .te5-modal__title { font-size: 19px; margin: 0; }
.te5-modal__headline { display: flex; align-items: flex-start; gap: 12px; }
/* Имя записи — ВТОРОЙ строкой: на одной линии с крестиком стоит тип («Водитель»),
   иначе длинное ФИО уезжает под кнопку закрытия. */
.te5-modal__subtitle { margin-top: 2px; font-size: 14px; color: var(--te5-text-2); }
/* 🛑 Скоуп на `dialog` здесь ОБЯЗАТЕЛЕН, а не для симметрии: тот же класс выпускает
   `driver.js` (профиль и выход водителя), и его крестик в `driver.css:814` объявляет
   `min-width/min-height`, но НЕ `margin` — голое правило сдвинуло бы его на 10px и
   утащило цель нажатия из угла. Классы `__head`/`__ro`/`__section*` водитель не
   выпускает вовсе, поэтому им скоуп не нужен. */
dialog.te5-modal-backdrop .te5-modal__close {
  flex: none; width: 44px; height: 44px; margin: -10px -10px 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: 8px; background: transparent;
  color: var(--te5-text-2); font: inherit; font-size: 22px; line-height: 1; cursor: pointer;
}
dialog.te5-modal-backdrop .te5-modal__close:hover { background: var(--te5-hover-bg); color: var(--te5-text); border-color: var(--te5-border); }
/* Подвал стоит на дне окна и в прокрутку не входит: у карточки водителя список полей
   выше экрана, и «Сохранить» было достижимо только прокруткой до конца. Модификатор,
   а не базовый класс: короткие окна подтверждения линию над кнопками не заводят. */
dialog.te5-modal-backdrop .te5-modal__actions--footer {
  flex: none; margin: 0; padding: 12px 22px 18px;
  background: var(--te5-card); border-top: 1px solid var(--te5-border);
}
/* Заголовок блока внутри карточки («Доступ», «MAX-бот») — оба одного кегля:
   разный размер у соседних заголовков читается как ошибка вёрстки. */
.te5-modal__section { margin-top: 16px; border-top: 1px solid var(--te5-border-2); padding-top: 14px; }
.te5-modal__section-title { font-size: 15px; font-weight: 700; color: var(--te5-text); margin-bottom: 10px; }
/* Значение только на чтение (логин водителя): меняется отдельной кнопкой, поэтому
   не поле ввода, но и не подпись — габарит поля, чтобы колонка не рвалась. */
.te5-modal__ro {
  display: flex; align-items: center; min-height: 38px; padding: 0 12px;
  border: 1px solid var(--te5-border-2); border-radius: 6px; background: var(--te5-row-ln);
}
.te5-modal__ro .te5-reg { font-size: 14px; }
/* Кнопки доступа: строки задаются ЯВНО (заказ владельца — QR, пара «Изменить…»,
   сброс, блокировка), а не переносом по ширине. */
.te5-access { display: flex; flex-direction: column; gap: 8px; }
.te5-access__row { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; }
.te5-access__row--2 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.te5-access .te5-btn { min-height: 40px; white-space: normal; }
@media (max-width: 420px) {
  /* «Изменить логин» и «Изменить пароль» в одну строку на 360px не влезают. */
  .te5-access__row--2 { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- dispatcher notifications ---------- */
.te5-notification-card__count {
  font-size: 32px;
  line-height: 1;
  font-weight: 780;
  letter-spacing: -.03em;
  color: var(--te5-primary);
}
.te5-notification-card__list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 12px;
}
.te5-notification-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.te5-notification-tabs {
  display: inline-flex;
  gap: 4px;
  margin: 2px 0 14px;
  padding: 4px;
  border: 1px solid var(--te5-border);
  border-radius: 999px;
  background: var(--te5-bg);
}
.te5-notification-tabs button {
  min-height: 34px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--te5-text-2);
  font: inherit;
  font-size: 13px;
  font-weight: 650;
  cursor: pointer;
}
.te5-notification-tabs button.is-active {
  background: var(--te5-card);
  color: var(--te5-text);
  box-shadow: 0 1px 4px rgba(20,28,42,.10);
}
.te5-notification-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.te5-notification {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 12px 14px;
  border: 1px solid var(--te5-border);
  border-radius: 12px;
  background: var(--te5-bg);
}
.te5-notification.is-new {
  border-color: var(--te5-primary-ln);
  background: var(--te5-primary-bg);
}
.te5-notification__body { min-width: 0; }
.te5-notification__title {
  font-size: 14px;
  font-weight: 750;
  color: var(--te5-text);
}
.te5-notification__text {
  margin-top: 3px;
  color: var(--te5-text);
  line-height: 1.4;
}
.te5-notification__meta {
  margin-top: 5px;
  color: var(--te5-text-2);
  font-size: 12px;
}
.te5-notification__severity { margin-top: 6px; }
.te5-notification__action { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 8px; }
@media (max-width: 420px) {
  .te5-notification { grid-template-columns: minmax(0, 1fr); }
  .te5-notification__action { justify-content: flex-start; }
  .te5-notification-toolbar { align-items: stretch; flex-direction: column; }
  .te5-notification-toolbar > .te5-btn { min-height: 44px; }
}

/* ---------- dispatcher ↔ driver chat ---------- */
dialog.te5-modal-backdrop .te5-modal--driver-chat {
  width: min(720px, calc(100vw - 32px));
  height: min(760px, calc(100dvh - 32px));
  max-height: calc(100dvh - 32px);
  padding: 0;
  overflow: clip;
}
.te5-driver-chat {
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr) auto auto auto auto auto;
  min-height: 0;
  height: 100%;
}
.te5-driver-chat__header { grid-row: 1; min-width: 0; }
.te5-driver-chat__header .te5-modal__headline { min-width: 0; }
.te5-driver-chat__header .te5-modal__title { min-width: 0; flex: 1; overflow-wrap: anywhere; }
.te5-driver-chat__back { flex: none; min-height: 44px; margin: -10px 0 0 -10px; }
.te5-driver-chat__older { grid-row: 2; justify-self: center; margin: 10px 16px 0; min-height: 44px; }
.te5-driver-chat__history {
  grid-row: 3;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 14px 22px;
}
.te5-driver-chat__date {
  margin: 12px 0 8px;
  color: var(--te5-muted);
  font-size: 12px;
  text-align: center;
}
.te5-driver-chat__message {
  width: fit-content;
  max-width: min(82%, 560px);
  margin: 0 0 10px;
  padding: 9px 11px;
  border: 1px solid var(--te5-border);
  border-radius: 12px;
  background: var(--te5-bg);
}
.te5-driver-chat__message.is-own {
  margin-left: auto;
  border-color: var(--te5-primary-ln);
  background: var(--te5-primary-bg);
}
.te5-driver-chat__meta { margin-bottom: 3px; color: var(--te5-muted); font-size: 12px; }
.te5-driver-chat__text { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.42; }
.te5-driver-chat__state { margin: auto; padding: 24px 8px; color: var(--te5-text-2); text-align: center; }
.te5-driver-chat__retry { display: flex; margin: 0 auto; min-height: 44px; }
.te5-driver-chat__new { grid-row: 4; justify-self: center; margin: 0 16px 8px; min-height: 44px; }
.te5-driver-chat__stale { grid-row: 5; }
.te5-driver-chat > .te5-banner { grid-row: 6; }
.te5-driver-chat__readonly { grid-row: 7; }
.te5-driver-chat__stale,
.te5-driver-chat__readonly { padding: 8px 22px; text-align: center; }
.te5-driver-chat > .te5-banner { margin: 0 22px 10px; }
.te5-driver-chat__composer {
  grid-row: 8;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: end;
  padding: 12px 22px calc(14px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--te5-border);
  background: var(--te5-card);
}
.te5-driver-chat__composer .te5-textarea { min-height: 44px; max-height: 132px; resize: vertical; }
.te5-driver-chat__composer .te5-btn { min-height: 44px; }
.te5-driver-chat-catalog {
  display: grid;
  grid-template-rows: auto auto auto minmax(0, 1fr);
  min-height: 0;
  height: 100%;
}
.te5-driver-chat-catalog__tools { padding: 14px 22px 8px; }
.te5-driver-chat-catalog__tools .te5-input { width: 100%; min-height: 44px; }
.te5-driver-chat-catalog__notice {
  margin: 0 22px 8px;
  padding: 7px 10px;
  border: 1px solid var(--te5-warning-ln);
  border-radius: var(--te5-radius-control);
  background: var(--te5-warning-bg);
  color: var(--te5-warning);
  font-size: 13px;
}
.te5-driver-chat-catalog__list {
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 6px 22px calc(16px + env(safe-area-inset-bottom));
}
.te5-driver-chat-catalog__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  width: 100%;
  min-height: 72px;
  padding: 11px 12px;
  border: 0;
  border-bottom: 1px solid var(--te5-border-2);
  background: transparent;
  color: var(--te5-text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.te5-driver-chat-catalog__row:hover { background: var(--te5-hover-bg); }
.te5-driver-chat-catalog__row:focus-visible { position: relative; z-index: 1; }
.te5-driver-chat-catalog__heading { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.te5-driver-chat-catalog__heading strong { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.te5-driver-chat-catalog__time { margin-left: auto; color: var(--te5-muted); font-size: 12px; white-space: nowrap; }
.te5-driver-chat-catalog__unread {
  min-width: 20px;
  padding: 2px 6px;
  border-radius: 999px;
  background: var(--te5-primary);
  color: var(--te5-on-primary);
  font-size: 11px;
  font-weight: 800;
  text-align: center;
}
.te5-driver-chat-catalog__vehicle {
  overflow: hidden;
  color: var(--te5-text-2);
  font-size: 13px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.te5-driver-chat-catalog__preview {
  display: -webkit-box;
  overflow: hidden;
  color: var(--te5-muted);
  font-size: 13px;
  line-height: 1.35;
  overflow-wrap: anywhere;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.te5-driver-chat-catalog__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 180px;
  padding: 24px;
  color: var(--te5-text-2);
  text-align: center;
}
.te5-driver-chat-catalog__empty .te5-btn { min-height: 44px; }
@media (max-width: 600px) {
  dialog.te5-modal-backdrop .te5-modal--driver-chat {
    width: calc(100vw - 16px) !important;
    height: calc(100dvh - 16px);
    max-height: calc(100dvh - 16px);
  }
  .te5-driver-chat__history { padding: 12px 14px; }
  .te5-driver-chat__message { max-width: 90%; }
  .te5-driver-chat__stale,
  .te5-driver-chat__readonly { padding-inline: 14px; }
  .te5-driver-chat > .te5-banner { margin-inline: 14px; }
  .te5-driver-chat__composer { padding-inline: 14px; }
  .te5-driver-chat__back { padding-inline: 9px; }
  .te5-driver-chat-catalog__tools { padding-inline: 14px; }
  .te5-driver-chat-catalog__notice { margin-inline: 14px; }
  .te5-driver-chat-catalog__list { padding-inline: 8px; }
  .te5-driver-chat-catalog__row { min-height: 88px; }
}

/* ---------- live dispatch board ---------- */

.te5-dispatch { min-width: 0; padding-bottom: 132px; }
.te5-dispatch__refresh { display: flex; align-items: center; gap: 12px; color: var(--te5-muted); font-size: 12.5px; }
.te5-dispatch__refresh .te5-btn { min-height: 44px; }
.te5-dispatch__filters { margin-bottom: 14px; }
.te5-dispatch__filter-grid { display: grid; grid-template-columns: minmax(160px, .7fr) minmax(220px, 1.1fr) minmax(160px, .75fr) minmax(200px, 1fr) minmax(200px, 1fr); gap: 12px; }
.te5-dispatch__filter-grid :is(.te5-input, .te5-select) { min-height: 44px; height: 44px; }
.te5-dispatch__board { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.te5-dispatch__section { min-width: 0; }
.te5-dispatch__section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin: 0 2px 7px; }
.te5-dispatch__section-head h2 { margin: 0; font-size: 17px; }
.te5-dispatch__section-count { color: var(--te5-muted); font-size: 12px; }
.te5-dispatch__subgroup + .te5-dispatch__subgroup { margin-top: 12px; }
.te5-dispatch__subgroup-title { margin: 0 0 7px 2px; font-size: 13px; color: var(--te5-text-2); }
.te5-dispatch__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; min-width: 0; }
.te5-dispatch-card { position: relative; min-width: 0; padding: 13px 13px 12px 60px; background: var(--te5-surface-raised); border: 1px solid var(--te5-border); border-radius: var(--te5-radius-card); box-shadow: var(--te5-shadow-sm); cursor: pointer; }
.te5-dispatch-card.is-selected { border-color: var(--te5-primary); box-shadow: 0 0 0 2px var(--te5-primary-bg), var(--te5-shadow-sm); }
.te5-dispatch-card.is-closed { opacity: .72; }
.te5-dispatch-card__select { position: absolute; top: 8px; left: 8px; width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
.te5-dispatch-card__select input { width: 20px; height: 20px; }
.te5-dispatch-card__title { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; min-width: 0; }
.te5-dispatch-card__title .te5-reg { font-size: 15px; }
.te5-dispatch-card__vehicle { margin-top: 3px; color: var(--te5-text-2); overflow-wrap: anywhere; }
.te5-dispatch-card__meta { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px 12px; margin: 12px 0 0; }
.te5-dispatch-card__meta div { min-width: 0; overflow-wrap: anywhere; }
.te5-dispatch-card__meta dt { margin: 0 0 2px; color: var(--te5-muted); font-size: 11px; }
.te5-dispatch-card__meta dd { margin: 0; font-size: 12.5px; }
.te5-dispatch-card__signals { display: flex; flex-direction: column; gap: 5px; margin-top: 10px; font-size: 12px; }
.te5-dispatch-card__signal { padding: 6px 8px; border-radius: 6px; background: var(--te5-open-bg); border: 1px solid var(--te5-open-ln); color: var(--te5-open); }
.te5-dispatch-card__signal--warning { background: var(--te5-warn-bg); border-color: var(--te5-warn-ln); color: var(--te5-warn); }
.te5-dispatch-card__signal--danger { background: var(--te5-bad-bg); border-color: var(--te5-bad-ln); color: var(--te5-bad); }
.te5-dispatch-card__support { margin-top: 9px; color: var(--te5-muted); font: 11px var(--te5-mono); }
/* Плавающая панель действий — ОДНО правило на диспетчерскую и на «Учёт техники».
   Второй экземпляр с теми же числами разъехался бы с первым молча. */
.te5-actionbar--float,
.te5-dispatch__actions { position: fixed; z-index: 24; left: 50%; bottom: calc(env(safe-area-inset-bottom, 0px) + 12px); transform: translateX(-50%); width: min(1232px, calc(100vw - 32px)); }
.te5-dispatch__actions .te5-card__body { display: grid; grid-template-columns: minmax(180px, .8fr) minmax(220px, 1fr) auto; align-items: end; gap: 12px; }
.te5-dispatch__selection { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 0; }
.te5-dispatch__selection .te5-btn { min-height: 44px; }
.te5-dispatch__action-buttons { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
.te5-dispatch__action-buttons .te5-btn { min-height: 44px; }
.te5-dispatch__preview-list { margin: 12px 0 0; padding-left: 20px; }
.te5-dispatch__preview-list li + li { margin-top: 5px; }
.te5-dispatch__modal-copy { color: var(--te5-text-2); line-height: 1.5; }
.te5-dispatch :is(button, input, select, .te5-dispatch-card):focus-visible,
.te5-modal :is(button, input, select):focus-visible { outline: 2px solid var(--te5-primary); outline-offset: 2px; }

@media (max-width: 1040px) {
  .te5-dispatch__filter-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .te5-dispatch__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .te5-dispatch__actions .te5-card__body { grid-template-columns: minmax(160px, .7fr) minmax(200px, 1fr); }
  .te5-dispatch__action-buttons { grid-column: 1 / -1; justify-content: stretch; }
  .te5-dispatch__action-buttons .te5-btn { flex: 1; }
}

@media (max-width: 640px) {
  .te5-dispatch { padding-left: 12px; padding-right: 12px; padding-bottom: 238px; }
  .te5-dispatch .te5-pagehead { gap: 10px; }
  .te5-dispatch__refresh { width: 100%; justify-content: space-between; }
  .te5-dispatch__filter-grid { grid-template-columns: 1fr; }
  .te5-dispatch__grid { grid-template-columns: minmax(0, 1fr); }
  .te5-dispatch-card { padding-left: 60px; }
  .te5-dispatch-card__meta { grid-template-columns: minmax(0, 1fr); }
  .te5-dispatch__actions { width: calc(100vw - 16px); bottom: calc(env(safe-area-inset-bottom, 0px) + 8px); }
  .te5-dispatch__actions .te5-card__body { grid-template-columns: minmax(0, 1fr); max-height: 220px; overflow-y: auto; }
  .te5-dispatch__object-field,
  .te5-dispatch__action-buttons { grid-column: auto; }
  .te5-dispatch__action-buttons { display: grid; grid-template-columns: 1fr; }
  .te5-dispatch__action-buttons .te5-btn { width: 100%; }
  .te5-dispatch__selection { flex-direction: row; align-items: center; justify-content: space-between; }
  .te5-dispatch__selection strong { min-width: 0; }
  .te5-modal-backdrop { padding: 8px; }
  .te5-dispatch-modal { width: 100%; max-height: calc(100dvh - 16px); border-radius: 12px 12px 8px 8px; }
  .te5-modal__actions .te5-btn { min-height: 44px; flex: 1; }
}

/* Значение + инлайн-иконка копирования (reveal временного пароля и т.п.) */
.te5-copy-row { display: flex; align-items: center; gap: 8px; }
.te5-copy-row .te5-reg { flex: 1; min-width: 0; word-break: break-all; }
.te5-copy-ic { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 32px; height: 32px; padding: 0; border: 1px solid var(--te5-border); border-radius: 8px; background: transparent; color: var(--te5-text-2); cursor: pointer; transition: color .12s, border-color .12s, background .12s; }
.te5-copy-ic:hover { color: var(--te5-text); border-color: var(--te5-border-2); background: var(--te5-hover-bg); }
/* Обводка берёт АКЦЕНТ, а не `--te5-primary-bg`: тот — фон чипа, на карточке даёт 1.14. */
.te5-copy-ic:focus-visible { outline: 2px solid var(--te5-primary); outline-offset: 2px; }

/* ---------- login ---------- */

.te5-login { min-height: 100vh; min-height: 100dvh; display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 24px; padding: 24px; }
.te5-login__brand { display: flex; align-items: center; gap: 12px; }
.te5-login__mark { width: 40px; height: 40px; border-radius: 9px; }
.te5-login__title { font-weight: 800; font-size: 20px; letter-spacing: -.01em; }
.te5-login__sub { font-size: 12px; color: var(--te5-muted); }
.te5-login__card {
  background: var(--te5-card); border: 1px solid var(--te5-border); border-radius: 10px;
  box-shadow: 0 6px 24px rgba(20,28,42,.10); width: 360px; max-width: 100%; padding: 28px;
}
.te5-login__card h1 { font-size: 18px; font-weight: 700; margin: 0 0 4px; }
.te5-login__hint { font-size: 12.5px; color: var(--te5-muted); margin-bottom: 20px; }

/* ---------- KPI ---------- */

.te5-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 16px; }
/* 🛑 Плитка бывает кликабельная (фильтр списка на дашборде, правка водителя и указаний в
   карточке смены) и обычная («ТС», «Заказчик», «Текущий объект» — это просто справка).
   Палец и подсветка — ТОЛЬКО у первой: до 10.09.2026 `cursor` не задавался вовсе и на
   кнопку плитка не походила, а правка первого захода выдала палец всем разом, то есть
   пообещала нажатие там, где его нет. Разводит их ТЕГ: кликабельная — `<button>`. */
.te5-kpi { text-align: left; background: var(--te5-card); border: 1px solid var(--te5-border); border-radius: 8px; padding: 14px 16px; font: inherit; display: block; color: inherit; text-decoration: none; }
button.te5-kpi,
a.te5-kpi { cursor: pointer; }
/* 🛑 Браузер центрирует содержимое <button> по вертикали САМ — правил в файле нет, а
   `align-items` у такой кнопки вычисляется как `normal`, поэтому по CSS этого не видно.
   В ряду плиток кнопка («Водитель», «Указания на смену») из-за этого начинала подпись на
   22px ниже соседних блоков (замер на проде 10.09.2026). Прижимаем явно. */
button.te5-kpi { display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start; }
button.te5-kpi:hover,
a.te5-kpi:hover { border-color: var(--te5-primary-ln); box-shadow: 0 2px 10px rgba(20,28,42,.06); }
/* Дневной борд — ПЯТЬ плиток одной ширины: Всего · На базе · В пути · На объекте ·
   Завершена. Базовая сетка кита рассчитана на четыре, и пятая уходила на вторую строку
   одна (замер на проде 10.09.2026). */
.te5-kpis--day { grid-template-columns: repeat(5, 1fr); }
.te5-kpi__n { font-size: 24px; font-weight: 700; font-family: var(--te5-mono); }
.te5-kpi__label { font-size: 12.5px; color: var(--te5-text-2); margin-top: 2px; }
/* Карточка листа — ПЯТЬ плиток: ТС · Водитель · Заказчик · Объект · Указания на смену.
   Госномер и «БТС» короткие, ФИО, адрес и указания длинные — им и ширина. Ниже 900px —
   две колонки, последняя плитка (указания) на обе. Число колонок только здесь, не
   инлайном (инлайн перебивает медиа-запрос — замер 29.08.2026). */
.te5-kpis--waybill { grid-template-columns: 0.8fr 1.2fr 0.8fr 1.2fr 1.4fr; }
.te5-kpi__note { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; white-space: normal; text-align: left; }
/* Плитка ТС: рабочий номер («456») крупно и первым — им машину зовут в разнарядке и в чате,
   полный госномер уходит вниз блёклой строкой (владелец, 10.09.2026). Кегль хвоста не ниже
   12px: это читаемый текст, а не подпись к иконке. */
.te5-kpi__plate { font-family: var(--te5-mono); font-weight: 700; font-size: 22px; letter-spacing: 0.02em; }
.te5-kpi__reg-full { margin-top: 3px; font-family: var(--te5-mono); font-size: 12px; font-weight: 500; color: var(--te5-muted); }

/* ---------- two-column ---------- */

.te5-cols { display: grid; grid-template-columns: 1fr 320px; gap: 16px; align-items: start; }
@media (max-width: 900px) {
  .te5-cols { grid-template-columns: 1fr !important; }
  .te5-kpis { grid-template-columns: repeat(2, 1fr); }
  .te5-kpis--waybill { grid-template-columns: repeat(2, 1fr); }
  .te5-kpis--waybill > .te5-kpi:last-child { grid-column: 1 / -1; }
  .te5-main { padding: 16px; }
  .te5-pagehead-stick { margin-top: -16px; margin-inline: -16px; padding-inline: 16px; }
}

/* Шапка умеет схлопываться не только по viewport, но и по фактическому wrap:
   te5.js добавляет .te5-header--compact, если ссылки навигации полезли на
   вторую строку внутри max-width контейнера. */
.te5-header--compact .te5-header__inner {
  flex-wrap: nowrap;
  gap: 10px;
}
.te5-header--compact .te5-logo { min-width: 0; }
.te5-header--compact .te5-logo__name {
  overflow: hidden;
  text-overflow: ellipsis;
}
.te5-header--compact .te5-burger { display: flex; }
.te5-header--compact .te5-header__right {
  margin-left: auto;
  gap: 10px;
}
/* В блоке режима остаётся ТОЛЬКО переключатель показа: всё остальное, что делает
   накладку накладкой, объявлено один раз в `.te5-nav.is-open` (низ файла). */
.te5-header--compact .te5-nav { display: none; }
.te5-header--compact .te5-nav.is-open { display: flex; }

/* Бургер без участия JS — только на телефоне (≤767.98; ровно на 768 шапка
   развёрнута). Выше этой ширины навигация показана, а `te5.js::sync()` меряет
   перенос пунктов и схлопывает в бургер, только если они не влезли. Прежний порог
   1279.98 («десктоп от 1280», 31.07.2026) прятал навигацию на мониторе при масштабе
   175–200 % — снят словом j 28.09.2026. Порог продублирован в te5.js::sync(). */
@media (max-width: 767.98px) {
  /* Липкость шапки объявлена БЕЗУСЛОВНО выше (`.te5-header`), и дубль здесь
     читался как условие «липнет только на узких», которого нет. */
  .te5-header__inner { flex-wrap: nowrap; gap: 10px; }
  .te5-logo { min-width: 0; }
  .te5-logo__name {
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .te5-burger { display: flex; }
  .te5-header__right {
    margin-left: auto;
    gap: 10px;
  }
  /* Тот же переключатель, что и у класса-режима: этот блок — единственное, что
     работает до загрузки JS, поэтому он обязан жить, но дублировать оформление
     ему больше не нужно. */
  .te5-nav { display: none; }
  .te5-nav.is-open { display: flex; }
}

body.te5-owner .te5-owner-rowview,
body.te5-owner .te5-owner-more-columns,
body.te5-owner .te5-owner-add-short,
body.te5-owner .te5-owner-period,
body.te5-owner .te5-owner-sheet__scrim,
body.te5-owner .te5-owner-summary__stack,
body.te5-owner [data-owner-more-open],
body.te5-owner [data-owner-more-rowview],
body.te5-owner .te5-owner-actions__scrim { display: none; }

/* 🛑 U4: обёртки панели действий заведены ради телефона, а на десктопе обязаны вести себя
   ровно как прежний плоский ряд — поэтому на десктопе их НЕТ в раскладке (`display: contents`):
   кнопки остаются прямыми флекс-детьми `.te5-owner-actions`, как до группировки. Любое другое
   значение (inline-flex от `[role="group"]`, flex с центрированием) сдвигало ряд на 1–4px —
   замер попиксельным диффом 1280px, 02.09.2026. Селектор скоупится через `.te5-owner-actions`,
   иначе проигрывает по специфичности правилу `[role="group"]` (0,3,1). */
body.te5-owner .te5-owner-actions .te5-owner-actions__bar,
body.te5-owner .te5-owner-actions .te5-owner-actions__more { display: contents; }

@media (max-width: 768px) {
  .te5-field,
  .te5-input,
  .te5-select,
  .te5-btn { min-width: 0; }
  .te5-btn { white-space: normal; }

  /* Поля шапки ужались вдвое — панель следует за ними, иначе на телефоне она
     наезжает на край экрана и перестаёт читаться карточкой. */
  .te5-nav.is-open { --te5-nav-inset: 6px; }
  .te5-header__inner { padding: 6px 12px; }
  .te5-header__right {
    gap: 6px;
  }
  .te5-header__right .te5-header__user { display: none; }
  .te5-nav__logout { display: block; }
  .te5-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    padding-bottom: 4px;
    scrollbar-width: none;
  }
  .te5-tabs::-webkit-scrollbar { display: none; }
  .te5-tabs .te5-btn {
    flex: 0 0 auto;
    min-height: 40px;
    padding: 0 14px;
  }
  .te5-pagehead { align-items: stretch; }
  .te5-pagehead__actions {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    justify-content: center;
  }
  .te5-pagehead__actions .te5-btn {
    width: 100%;
    min-height: 52px;
    padding: 0 14px;
    font-size: 15px;
  }
  .te5-card__head .te5-btn {
    min-height: 42px;
    padding: 0 14px;
    min-width: 160px;
    justify-content: center;
  }
  .te5-table-scroll {
    margin: 0;
    border-radius: 0 0 8px 8px;
  }
  .te5-table-scroll .te5-table { min-width: 680px; }

  /* Учёт техники — полевая PWA владельца, а не диспетчерская таблица. На телефоне
     одна строка становится вертикальной карточкой; data-label остаётся рядом со
     значением и в view-, и в edit-режиме. */
  /* Ручные даты остаются парой, а отдельная кнопка переносится целиком: так крайняя
     правая кнопка десктопа не распирает узкий экран. */
  /* На телефоне быстрые периоды растягиваются на четыре равные доли — это главный
     способ выбора, а ручные даты остаются под ними одной строкой. */
  body.te5-owner .te5-owner-presets { display: grid; grid-template-columns: repeat(4, 1fr); }
  body.te5-owner .te5-owner-presets .te5-btn { width: 100%; padding-left: 4px; padding-right: 4px; }
  body.te5-owner .te5-owner-range { width: 100%; }
  body.te5-owner .te5-owner-range__input { flex: 1 1 0; width: auto; min-width: 0; }
  body.te5-owner #ownerApply { flex: 1 0 100%; margin-left: 0; }
  body.te5-owner .te5-owner-show-deleted { min-height: 44px; }
  body.te5-owner .te5-owner-count { margin-left: 0; }
  body.te5-owner .te5-owner-summary .te5-card__body { padding: 14px 16px; }
  body.te5-owner .te5-owner-bar-row { margin-top: 10px; }
  body.te5-owner .te5-owner-summary__period { display: none; }
  /* U6: кегли KPI по референсу Серёжи (разработчика, не Влада). Сумма — единственное крупное число экрана,
     всё вокруг неё уходит на 14px, иначе подпись спорит с ответом. */
  body.te5-owner .te5-owner-summary__money {
    font-size: 32px;
    letter-spacing: -.025em;
  }
  body.te5-owner .te5-owner-summary__head { font-size: 14px; }
  body.te5-owner .te5-owner-bar-row__share { font-size: 14px; }
  body.te5-owner .te5-owner-summary__meta {
    margin-top: 10px;
    font-size: 14px;
    color: var(--te5-text-2);
  }
  body.te5-owner .te5-owner-summary__note { font-size: 14px; }
  /* U2: KPI и сегмент-контрол разрезов сводки. */
  /* U6: подложка сегментов снята — заливка и рамка делали из выбора ещё одну «кнопку во всю
     ширину», а таких на экране и так было пять. Границу разреза держит одна линия под
     контролом, тем же токеном, что и линии между рядами списка. */
  body.te5-owner .te5-owner-summary__segments {
    display: flex;
    gap: 6px;
    margin-top: 14px;
    padding: 8px;
    border-bottom: 1px solid var(--te5-row-ln);
  }
  body.te5-owner .te5-owner-summary__segments button {
    /* auto, не 0: равные трети не вмещают «Недобрали» при 16px — подпись налезала на соседа. */
    flex: 1 1 auto;
    min-width: 0;
    min-height: 44px; /* тап-цель ≥ 44px — пол экрана владельца, не 40 референса */
    padding: 0 10px;
    border: 0;
    border-radius: var(--te5-radius-control);
    background: transparent;
    color: var(--te5-text-2);
    font: inherit;
    font-size: 14px;
    font-weight: 600;
  }
  /* Выбранный сегмент отличается ЗАЛИВКОЙ, а не оттенком карточки: на снимке телефона
     390px (02.09.2026) выбор был неотличим от соседей. */
  body.te5-owner .te5-owner-summary__segments button[aria-selected="true"] {
    background: var(--te5-primary);
    color: var(--te5-on-primary);
  }
  body.te5-owner .te5-owner-summary__break[data-owner-break-panel] { display: none; }
  body.te5-owner .te5-owner-summary__breaks[data-owner-break="shortfall"] >
    [data-owner-break-panel="shortfall"],
  body.te5-owner .te5-owner-summary__breaks[data-owner-break="customers"] >
    [data-owner-break-panel="customers"],
  body.te5-owner .te5-owner-summary__breaks[data-owner-break="hours"] >
    [data-owner-break-panel="hours"] { display: block; }
  /* 🛑 Заголовок разреза на телефоне СКРЫТ: он дословно повторяет выбранный сегмент над
     ним. Скоупим `[data-owner-break-panel]` — у фидов («Фитинги», «ГНБ») сегментов нет
     вовсе, и голое правило унесло бы у них подписи разборов, не дав ничего взамен. */
  body.te5-owner .te5-owner-summary__break[data-owner-break-panel] >
    .te5-owner-summary__sub { display: none; }
  /* У фидов заголовок разреза остаётся — сохраняем ему прежний телефонный отступ. */
  body.te5-owner .te5-owner-summary__sub { margin-top: 14px; }
  /* Отступ, который держал скрытый заголовок, переезжает на сам список. */
  body.te5-owner .te5-owner-summary__break[data-owner-break-panel] >
    .te5-owner-break { margin-top: 12px; }
  body.te5-owner .te5-owner-break__label {
    font-size: 15px;
    color: var(--te5-text);
  }
  body.te5-owner .te5-owner-break__value { font-size: 15px; }
  /* 🛑 Построчные дорожки на телефоне сняты — их заменила одна составная полоса ниже.
     Пять дорожек подряд на 358px читались столбиком в пол-экрана, а доли между собой не
     сравнивались: каждая мерилась от МАКСИМУМА, а не от суммы разреза. */
  body.te5-owner .te5-owner-break__track { display: none; }
  body.te5-owner .te5-owner-summary__stack {
    display: flex;
    gap: 2px;
    height: 8px;
    margin-top: 10px;
    border-radius: 4px;
    overflow: hidden;
  }
  /* Пять ступеней от primary к фону карточки: шестая и дальше остаются самой светлой —
     хвост «Прочее» и без того подписан числом. Цвет смешивается с токеном карточки, а не
     с белым: в тёмной теме белая примесь дала бы грязный оттенок. */
  body.te5-owner .te5-owner-summary__stack > i {
    background: color-mix(in srgb, var(--te5-primary) 12%, var(--te5-card));
  }
  body.te5-owner .te5-owner-summary__stack > i:nth-child(1) {
    background: color-mix(in srgb, var(--te5-primary) 100%, var(--te5-card));
  }
  body.te5-owner .te5-owner-summary__stack > i:nth-child(2) {
    background: color-mix(in srgb, var(--te5-primary) 70%, var(--te5-card));
  }
  body.te5-owner .te5-owner-summary__stack > i:nth-child(3) {
    background: color-mix(in srgb, var(--te5-primary) 45%, var(--te5-card));
  }
  body.te5-owner .te5-owner-summary__stack > i:nth-child(4) {
    background: color-mix(in srgb, var(--te5-primary) 25%, var(--te5-card));
  }
  body.te5-owner .te5-owner-actions .te5-owner-count { display: none; }
  /* 🛑 ДВЕ колонки, а не три: счётчик едет внутри надписи «Машины». Тремя колонками
     «Записей: 29» переносилось на вторую строку, а `<select>` в остатке ширины обрезался
     до «Дата: свежи» (снимок телефона 390px, 02.09.2026). */
  body.te5-owner .te5-owner-sort {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 8px;
    align-items: center;
    margin: 18px 0 10px;
  }
  body.te5-owner .te5-owner-sort__section {
    display: inline;
    grid-column: 1;
    font-size: 15px;
    font-weight: 700;
    color: var(--te5-text);
    white-space: nowrap;
  }
  body.te5-owner .te5-owner-sort__count {
    display: inline;
    font-size: 15px;
    font-weight: 400;
    color: var(--te5-text-2);
  }
  body.te5-owner .te5-owner-sort__label { display: none; }
  /* 🛑 Селект НЕ растягивается в остаток ширины: пустая рамка в пол-экрана читалась как
     поле ввода, которое забыли заполнить. Ширина по содержимому, потолок — своя ячейка
     грида (`minmax(0, 1fr)`): длинная подпись сортировки обрезается селектом, а заголовок
     секции защищает колонка, не процент. */
  body.te5-owner .te5-owner-sort__select {
    grid-column: 2;
    justify-self: end;
    width: auto;
    /* Ячейка грида уже равна остатку после «Машины 29»; проценты считаются от неё. */
    max-width: 100%;
    min-width: 0;
    min-height: 32px;
    padding: 6px 28px 6px 10px;
    border: 1px solid var(--te5-border);
    border-radius: 999px;
    background: var(--te5-card);
    /* 🛑 16px, не 13: iOS Safari зумит страницу при фокусе на контроле мельче 16px. */
    font-size: 16px;
    color: var(--te5-text-2);
    font-weight: 400;
  }
  body.te5-owner .te5-owner-actions .te5-btn,
  body.te5-owner .te5-owner-actions a { width: 100%; }
  body.te5-owner .te5-owner-actions {
    display: grid;
    grid-template-columns: 1fr;
  }
  body.te5-owner .te5-owner-actions [role="group"] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--te5-gap-tight);
  }
  body.te5-owner .te5-owner-actions [data-owner-zero-hours] { grid-column: 1 / -1; }
  body.te5-owner .te5-owner-table-wrap {
    overflow: visible;
    border-radius: 0;
  }
  body.te5-owner .te5-owner-table {
    display: block;
    min-width: 0 !important;
  }
  body.te5-owner .te5-owner-table thead { display: none; }
  body.te5-owner .te5-owner-table tbody {
    display: grid;
    gap: 12px;
  }
  body.te5-owner .te5-owner-table tr {
    display: block;
    overflow: hidden;
    border: 1px solid var(--te5-border);
    border-radius: 10px;
    background: var(--te5-card);
  }
  body.te5-owner .te5-owner-table td {
    display: grid;
    grid-template-columns: minmax(92px, .7fr) minmax(0, 1.3fr);
    gap: 12px;
    align-items: center;
    min-width: 0 !important;
    padding: 10px 12px;
    border-bottom: 1px solid var(--te5-row-ln);
    white-space: normal;
    overflow-wrap: anywhere;
  }
  body.te5-owner .te5-owner-table td::before {
    content: attr(data-label);
    color: var(--te5-muted);
    font-size: 16px;
    font-weight: 600;
    letter-spacing: .3px;
    text-transform: uppercase;
  }
  body.te5-owner .te5-owner-table td[data-owner-select-cell] {
    grid-template-columns: minmax(92px, .7fr) minmax(0, 1.3fr);
    text-align: left;
    min-height: 44px;
  }
  /* Номер-кнопка на мобиле — полноразмерная цель нажатия: строка тут карточка, и попасть
     пальцем в текст размером со строку иначе не выйдет (порог 44px). */
  body.te5-owner .te5-owner-rowbtn { min-height: 44px; }
  body.te5-owner .te5-owner-table input.te5-input {
    min-width: 0;
    min-height: 44px;
    font-size: 16px;
  }
  /* 🛑 Ряд действий этой страницы НЕ подчиняется общему мобильному правилу кита
     (`.te5-pagehead__actions` → грид в две равные колонки во всю ширину с центрированием).
     Оно рассчитано на две одинаковые кнопки-действия, а тут их две РАЗНЫХ по смыслу:
     «обновить из путевых» — иконка, «Старый PWA» — запасной выход. Центрированная пара
     повисала отдельной строкой ни к чему не привязанная (замечание владельца 02.09.2026).
     Порядок на телефоне: заголовок и действия одной строкой, вкладки — своей во всю
     ширину; `order` нужен потому, что в DOM вкладки стоят МЕЖДУ ними. */
  body.te5-owner .te5-owner-pagehead > h1 { order: 1; }
  body.te5-owner .te5-owner-pagehead__actions {
    order: 2;
    width: auto;
    display: flex;
    grid-template-columns: none;
    justify-content: flex-end;
    margin-left: auto;
    padding-bottom: 0;
  }
  body.te5-owner .te5-owner-tabs { order: 3; flex: 1 0 100%; }
  /* Вкладки — навигация, а не действия: обычный вес, выбранная выделяется весом и цветом. */
  body.te5-owner .te5-owner-tabs [role="tab"] {
    font-size: 15px;
    font-weight: 400;
  }
  body.te5-owner .te5-owner-tabs [role="tab"][aria-selected="true"] { font-weight: 600; }
  /* Кегль называем явно: общее мобильное правило кита опускает кнопки ряда до 15px, а на
     экране владельца свой пол — 13px внутри этого медиа-блока (гейт
     `owner-readable-text-keeps-a-floor`, базовые правила по-прежнему держат 16px). */
  body.te5-owner .te5-owner-pagehead__actions .te5-btn {
    width: auto;
    min-height: 44px;
    font-size: 16px;
  }
  /* 🛑 Здесь остаются только габариты. Цвет на телефоне снимается НИЖЕ, в блоке
     «U4: панель действий и меню» — кэмел задан инлайном в `console_owner.html`, поэтому
     без `!important` его не перебить. Прежняя редакция гасила его тремя `!important` без
     единого слова почему, и кнопка становилась белой: это читалось как поломка. Теперь
     это решение — «Старый PWA» на телефоне рисуется призрачной ссылкой (рамка и текст
     primary) по референсу Серёжи (разработчика, не Влада) 02.09.2026, а не остаётся без оформления. */
  /* 🛑 36px — НИЖЕ обычного порога 44px, и это осознанно: «Старый PWA» — запасной выход,
     а не рабочая кнопка, и в одной строке с заголовком он не имеет права спорить с ним
     ростом. Решение владельца по референсу 02.09.2026; поднимать обратно — только вместе с
     переносом ссылки на свою строку. */
  body.te5-owner .te5-owner-pagehead__actions a[href="/console/owner-pwa/"] {
    width: auto;
    min-height: 36px;
    padding: 0 12px;
    font-size: 13px;
    font-weight: 600;
  }
  body.te5-owner .te5-owner-rowview {
    display: inline-flex;
    margin: 12px;
  }
  body.te5-owner .te5-owner-rowview button {
    min-height: 44px;
    padding: 7px 16px;
    border: 0;
    border-radius: var(--te5-radius-control);
    background: transparent;
    color: var(--te5-text-2);
    font: inherit;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
  }
  body.te5-owner .te5-owner-rowview button.is-active {
    background: var(--te5-primary);
    color: var(--te5-on-primary);
  }
  body.te5-owner .te5-owner-table-shell { position: relative; }

  /* Ряды от края до края карточки: отступ обёртки и своя рамка tbody давали «карточку в
     карточке» с пустотой по бокам каждого ряда (снимок владельца 02.09.2026). */
  body.te5-owner [data-rowview="cards"] > .te5-owner-table-wrap {
    overflow: visible;
    padding: 0;
  }
  /* U6: базовый кегль ряда — 13px (второстепенное: номер, дата, заказчик, часы). Названию
     техники и выручке ниже возвращается 15px: по ним ряд и опознают. */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry { font-size: 13px; }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry .te5-chip {
    padding: 2px 7px;
    font-size: 13px;
    font-weight: 600;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry tbody {
    display: grid;
    gap: 0;
    overflow: hidden;
    border: 0;
  }
  /* U1: двухстрочный ряд машины (flex-wrap, перенос через tr::after). */
  /* Полоса выручки в ряду снята по референсу Серёжи (разработчика, не Влада) 02.09.2026, сумма остаётся. */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry tr {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    column-gap: 6px;
    row-gap: 2px;
    /* baseline, не center: название 15px и номер 13px в одной строке иначе «пляшут». */
    align-items: baseline;
    min-height: 64px;
    padding: 11px 13px 11px 40px;
    overflow: visible;
    border: 0;
    border-bottom: 1px solid var(--te5-row-ln);
    border-radius: 0;
    background: var(--te5-card);
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry tr::after {
    content: "";
    flex-basis: 100%;
    order: 35;
    height: 0;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry tr:last-child { border-bottom: 0; }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry tr:nth-child(even) {
    background: var(--te5-surface-raised);
  }
  /* 🛑 Ячейка тут — inline-кусок строки, а не колонка. Базовый ховер кита красит td
     (`.te5-table tr.is-clickable:hover td`) — на телефоне это серые пятна под каждым словом,
     и на тапе ховер залипает. Красим строку, ячейки гасим (как в «Таблице» ниже). */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry tr.is-clickable:hover {
    background: var(--te5-row-hover);
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry tr.is-clickable:hover td {
    background: transparent;
  }
  /* Inset-рамка даты у конфликтной/убранной строки (базовое правило ~1039) посреди
     inline-строки рисуется жёлтым обрубком перед «·»; смысл несёт чип в той же ячейке. */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry
    tr:is(.te5-owner-conflict-row, .te5-owner-deleted-row) td[data-owner-field="work_date"] {
    box-shadow: none;
  }
  /* Дефект A (снимок в браузере): `overflow-wrap: anywhere` рвал слово в произвольной
     точке («Sunward» → «Sunwar»/«d») — снят с общего правила. Свободный текст
     (техника/заказчик) не переносится вовсе, а обрезается многоточием — см. правила
     `equipment_type`/`customer` ниже, тот же приём, что уже стоит в «Таблице» (строка
     ~1049, комментарий там же объясняет, почему перенос забракован). */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry td {
    display: block;
    min-width: 0 !important;
    padding: 0;
    border: 0;
    white-space: normal;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry td::before { content: none; }
  /* ponytail: зона выбора остаётся шириной 36px; чекбокс 18px на left:8px заканчивается
     на 26px, а контент начинается с 40px — между ними 14px. Горизонтальная цель узкая;
     при жалобах — режим выбора кнопкой «Выбрать», до него чекбоксы скрыты.
     🛑 `min-height` обязан совпадать с `min-height` ряда: ячейка растянута `top:0; bottom:0`,
     и значение больше высоты ряда распирало бы строку изнутри. */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry td[data-owner-select-cell] {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    width: 36px;
    min-height: 64px;
    padding-left: 8px;
    box-sizing: border-box;
  }
  /* 🛑 Свой квадрат вместо нативной галочки: системный чекбокс на 22px в ряду 64px читался
     самым тяжёлым элементом строки, спорил с названием техники и в тёмной теме рисовался
     платформенным серым мимо наших токенов. `-webkit-appearance` нужен отдельно — iOS
     Safari шорткат `appearance` до сих пор понимает не везде. */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-select] {
    -webkit-appearance: none;
    appearance: none;
    /* 🛑 `!important` тут ОБЯЗАТЕЛЕН и не заменяется «добавить ещё один класс в селектор»:
       базовое правило размера объявлено как `:is(…, #ownerShowDeleted)`, а специфичность
       `:is()` равна САМОМУ СИЛЬНОМУ аргументу — один id поднимает всю группу до (1,1,1), и
       колонка id перевешивает любое число классов. Без `!important` чекбокс остался бы 22px,
       и отказ был бы молчаливым: текст правила в CSS есть, на экране его нет. */
    width: 18px !important;
    height: 18px !important;
    margin: 0;
    border: 1.5px solid var(--te5-border);
    border-radius: 4px;
    background: var(--te5-card);
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-select]:checked {
    border-color: var(--te5-primary);
    background: var(--te5-primary);
  }
  /* Галочка — две стороны рамки, повёрнутые на 45°: свой глиф не зависит от шрифта, а
     data-URI картинку пришлось бы дублировать под каждую тему. */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry
    [data-owner-select]:checked::after {
    content: "";
    display: block;
    width: 5px;
    height: 9px;
    margin: 1px 0 0 5px;
    border: solid var(--te5-on-primary);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="equipment_type"] {
    order: 10;
    flex: 0 1 auto;
    min-width: 0;
    font-size: 15px;
    font-weight: 600;
    /* Однострочная обрезка многоточием — тот же приём, что и в «Таблице» (та же
       колонка там уже режется так же, `title` с полным значением уже проставлен
       JS'ом). Слово физически не влезает в узкую колонку → лучше обрезать, чем
       ломать посимвольно. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="plate_short"] {
    order: 20;
    flex: none;
    font-size: 13px;
    font-weight: 400;
    color: var(--te5-text-2);
    justify-self: start;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry .te5-owner-rowbtn {
    min-height: 0;
    padding: 0;
    line-height: inherit;
    vertical-align: baseline; /* номер стоит на одной базовой линии с названием */
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="status"] {
    order: 55;
    flex: none;
    min-width: 0;
    margin-left: 0;
  }
  /* 🛑 Чип «Работала» в плашках СКРЫТ, а не покрашен: рабочая строка узнаётся по часам и
     выручке, а видимый чип делал ряд трёхстрочным и утаскивал выручку на третью строку
     (U1d). Цветным остаётся только нерабочий статус — он и есть новость. */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry tr[data-owner-working] [data-owner-field="status"] {
    display: none;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry tr:not([data-owner-working]) .te5-owner-status {
    color: var(--te5-warning);
    background: var(--te5-warning-bg);
    border-color: var(--te5-warning-ln);
  }
  /* Дефект B (снимок в браузере, снят раскладкой Дефекта 7): разрешённый перенос чипа
     сделал «Нет водителя» двухстрочным и крупнее названия техники — чип остаётся
     однострочным (`nowrap`). Прежний потолок 112px снят: в двухколоночной раскладке у
     чипа своя строка вместе с названием техники, места достаточно для полного текста
     («Нет водителя» не должно обрезаться), а колонка `auto` не даёт ему вылезти за
     карточку — под него отдаётся ровно столько места, сколько он занимает. */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="status"] .te5-chip {
    white-space: nowrap;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="customer"] {
    order: 40;
    flex: 0 1 auto;
    min-width: 0;
    color: var(--te5-text-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="work_date"] {
    order: 30;
    flex: none;
    color: var(--te5-text-2);
    white-space: nowrap;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="work_date"] > .te5-chip {
    display: inline;
    margin-right: 4px;
    white-space: nowrap;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry .te5-owner-badge__text {
    display: none;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry :is(
    [data-owner-field="work_date"], [data-owner-field="hours"])::before {
    content: "·";
    margin-right: 6px;
    color: var(--te5-text-2);
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="hours"] {
    order: 50;
    flex: none;
    color: var(--te5-text-2);
    white-space: nowrap;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry tr:not([data-owner-working]) [data-owner-field="hours"][data-owner-zero] {
    display: none;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry :is([data-owner-field="rate"],
    [data-owner-field="potential"], [data-owner-field="note"],
    [data-owner-field="extra_trips"]) { display: none; }
  /* Дефект 3: голое число часов без единицы. `te5-owner.js` оборачивает ТОЛЬКО заполненное
     значение в `.te5-owner-hours-value` (прочерк «—» суффикс не получает); суффикс рисует
     CSS и ТОЛЬКО в «Плашках» — в «Таблице» и на десктопе единицу называет заголовок колонки. */
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry .te5-owner-hours-value::after {
    content: " ч";
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="revenue"] {
    order: 60;
    flex: none;
    display: block;
    margin-left: auto;
    min-height: 0;
    padding: 0;
    font-size: 15px;
    font-weight: 700;
    white-space: nowrap;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry .te5-owner-kop {
    display: none;
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="revenue"][data-owner-zero] {
    color: var(--te5-text-2);
  }
  body.te5-owner [data-rowview="cards"] .te5-owner-table--registry [data-owner-field="revenue"][style*="--owner-revenue-percent"]::before {
    content: none;
  }

  body.te5-owner [data-rowview="table"] > .te5-owner-table-wrap {
    overflow-x: auto;
    overflow-y: auto;
    max-height: calc(100vh - 120px);
    max-height: calc(100dvh - 120px);
    padding: 0;
    border-radius: 0;
  }
  /* 🛑 Порядок колонок на ТЕЛЕФОНЕ разворачивает CSS, а не `REG_FIELDS`. Референс-макет
     владельца (фрейм 1b): «дата + номер приклеена слева, дальше сразу выручка и статус».
     В DOM порядок остаётся десктопным — на нём висят `colgroup`, сортировка, окно правки
     и тесты, а спека волны 3 менять его прямо запрещает.

     Замер до правки (стенд 390×844, 01.09.2026): в этом режиме на экран влезали дата,
     номер и половина «Техники» — ни часов, ни денег, внизу честное «→ ещё 9 колонок».
     Режим существовал и не отвечал НИ НА ОДИН вопрос владельца.

     Разворот делает грид: строка становится гридом с фиксированными треками, ячейка
     садится в свой трек по `grid-column`. Треки именно в px, а не `auto`/`fr`: у каждой
     строки свой грид, и по содержимому они разъедутся между строками — колонки перестанут
     быть колонками. Пин — `phone-table-puts-money-right-after-the-pinned-id`. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry {
    display: block;
    /* Сумма треков строки выше: 78+112+196+56+96+130+146+96+112+160. Меньше суммы —
       треки сожмутся и обрезка вернётся; больше — справа появится мёртвая полоса. */
    min-width: 1182px !important;
  }
  /* 🛑 Липкость ШАПКИ живёт здесь, а не на `th`. Строка — грид, поэтому содержащий блок
     ячейки это `tr` высотой в одну строку: вертикально у липкого `th` ход нулевой, и шапка
     уезжает вместе со списком при живых `z-index`, тени и фоне «под липкую». Замер стенда
     02.09.2026 при `scrollTop=300`: верх `th` ушёл с 460 на 160 — ровно на величину
     прокрутки. У `thead` содержащий блок — вся таблица, ход есть.
     🛑 Фон обязателен: без него строки списка просвечивают сквозь шапку.
     Горизонтальная липкость даты и номера остаётся на самих ячейках — по ширине их `tr`
     растянут на всю таблицу, там хода достаточно. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry thead {
    display: block;
    position: sticky;
    top: 0;
    z-index: 6;
    background: var(--te5-surface-raised);
  }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry tbody { display: block; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry tr {
    display: grid;
    /* идентификатор (номер над датой) · выручка · статус · часы · доп. рейс · заказчик ·
       техника · ставка · потенциал · примечание — ДЕСЯТЬ треков на одиннадцать полей.
       Трек рейсов (96px) — по заголовку «Доп. рейс» с кареткой сортировки: значение
       в нём однозначное, а шапка тут единственная тап-цель сортировки.
       🛑 Дата и номер делят ОДИН трек в два яруса (решение владельца 02.09.2026): порознь
       они съедали 142px из 356 видимых, и статус самой длинной строки («Нет водителя») не
       успевал начаться до сгиба. Так же устроен и референс-макет Серёжи (разработчика, не Влада). Цена названа:
       строка выше, на экран влезает 11 записей вместо 13.
       🛑 Ширины назначены по САМОМУ ДЛИННОМУ содержимому колонки, замер в браузере
       02.09.2026 (`scrollWidth` против `clientWidth` по всем ячейкам страницы), а не на
       глаз. Прежние значения обрезали четыре колонки разом: статус на 49px («Нет
       водителя»), технику на 22px («Хендай 210»), потенциал на 3px, ставку на 2px —
       и обрезка читалась как поломка, а не как «прокрути вбок».
       🛑 Трек держит и ЗАГОЛОВОК колонки, а не только её значения: у «Номера» при 62px
       обрезалась парная каретка сортировки `⇅` (11px, замер 02.09.2026) — обрезанный
       признак нажимаемости читается как сломанная кнопка, а шапка тут единственная тап-цель
       сортировки. Мерить обрезку по `th` и по кнопке внутри него, а не только по `td`.
       🛑 Денежные треки считаны по ПРЕДЕЛУ ФОРМАТА, а не по данным стенда: `999 999,99 ₽`
       рисуется в 88px плюс 24px полей ячейки = 112. На стенде максимум был 41 262 ₽ (103),
       мерка «влезло» зеленела, а шестизначная сумма обрезалась бы уже в проде. Находка —
       мульти-ревью 02.09.2026.
       🛑 Ширину текста мерить `Range.getBoundingClientRect()` ПО НАСТОЯЩЕЙ ЯЧЕЙКЕ. Два
       соседних способа врут в РАЗНЫЕ стороны: `scrollWidth` клампится шириной ячейки и на
       влезающем тексте возвращает саму ширину (ответ «влезло» тавтологичен), а
       синтетический `<span>` со `style.font = getComputedStyle(cell).font` рисуется
       ЗАПАСНЫМ шрифтом — шорткат `font` в Chrome пуст — и завышает. По завышенным числам
       треки в первой редакции этой правки раздулись на 60px и вытолкнули статус за первый
       экран, то есть «починка обрезки» испортила ровно то, что чинила.
       🛑 Ширину таблицы это увеличивает, и так и надо: таблица тут ПРОКРУЧИВАЕТСЯ, экран
       строку целиком не показывает по построению. Ужимать трек ради «влезло» — значит
       менять обрезку на многоточие, то есть прятать данные вместо прокрутки.
       Правишь любой трек — правь `min-width` таблицы ниже: их сумма. */
    grid-template-columns: 78px 112px 196px 56px 96px 130px 146px 96px 112px 160px;
    align-items: center;
    /* Два яруса по ~26px плюс поля. Меньше — ярусы слипаются, номер и дата читаются одной
       строкой; больше — на экран перестают влезать одиннадцать записей. */
    min-height: 60px;
    /* 🛑 СНИМАЕМ `overflow: hidden`, который строка получает от карточного правила выше.
       Липкая ячейка клампится БЛИЖАЙШИМ клипающим предком: пока клипает сама строка,
       дата и номер «прилипают» внутри неё и уезжают вбок вместе с ней. Замер в браузере
       02.09.2026: при scrollLeft=420 от них оставались обрывки у левого края.
       🛑 jsdom этого не ловит — раскладку он не считает; сторож ниже проверяет ИМЕННО
       отсутствие клипа у строки, а не сам факт `position: sticky`. */
    overflow: visible;
    border: 0;
    border-radius: 0;
    background: var(--te5-card);
  }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry tbody tr {
    border-bottom: 1px solid var(--te5-row-ln);
  }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry :is(th, td) {
    /* 🛑 `grid-row: 1` ОБЯЗАТЕЛЕН. Порядок ячеек в DOM десктопный, а треки назначены
       вразнобой: как только очередная ячейка встаёт левее предыдущей, автораскладка
       грида уводит её на новую строку — строка рассыпается лесенкой. Снимок стенда
       02.09.2026 до этой строки: одна запись занимала пять строк экрана.
       🛑 jsdom этого не видит ВООБЩЕ — раскладку он не считает, и тест на порядок
       колонок оставался зелёным на сломанном экране. Проверяется только браузером.
       🛑 `span 2` — потому что строка теперь ДВУХЪЯРУСНАЯ: ярусы нужны только колонке
       идентификатора (номер над датой), остальные тянутся на оба. Без `span 2` ячейка
       сядет в первый ярус, и под ней откроется пустая половина строки. */
    grid-row: 1 / span 2;
    min-width: 0 !important;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* 🛑 Пометка строки («⚠ конфликт», «⚠ проверить», «⊘ Убрана») в этом режиме — ТОЛЬКО глиф
     и ТОЛЬКО вне потока. Подпись целиком требует 106px, а первая ячейка строки это
     приклеенная дата шириной 68px (замер 02.09.2026): в потоке чип выталкивал саму дату за
     край приклеенной колонки — то есть пометка ломала ровно то, ради чего заведена.
     Причина остаётся в `title`, он же доступное имя чипа. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    .te5-owner-badge__text { display: none; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    td[data-owner-field="work_date"] .te5-chip {
    position: absolute;
    top: 2px;
    right: 2px;
    z-index: 1;
    padding: 0 3px;
    border-radius: var(--te5-radius-sm, 4px);
    line-height: 1.1;
  }
  /* Ячейка выбора в этом режиме не нужна: выбор строк живёт в «Плашках», где чекбоксы видны,
     а переключение режима выбор СНИМАЕТ (`te5-owner.js`) — невидимый выбор не имеет права
     пережить переход, иначе массовые часы запишут деньги в набор строк, которого человека
     на экране нет. Из DOM НЕ убираем — на ней держится чекбокс шапки и его тест. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th[data-owner-select-head], td[data-owner-select-cell]) { display: none; }

  /* 🛑 Номер и дата делят трек 1: номер верхним ярусом (он называет строку), дата нижним.
     Оба `grid-row` обязательны — с одним автораскладка положит вторую ячейку куда попало. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="plate_short"] { grid-column: 1; grid-row: 1; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="work_date"] { grid-column: 1; grid-row: 2; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="revenue"] { grid-column: 2; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="status"] { grid-column: 3; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="hours"] { grid-column: 4; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="extra_trips"] { grid-column: 5; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="customer"] { grid-column: 6; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="equipment_type"] { grid-column: 7; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="rate"] { grid-column: 8; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="potential"] { grid-column: 9; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td)[data-owner-field="note"] { grid-column: 10; }

  body.te5-owner [data-rowview="table"] .te5-owner-table--registry th {
    /* 🛑 Вертикальной опоры (`top: 0`) здесь БЫТЬ НЕ ДОЛЖНО: она не действует (см. правило
       thead выше) и маскирует отсутствие рабочей липкости — сторож
       `phone-table-head-sticks-from-thead-not-from-the-cell` её и ловит. */
    /* Наложение: угловые ячейки шапки (5) > липкие td даты и номера (4) > обычный th (3) >
       обычная td (не спозиционирована — под любым th/td с z-index по построению). */
    position: relative;
    z-index: 3;
    /* Тень вместо border-bottom: у липкой шапки граница таблицы остаётся на
       непрокрученной позиции. Токен тот же, что у обычного .te5-table th. */
    box-shadow: 0 1px 0 0 var(--te5-border-2);
  }
  /* 🛑 Шапка — ЕДИНСТВЕННАЯ тап-цель сортировки в этом режиме, и целиться в неё пальцем.
     Общее правило кнопки-заголовка даёт `padding: 8px 16px` без собственной высоты, то
     есть ~34px — ниже порога 44px. Здесь высота задаётся явно, а горизонтальные поля
     ужимаются до 12px: треки узкие (56-160px), и 16px с двух сторон съедали подпись. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry .te5-owner-th__btn {
    /* 🛑 44px — минимум пальца. Ярусов в шапке ДВА («Номер» над «Датой»), и высота тут
       именно на ЯРУС, а не на шапку: сортировок две, кнопки две, ужать одну до 28px значит
       сделать её непопадаемой. Шапка целиком выходит 88px — цена двухъярусной колонки,
       названа здесь же. `height: 100%` растягивает кнопку одноярусных колонок на всю
       ячейку, иначе тап-цель у них была бы вдвое ниже видимого заголовка. */
    min-height: 44px;
    height: 100%;
    padding: 8px 12px;
  }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry thead tr { min-height: 88px; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry td {
    display: block;
    padding: 4px 12px;
    /* Разделитель рисует СТРОКА (tbody tr выше). Общий `.te5-table td` ставит свой
       border-bottom, и вместе они давали две линии с полосой пустоты между ними. */
    border-bottom: 0;
  }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry td::before { content: none; }

  /* 🛑 Липнут ОБА идентификатора, а не одна дата: за день строк до 29, по одной на машину,
     и при свайпе вбок строка без номера теряет имя. Второй сдвинут ровно на ширину первого
     трека. 🛑 Офсет у обоих НУЛЕВОЙ — они делят ОДИН трек и стоят ярусами, а не рядом;
     ненулевой `left` у второго увёл бы его вправо на пустое место. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    :is(th, td):is([data-owner-field="work_date"], [data-owner-field="plate_short"]) {
    position: sticky;
    left: 0;
  }
  /* Фон липких td — токен поверхности ПОД таблицей, у th — токен самой шапки
     (--te5-surface-raised, см. .te5-table th): иначе угловые ячейки заметно темнее
     соседних в тёмной теме. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    td:is([data-owner-field="work_date"], [data-owner-field="plate_short"]) {
    z-index: 4;
    background: var(--te5-card);
    /* 🛑 Липкие ячейки тянутся на ВСЮ высоту строки. Они единственные красят собственный
       фон (иначе прокручиваемое содержимое просвечивало бы сквозь них), а высота у них
       разная по построению: в номере лежит кнопка правки и он занимает всю строку, в дате
       только текст — 23px по центру. Замер 02.09.2026: на подсвеченной строке это давало
       уступ из двух полос разной высоты. `align-self` без `align-items` не хватает —
       растянутая ячейка прижала бы текст к верху. */
    align-self: stretch;
    display: flex;
    align-items: center;
  }
  /* Иерархия ярусов: номер называет строку и потому главный — вес; дата вторична — тоном.
     Разделять их линией не надо, разницы веса и цвета хватает, а линия в 78px читалась бы
     как граница ячейки. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    td[data-owner-field="plate_short"] { font-weight: 700; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    td[data-owner-field="work_date"] { color: var(--te5-text-2); }
  /* 🛑 Вертикальные поля у ярусов режем до нуля, а высоту строки держит `min-height` выше.
     Общее `padding: 4px 12px` платится ДВАЖДЫ (ярусов два) и вместе с собственными полями
     кнопки номера давало строку 76px — девять записей на экран вместо тринадцати в
     одноярусной раскладке. Кегль при этом не трогаем: пол кегля здесь задаёт гейт
     `owner-readable-text-keeps-a-floor` (13px внутри этого медиа-блока), а ужимать текст
     ради высоты всё равно нельзя — только воздух. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    td:is([data-owner-field="plate_short"], [data-owner-field="work_date"]) {
    padding-top: 0;
    padding-bottom: 0;
    line-height: 1.2;
  }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    td[data-owner-field="plate_short"] .te5-owner-rowbtn { padding: 0; min-height: 0; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    th:is([data-owner-field="work_date"], [data-owner-field="plate_short"]) {
    z-index: 5;
    background: var(--te5-surface-raised);
    box-shadow: 0 1px 0 0 var(--te5-border-2);
  }
  /* Кромку отрыва рисуют ОБА яруса приклеенной колонки: они делят трек по вертикали, и
     линия на одном оборвалась бы на половине высоты строки.
     🛑 ЛИНИЯ, а не размытая тень. Прежние `10px 0 12px -12px` давали на светлом полотне
     серое пятно шириной в десяток пикселей, наползавшее на соседнюю колонку, — владелец
     забраковал его 02.09.2026 («тень справа от номеров некрасивая»). Радиус размытия
     обязан оставаться нулевым: сторож `phone-table-head-is-thumb-sized-and-pinned-edge-is-
     a-hairline` читает третье число `box-shadow`. Именно `box-shadow`, а не `border-right`:
     граница добавила бы ячейке ширину и сдвинула бы весь трек. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    td:is([data-owner-field="plate_short"], [data-owner-field="work_date"]) {
    box-shadow: 1px 0 0 0 var(--te5-border);
  }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry
    th[data-owner-field="plate_short"] {
    box-shadow: 1px 0 0 0 var(--te5-border), 0 1px 0 0 var(--te5-border-2);
  }
  /* 🛑 Подсветку строки красит САМА СТРОКА, а не её ячейки. Общее правило кита
     (`.te5-table tr.is-clickable:hover td`) красит ячейки, а в гриде ячейка ростом со своё
     содержимое (~23px) и стоит по центру строки высотой 60px — подсветка выходила узкой
     полосой посередине, тогда как приклеенные ячейки (у них `align-self: stretch`, им нужен
     непрозрачный фон) красились во всю высоту. На экране это читалось как уступ и артефакт
     отрисовки, замечено на скриншотах 02.09.2026. Гасим ячейки прозрачным и красим строку;
     приклеенным фон оставляем — сквозь них иначе просвечивает прокрутка. */
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry tbody tr.is-clickable:hover {
    background: var(--te5-row-hover);
  }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry tbody tr.is-clickable:hover
    td { background: transparent; }
  body.te5-owner [data-rowview="table"] .te5-owner-table--registry tbody tr:hover
    td:is([data-owner-field="work_date"], [data-owner-field="plate_short"]) {
    background: var(--te5-row-hover);
  }
  body.te5-owner [data-rowview="table"] .te5-owner-table-shell::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 44px;
    z-index: 5;
    width: 28px;
    background: linear-gradient(to right, transparent, var(--te5-card));
    pointer-events: none;
  }
  body.te5-owner [data-rowview="table"] .te5-owner-more-columns {
    display: block;
    min-height: 44px;
    padding: 10px 12px;
    color: var(--te5-text-2);
    text-align: right;
  }

  /* U3: карточка периода и шторка */
  body.te5-owner .te5-owner-period {
    display: flex;
    align-items: center;
    gap: var(--te5-gap-tight);
    min-height: 56px;
    margin-bottom: 12px;
    padding: 6px 8px 6px 12px;
    border: 1px solid var(--te5-border);
    border-radius: var(--te5-radius-card);
    background: var(--te5-card);
    box-shadow: var(--te5-shadow-sm);
    font-size: 16px;
  }
  body.te5-owner .te5-owner-period__range {
    min-width: 0;
    flex: 1;
    color: var(--te5-text);
    font-size: 14px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }
  body.te5-owner .te5-owner-period__change {
    flex: none;
    min-height: 44px;
    padding: 0 12px;
    border-color: var(--te5-primary-ln);
    background: var(--te5-primary-bg);
    color: var(--te5-primary);
    font-size: 13px;
    font-weight: 600;
  }
  body.te5-owner .te5-owner-sheet { display: none; }
  body.te5-owner [data-owner-sheet][open] {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 80;
  }
  body.te5-owner [data-owner-sheet][open] .te5-owner-sheet__scrim {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    background: rgba(20, 28, 42, .56);
  }
  body.te5-owner [data-owner-sheet][open] .te5-owner-sheet__panel {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    max-height: calc(100dvh - 32px);
    overflow-y: auto;
    padding-bottom: env(safe-area-inset-bottom);
    border-radius: 16px 16px 0 0;
    background: var(--te5-card);
    box-shadow: var(--te5-shadow-float);
  }
  body.te5-owner [data-owner-sheet][open] .te5-filter-panel {
    margin: 0;
    border: 0;
    border-radius: 16px 16px 0 0;
    box-shadow: none;
  }
  body.te5-owner [data-owner-sheet][open] .te5-owner-presets .te5-btn--primary {
    border-color: var(--te5-primary-ln);
    background: var(--te5-primary-bg);
    color: var(--te5-primary);
  }
  /* U6: кегли шторки. «Показать» крупнее пресетов и дат — это единственное действие,
     закрывающее шторку, остальное в ней только настраивает. */
  body.te5-owner .te5-owner-sheet .te5-owner-presets .te5-btn {
    font-size: 14px;
    font-weight: 600;
  }
  /* 🛑 16px, не 14: это `<input type="date">`, iOS Safari зумит страницу при фокусе на
     контроле мельче 16px, и шторка на `position: fixed` разъезжается с экраном. */
  body.te5-owner .te5-owner-sheet .te5-owner-range__input {
    font-size: 16px;
    font-weight: 400;
  }
  body.te5-owner .te5-owner-sheet #ownerApply {
    font-size: 15px;
    font-weight: 600;
  }
  /* U4: панель действий и меню */
  /* 🛑 Обе обёртки скоупим через `.te5-owner-actions` НЕ для красоты: на них висит
     `role="group"`, а десктопное правило `body.te5-owner .te5-owner-actions [role="group"]`
     (inline-flex + gap 8px) имеет специфичность (0,3,1). Голый `.te5-owner-actions__bar`
     — (0,2,1), и медиазапрос специфичность НЕ поднимает: `display` и `gap` телефона
     проигрывали бы молча, меню висело бы открытым всегда, а панель раскладывалась бы в
     порядке DOM. Равная специфичность + позиция ниже по файлу = телефон выигрывает. */
  body.te5-owner .te5-owner-actions { display: contents; }
  body.te5-owner .te5-owner-actions .te5-owner-actions__bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 25;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, .9fr)) minmax(0, 1.25fr) minmax(44px, .55fr);
    gap: 6px;
    padding: 8px 12px calc(8px + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid var(--te5-border);
    background: color-mix(in srgb, var(--te5-card) 92%, transparent);
    box-shadow: var(--te5-shadow-float);
    backdrop-filter: blur(12px);
  }
  body.te5-owner .te5-owner-actions__bar .te5-btn {
    width: 100%;
    min-height: 44px;
    padding: 6px 4px;
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
  }
  body.te5-owner .te5-owner-actions__bar [data-owner-bulk-hours="8"] { order: 1; }
  body.te5-owner .te5-owner-actions__bar [data-owner-bulk-hours="11"] { order: 2; }
  body.te5-owner .te5-owner-actions__bar [data-registry-add] { order: 3; }
  body.te5-owner .te5-owner-actions__bar [data-owner-more-open] { order: 4; }
  body.te5-owner .te5-owner-add-full,
  body.te5-owner .te5-owner-rowview { display: none; }
  body.te5-owner .te5-owner-add-short { display: inline; }
  body.te5-owner [data-owner-more-open],
  body.te5-owner [data-owner-more-rowview] { display: inline-flex; }
  /* Подпись «Без выбора — всем без часов» / «Выбрано: N» — первой строкой панели на всю
     ширину: суффиксы «8 ч всем» в кнопках не влезали при 16px и переносились посреди «8 ч». */
  body.te5-owner .te5-owner-actions__bar .te5-owner-bulk-label {
    grid-column: 1 / -1;
    order: 0;
    color: var(--te5-text-2);
    font-size: 13px;
    font-weight: 400;
    line-height: 1.2;
  }
  body.te5-owner .te5-owner-actions .te5-owner-actions__more {
    display: none;
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: calc(69px + env(safe-area-inset-bottom, 0px));
    z-index: 32;
    padding: 8px;
    border: 1px solid var(--te5-border);
    border-radius: var(--te5-radius-card);
    background: var(--te5-card);
    box-shadow: var(--te5-shadow-md);
  }
  body.te5-owner .te5-owner-actions .te5-owner-actions__more[open] {
    display: grid;
    grid-template-columns: 1fr;
    gap: 6px;
  }
  body.te5-owner .te5-owner-actions__more .te5-btn {
    width: 100%;
    min-height: 44px;
    justify-content: flex-start;
    color: var(--te5-text);
    font-size: 14px;
    font-weight: 400;
    text-align: left;
  }
  /* Этажи: панель 25 (под липкой шапкой 30 — они не пересекаются), скрим 31 и меню 32
     ВЫШЕ шапки, иначе шапка остаётся яркой и кликабельной под открытым меню. Оба ниже
     подложки модалки (60) и тостов (100). */
  body.te5-owner .te5-owner-actions__more[open] + .te5-owner-actions__scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 31;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    background: rgba(20, 28, 42, .45);
    touch-action: none;
  }
  /* Отступ под фиксированную панель — только там, где она есть: на фидах (Фитинги/ГНБ)
     панели нет, и без `:has()` внизу висели 88px пустоты (нашло ревью 02.09.2026). */
  body.te5-owner .te5-main:has(.te5-owner-actions__bar) {
    padding-bottom: calc(88px + env(safe-area-inset-bottom, 0px));
  }
  /* Открытая шторка или меню запирают прокрутку фона — как у модалки и навигации. */
  body.te5-owner:has([data-owner-sheet][open]),
  body.te5-owner:has(.te5-owner-actions__more[open]) { overflow: hidden; }
  body.te5-owner .te5-owner-pagehead__actions a[href="/console/owner-pwa/"] {
    background: transparent !important;
    border-color: var(--te5-primary-ln) !important;
    color: var(--te5-primary) !important;
  }
}

/* ---------- timeline ---------- */

.te5-timeline { list-style: none; margin: 0; padding: 0; }
.te5-timeline li { display: flex; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--te5-row-ln); font-size: 13px; align-items: baseline; }
.te5-timeline li:last-child { border-bottom: none; }
/* Граница поколений: до неё водитель видел одно, после начал день заново. Полоса рисуется
   акцентом слева, а не заливкой — заливка спорила бы с чипами статуса рядом. */
.te5-timeline__divider { border-left: 3px solid var(--te5-primary); padding-left: 9px; }
/* Отметки закрытого поколения остаются в ленте (в этом смысл сброса), но приглушены.
   Цвет берётся токеном, а не своим значением: контраст-гейт консоли считает именно
   токены, и собственный hex выпал бы из-под проверки молча. */
.te5-timeline__past time,
.te5-timeline__past > span,
/* 🛑 Строка ТАБЛИЦЫ (карточка «Работы»), а не только пункт ленты. Правило било по `time`
   и `> span`, поэтому тот же класс на `<tr>` не красил НИЧЕГО: класс в разметке есть,
   тест зелёный, а на экране приглушения нет. Тот же капкан, что «CSS написан, а JS
   класс не выпускает», только с другой стороны. */
.te5-timeline__past > td { color: var(--te5-text-2); }
.te5-timeline time { font-family: var(--te5-mono); font-size: 12.5px; color: var(--te5-text-2); white-space: nowrap; }

/* ---------- mobile (driver / customer) ---------- */

.te5-mobile { max-width: 480px; margin: 0 auto; padding: 16px; padding-bottom: 40px; }
.te5-mobile-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: nowrap;
  margin-bottom: 14px;
}
.te5-mobile-head__brand {
  min-width: 0;
  flex: 1 1 150px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.te5-mobile-head__mark { width: 34px; height: 34px; border-radius: 8px; }
.te5-mobile-burger {
  width: 38px;
  height: 38px;
  flex: 0 0 38px;
  border-radius: 9px;
  border: 1px solid var(--te5-border);
  background: var(--te5-card);
  color: var(--te5-text);
  font: inherit;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.te5-mobile-burger:hover { border-color: var(--te5-primary); background: var(--te5-hover-bg); }
.te5-mobile-head__copy { min-width: 0; }
.te5-mobile-head__title {
  font-weight: 700;
  font-size: 15px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.te5-mobile-head__actions {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  min-width: 0;
}
.te5-mobile-head__actions .te5-chip {
  max-width: 112px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.te5-mobile-head__status {
  max-width: 156px;
  min-height: 38px;
  padding: 0 18px;
  font-size: 15px;
  border-width: 1.5px;
  box-shadow: 0 0 0 3px var(--te5-primary-bg);
}
/* Обёртка статуса: вне scale — компактная inline-плашка по контенту (вид не меняется);
   в scale (≤768) занимает 100% ширины → статус уходит на свою строку (chip внутри
   остаётся компактным, max-width:156px). */
.te5-mobile-head__statusrow { display: inline-flex; align-items: center; min-width: 0; }
.te5-mobile-menu {
  margin: -4px 0 14px;
  border: 1px solid var(--te5-border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--te5-card);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.12);
}
.te5-mobile-menu[hidden] { display: none; }
.te5-mobile-menu__item {
  width: 100%;
  min-height: 46px;
  padding: 0 14px;
  border: 0;
  background: var(--te5-card);
  color: var(--te5-text);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}
.te5-mobile-menu__item:hover { background: var(--te5-hover-bg); }
.te5-mobile-menu__logout {
  color: var(--te5-bad);
  background: var(--te5-bad-bg);
}
.te5-mobile-menu__logout:hover {
  color: var(--te5-bad);
  background: var(--te5-bad-bg);
}
/* «Привязать MAX»: акцент-приглашение; привязано (.is-linked) — спокойный ok-тон. */
.te5-mobile-menu__maxlink {
  color: var(--te5-primary);
  background: var(--te5-primary-bg);
  border-bottom: 1px solid var(--te5-border);
}
.te5-mobile-menu__maxlink:hover { background: var(--te5-primary-bg); }
.te5-mobile-menu__maxlink.is-linked {
  color: var(--te5-ok);
  background: var(--te5-ok-bg);
}
.te5-mobile-menu__maxlink.is-linked:hover { background: var(--te5-ok-bg); }
.te5-driver-log-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: start;
  padding: 9px 0;
  border-bottom: 1px solid var(--te5-row-ln);
  font-size: 13.5px;
}
.te5-driver-log-row:last-child { border-bottom: none; }
.te5-driver-log-row__event { min-width: 0; }
.te5-driver-log-row__time {
  color: var(--te5-text-2);
  font-family: var(--te5-mono);
  font-size: 12px;
  font-weight: 400;
  text-align: right;
  white-space: nowrap;
}
.te5-driver-log-row__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  min-width: 86px;
}
.te5-route-event-edit {
  min-height: 36px;
  padding: 0 10px;
  border: 1px solid var(--te5-input-ln);
  border-radius: 10px;
  background: var(--te5-card);
  color: var(--te5-primary);
  font: inherit;
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}
.te5-route-event-edit:active { transform: scale(.97); }
.te5-driver-log-row--pending { color: var(--te5-warn); }
.te5-driver-log-row--pending .te5-driver-log-row__time { color: var(--te5-warn); }
.te5-cta {
  width: 100%; min-height: 84px; border: none; border-radius: 12px; background: var(--te5-primary); color: var(--te5-on-primary);
  font: inherit; font-size: 18px; font-weight: 700; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 10px;
  /* T18 (j 02.07): текст CTA центрируется по ВСЕЙ кнопке, «будто эмодзи нет» — эмодзи absolute у левого
     края (канон «Sign in with …»-кнопок). Side-padding СИММЕТРИЧНЫЙ (центр сохранён) и только у CTA
     С эмодзи (`--emo`, ставит JS) — кнопки без эмодзи (объекты/Сохранить/customer) не теряют ширину. */
  position: relative;
}
.te5-cta--emo { padding-left: 52px; padding-right: 52px; }
.te5-cta .te5-tile__emo {
  position: absolute; left: 8px; top: 50%; transform: translateY(-50%);
  font-size: 32px; width: auto;  /* width:auto сбрасывает 1.5em-бокс базового __emo (глиф ровно на left) */
}
/* узкие ≤360: эмодзи ещё компактнее (на 320px текст заходил на эмодзи; симметрия → центр сохранён) */
@media (max-width: 360px) {
  .te5-cta--emo { padding-left: 46px; padding-right: 46px; }
  .te5-cta .te5-tile__emo { left: 6px; font-size: 28px; }
}
.te5-cta:hover { background: var(--te5-primary-hover); }
.te5-cta:disabled { opacity: .55; cursor: not-allowed; }
.te5-cta--secondary { background: var(--te5-card); color: var(--te5-text); border: 1px solid var(--te5-input-ln); min-height: 56px; font-size: 15px; }
.te5-cta--secondary:hover { background: var(--te5-hover-bg); }
.te5-touch { min-height: 48px; }

/* ===== Тикет A: мобильный ×1.5 driver-UI (scope .te5-driver-scale, только /driver) =====
   Базовые классы — для де-инлайненных узлов driver.js (значения 1:1 прежним инлайнам,
   вид вне мобилы не меняется); scoped-блок крупнит их ~×1.5 только под driver-маркером. */
.te5-driver-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.te5-driver-section-label { font-size: 12px; font-weight: 600; color: var(--te5-muted); text-transform: uppercase; letter-spacing: .4px; }
.te5-cta__sub { display: block; font-size: 12px; font-weight: 400; opacity: .75; }
/* (col-обёртка nag-кнопок удалена — T19 убрал подписи, колонка больше не рендерится) */
.te5-driver-work-row { display: flex; justify-content: space-between; gap: 8px; padding: 8px 0; border-bottom: 1px solid var(--te5-row-ln); font-size: 13.5px; }

@media (max-width: 768px) {
  body.te5.te5-driver-scale { font-size: 21px; }
  .te5-driver-scale .te5-cta { min-height: 120px; font-size: 26px; }
  /* --secondary ПОСЛЕ .te5-cta (равная специфичность → порядок решает, KTD-5) */
  .te5-driver-scale .te5-cta--secondary { min-height: 84px; font-size: 22px; }
  /* T8 (j 02.07): nag «Включить уведомления» — меньше шрифт (22 переносил на 2 строки) → 1 строка,
     и не такая огромная. ПОСЛЕ --secondary (равная спец. 0,2,0 → порядок решает). */
  .te5-driver-scale .te5-cta--nag { min-height: 84px; font-size: 18px; }
  .te5-driver-scale .te5-cta__sub { font-size: 17px; }
  /* хедер: бургер / лого / номер ПЛ / кнопка темы — крупнее (статус-чип «На объекте» НЕ трогаем —
     решение j 2026-06-26). __title с ellipsis: если статус длинный и не влезает — отдельно решим. */
  .te5-driver-scale .te5-mobile-head { flex-wrap: wrap; }
  /* 2 ряда: (1) бургер + лого + номер ПЛ + тема — по краям, номер растягивается между;
     (2) статус «На объекте» своей строкой. Статус вынесен из __actions в DOM (driver.js
     head), уходит на 2-й ряд → освобождает 1-й для номера ПЛ — j 2026-06-26. */
  .te5-driver-scale .te5-mobile-head { gap: 8px; }
  .te5-driver-scale .te5-mobile-burger { order: 1; width: 58px; height: 58px; flex: 0 0 58px; font-size: 30px; border-radius: 12px; }
  .te5-driver-scale .te5-mobile-head__brand { order: 2; gap: 8px; }
  .te5-driver-scale .te5-mobile-head__actions { order: 3; }
  .te5-driver-scale .te5-mobile-head__statusrow { order: 4; flex-basis: 100%; display: flex; }
  /* статус «На объекте» — во всю полоску ряда: высокий, текст крупный, углы менее
     круглые (12px вместо pill). Чип растягивается на 100% (max-width снят) — j 2026-06-26. */
  .te5-driver-scale .te5-mobile-head__status {
    width: 100%;
    max-width: none;
    min-height: 60px;
    border-radius: 12px;
    font-size: 22px;
    font-weight: 700;
    justify-content: center;
  }
  .te5-driver-scale .te5-mobile-head__mark { width: 46px; height: 46px; border-radius: 11px; }
  /* номер ПЛ 20px — максимум, что влезает целиком рядом с крупными бургером+темой на
     390px (22px обрезает длинный «ПЛ-MAXTEST-001»; лого/гэпы уже ужаты до предела). */
  .te5-driver-scale .te5-mobile-head__title { font-size: 20px; }
  .te5-driver-scale .te5-theme-toggle { width: 56px; height: 56px; font-size: 26px; }
  .te5-driver-scale .te5-driver-section-label { font-size: 18px; }
  .te5-driver-scale .te5-driver-work-row { font-size: 20px; }
  .te5-driver-scale .te5-driver-log-row { font-size: 20px; }
  .te5-driver-scale .te5-driver-log-row__time { font-size: 17px; }
  .te5-driver-scale .te5-route-event-edit { min-height: 48px; font-size: 17px; padding: 0 14px; }
}
@media (max-width: 340px) {
  /* 2→1 кол только на ОЧЕНЬ узких (≤340: старые/mini до iPhone SE). Телефон j (360/375) — 2 кол
     (правка j 02.07: рефлоу стоял на 380 → mini/SE давали 1 кол; j хочет 2 в ряд). */
  .te5-driver-scale .te5-driver-actions { grid-template-columns: 1fr; }
}
/* ===== /Тикет A ===== */

/* ===== Тикет B (TE-16): плиточный язык полевого флоу =====
   Плитка действия — эмодзи слева + текст, белая (без цвета — главный экран, spec §Цвета).
   Размеры АБСОЛЮТНЫЕ и НЕ под .te5-driver-scale (KTD-7: иначе компаунд с ×1.5 = гигантизм).
   Размерный язык консолидируется в B8; плитка действия в размере «толстая 113»
   (spec §Размеры; выбор j 29.06 — компактнее «огромного 132», меньше скролла, всё ещё под перчатку). */
.te5-tile {
  display: flex; align-items: center; gap: 12px; text-align: left; width: 100%;
  min-height: 113px; border-radius: 16px; border: 2px solid var(--te5-border);
  background: var(--te5-card); color: var(--te5-text); cursor: pointer;
  padding: 10px 14px; font: inherit; font-size: 22px; font-weight: 800; line-height: 1.15;
}
.te5-tile:active { transform: scale(.98); }
.te5-tile__emo { flex: 0 0 auto; width: 1.5em; text-align: center; font-size: 36px; line-height: 1; }
.te5-tile__label { flex: 1; }
.te5-tile--full { grid-column: 1 / -1; }
/* Главный экран (действия): контент плитки ПО ЦЕНТРУ — как hero «Начал работу» / «Завершить
   смену», не слева (j 2026-06-29). Базовая .te5-tile остаётся left-aligned для picker'а
   по разделам (B2 — список работ читается как меню, слева). */
/* C1 (j 29.06 прод): min-width:0 — грид-ячейка сжимается до 1fr, не раздувается по min-content
   контента (эмодзи+длинная метка действия) → нет горизонтального оверфлоу экрана.
   + ужатые эмодзи/gap/padding для 2-кол плиток, чтобы длинные надписи влезали без клипа. */
.te5-driver-actions .te5-tile { justify-content: center; min-width: 0; }
.te5-driver-actions .te5-tile .te5-tile__label { flex: 0 1 auto; min-width: 0; text-align: center; }
/* C1-полиш (j 29.06): тесный эмодзи↔текст + ужатые отступы ТОЛЬКО для 2-кол плиток
   (чтоб «Простой»/«Убыл с объекта» влезали). Full-width (Добавить работу/QR) — базовый отступ
   как было (места полно). Фикс scoped — никакие другие кнопки не задеты. */
.te5-driver-actions .te5-tile:not(.te5-tile--full) { gap: 6px; padding: 10px; }
.te5-driver-actions .te5-tile:not(.te5-tile--full) .te5-tile__emo { font-size: 30px; width: auto; }
/* T16 (правка j 02.07, финал — история left→center→left→center): метка 2-кол по ЦЕНТРУ. У 2-строчных
   («Убыл с/объекта», «Второй/объект») обе строки центрируются в боксе метки; группа [эмодзи|текст]
   и так центрирована в плитке (justify-content:center). j выбрал центр по скрину #53. */
.te5-driver-actions .te5-tile:not(.te5-tile--full) .te5-tile__label { text-align: center; }

/* Акцент-полосы picker'а (синий/жёлтый/бирюза слева) УБРАНЫ (правка j 02.07 — раздел и так подписан,
   цвета лишние). Мёртвые классы полос и бирюзовый токен удалены (плитки picker'а просто белые). */
/* C1 (j 02.07): заголовок раздела picker — КРУПНЫЙ и ЯРКИЙ (не блёклый muted 12px). Перебивает
   наследуемый .te5-driver-section-label (+ scale-override ниже, т.к. `.te5-driver-scale
   .te5-driver-section-label` 18px иначе побеждает). Чёткий подзаголовок ВЫВОЗ/ОЖИДАНИЕ/ПРОЧЕЕ. */
.te5-picker__head { margin: 18px 2px 10px; font-size: 22px; font-weight: 800; color: var(--te5-text); letter-spacing: .3px; }
.te5-driver-scale .te5-picker__head { font-size: 22px; }
/* C2 (j 02.07): picker — 2 плитки в ряд (компактнее). Короткие метки в driver.js. Плитки —
   компактная обработка: min-width:0 (грид-ячейка сжимается, иначе длинное «Перебазировка» распирает
   > контейнера → оверфлоу), меньше эмодзи/шрифт, break-word на случай длинного одиночного слова. */
.te5-picker__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
/* T14 (j 02.07): группа [эмодзи+текст] по ЦЕНТРУ плитки picker (как действия главного
   `.te5-driver-actions .te5-tile`) — была прижата влево. Текст метки остаётся left (жмётся к эмодзи). */
.te5-picker__grid .te5-tile { min-width: 0; gap: 6px; padding: 12px 10px; font-size: 18px; justify-content: center; }
.te5-picker__grid .te5-tile__emo { font-size: 26px; width: auto; }
.te5-picker__grid .te5-tile__label { flex: 0 1 auto; min-width: 0; overflow-wrap: break-word; }
/* B2 (j 02.07): экран простоя — 3 причины по 1 в ряд (1 колонка, перебивает picker-2-кол; 0,2,0 >
   .te5-picker__grid 0,1,0), текст плиток ПО ЦЕНТРУ. Базовый .te5-tile (picker-меню) не тронут (KTD). */
.te5-picker__grid.te5-idle-reasons { grid-template-columns: 1fr; }
/* T15 (правка j 02.07): причины простоя — КРУПНЫЙ шрифт (22px как плитки действий/базовый .te5-tile,
   не мелкие 18px picker'а — это полноширинные tap-цели выбора причины, а не список). Эмодзи крупнее. */
.te5-idle-reasons .te5-tile { justify-content: center; font-size: 22px; }
.te5-idle-reasons .te5-tile__emo { font-size: 32px; }
.te5-idle-reasons .te5-tile__label { flex: 0 1 auto; text-align: center; }

/* screen-router (KTD-1) + C3/C4 (j 29.06): под-экраны рисуют МИНИМАЛЬНЫЙ навбар в #driverHead
   [‹ Назад | Заголовок центр | ☀тема] — статус/бургер/номер скрыты. Тело экрана без своей шапки. */
.te5-screen-nav { display: flex; align-items: center; gap: 10px; }
/* T2 (j 02.07): кнопки навбара (Назад-стрелка + тема) — ЕДИНЫЙ размер с бургером главного экрана
   (`.te5-mobile-burger`): база 38×38 radius 9, scale ≤768 → 58×58 radius 12 (ниже). «Назад» = только
   крупная стрелка «‹» (без текста), квадрат как бургер → единый стиль первой страницы и под-экранов. */
.te5-screen-nav__back {
  flex: 0 0 38px; width: 38px; height: 38px; padding: 0;
  border: 1px solid var(--te5-border); background: var(--te5-card); color: var(--te5-text);
  font: inherit; border-radius: 9px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.te5-screen-nav__back:hover { border-color: var(--te5-primary); background: var(--te5-hover-bg); }
.te5-screen-nav__back:active { transform: scale(.97); }
/* T10 (j 02.07): стрелка — SVG-шеврон (толще/длиннее граней, чем глиф «‹»), центрирован flex'ом
   родителя; currentColor = тема-корректно. База 22 / scale 30 (пропорц. кнопке 38/58). */
.te5-screen-nav__chev { width: 22px; height: 22px; display: block; }
/* Три полоски бургера — SVG того же размера, что шеврон «Назад»: глиф «☰» сидел ниже
   центра квадрата из-за базовой линии шрифта (владелец 03.09.2026, кадр с iPhone). */
.te5-mobile-burger__icon { width: 22px; height: 22px; display: block; }
/* заголовок — flex:1 между Назад и темой, текст по центру; длинный обрезается ellipsis (не рвёт навбар) */
.te5-screen-nav__title { flex: 1; min-width: 0; margin: 0; font-size: 18px; font-weight: 800; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* кнопка темы в навбаре — тот же квадрат 38 (база) / 58 (scale ниже), рамка как бургер (не круг). */
.te5-screen-nav .te5-theme-toggle {
  width: 38px; min-width: 38px; height: 38px; min-height: 38px; flex: 0 0 38px; padding: 0;
  border-radius: 9px; border: 1px solid var(--te5-border); background: var(--te5-toggle-bg); box-shadow: none; font-size: 20px;
}
/* scale ≤768: навбар-кнопки 58×58 как бургер (спецификность 0,2,0 / 0,3,0 бьёт scale-тему 56px 0,2,0). */
@media (max-width: 768px) {
  .te5-driver-scale .te5-screen-nav__back { width: 58px; height: 58px; flex: 0 0 58px; border-radius: 12px; }
  .te5-driver-scale .te5-screen-nav__chev { width: 30px; height: 30px; }
  .te5-driver-scale .te5-screen-nav .te5-theme-toggle { width: 58px; height: 58px; min-width: 58px; min-height: 58px; flex: 0 0 58px; font-size: 30px; border-radius: 12px; }
}

/* C2 (j 29.06): persistent-слот «Включить уведомления» наверху (после #driverHead, вне #driverBody).
   Пустой — скрыт, чтоб не давать отступ на экранах где nag не нужен (push включён/не поддержан). */
.te5-driver-nag:empty { display: none; }
/* Статус смены в теле (правка j 02.07): полноширинная плашка «На базе»/«Работает» под nag, перед hero. */
.te5-driver-statusbar { display: flex; margin: 0 0 12px; }
.te5-driver-statusbar .te5-chip { flex: 1; justify-content: center; }
.te5-form { display: flex; flex-direction: column; gap: 12px; }

/* B3 форма работы: степлер ± (рейсы/объём), подсказка часовых, коммент по кнопке, крупное «Сохранить» */
/* D3 (j 02.07): метки формы КАПСОМ + крупнее + цвет темы (как заголовки разделов picker). */
.te5-form__label { font-size: 20px; font-weight: 800; margin-top: 10px; text-transform: uppercase; letter-spacing: .3px; color: var(--te5-text); }  /* T5 (j 02.07): 20px крупнее (было 18) */
/* (инлайн-хинт объёма «в среднем 25–35» и его тише-класс удалены — правка j 02.07: лишний текст) */
.te5-form__hint {
  font-size: 15px; color: var(--te5-text-2); background: var(--te5-card);
  border: 1px solid var(--te5-border); border-radius: 12px; padding: 14px;
}
.te5-stepper { display: flex; align-items: stretch; gap: 14px; }
.te5-stepper__btn {
  flex: 0 0 auto; width: 90px; min-height: 90px; font-size: 46px; font-weight: 800; line-height: 1;
  border-radius: 18px; border: 2px solid var(--te5-input-ln); background: var(--te5-card); color: var(--te5-text); cursor: pointer;
}
.te5-stepper__btn:active { transform: scale(.96); }
/* T4 (j 02.07): ± на лимите — серые (disabled-вид), «типа заблокировано». Тап = no-op (setVal
   всё равно клампит min/max), класс чисто визуальный → не ломает hold/keyboard. */
.te5-stepper__btn--off { opacity: .38; cursor: default; }
.te5-stepper__val {
  flex: 1; display: flex; align-items: center; justify-content: center; min-height: 90px;
  /* T5 (j 02.07): 38px — крупнее (было 32, j: «верни крупнее»); nowrap: «30.0 м³» в ОДНУ строку.
     Рейсы «1» и объём «N м³» — ОДИН класс → одинаковый шрифт (T4). */
  font-size: 38px; font-weight: 900; white-space: nowrap; background: var(--te5-card); border: 2px solid var(--te5-input-ln); border-radius: 18px;
}
/* C5: значение объёма — тапабельное (ручной ввод цифрами в попапе). Пунктирная рамка =
   «нажми, чтобы ввести» (тот же язык, что кнопка «Добавить комментарий» .te5-form__cmt). */
.te5-stepper__val--edit { cursor: pointer; color: var(--te5-text); font-family: inherit; padding: 0; -webkit-appearance: none; appearance: none; border-style: dashed; }
.te5-stepper__val--edit:active { transform: scale(.98); }
.te5-time-date {
  min-height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--te5-input-ln);
  border-radius: 14px;
  background: var(--te5-card);
  color: var(--te5-text);
  font-size: 28px;
  font-weight: 900;
}
.te5-time-stepper .te5-stepper__val { font-family: var(--te5-mono); }
.te5-object-total-row .te5-driver-log-row__time {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}
/* Узкие/старые телефоны ≤360px (edge, ревью-матрица 02.07): значение объёма `flex:1`+`nowrap` не
   сжималось ниже «30.0 м³» → кнопка «+» вылезала за экран (горизонт-скролл). Ужимаем степлер-кнопки
   и шрифт значения — «30.0 м³» остаётся в 1 строку, ряд влезает без оверфлоу. */
@media (max-width: 360px) {
  .te5-stepper__btn { width: 64px; font-size: 38px; }
  .te5-stepper__val { font-size: 32px; }  /* T5: крупнее (было 26), «30.0 м³» ещё влезает при ужатых ± */
}
.te5-form__cmt {
  /* высота = блокам цифр степлера (90px) + крупнее шрифт (правка j 02.07: «невидно нихера») */
  min-height: 90px; border: 2px dashed var(--te5-input-ln); border-radius: 14px; background: transparent;
  color: var(--te5-text-2); font: inherit; font-size: 20px; font-weight: 700; cursor: pointer;
}
.te5-textarea {
  width: 100%; min-height: 90px; border: 2px solid var(--te5-input-ln); border-radius: 14px; padding: 12px;
  font: inherit; font-size: 20px; background: var(--te5-card); color: var(--te5-text);
}
/* «Сохранить» = primary-CTA (зелёная). Размер/шрифт берёт из .te5-cta (на мобиле scale → 120px/26px,
   как hero — крупнее предварительных 104; на десктопе base 84). Отдельный min-height тут был бы мёртв
   (`.te5-driver-scale .te5-cta` 0,2,0 перебивает 0,1,0) — поэтому только цвет. B8-консолидация 29.06. */
.te5-save { background: var(--te5-ok); }
.te5-save:hover { background: var(--te5-ok); }

/* B4 нампад одометра: дисплей «123 456», крупные клавиши под перчатку + переключатель ручного ввода */
.te5-odo { display: flex; flex-direction: column; gap: 14px; }
.te5-odo__hint { font-size: 17px; font-weight: 800; color: var(--te5-text-2); }
.te5-odo__display {
  display: flex; align-items: center; justify-content: flex-end; min-height: 78px; padding: 8px 18px;
  font-size: 50px; font-weight: 900; letter-spacing: 1px;
  background: var(--te5-card); border: 2px solid var(--te5-input-ln); border-radius: 14px;
}
.te5-odo__unit { margin-left: 6px; font-size: 24px; font-weight: 700; color: var(--te5-text-2); }
/* Строка-кнопка времени на экране-хабе (решение владельца 06.08): оба времени видны
   сразу, тап правит одно. Детей ровно два, поэтому space-between безопасен —
   с переменной арностью он разъезжается (урок строки автопарка, W0 01.08).
   Метка сжимаема и переносится, значение — никогда: «07:15» в две строки нечитаемо. */
.te5-time-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; min-height: 84px; padding: 12px 18px; cursor: pointer; text-align: left;
  font: inherit; background: var(--te5-card); color: var(--te5-text);
  border: 2px solid var(--te5-input-ln); border-radius: 14px;
}
.te5-time-row:active { transform: scale(.99); }
.te5-time-row__label {
  flex: 1 1 auto; min-width: 0; font-size: 18px; font-weight: 800;
  text-transform: uppercase; letter-spacing: .3px; color: var(--te5-text-2);
}
.te5-time-row__val { flex: 0 0 auto; font-size: 34px; font-weight: 900; white-space: nowrap; }
/* Плейсхолдер не спорит со значением за место и за внимание: «не задано» набрано
   тем же 34/900 занимало 190px из 284 на 320px и наезжало на длинную метку
   («ВЕРНУЛСЯ НА ОБЪЕКТ» — замер 33px наложения). Пустота должна читаться тише данных. */
.te5-time-row__val--empty { font-size: 19px; font-weight: 700; color: var(--te5-text-2); }
@media (max-width: 360px) {
  .te5-time-row { padding-inline: 14px; }
  .te5-time-row__label { font-size: 15px; }
  .te5-time-row__val { font-size: 30px; }
  /* Правило выше идёт ПОЗЖЕ базового `--empty` при равной специфичности и потому
     возвращало плейсхолдеру крупный кегль — повторяем его здесь, иначе на самом
     узком экране пустота снова спорит со значением (замер: 30px вместо 19px). */
  .te5-time-row__val--empty { font-size: 18px; }
}
/* Длительность интервала рядом с вводом — единственный признак, по которому
   водитель отличит опечатку от ночной смены: обе дают валидный интервал. */
.te5-time-span {
  font-size: 17px; font-weight: 800; color: var(--te5-text-2);
  padding: 10px 14px; border-radius: 12px; background: var(--te5-card);
  border: 1px solid var(--te5-border);
}
.te5-numpad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.te5-numpad__key {
  min-height: 84px; font: inherit; font-size: 34px; font-weight: 800; cursor: pointer;
  background: var(--te5-card); color: var(--te5-text); border: 2px solid var(--te5-input-ln); border-radius: 16px;
}
.te5-numpad__key:active { transform: scale(.96); }
.te5-numpad__key--success { background: var(--te5-ok); color: #fff; border-color: var(--te5-ok); }
.te5-numpad__key--del { color: var(--te5-bad); }
.te5-odo__manual {
  width: 100%; min-height: 78px; padding: 8px 18px; text-align: right; font: inherit; font-size: 40px; font-weight: 800;
  background: var(--te5-card); color: var(--te5-text); border: 2px solid var(--te5-input-ln); border-radius: 14px;
}
.te5-odo__toggle {
  min-height: 56px; border: 2px dashed var(--te5-input-ln); border-radius: 14px; background: transparent;
  color: var(--te5-text-2); font: inherit; font-size: 16px; font-weight: 700; cursor: pointer;
}

/* B6 экран подтверждения завершения: «Да»/«Нет» широко разнесены (случайный тап не закроет смену) */
.te5-confirm { display: flex; flex-direction: column; gap: 20px; padding: 10px 2px; }
.te5-confirm__q { font-size: 22px; font-weight: 800; text-align: center; margin: 8px 0; }
.te5-confirm__yes {
  display: flex; align-items: center; justify-content: center; gap: 12px; min-height: 120px;
  border: none; border-radius: 18px; background: var(--te5-ok); color: #fff; font: inherit; font-size: 24px; font-weight: 900; cursor: pointer;
}
.te5-confirm__no {
  min-height: 96px; margin-top: 36px; border: 2px solid var(--te5-input-ln); border-radius: 18px;
  background: var(--te5-card); color: var(--te5-text); font: inherit; font-size: 20px; font-weight: 800; cursor: pointer;
}

/* B7 экран результата: ✅ + текст крупно (не тост) */
.te5-result { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 36px 16px; text-align: center; }
.te5-result__icon { font-size: 96px; line-height: 1; }
.te5-result__msg { font-size: 23px; font-weight: 800; }
.te5-result__sub { font-size: 15px; color: var(--te5-text-2); }
.te5-result .te5-cta { max-width: 280px; }
/* ===== /Тикет B ===== */

@media (max-width: 380px) {
  .te5-mobile { padding-left: 14px; padding-right: 14px; }
  .te5-mobile-head { gap: 8px; }
  .te5-mobile-head__brand { flex-basis: 118px; gap: 8px; }
  .te5-mobile-head__actions { gap: 6px; }
  .te5-mobile-head__actions .te5-chip {
    max-width: 124px;
    padding-left: 8px;
    padding-right: 8px;
    font-size: 13.5px;
  }
}

/* T20 (j 02.07): узкий перенос лога убран — время стало коротким («чч:мм:сс дд.мм», без года) →
   событие слева и время справа помещаются В ОДНУ линию и на мобиле (grid 2 колонки как на десктопе). */

/* ---------- floating console push action ---------- */

.te5-push-fab {
  position: fixed;
  right: 18px;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 18px);
  z-index: 9998;
  min-width: 46px;
  height: 46px;
  max-width: 46px;
  padding: 0 13px;
  border-radius: 999px;
  border: 1px solid var(--te5-primary-ln);
  background: var(--te5-primary-bg);
  color: var(--te5-primary);
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  overflow: hidden;
  white-space: nowrap;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
  transition: max-width 0.18s ease, border-color 0.15s ease, background 0.15s ease;
}
.te5-push-fab:hover,
.te5-push-fab:focus-visible {
  max-width: 210px;
  justify-content: flex-start;
  background: var(--te5-hover-bg);
  border-color: var(--te5-primary);
  outline: none;
}
.te5-push-fab__icon { flex: 0 0 auto; font-size: 18px; line-height: 1; }
.te5-push-fab__label {
  opacity: 0;
  transition: opacity 0.12s ease;
}
.te5-push-fab:hover .te5-push-fab__label,
.te5-push-fab:focus-visible .te5-push-fab__label,
.te5-push-fab.is-busy .te5-push-fab__label,
.te5-push-fab.is-error .te5-push-fab__label {
  opacity: 1;
}
.te5-push-fab.is-busy {
  max-width: 190px;
  color: var(--te5-warn);
  border-color: var(--te5-warn-ln);
  background: var(--te5-warn-bg);
}
.te5-push-fab.is-error {
  max-width: 230px;
  color: var(--te5-bad);
  border-color: var(--te5-bad-ln);
  background: var(--te5-bad-bg);
}

/* ══════════════════════════════════════════════════════════════════════════
   НАКЛАДКА НАВИГАЦИИ — ОДНО МЕСТО ДЛЯ ОБЩИХ СВОЙСТВ

   Выпадение поверх контента у консоли было и раньше, но его свойства стояли
   ДВАЖДЫ дословно — в `.te5-header--compact .te5-nav` и в медиа-запросе порога бургера.
   Любое новое свойство приходилось писать в оба места, а забытое расходилось
   молча. В блоках режимов остались только позиционирование и показ; всё, что
   делает панель панелью, живёт здесь.

   Медиа-блок при этом обязан жить: он единственный работает до загрузки JS.
   ══════════════════════════════════════════════════════════════════════════ */
.te5-nav.is-open {
  /* Поля по бокам: панель обязана читаться КАРТОЧКОЙ, выехавшей из-под полосы шапки,
     а не самой полосой (правка владельца 08.08.2026 по кадру прода: «сделай как на
     драйвере»). Считаются от содержимого шапки — `padding: 6px 24px`, в узком режиме
     `6px 12px`, — поэтому панель шире контента, но до края экрана не достаёт.
     🛑 Выступить ЗА шапку, как у водителя, здесь нельзя: она во всю ширину окна. */
  --te5-nav-inset: 12px;
  /* Заезд под полосу шапки. 🛑 Компенсируется тем же значением в `padding-top` —
     иначе первый пункт уходит под шапку и становится недостижим для тапа (у
     водителя этот дефект уже случался). Обе величины считаются от ОДНОЙ переменной. */
  --te5-nav-tuck: 14px;
  position: absolute;
  top: calc(100% - var(--te5-nav-tuck));
  left: var(--te5-nav-inset);
  right: var(--te5-nav-inset);
  /* Панель уходит ПОД подложку шапки (`.te5-header::after`, слой 1), поэтому её
     верхние 14px не видны — читается как «вылезает из-под навбара». */
  z-index: 0;
  border-radius: 0 0 18px 18px;
  flex-direction: column;
  gap: 2px;
  flex-wrap: nowrap;
  padding: 8px;
  /* 🛑 ПОСЛЕ шортката `padding`, иначе он затирает компенсацию заезда — живой замер
     поймал ровно это: первый пункт оказался на 6px ВЫШЕ низа полосы, то есть под ней.
     Тот же класс, что `padding: 12px 0`, снёсший `padding-left` в ленте водителя. */
  padding-top: calc(var(--te5-nav-tuck) + 8px);
  background: var(--te5-card);
  border-bottom: 1px solid var(--te5-border);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.14);
  /* Низкий вьюпорт (ноутбук с открытой консолью отладки, телефон в ландшафте)
     не должен прятать «Выйти из консоли» без возможности доскроллить. */
  max-height: 80dvh;
  overflow-y: auto;
}

/* Затемнение страницы под открытой накладкой. Слой на единицу НИЖЕ шапки
   (30), поэтому сама шапка вместе с накладкой остаётся читаемой поверх
   затемнения — приём замерен в проде Vercel. Литерал цвета тот же, что у
   модалки: второй токен на одно и то же понятие разошёлся бы. */
.te5-nav-scrim {
  position: fixed;
  inset: 0;
  z-index: 29;
  /* 🛑 Тот же рубеж, что у водителя: на iOS `overflow: hidden` на теле тач-скролл
     НЕ держит, и жест по слою прокручивает документ под ним. Диспетчер бывает и с
     планшета, поэтому асимметрия «у водителя есть, у консоли нет» — дефект. */
  touch-action: none;
  background: rgba(20, 28, 42, .45);
}

/* Тем же приёмом, что уже применён к модалке. `scrollbar-gutter: stable`
   объявлен глобально, поэтому страница не дёрнется по ширине. */
/* Типографика пунктов — там же, где и всё оформление накладки: раньше она стояла
   дословно в обоих блоках режимов, то есть ровно тот дубль, ради снятия которого
   правило и заводилось. */
.te5-nav.is-open a,
.te5-nav.is-open .te5-nav__logout button {
  width: 100%;
  padding: 11px 13px;
  text-align: left;
  font-size: 15px;
}

body:has(.te5-nav.is-open) { overflow: hidden; }

/* ── Накладка ВЫТЕКАЕТ из шапки (08.08.2026, тот же заказ, что у водителя) ─────
   Раскрытие обрезкой сверху вниз: `clip-path` не трогает раскладку, поэтому не
   двигает страницу — а уход от сдвига и был исходным заказом.

   🛑 Заезд под шапку и выступ по бокам, сделанные у ВОДИТЕЛЯ, здесь не нужны и
   вредны: там шапка — карточка с полями и скруглениями, и панель обязана выходить
   из-под неё; тут это сплошная полоса во всю ширину с `border-bottom`, стык уже
   слитный, а выступать за края экрана некуда. Общий у поверхностей только характер
   появления. */
@keyframes te5NavPour {
  from { clip-path: inset(0 0 100% 0); transform: translateY(-4px); opacity: .55; }
  to   { clip-path: inset(0 0 0 0); transform: none; opacity: 1; }
}

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

/* 🛑 Под guard'ом системной настройки: движение интерфейса у части людей вызывает
   тошноту и головокружение (WCAG 2.3.3). */
@media (prefers-reduced-motion: no-preference) {
  .te5-nav.is-open {
    animation: te5NavPour 240ms cubic-bezier(.22, .68, .32, 1);
  }
  .te5-nav-scrim {
    animation: te5ScrimFade 200ms ease-out;
  }
}

@media print {
  body.te5-print-daily * {
    visibility: hidden;
  }
  body.te5-print-daily #dailyFinalCard,
  body.te5-print-daily #dailyFinalCard * {
    visibility: visible;
  }
  body.te5-print-daily #dailyFinalCard {
    position: absolute;
    inset: 0 auto auto 0;
    width: 100%;
    border: 0;
  }
  body.te5-print-daily #dailyFinalCard .te5-pagehead__actions {
    display: none;
  }
}

/* ================================================== «Смотреть как» (TE-254)
   Кнопка стоит слева от уведомлений и ПОКАЗЫВАЕТ текущую роль — это половина её смысла:
   человек, забывший, в каком он режиме, ровно тот, ради кого она нужна. Меню открывается
   поверх шапки, поэтому оболочка позиционируется относительно. */
/* 🛑 Кнопка — ЗНАЧОК, размером и формой как соседи по шапке (уведомления, тема). Подпись
   «Смотрю как: Диспетчер» занимала двадцать символов в строке, где рядом ещё пять кнопок,
   и на 1440px навбар от неё уезжал в две строки. Роль называют подпись для читалки и
   отмеченный пункт меню. */
.te5-viewas {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 1px solid var(--te5-border);
  border-radius: 10px;
  background: var(--te5-card);
  color: var(--te5-text);
  font: inherit;
  cursor: pointer;
}
.te5-viewas__icon { display: block; }
/* Иконки набора (Lucide, `shared/icons.js::TE5.icon`). Размер — классом РОЛИ, не места:
   20px — текст, кнопки, пункты меню (умолчание); `--lg` 24px — шапка, таббар, тач-плитки
   водителя; `--sm` 16px — чипы и бейджи. Квадраты шапки консоли — 22px (между ролями, как было). */
.te5-icon { width: 20px; height: 20px; flex: 0 0 auto; display: block; }
.te5-icon--sm { width: 16px; height: 16px; }
.te5-icon--lg { width: 24px; height: 24px; }
/* Значок В СТРОКЕ текста или кнопки: размер от шрифта носителя, базовая линия как у
   буквы. Один ключ набора годится и бургеру (21px), и чипу (12px), и заголовку колонки —
   без правила на каждый слот. */
.te5-icon--inline { width: 1em; height: 1em; display: inline-block; vertical-align: -0.15em; flex: none; }
/* Экран водителя (PR-O, 28.09.2026): значок в слоте глифа берёт размер у слота (`font-size`),
   так что адаптивные правила `.te5-tile__emo` / `.te5-result__icon` / `.x-receipt__mark`
   работают как с эмодзи. `te5-log-ico` / `te5-btn-ico` — значок в строке текста (лента,
   кнопки-строки, заголовки баннеров). */
.te5-tile__emo > .te5-icon, .te5-result__icon > .te5-icon, .x-receipt__mark > .te5-icon,
.x-shift-strip__chev > .te5-icon, .te5-numpad__key > .te5-icon, .x-route-drop > .te5-icon {
  width: 1em; height: 1em; display: inline-block;
}
.te5-icon.te5-log-ico, .te5-icon.te5-btn-ico {
  display: inline-block; width: 1.1em; height: 1.1em; vertical-align: -0.2em; margin-right: 0.35em;
}
.te5-header-notifications .te5-icon { width: 22px; height: 22px; }
/* Тон значка (`TE5.ICON_TONES`): цвет по смыслу, токены `--te5-ico-*` в палитре выше.
   Цвет читается ТОКЕНОМ, а не литералом, поэтому поверхность с заливкой переопределяет
   токены на себе (`driver.css`: чип плитки, кнопка подтверждения) — своих правил на каждый
   тон ей не нужно. Здесь то же для заливок кита: значок остаётся цветом кнопки. */
.te5-icon--tone-blue { color: var(--te5-ico-blue); }
.te5-icon--tone-green { color: var(--te5-ico-green); }
.te5-icon--tone-amber { color: var(--te5-ico-amber); }
.te5-icon--tone-red { color: var(--te5-ico-red); }
.te5-icon--tone-violet { color: var(--te5-ico-violet); }
.te5-icon--tone-teal { color: var(--te5-ico-teal); }
.te5-icon--tone-slate { color: var(--te5-ico-slate); }
/* Заливки у значков НЕТ: `.te5-icon--fill` (PR-AA/AB, 28.09) снят словом j 29.09.2026 —
   «чтоб незакрашенные опять были, по цветам». Цвет — только тон выше, форма — контур. */
.te5-btn--primary, .te5-btn--danger, .te5-numpad__key--success, .te5-sw-update, .te5-chip--success {
  --te5-ico-blue: currentColor; --te5-ico-green: currentColor; --te5-ico-amber: currentColor;
  --te5-ico-red: currentColor; --te5-ico-violet: currentColor; --te5-ico-teal: currentColor;
  --te5-ico-slate: currentColor;
}

.te5-viewas:hover { border-color: var(--te5-accent, var(--te5-border)); }
.te5-header__right { position: relative; }
.te5-viewas__menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 40;
  min-width: 240px;
  padding: 6px;
  border: 1px solid var(--te5-border);
  border-radius: 12px;
  background: var(--te5-card);
  box-shadow: 0 8px 24px rgb(0 0 0 / 18%);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* 🛑 Браузерное `[hidden] { display: none }` — обычное правило и ПРОИГРЫВАЕТ любому
   классу с `display`. У меню выше задан `display: flex`, поэтому `menu.hidden = true`
   его не прятал: меню висело раскрытым с загрузки страницы, а проверка «hidden стоит»
   при этом зелена — она меряет собственное присваивание. Правило заведено ЯВНО. */
.te5-viewas__menu[hidden] { display: none; }
/* Заголовок списка. Глагол сказан ОДИН раз здесь, а не повторён в каждой строке. */
.te5-viewas__title {
  padding: 6px 12px 8px;
  color: var(--te5-muted);
  font-size: 12px;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.te5-viewas__item {
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: left;
  padding: 9px 12px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--te5-text);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}
.te5-viewas__item:hover { background: var(--te5-hover, rgb(0 0 0 / 6%)); }
/* Текущая роль помечена, а не просто выделена цветом: цвет один читатель видит, другой
   нет, а слово «сейчас» читают все. */
.te5-viewas__item.is-active { font-weight: 600; }
.te5-viewas__item.is-active::after { content: " · сейчас"; font-weight: 400; opacity: .65; }
/* Меню шестерёнки консоли (TE-380, 28.09.2026) — тот же список, что у ролей, плюс пункты
   другой природы: тема, push, вопрос, выход. Секция ролей и форма выхода — прозрачные
   обёртки, чтобы их кнопки были прямыми пунктами колонки; `[hidden]` у секции задан
   ЯВНО — `display: contents` перебил бы браузерное правило так же, как `flex` у меню. */
.te5-viewas__menu form,
.te5-viewas__menu [data-view-as-menu] { display: contents; }
.te5-viewas__menu [data-view-as-menu][hidden] { display: none; }
.te5-gear__sep { border: 0; border-top: 1px solid var(--te5-border); margin: 4px 0; }
/* Роли свёрнуты за «Войти как»: список — прозрачная обёртка (пункты остаются в колонке),
   раскрытые пункты сдвинуты под подпись, стрелка поворачивается. */
.te5-gear__sub { display: contents; }
.te5-gear__sub[hidden] { display: none; }
.te5-gear__sub .te5-viewas__item { padding-left: 42px; }
.te5-icon--chev { margin-left: auto; transition: transform .15s; }
[data-view-as-open][aria-expanded="true"] .te5-icon--chev { transform: rotate(90deg); }
/* «Выйти» — красный, тем же токеном, что у водителя (`te5-mobile-menu__logout`). */
.te5-viewas__item--logout { color: var(--te5-bad); background: var(--te5-bad-bg); }
.te5-viewas__item--logout:hover { color: var(--te5-bad); background: var(--te5-bad-bg); box-shadow: inset 0 0 0 1px var(--te5-bad-ln); }
.te5-viewas__item.is-busy { color: var(--te5-warn); }
.te5-viewas__item.is-error { color: var(--te5-bad); }
/* Полоса режима: видна ПОСТОЯННО, а не только в меню. Человек, забывший, от чьего имени
   открыт экран, — это тот самый случай, ради которого полоса и нужна. */
/* Ссылка возврата внутри метки режима: без неё форма входа, куда приземляет переключение
   на роль без сессии, становится тупиком — там нет ни шапки, ни переключателя. */
/* Строка журнала правок в карточке смены (TE-157). 🛑 Свои классы, а не `te5-epl__step*`:
   те объявлены ИНЛАЙНОМ в `console_epl.html` и на `waybill.html` не существуют — строки
   рисовались бы без оформления, подпись и чип слипались в одну строку. */
.te5-editlog__row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 0;
  border-bottom: 1px solid var(--te5-border);
}

.te5-editlog__row:last-child { border-bottom: none; }

.te5-editlog__head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: space-between;
}

.te5-viewas-bar__back {
  color: var(--te5-primary);
  font-weight: 600;
  text-decoration: underline;
  white-space: nowrap;
}

.te5-viewas-bar {
  position: sticky;
  top: 0;
  z-index: 50;
  padding: 8px 14px;
  background: var(--te5-warn-bg, #fff6e5);
  color: var(--te5-text);
  border-bottom: 1px solid var(--te5-border);
  font-size: 13px;
  text-align: center;
}

/* ---------- селектор с поиском (TE-307) ---------- */
/* 🛑 Обёртка `position: relative` — слой выпадает от неё, а не от страницы. Внутри
   таблиц и модалок абсолютный слой от страницы уезжал бы при прокрутке контейнера. */
.te5-esel { position: relative; width: 100%; min-width: 0; }
/* Кнопка повторяет метрику `.te5-select`: селектор встаёт на место нативного контрола,
   и ряд формы не должен «прыгать» по высоте при включении улучшения. */
.te5-esel__button {
  height: 38px; width: 100%; min-width: 0;
  border: 1px solid var(--te5-input-ln); border-radius: var(--te5-radius-control);
  padding: 0 12px; font: inherit; font-size: 14px;
  background: var(--te5-card); color: inherit; cursor: pointer;
  text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.te5-esel__button:hover { background: var(--te5-hover-bg); }
.te5-esel__button:focus-visible {
  border-color: var(--te5-primary); box-shadow: 0 0 0 2px var(--te5-primary-bg); outline: none;
}
.te5-esel--address .te5-esel__button,
.te5-esel--driver .te5-esel__button {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.te5-esel--address { width: min(100%, 320px); }
.te5-esel--address [data-esel-label],
.te5-esel--driver [data-esel-label] {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.te5-esel--address [data-esel-chevron],
.te5-esel--driver [data-esel-chevron] { flex: none; font-size: 16px; }
/* 🛑 `fixed`, а НЕ `absolute`. Абсолютный слой обрезается ЛЮБЫМ предком с `overflow`, а
   почти каждое место внедрения живёт внутри такого: `.te5-table-scroll` на дневном борде,
   в карточке ПЛ, в разнарядке и в справочнике. Живой замер 04.09.2026 (esel-metrics.mjs):
   слой считал себя высотой 322px, скроллер обрезал его на 60px, и hit-тест по центру
   строки возвращал страницу под таблицей — то есть варианты были ВИДНЫ и НЕ НАЖИМАЛИСЬ.
   🛑 `checkVisibility()` этого не ловит: он не знает про обрезку. Арбитр — только hit-тест.
   Координаты и ширину задаёт JS в момент открытия (`placePanel`), потому что у `fixed`
   нет привязки к кнопке. */
/* Компактность — решение владельца 17.09.2026 («панель великовата»): отступы и зазоры
   ужаты, кегли не тронуты (пол читаемости держит контраст-гейт). */
.te5-esel__panel {
  position: fixed; z-index: 60;
  max-width: min(420px, calc(100vw - 16px));
  padding: 6px; border: 1px solid var(--te5-border); border-radius: var(--te5-radius-card);
  background: var(--te5-surface-raised); box-shadow: var(--te5-shadow-md);
  display: grid; gap: 4px;
}
/* Массовые действия стоят ПАРОЙ и делят ряд поровну: «Выбрать все» без «Очистить всё»
   оставляет человека без обратного хода (BUG-59 п.3, слово владельца 17.09.2026). */
.te5-esel__bulks { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
.te5-esel__bulk { min-height: 32px; padding: 0 8px; }
.te5-esel__panel--address,
.te5-esel__panel--driver {
  max-width: min(560px, calc(100vw - 40px));
  min-width: min(320px, calc(100vw - 40px));
  padding: 0; gap: 0; overflow: hidden;
}
.te5-esel__toolbar {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 6px; padding: 9px; border-bottom: 1px solid var(--te5-border);
}
.te5-esel__panel--address .te5-esel__search::-webkit-search-cancel-button,
.te5-esel__panel--driver .te5-esel__search::-webkit-search-cancel-button { display: none; }
.te5-esel__panel--driver .te5-esel__bulk {
  border: 0; padding: 0; background: none; color: inherit; font: inherit; cursor: pointer;
}
.te5-esel__tool {
  min-width: 38px; min-height: 38px; padding: 0 10px;
  border: 1px solid var(--te5-input-ln); border-radius: var(--te5-radius-control);
  background: var(--te5-card); color: var(--te5-text); font: inherit; font-size: 18px;
  cursor: pointer;
}
.te5-esel__tool:hover { background: var(--te5-hover-bg); }
.te5-esel__tool:focus-visible { outline: 2px solid var(--te5-primary); outline-offset: 1px; }
.te5-esel__summary {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 10px; background: var(--te5-hover-bg); color: var(--te5-text-2);
  font-size: 12px;
}
.te5-esel__count { font-size: 12px; color: var(--te5-muted); }
/* Прокрутка ВНУТРИ слоя, тем же потолком, что у длинной группы галочек (замер: 147
   объектов заказчика). 🛑 `padding` у скроллера нет намеренно — он ломает липкость
   и клипует содержимое (инвариант console-ui.md). */
.te5-esel__list {
  display: grid; gap: 2px; max-height: 240px; overflow-y: auto; overscroll-behavior: contain;
  /* 🛑 `grid-auto-rows: min-content` ОБЯЗАТЕЛЕН, пока строка несёт `min-height`. Строка —
     grid-ЭЛЕМЕНТ, и трек по умолчанию считается по её АВТОМАТИЧЕСКОМУ МИНИМУМУ, то есть по
     `min-height: 28px`, а не по содержимому: всё, что выше, ОБРЕЗАЕТСЯ (`scrollHeight`
     втрое больше `clientHeight`). На однострочных подписях площадок это незаметно —
     содержимое ниже минимума, — и вылезло только на водительской строке с метастрокой
     (TE-307): подразделение, ник и телефон были не видны.
     🛑 Лечить это `align-self: start` НЕЛЬЗЯ, хотя высота от него становится верной: трек
     остаётся 28px, и строки НАКЛАДЫВАЮТСЯ друг на друга — под центром первой лежит вторая,
     то есть человек нажимает не того водителя. Обрезка сменилась бы промахом по цели.
     🛑 Ни одного из двух дефектов DOM-стенд не видит по построению: у него нет ни CSS, ни
     раскладки, ни hit-теста. Оба нашёл живой замер `tests/e2e/browser/esel-metrics.mjs`
     (05.09.2026), он же их и пинит — высотой строки и `elementFromPoint` по её центру. */
  grid-auto-rows: min-content;
}
.te5-esel__panel--address .te5-esel__list,
.te5-esel__panel--driver .te5-esel__list { max-height: 246px; padding: 5px; }
.te5-esel__row {
  display: flex; align-items: baseline; gap: 8px;
  border: none; background: none; color: var(--te5-text);
  font: inherit; font-size: 13px; text-align: left; cursor: pointer;
  border-radius: 6px; padding: 4px 8px;
  /* Подпись площадки переносится, а не обрезается: обрезанный адрес неразличим от
     соседнего по той же улице. */
  white-space: normal; word-break: break-word;
  /* Цель нажатия не меньше строки таблицы — тот же довод, что у `.te5-check`. */
  min-height: 28px;
}
.te5-esel__row:hover { background: var(--te5-row-ln); }
.te5-esel__row:focus-visible { outline: 2px solid var(--te5-primary); outline-offset: -2px; }
.te5-esel__row[disabled] { color: var(--te5-muted); cursor: not-allowed; }
.te5-esel__row--on { background: var(--te5-primary-bg); }
/* 🛑 ВЫДЕЛЕННАЯ клавиатурой строка и ОТМЕЧЕННАЯ — разные состояния, и различать их надо
   не только цветом: в multiple они встречаются на одной строке разом. Рамка внутрь плюс
   фон наведения — так «где я» читается и поверх отметки, и в обеих темах. */
.te5-esel__row--active {
  background: var(--te5-row-ln);
  box-shadow: inset 0 0 0 2px var(--te5-primary);
}
.te5-esel__row--active.te5-esel__row--on { background: var(--te5-primary-bg); }
.te5-esel--driver .te5-esel__row--on:hover { background: var(--te5-primary-bg); }
.te5-esel__tick { flex: 0 0 14px; color: var(--te5-primary); }
/* Строка водителя (TE-307): ФИО и под ним подразделение · ник MAX · телефон.
   🛑 Колонка живёт ВНУТРИ строки, а не вместо неё: сама строка остаётся горизонтальным
   рядом, потому что в `multiple` слева от подписи стоит галочка, и разворот всей строки
   в колонку увёл бы её под текст. */
.te5-esel__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* Жирное ФИО — единственное, что взято из вида прототипа (решение владельца 06.09.2026 по
   стенду «как сейчас против дельты»): без веса имя и метастрока читаются одним абзацем. */
.te5-esel__name { overflow-wrap: anywhere; font-weight: 600; }
/* 🛑 Метаданные переносятся, а не обрезаются: обрезанный номер и обрезанный ник не
   объясняют, почему строка попала в выдачу, — а объяснение и есть их единственная задача
   (возражение Димы на созвоне 02.09.2026, зафиксировано в TE-307). */
.te5-esel__meta {
  display: flex; flex-wrap: wrap; gap: 2px 10px;
  color: var(--te5-muted); font-size: 12px; line-height: 1.35;
}
.te5-esel--address .te5-esel__meta { display: block; }
.te5-esel__meta > span { overflow-wrap: anywhere; }
/* 🛑 Подсветка красится ТОКЕНАМИ, а не браузерным жёлтым по умолчанию: в тёмной теме
   дефолтный `mark` даёт чёрный текст на жёлтом и выпадает из палитры экрана. */
.te5-esel__row mark {
  background: var(--te5-mark-bg); color: var(--te5-mark-text, inherit); border-radius: 2px; padding: 0 1px;
}
