/*
 * Оформление RentDesk.
 *
 * Задача — та же плотность, что в ВС Автопрокат: много строк на экране, кнопки
 * справа от таблицы, всё под рукой. Но подача спокойнее: одна сетка отступов,
 * мягкие границы, один акцентный цвет. Никаких широких пустот и крупных карточек —
 * это рабочая программа на весь день, а не сайт.
 */

:root {
  --bg: #eef1f5;
  --panel: #ffffff;
  --line: #d7dde5;
  --line-soft: #e8ecf1;
  --text: #1d2733;
  --text-soft: #5b6878;
  --text-dim: #8b98a8;

  --accent: #1f6feb;
  --accent-dark: #1a5fcc;
  --accent-soft: #e8f0fe;

  --ok: #17864a;
  --warn: #b26a00;
  --danger: #c0392b;

  --row: 32px;
  --radius: 6px;
  --gap: 12px;
  --font: 13px/1.45 "Segoe UI", "Inter", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  font: var(--font);
  color: var(--text);
  background: var(--bg);
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ─────────────────────────────────────────────── шапка и главное меню */

.top {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 44px;
  padding: 0 12px;
  background: #16283d;
  color: #dfe7f1;
  position: sticky;
  top: 0;
  z-index: 30;
}

/* Название и компания — в одну строку и без переносов: как только шапке тесно,
   ломался именно этот блок и утаскивал меню на второй ряд. */
.top .brand {
  font-weight: 600;
  letter-spacing: .2px;
  color: #fff;
  display: flex;
  align-items: baseline;
  gap: 6px;
  white-space: nowrap;
  flex: 0 0 auto;
}
.top .brand span { font-weight: 400; font-size: 12px; color: #8ea6c4; }
/* Метка сборки из шапки ушла: там и без неё кнопкам тесно. Живёт в подвале
   шахматки справа от легенды — и в подсказке названия программы. */

/* Меню держим одной строкой: на узком экране оно прокручивается вбок, а не
   переносится вторым рядом поверх страницы. */
.menu {
  display: flex;
  gap: 1px;
  margin-left: auto;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
}
.menu::-webkit-scrollbar { display: none; }

.menu > .item { position: relative; flex: 0 0 auto; }

.menu > .item > a,
.menu > .item > button {
  display: block;
  padding: 6px 9px;
  border: 0;
  background: none;
  color: #cfdaea;
  font: inherit;
  white-space: nowrap;
  border-radius: var(--radius);
  cursor: pointer;
}

/* Тесный экран: первым уходит название компании — меню важнее. */
@media (max-width: 1280px) {
  .top .brand span { display: none; }
}
.menu > .item > a:hover,
.menu > .item > button:hover { background: #223c59; color: #fff; text-decoration: none; }
.menu > .item.active > a,
.menu > .item.active > button { background: #27466b; color: #fff; }

.menu .drop {
  display: none;
  position: absolute;
  right: 0;
  top: 100%;
  min-width: 230px;
  padding: 5px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 10px 26px rgba(20, 35, 55, .16);
}
/* Открывает список menu.js — прокручиваемая шапка обрезает всё, что вылезает
   за её края, поэтому список ставится по координатам экрана, а не наведением. */
.menu .item.open .drop { display: block; }
.menu .drop a {
  display: block;
  padding: 6px 10px;
  color: var(--text);
  border-radius: 4px;
}
.menu .drop a:hover { background: var(--accent-soft); text-decoration: none; }
.menu .drop .sep { height: 1px; margin: 5px 4px; background: var(--line-soft); }

/* Значок «ждёт проверки» (5.30): правки в кассе и аренды, открытые задним
   числом. Стоит сразу за меню и виден на любом экране, включая шахматку, —
   иначе о правке узнаёшь, только если сам зашёл её искать. */
.top .flag {
  flex: 0 0 auto;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 24px;
  padding: 0 9px;
  border-radius: 12px;
  background: #b4530f;
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
}
.top .flag:hover { background: #cf6314; text-decoration: none; }

.who { display: flex; align-items: center; gap: 8px; color: #a9bcd4; font-size: 12px; }
.who b { color: #fff; font-weight: 500; }

/* ─────────────────────────────────────────────── рабочая область */

.page { padding: var(--gap); }

.head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.head h1 { margin: 0; font-size: 16px; font-weight: 600; }
.head .sub { color: var(--text-soft); font-size: 12px; }
.head .right { margin-left: auto; display: flex; gap: 8px; align-items: center; }

.work { display: flex; gap: var(--gap); align-items: flex-start; }
.work > .main { flex: 1; min-width: 0; }

/* Кнопки столбиком справа от таблицы — как в ВС */
.side { display: flex; flex-direction: column; gap: 6px; width: 172px; flex: none; }

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.panel > .panel-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line-soft);
  background: #f7f9fb;
  font-weight: 600;
}
.panel > .panel-body { padding: 12px; }

/* ─────────────────────────────────────────────── таблицы */

/*
 * table-layout: fixed — иначе ширины колонок из кода остаются пожеланием:
 * содержимое в nowrap раздувает таблицу шире панели, и правые колонки (в кассе —
 * приход, расход и метки) уезжают за край. При fixed заданные ширины держатся,
 * остаток делят колонки без ширины, а длинный текст обрезается многоточием.
 */
/*
 * Шрифт в списках на шаг мельче основного: в справочниках по десятку колонок
 * (организация, собственник, филиал, три срока), и при 13px крайние правые
 * колонки не помещались в экран ноутбука — название машины схлопывалось в одну
 * букву. 12px и узкие отступы возвращают все колонки на экран.
 */
table.grid { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: 12px; }

/*
 * Список прокручивается сам, а не тянет за собой всю страницу: фильтры и итоги
 * остаются на месте, шапка столбцов липнет к верху этой области, и первая строка
 * никуда не прячется. Высота — экран минус то, что обычно стоит над списком.
 */
.grid-wrap { overflow: auto; max-height: calc(100vh - 210px); }

table.grid th {
  position: sticky;
  top: 0;
  /* без z-index строки прокручиваются ПОВЕРХ прилипшей шапки — первая строка
     выглядывает над заголовками столбцов */
  z-index: 2;
  text-align: left;
  font-weight: 600;
  color: var(--text-soft);
  background: #f7f9fb;
  border-bottom: 1px solid var(--line);
  padding: 6px 7px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
table.grid td {
  padding: 0 7px;
  height: var(--row);
  border-bottom: 1px solid var(--line-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/*
 * Исключение для сравнения карточек: там значения (адрес, паспорт, примечание)
 * надо видеть целиком, а не по многоточие — колонки подстраиваются под текст.
 */
table.grid.free { table-layout: auto; }
table.grid.free td { white-space: normal; overflow: visible; height: auto; padding: 6px 10px; }

table.grid tbody tr:hover { background: #f4f8ff; }
table.grid tbody tr.selected { background: var(--accent-soft); }
table.grid tbody tr.archived td { color: var(--text-dim); }
/*
 * Закрытая замком аренда и аренда, ждущая правок (5.28). В списке из сотни
 * строк важнее не «где закрытые», а «где мои»: закрытые уходят на второй план
 * приглушением, ждущие — светятся тёплым, как невыполненная задача.
 */
table.grid tbody tr.rent-done td { color: var(--text-soft); }
table.grid tbody tr.rent-wait td { background: #fff8ec; }
table.grid tbody tr.rent-wait:hover td { background: #fdf0d8; }
/* Строка кассы, отмеченная галочкой для подсчёта */
table.grid tbody tr.picked { background: #fff6dd; }
table.grid tbody tr.picked:hover { background: #fdefc9; }
table.grid td.num, table.grid th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.grid td.mid, table.grid th.mid { text-align: center; }
table.grid .empty { color: var(--text-dim); text-align: center; padding: 26px; height: auto; }

/* ─────────────────────────────────────────────── кнопки */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 30px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  color: var(--text);
  font: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover { border-color: #b9c4d2; background: #f7f9fc; text-decoration: none; }
.btn:active { background: #eef2f7; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn.primary:hover { background: var(--accent-dark); border-color: var(--accent-dark); }
.btn.danger { color: var(--danger); }
.btn.danger:hover { background: #fdf0ee; border-color: #e8b6ae; }
.btn.wide { width: 100%; justify-content: flex-start; }
/* Кнопка внутри строки списка: чтобы строка не стала выше остальных. */
.btn.small { height: 22px; padding: 0 8px; font-size: 12px; }
.btn[disabled] { opacity: .5; cursor: default; }
.btn .ico { width: 16px; text-align: center; color: var(--text-soft); }
.btn.primary .ico { color: #fff; }

/* ─────────────────────────────────────────────── формы */

.form { display: flex; flex-direction: column; gap: 14px; max-width: 720px; }
.form.wide { max-width: none; }

.field { display: grid; grid-template-columns: 210px 1fr; align-items: center; gap: 10px; }
.field > label { color: var(--text-soft); }
.field .hint { grid-column: 2; margin-top: -6px; color: var(--text-dim); font-size: 12px; }
.field.stack { display: block; }
.field.stack > label { display: block; margin-bottom: 5px; }

input[type=text], input[type=password], input[type=number], input[type=time],
input[type=date], input[type=datetime-local],
input[type=email], select, textarea {
  height: 30px;
  padding: 0 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  color: var(--text);
  font: inherit;
  width: 100%;
  max-width: 420px;
}
textarea { height: auto; padding: 7px 9px; }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(31, 111, 235, .13);
}
input[type=checkbox] { width: 15px; height: 15px; accent-color: var(--accent); }

/*
 * Поле даты в виде «13 августа 2026» с кнопкой календаря — как в ВС.
 * Разметку делает public/dates.js; без него на экране остаётся обычное поле даты.
 */
.dt { position: relative; display: inline-flex; width: 100%; max-width: 420px; }
.dt .dt-text {
  height: 30px; padding: 0 34px 0 9px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: #fff; color: var(--text); font: inherit; width: 100%;
}
.dt .dt-btn {
  position: absolute; right: 1px; top: 1px;
  display: flex; align-items: center; gap: 1px;
  height: 28px; padding: 0 5px;
  border: none; border-left: 1px solid var(--line-soft);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: #f4f6f9; color: var(--text-soft);
  font: inherit; font-size: 10px; cursor: pointer;
}
.dt .dt-btn:hover { background: var(--accent-soft); color: var(--accent); }
/* Значок календаря: рамка с «шапкой» — рисуем сами, чтобы не тащить шрифт иконок */
.dt .dt-btn i {
  display: block; width: 11px; height: 11px;
  border: 1px solid currentColor; border-radius: 1px;
  border-top-width: 3px;
}

.dt-pop {
  position: absolute; z-index: 60;
  width: 218px; padding: 6px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(16, 24, 40, .16);
  font-size: 12px;
}
.dt-head { display: flex; align-items: center; justify-content: space-between; padding: 2px 2px 6px; }
.dt-head b { color: var(--accent); font-weight: 600; }
.dt-arr {
  width: 22px; height: 22px; padding: 0;
  border: none; border-radius: var(--radius); background: transparent;
  color: var(--text-soft); font: inherit; font-size: 15px; line-height: 1; cursor: pointer;
}
.dt-arr:hover { background: var(--accent-soft); color: var(--accent); }
.dt-grid { width: 100%; border-collapse: collapse; table-layout: fixed; }
.dt-grid th {
  padding: 2px 0; font-weight: 500; font-size: 11px; color: var(--text-dim); text-align: center;
}
.dt-grid th.we { color: var(--warn); }
.dt-grid td { padding: 0; }
.dt-grid td button {
  width: 100%; height: 24px; padding: 0;
  border: 1px solid transparent; border-radius: var(--radius);
  background: transparent; color: var(--text); font: inherit; cursor: pointer;
}
.dt-grid td button:hover { background: var(--accent-soft); }
.dt-grid td button.we { color: var(--warn); }
.dt-grid td button.out { color: var(--text-dim); }          /* хвосты соседних месяцев */
.dt-grid td button.now { border-color: var(--accent); }     /* сегодня — рамкой */
.dt-grid td button.sel { background: var(--accent); border-color: var(--accent); color: #fff; }
.dt-today {
  width: 100%; margin-top: 6px; height: 24px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: #fff; color: var(--text-soft); font: inherit; font-size: 11px; cursor: pointer;
}
.dt-today:hover { border-color: var(--accent); color: var(--accent); }

input.short { max-width: 110px; }
input.mid { max-width: 220px; }
/* Цена и количество правятся прямо в строке начислений — поле по ширине столбца */
.grid input.cell-num {
  width: 100%; max-width: 100%; padding: 2px 4px; text-align: right; font: inherit;
}
/* Исполнитель услуги выбирается в той же строке — список по ширине столбца */
.grid select.cell-sel {
  width: 100%; max-width: 100%; padding: 2px 4px; font: inherit;
}
select.short { max-width: 140px; }
select.mid { max-width: 260px; }

/* Два поля в строку: дата и сумма проводки логичнее видеть рядом, а не столбиком */
.cols { display: flex; gap: 18px; flex-wrap: wrap; }
.cols > .field { grid-template-columns: auto 1fr; }

/*
 * Карточка аренды в один экран — как редактор аренды в ВС.
 *
 * Столбик полей во всю ширину читается хуже, чем кажется: подписи разъезжаются с
 * значениями, а карточка уходит вниз за край экрана, и менеджер крутит колесо,
 * чтобы дописать пробег. Три колонки с узкими подписями умещают всё сразу.
 */
.card-cols {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px 22px; align-items: start;
}
@media (max-width: 1280px) { .card-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 860px) { .card-cols { grid-template-columns: 1fr; } }
.card-cols .cg-head {
  font-size: 11px; font-weight: 600; letter-spacing: .4px; text-transform: uppercase;
  color: var(--text-dim); padding-bottom: 5px; margin-bottom: 8px;
  border-bottom: 1px solid var(--line-soft);
}
.form.tight { gap: 6px; max-width: none; }
.form.tight .field { grid-template-columns: 128px minmax(0, 1fr); gap: 8px; }
.form.tight .field > label { font-size: 12px; }
.form.tight .field.wide { grid-template-columns: 1fr; gap: 3px; }
.form.tight input:not([type=checkbox]), .form.tight select {
  height: 26px; padding: 0 7px; font-size: 12px; max-width: none;
}
.form.tight textarea { padding: 5px 7px; font-size: 12px; }
.form.tight .pair { display: flex; gap: 6px; }
.form.tight .pair > input { min-width: 0; }
/* Пояснение живёт в подсказке при наведении: текст нужен раз, место занимал бы всегда */
.field .q {
  margin-left: 4px; color: var(--text-dim); font-size: 11px;
  border: 1px solid var(--line); border-radius: 50%; padding: 0 4px; cursor: help;
}
.card-save {
  display: flex; justify-content: flex-end; padding-top: 10px; margin-top: 10px;
  border-top: 1px solid var(--line-soft);
}
/* Продление и отмена — редкие действия: строкой внизу, раскрываются щелчком */
.card-extra { display: flex; gap: 22px; flex-wrap: wrap; margin-top: 10px; }
details.mini summary { cursor: pointer; color: var(--accent); font-size: 12px; }
details.mini form {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 8px;
}
details.mini .hint { font-size: 11px; max-width: 420px; }

/*
 * Первый экран карточки аренды по образцу ВС: слева договор, справа деньги.
 *
 * Деньги стоят рядом с полями не для красоты: у стойки менеджер добавляет мойку и
 * тут же называет сумму. Пока начисления жили только на своей вкладке, каждая
 * такая мелочь стоила двух переключений и возврата глазами к тому же месту.
 */
.rent-main { display: grid; grid-template-columns: minmax(0, 420px) minmax(0, 1fr); gap: 18px 26px; align-items: start; }
@media (max-width: 1100px) { .rent-main { grid-template-columns: 1fr; } }
.rm-col { min-width: 0; display: flex; flex-direction: column; gap: 14px; }
/*
 * Каждый раздел карточки — отдельная коробка с рамкой и шапкой: аренда, доп. услуги,
 * оплата, клиент. Пока разделы отличались только тонкой линией под заголовком, глаз
 * не находил границу «где кончилась аренда и началась услуга» — менеджер читал всё
 * подряд одним списком.
 */
.rm-box {
  min-width: 0; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 0 12px 12px;
}
.rm-box .cg-head {
  font-size: 11px; font-weight: 600; letter-spacing: .4px; text-transform: uppercase;
  color: var(--text-soft); padding: 8px 12px 7px; margin: 0 -12px 10px;
  background: #f4f7fa; border-bottom: 1px solid var(--line-soft);
  border-radius: var(--radius) var(--radius) 0 0;
}
.rm-box .grid-wrap { max-height: none; margin: 0 -12px; }
.rm-box .grid-wrap table { border-left: 0; border-right: 0; }
.rm-box .toolbar { border-bottom: 0; background: transparent; padding: 8px 0 0; }
.rm-box .toolbar.wrap { flex-wrap: wrap; }
/* Данные клиента правятся в его карточке — здесь они только показаны */
.ro { font-size: 12px; color: var(--text); padding: 4px 0; min-height: 18px; }
.ro-line { display: flex; align-items: center; gap: 6px; min-width: 0; }
.ro-line .grow, .ro-line select.grow { flex: 1 1 auto; min-width: 0; }
.ro-line .ro { padding: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ro-line .hint { font-size: 11px; white-space: nowrap; margin-top: 0; }
/*
 * Пусто там, где договор без этого будет неполным. Пишем это у самого поля и
 * повторяем строкой под разделом: менеджер видит дырку до печати, а не когда
 * клиент уже стоит у стойки с ручкой.
 */
.ro.miss { color: #92400e; font-style: italic; }
.gap-note {
  margin-top: 8px; padding: 7px 9px; font-size: 12px; line-height: 1.45;
  background: #fff7e6; color: #92400e; border: 1px solid #f5c98a;
  border-radius: var(--radius);
}
.gap-note + .gap-note { margin-top: 6px; }
.gap-note a { color: inherit; }
/*
 * Подсказка «предложите гостю» от агента дозагрузки. Нарочно спокойнее, чем
 * `.gap-note`: там про ошибку в аренде, которую надо чинить, здесь про
 * возможность продать. Тревожный жёлтый на такой строке приучил бы менеджера
 * пугаться там, где ничего не сломано.
 */
.pitch-note {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 8px; padding: 7px 9px; font-size: 12px; line-height: 1.45;
  background: #f2f8ff; color: #1f3d63; border: 1px solid #cfe0f5;
  border-radius: var(--radius);
}
.pitch-note + .pitch-note { margin-top: 6px; }
.pitch-note .hint { display: block; }
.pitch-note form { flex: 0 0 auto; }
/* Карандаш — вход в связанную карточку: клиент, машина, документы */
.pen {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border: 1px solid var(--line); border-radius: 6px;
  color: var(--text-soft); text-decoration: none; font-size: 12px; background: #fff;
}
.pen:hover { border-color: var(--accent); color: var(--accent); }
details.mini.in-box { margin: 2px 0 0; }
details.mini.in-box[open] { padding-bottom: 4px; }
details.mini.in-box > .field { margin-top: 6px; }
.rm-total {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 5px 2px; font-size: 13px; border-top: 1px solid var(--line-soft);
}
.rm-total span { color: var(--text-soft); }
.rm-total.big { font-size: 15px; }
.rm-total.debt b { color: var(--danger); }
.rm-total.ok b { color: var(--ok); }
.rm-bar { padding: 6px 2px 0; }

/* Чем и когда заплатили — под строкой «Оплачено» */
.rm-pays { padding: 2px 2px 4px; }
.rm-pay {
  display: flex; justify-content: space-between; align-items: baseline; gap: 8px;
  font-size: 12px; color: var(--text-soft); padding: 2px 0;
}
.rm-pay b { color: var(--text); font-variant-numeric: tabular-nums; font-weight: 500; }
.rm-pay .rm-pay-way { flex: 1; }
.rm-pay.back b { color: var(--danger); }

/* Итоги над таблицей: приход, расход, сальдо */
.totals { display: flex; gap: 22px; align-items: baseline; flex-wrap: wrap; }
.totals b { font-variant-numeric: tabular-nums; font-size: 15px; }
.totals b.ok { color: var(--ok); }
.totals b.warn { color: var(--warn); }

/* Две кнопки в одной ячейке таблицы («подтвердить» / «откатить») */
form.inline { display: inline-block; margin-right: 4px; }
/* Строка истории правок: кто, когда и что поменял */
.line { padding: 6px 0; border-bottom: 1px solid var(--line-soft); }
.line:last-child { border-bottom: 0; }
/* «Сумма: 15 000,00 ₸ → 17 000,00 ₸» — старое значение приглушено, новое жирным */
.diff { font-size: 12.5px; line-height: 1.5; }
.diff .hint { text-decoration: line-through; }

.check { display: flex; align-items: center; gap: 8px; }
.check label { color: var(--text); }

/*
 * Блок формы (оплата, возврат залога, штраф). Рамка по --line, а не по --line-soft,
 * и своя подложка: на белом экране блоки с мягкой рамкой сливались с фоном, и было
 * не видно, где кончается одна форма и начинается другая.
 */
fieldset {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fbfcfe;
  padding: 12px 14px 14px;
  margin: 0;
}
fieldset > legend {
  padding: 2px 8px; color: var(--text-soft); font-weight: 600; font-size: 12px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
}

/* ─────────────────────────────────────────────── тарифная сетка */

/*
 * Та же история, что и с шахматкой: без table-layout: fixed ширину колонки
 * диктует самый длинный заголовок («Стоимость перепробега 1 км»), и сетка
 * расползается на две ширины экрана. При fixed колонки цен делят остаток
 * поровну, а машина и галочка прилипают слева — видно, чья это строка,
 * даже когда докрутил до «от 30 суток».
 */
table.grid.tariffs {
  table-layout: fixed;
  width: 100%;
  min-width: calc(236px + var(--cols) * 78px);
}
table.grid.tariffs th, table.grid.tariffs td { padding: 4px 6px; }
table.grid.tariffs th { vertical-align: bottom; line-height: 1.25; }
table.grid.tariffs th span { display: block; font-size: 12px; }
/* Интервал печатаем под подписью: подписи в ВС разъехались с интервалами */
table.grid.tariffs th i {
  display: block;
  font-style: normal;
  font-weight: 400;
  font-size: 10.5px;
  color: var(--text-dim);
}
table.grid.tariffs th.pick, table.grid.tariffs td.pick {
  position: sticky; left: 0; z-index: 2; width: 26px; text-align: center; background: #fff;
}
table.grid.tariffs th.pick { background: #f7f9fb; }
table.grid.tariffs th.car, table.grid.tariffs td.car {
  position: sticky; left: 26px; z-index: 2; width: 210px; background: #fff;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
table.grid.tariffs th.car { background: #f7f9fb; }
table.grid.tariffs td.car i { display: block; font-style: normal; font-size: 11px; }
table.grid.tariffs tbody tr:hover td.pick,
table.grid.tariffs tbody tr:hover td.car { background: var(--accent-soft); }
/* Поле цены во всю клетку: 244 машины × 12 периодов, каждый лишний пиксель виден */
table.grid.tariffs input.cell {
  width: 100%; max-width: none; height: 26px; padding: 0 6px; text-align: right;
}
/* Перепробег — одна колонка, и вся настройка стоит в её шапке: галочка, лимит
   километров в сутки и цена километра. Строки под ней — цена километра по
   конкретной машине. Выключенный лимит гасим, но не прячем: видно, что он есть. */
table.grid.tariffs th.mileage-head { white-space: normal; overflow: visible; }
table.grid.tariffs th.mileage-head .m-on { display: block; font-size: 12px; }
table.grid.tariffs th.mileage-head .m-on label {
  display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
}
table.grid.tariffs th.mileage-head .m-set {
  display: flex; align-items: center; justify-content: flex-end; gap: 4px;
  margin-top: 2px; font-style: normal; font-weight: 400; font-size: 10.5px;
  color: var(--text-dim);
}
table.grid.tariffs th.mileage-head input.tiny { width: 58px; height: 22px; }
/* Гаснет сразу по щелчку галочки, до сохранения — видно, что настройка выключена */
table.grid.tariffs th.mileage-head .m-note {
  display: block; margin-top: 3px; font-style: normal; font-weight: 400;
  font-size: 10px; line-height: 1.2; color: var(--text-dim); text-align: right;
}
table.grid.tariffs th.mileage-head:has(input[type=checkbox]:not(:checked)) .m-set,
table.grid.tariffs th.mileage-head:has(input[type=checkbox]:not(:checked)) .m-note { opacity: .4; }
/* Пустая клетка перепробега — не «цены нет», а «как у всех»: в ней серым стоит
   общая цена из шапки, и выглядеть она должна подсказкой, а не значением */
table.grid.tariffs input.cell::placeholder { color: var(--text-dim); opacity: 1; }

/* Стрелки счётчика съедают треть узкой клетки и цену ими всё равно не набирают */
table.grid.tariffs input[type=number] { -moz-appearance: textfield; }
table.grid.tariffs input[type=number]::-webkit-outer-spin-button,
table.grid.tariffs input[type=number]::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}

/* Скидки и наценки: строка — класс машин, поля вводятся прямо в клетках.
   Пример «3 000 → 3 300» рядом с процентом: без него процент — цифра в вакууме. */
table.grid.rules input.cell { width: 100%; max-width: none; height: 26px; padding: 0 6px; }
table.grid.rules input.cell[type=number] { text-align: right; }
table.grid.rules td.example s { color: var(--text-dim); }
table.grid.rules td.example b { font-size: 13px; }

/*
 * Правил здесь пять-шесть строк, а не сотня: своя прокрутка области списку не
 * нужна — она только прятала нижние строки и обрезала бы выпадающий список
 * «кроме машин».
 */
.rules-wrap { overflow: visible; max-height: none; }
/* Панель обычно подрезает содержимое по своим углам (`overflow: hidden`), но
   здесь это мешает дважды: выпадающий список «кроме машин» обрезался бы по
   нижнему краю, а прибитая к низу кнопка сохранения не липнет внутри
   подрезанного предка. */
.panel.rules-panel { overflow: visible; }
.save-bar { border-radius: 0 0 var(--radius) var(--radius); }
.save-bar .hint { font-size: 11px; }

/*
 * «Кроме машин»: список выпадает поверх таблицы, а не прокручивается внутри
 * клетки. В премиуме 27 машин — в клетке шириной 230px они давали прокрутку и
 * вниз, и вбок, а раскрытыми растягивали строку на весь экран. Две колонки
 * поверх — весь список виден сразу и таблицу не двигает.
 */
table.grid.rules td { position: relative; }
table.grid.rules details.skip > summary {
  cursor: pointer; color: var(--accent); white-space: normal; line-height: 1.35;
}
table.grid.rules details.skip .skip-box {
  position: absolute; right: 4px; top: 100%; z-index: 5;
  width: 460px; max-height: none; overflow: visible;
  columns: 2; column-gap: 16px;
  padding: 8px 10px; background: #fff;
  border: 1px solid var(--line); border-radius: 6px;
  box-shadow: 0 6px 18px rgba(28, 37, 48, .16);
}
table.grid.rules .skip-box .check {
  break-inside: avoid; padding: 1px 0; gap: 6px; white-space: nowrap;
}

/* ─────────────────────────────────────────────── вкладки */

.tabs { display: flex; gap: 3px; border-bottom: 1px solid var(--line); padding: 0 8px; background: #f7f9fb; }
.tabs a, .tabs button {
  padding: 8px 14px;
  border: 1px solid transparent;
  border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  background: none;
  color: var(--text-soft);
  font: inherit;
  cursor: pointer;
  margin-bottom: -1px;
}
.tabs a:hover, .tabs button:hover { color: var(--text); text-decoration: none; }
.tabs .on, .tabs a.on, .tabs button.on {
  background: var(--panel);
  border-color: var(--line);
  color: var(--text);
  font-weight: 600;
}

/* ─────────────────────────────────────────────── мелочи */

.tag {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 10px;
  font-size: 11.5px;
  background: #eef1f5;
  color: var(--text-soft);
}
.tag.ok { background: #e6f5ec; color: var(--ok); }
.tag.warn { background: #fdf1e0; color: var(--warn); }
.tag.off { background: #f2f4f7; color: var(--text-dim); }
.tag.alarm { background: #fdecea; color: var(--danger); }

/*
 * План на день: выдача и возврат идут в одном списке вперемешку, и различать их
 * нужно боковым зрением, не вчитываясь. Полоса по левому краю строки — зелёная
 * «машина уезжает», оранжевая «машина возвращается».
 */
.grid tr.row-out td:first-child { box-shadow: inset 3px 0 0 var(--ok); }
.grid tr.row-back td:first-child { box-shadow: inset 3px 0 0 var(--warn); }

.msg { padding: 9px 12px; border-radius: var(--radius); margin-bottom: 10px; }
.msg.err { background: #fdecea; color: #8c231a; border: 1px solid #f3c4bd; }
/* Заявка с сайта, которую ещё не взяли в работу: текст слева, кнопка справа */
.msg.fresh-note {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  background: #fff7e6; color: #92400e; border: 1px solid #f5c98a;
}
.msg.fresh-note form { margin: 0; }
.msg.ok { background: #e8f6ee; color: #135e35; border: 1px solid #bfe3ce; }

.filter { display: flex; align-items: center; gap: 8px; }
.filter input[type=text] { max-width: 260px; height: 28px; }

/* wrap: фильтров на строку стало больше, чем влезает в узкое окно */
.toolbar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 8px 10px; border-bottom: 1px solid var(--line-soft); background: #fbfcfe; }

.footer { padding: 10px 14px; color: var(--text-dim); font-size: 12px; }

/* ─────────────────────────────────────────────── вход */

.login-wrap { display: flex; align-items: center; justify-content: center; height: 100%; }
.login {
  width: 340px;
  padding: 24px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 14px 40px rgba(20, 35, 55, .10);
}
.login h1 { margin: 0 0 2px; font-size: 19px; }
.login .sub { color: var(--text-soft); margin-bottom: 18px; font-size: 12.5px; }
.login .field { display: block; margin-bottom: 12px; }
.login .field label { display: block; margin-bottom: 5px; color: var(--text-soft); }
.login input { max-width: none; }
.login .btn { width: 100%; height: 34px; margin-top: 6px; }

/* ─────────────────────────────────────────────── оплата: полоса и шахматка

   Цвет — это ответ на вопрос «сколько человек уже заплатил», а не тип записи.
   Легенда одна на список аренд и на шахматку: зелёного столько, сколько внесено. */

/*
 * Оттенки приглушены 10.09.2026 (Максим: «в ВС глазу приятнее»). Смысл цветов
 * прежний — легенда 5.13а не меняется, меняется только насыщенность: шахматка
 * висит на экране весь день, и чистые «светофорные» тона к вечеру утомляют.
 * Зелёный и красный при этом стали ТЕМНЕЕ прежних, поэтому белый текст на них
 * читается не хуже, чем раньше.
 */
:root {
  --pay-green: #3d9a63;
  --pay-green-soft: #dcefe2;
  --pay-red: #cf6353;
  --pay-white: #ffffff;
  --pay-grey: #ccd5de;
  --pay-blue: #7aa8db;
  /* Левый борт шахматки (машина + город) — своим фоном, как в ВС */
  --chess-side: #f2f5f9;
}

.paybar {
  position: relative;
  width: 74px;
  height: 9px;
  border: 1px solid var(--line);
  border-radius: 5px;
  overflow: hidden;
  background: var(--pay-white);
}
.paybar i { display: block; height: 100%; background: var(--pay-green); }
.paybar.unpaid { background: var(--pay-red); }
.paybar.part { background: var(--pay-red); }
.paybar.paid { background: var(--pay-green); }
.paybar.reserve { background: var(--pay-white); }
.paybar.service { background: var(--pay-grey); }
.paybar.service i { display: none; }

.legend { flex-wrap: wrap; font-size: 12px; color: var(--text-soft); }
.legend span, .vs-legend span { display: inline-flex; align-items: center; gap: 5px; }
.legend .chip, .vs-legend .chip {
  width: 26px; height: 10px; border: 1px solid var(--line); border-radius: 4px;
  flex: 0 0 auto;
}
.legend .chip.reserve, .vs-legend .chip.reserve { background: linear-gradient(90deg, var(--pay-green) 40%, var(--pay-white) 40%); }
.legend .chip.part, .vs-legend .chip.part { background: linear-gradient(90deg, var(--pay-green) 55%, var(--pay-red) 55%); }
.legend .chip.paid, .vs-legend .chip.paid { background: var(--pay-green); }
.legend .chip.unpaid, .vs-legend .chip.unpaid { background: var(--pay-red); }
.legend .chip.service, .vs-legend .chip.service { background: var(--pay-grey); }
.legend .chip.transfer, .vs-legend .chip.transfer { background: var(--pay-blue); }
/* Замок и очередь правок (5.28): цвет оплаты остаётся, меняется насыщенность */
.legend .chip.done, .vs-legend .chip.done { background: var(--pay-green); opacity: .45; }
.legend .chip.wait, .vs-legend .chip.wait {
  background: var(--pay-white, #fff); border: 2px dashed var(--warn);
}

/* Легенда переехала со шапки в правую панель: сверху у ВС кнопки, а не подсказки */
/* Подвал шахматки: две строки подсказок в ряд — цвета записей и состояние машин */
.chess-legend {
  flex: none;
  border-top: 1px solid var(--line-soft);
  padding: 7px 10px; display: flex; align-items: flex-end; gap: 12px;
  background: var(--panel);
}
.chess-legend .legends { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
/* Любую легенду в программе можно убрать кнопкой — подсказка нужна первую
   неделю, а место занимает всегда. Кнопку ставит legend.js, стили общие.
   Свёрнутая легенда остаётся тонкой строкой, иначе её не вернуть. */
.legend-toggle {
  flex: none; align-self: flex-end;
  padding: 2px 8px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel); color: var(--text-soft); font: inherit; font-size: 11px;
  line-height: 1.4; white-space: nowrap; cursor: pointer;
}
.legend-toggle:hover { background: var(--accent-soft); color: var(--text); }
.legend-off { padding-top: 2px; padding-bottom: 2px; align-items: center; }
.legend-off > *:not(.legend-toggle):not(.legend-keep) { display: none; }
.legend-off .legend-toggle { margin-right: auto; align-self: center; }
/* Метка сборки: справа от легенды пусто, а знать версию надо — по ней видно,
   доехало ли обновление. */
.chess-legend .build-mark {
  flex: none; white-space: nowrap; font-size: 11px; color: var(--text-dim);
}
.vs-legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px;
  font-size: 11px; line-height: 1.3; color: var(--text-dim);
}
.vs-legend span { display: inline-flex; align-items: center; gap: 4px; }
.vs-legend .chip { margin-top: 0; }

/*
Состояние машины (5.13в). Четыре цвета названы Максимом словами, а не кодами:
скоро ТО — жёлтый, ТО просрочено — красный, страховка на исходе — голубой,
страховка кончилась — фиолетовый. Держим их одним набором переменных, потому
что тем же цветом красится и фон строки, и точка рядом с названием.
*/
:root {
  --car-pti-soon: #ffe680;
  --car-pti-out:  #ff8f8f;
  --car-ins-soon: #a8dcf5;
  --car-ins-out:  #d3b3f0;
}
.vs-legend.cars { margin-top: 0; }
.vs-legend .vs-box-head { margin-bottom: 0; margin-right: 2px; }
.vs-legend span b { font-weight: 600; color: var(--text-soft); }
.vs-legend .chip.a-pti-soon { background: var(--car-pti-soon); }
.vs-legend .chip.a-pti-out  { background: var(--car-pti-out); }
.vs-legend .chip.a-ins-soon { background: var(--car-ins-soon); }
.vs-legend .chip.a-ins-out  { background: var(--car-ins-out); }

.chess-wrap {
  overflow-x: auto;
  position: relative;
  /*
   * Ширина левого борта: колонка машины плюс узкая колонка города. В названии
   * машины должен помещаться и номер («Mercedes-Benz GLC coupe (х123ру39)») —
   * иначе менеджер не отличает две одинаковые машины друг от друга.
   */
  --car-col: 236px;
  --left-cols: calc(var(--car-col) + 34px);
}
/* Город один — колонки «Гор.» нет, борт ровно на ширину названия машины */
.chess-wrap.no-place { --left-cols: var(--car-col); }
.chess-wrap.no-place table.chess th.car { border-right: 1px solid var(--line); }

/*
 * Столб «сегодня» на всю высоту шахматки.
 *
 * Заголовок дня подсвечен и без него, но в парке 65 строк: у нижних машин шапка
 * уже за краем экрана, и «где сейчас» приходится искать глазами. Столб рисует
 * public/chess.js по координатам заголовка — колонкой это не сделать, потому что
 * занятые клетки склеены colspan и своей ячейки на сегодня у них нет.
 *
 * z-index: 1 — ниже прилипших колонки машины (2) и шапки (3, 4): при прокрутке
 * вбок столб должен уезжать ПОД название машины, а не поверх него.
 */
.today-col {
  position: absolute;
  top: 0;
  z-index: 1;
  pointer-events: none;
  background: rgba(37, 99, 235, .07);
  border-left: 1px solid rgba(37, 99, 235, .45);
  border-right: 1px solid rgba(37, 99, 235, .45);
}

/*
 * Раскладка шахматки.
 *
 * table-layout: fixed — обязательно. При обычном расчёте ширину колонки задаёт
 * самая длинная надпись в ней, а надпись на полосе аренды («Семиров Владимир
 * Владимирович 09:55») растягивает те сутки, которые полоса накрывает. Из-за
 * этого дни выходили разной ширины, а на экран влезало три штуки вместо месяца.
 * При fixed ширина берётся только из первой строки: колонки машины и города
 * заданы жёстко, вся остальная ширина делится между днями поровну.
 *
 * Ширину таблицы считаем так, чтобы на экране всегда помещалось --vis суток
 * (20 или всё окно, если оно короче). Окно длиннее — таблица шире экрана и
 * прокручивается вбок. Пределы: сутки не уже 22 px (иначе не прочитать число)
 * и не шире 72 px (иначе короткий период растягивается на пол-экрана).
 */
table.chess {
  border-collapse: collapse;
  table-layout: fixed;
  font-size: 12px;
  width: calc(var(--left-cols) + (100% - var(--left-cols)) * var(--days) / var(--vis));
  min-width: calc(var(--left-cols) + var(--days) * 22px);
  max-width: calc(var(--left-cols) + var(--days) * 72px);
}
table.chess th, table.chess td { border: 1px solid var(--line-soft); padding: 0; }

table.chess th.car {
  position: sticky;
  left: 0;
  z-index: 2;
  width: var(--car-col);
  padding: 2px 7px;
  text-align: left;
  /* Обычный вес, как в ВС (Максим, 10.09.2026): th по умолчанию полужирный,
     и левый борт из 61 названия выглядел тяжелее самой сетки. */
  font-weight: 400;
  line-height: 1.25;
  background: var(--chess-side);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
table.chess th.car i { display: block; color: var(--text-dim); font-style: normal; font-size: 10px; }
/* Название машины — чёрным, как в ВС (Максим, 10.09.2026). Синим левый борт
   читался как список ссылок и спорил с цветными полосами справа; кликается оно
   по-прежнему, подчёркивание под курсором на месте. */
table.chess th.car a { color: #16202b; }
table.chess th.car a:hover { color: var(--accent); }
table.chess thead th { background: #fbfcfe; position: sticky; top: 0; z-index: 3; }
table.chess thead th.car { z-index: 4; }
table.chess th.day {
  /* ширину не задаём: при table-layout: fixed её поровну делят все дни окна */
  padding: 2px 0;
  text-align: center;
  font-weight: 600;
  line-height: 1.25;
  color: var(--text-soft);
}
table.chess th.day.weekend { background: #f7f3ec; color: #9c6813; }
table.chess th.day em,
table.chess th.day i {
  display: block; font-style: normal; font-weight: 400; font-size: 9px; color: var(--text-dim);
  min-height: 11px;
}
table.chess th.day em { color: var(--text-soft); }

table.chess tr.on th.car { background: var(--accent-soft); }
/* Борт под курсором — заметно светлее своего фона, иначе подсветка строки на
   сером борту не читается */
table.chess tbody tr:hover th.car,
table.chess tbody tr:hover th.place { background: #e7eefb; }

/*
Цвет названия машины — её состояние (5.13в). Правила идут после hover и после
tr.on намеренно: если у машины кончилась страховка, это важнее подсветки поиска
и важнее «мышь проехала мимо». Точки слева от названия показывают все поводы
сразу — фоном-то можно показать только один.
*/
table.chess tbody tr th.car.a-pti-soon { background: var(--car-pti-soon); }
table.chess tbody tr th.car.a-pti-out  { background: var(--car-pti-out); }
table.chess tbody tr th.car.a-ins-soon { background: var(--car-ins-soon); }
table.chess tbody tr th.car.a-ins-out  { background: var(--car-ins-out); }
table.chess th.car .flags {
  display: inline-flex; gap: 2px; vertical-align: middle; margin-right: 4px;
}
table.chess th.car .fl {
  width: 7px; height: 7px; border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, .3); flex: 0 0 auto;
}
table.chess th.car .fl.pti-soon { background: var(--car-pti-soon); }
table.chess th.car .fl.pti-out  { background: var(--car-pti-out); }
table.chess th.car .fl.ins-soon { background: var(--car-ins-soon); }
table.chess th.car .fl.ins-out  { background: var(--car-ins-out); }

table.chess td.free { height: 22px; background: var(--panel); }
table.chess td.free a { display: block; height: 22px; }
table.chess td.free a:hover { background: var(--accent-soft); }

/*
 * Чересполосица и подсветка строки под курсором (Максим, 10.09.2026: «чтобы
 * глаз радовался»). В парке 65 строк одинаковой высоты — на сплошном белом
 * менеджер, ведя палец от названия машины к нужному числу, сползает на соседнюю
 * строку. Полутон еле заметный: сетка не должна спорить с полосами аренд.
 */
table.chess tbody tr:nth-child(even) td { background: #f7f9fb; }
table.chess tbody tr:hover td { background: #eef4fb; }

table.chess td.busy { padding: 1px; }
/* Занятые сутки — это дорожки: две записи одного дня (возврат в обед и выдача
   вечером) стоят каждая на своих часах, а пересёкшиеся по времени — в разных
   рядах. Слой `gaps` под полосами ловит клик по свободным часам. */
/* Высота трека фиксирована: строка машины с двумя записями в одних сутках была
   вдвое выше соседних, и сетка «прыгала» (Максим, 21.08.2026). Дорожки делят
   между собой одну и ту же высоту, поэтому все строки ровные. */
table.chess .track { position: relative; display: flex; flex-direction: column; gap: 1px; height: 20px; }
table.chess .track .gaps { position: absolute; inset: 0; }
table.chess .track .gaps .gap { position: absolute; top: 0; bottom: 0; border-radius: 3px; }
table.chess .track .gaps .gap:hover { background: var(--accent-soft); }
/* Дорожка лежит поверх слоя `gaps` и на всю ширину клетки, поэтому сама клики
   не ловит — иначе пустое место рядом с короткой записью (трансфер, аренда на
   пару часов) съедало нажатие, и «ткнуть в этот день и сдать машину ещё раз»
   было нельзя (Максим, 21.08.2026). Нажимаются только сами полосы. */
table.chess .lane { position: relative; flex: 1 1 0; min-height: 0; pointer-events: none; }
table.chess .bar { pointer-events: auto; }
/* Часы, а не сутки: --l — от начала блока до выдачи, --r — от возврата до его
   конца. Аренда с 14:00 оставляет левую часть клетки незакрашенной, и видно,
   что до обеда машина свободна (src/routes/chess.js) */
table.chess .bar {
  position: absolute;
  left: var(--l, 0);
  right: var(--r, 0);
  top: 0;
  display: block;
  /* Просвет между соседними записями: даже полчаса между арендами должны быть
     видны глазом, иначе две записи читаются как одна (Максим, 21.08.2026). */
  margin-right: 3px;
  bottom: 0;
  line-height: 1;
  padding: 0 5px;
  border-radius: 3px;
  /* Надпись читается по заливке под ней, как в ВС (Максим, 10.09.2026): тёмная
     по умолчанию — на бледно-зелёной брони, приглушённом красном, сером сервисе
     и голубом трансфере; белая только там, где заливка тёмная (класс `ink-light`
     ставит src/routes/chess.js). */
  color: #172430;
  font-size: 11px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border: 1px solid rgba(20, 48, 31, .12);
  /* --paid задаёт долю оплаты: слева зелёное, справа — неоплаченный остаток */
  background: linear-gradient(90deg, var(--pay-green) var(--paid), var(--pay-red) var(--paid));
}
.chess .bar:hover { text-decoration: none; filter: brightness(1.06); }
.chess .bar.reserve {
  background: linear-gradient(90deg, var(--pay-green) var(--paid), var(--pay-green-soft) var(--paid));
}
.chess .bar.paid { background: var(--pay-green); }
.chess .bar.unpaid { background: var(--pay-red); }
.chess .bar.service { background: var(--pay-grey); }
.chess .bar.transfer { background: var(--pay-blue); }
/* Тёмная заливка под надписью — пишем белым */
.chess .bar.ink-light { color: #fff; }

/* Две записи в сутках — полоса вдвое ниже, поэтому мельче шрифт; с трёх дорожек
   текст уже не прочитать, там остаётся цветная полоса и подсказка по наведению. */
.chess .track.lanes-2 .bar { font-size: 9px; padding: 0 3px; }
.chess .track.lanes-2 .bar .t { font-size: 8px; }
.chess .track.lanes-3 .bar, .chess .track.lanes-4 .bar,
.chess .track.lanes-many .bar { font-size: 0; padding: 0 2px; }

/* Время выдачи и возврата прямо в полосе — как в ВС: менеджеру важно «во сколько» */
.chess .bar { display: flex; align-items: center; gap: 6px; }
.chess .bar span { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.chess .bar .t { font-style: normal; opacity: .85; font-size: 10px; font-weight: 400; flex: none; }
.chess .bar.hit { outline: 2px solid var(--accent); outline-offset: -2px; }
.chess .bar.sel { outline: 2px solid var(--text); outline-offset: -2px; }

/*
 * Замок и очередь правок (5.28, просьба Максима 27.08.2026). Цвет полосы менять
 * нельзя — он означает оплату (легенда 5.13а), поэтому закрытая аренда просто
 * бледнее: дело сделано, глазу там задерживаться незачем. А завершённая, но не
 * закрытая обведена пунктиром — это очередь на правки, и на общем фоне она
 * должна цепляться взглядом.
 */
.chess .bar.done { opacity: .5; }
.chess .bar.done:hover { opacity: 1; }
.chess .bar.wait { outline: 2px dashed var(--warn); outline-offset: -2px; }

/* Новая заявка с сайта, которую ещё не разобрали. Заметность здесь важнее
   спокойствия экрана: такая полоса не должна провисеть до утра. Мигание
   медленное (2 с) — быстрое на шахматке из 65 строк невозможно смотреть.
   Метка снимается кнопкой «Заявка разобрана» в карточке. */
.chess .bar.fresh {
  outline: 2px solid var(--fresh, #f59e0b);
  outline-offset: -2px;
  animation: fresh-pulse 2s ease-in-out infinite;
}
@keyframes fresh-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, .55); }
  50%      { box-shadow: 0 0 0 3px rgba(245, 158, 11, 0); }
}
/* Кому мигание мешает (открытая шахматка на экране в офисе) — остаётся рамка. */
@media (prefers-reduced-motion: reduce) {
  .chess .bar.fresh { animation: none; }
}
.vs-line.fresh { color: #92400e; background: rgba(245, 158, 11, .12); }
.vs-line.fresh b { color: #b45309; }

table.chess th.place {
  /* left = ширина колонки машины: колонки «прилипают» друг к другу при прокрутке */
  position: sticky; left: var(--car-col); z-index: 2;
  width: 34px;
  padding: 2px 3px; text-align: center;
  overflow: hidden;
  /* Правый край борта заметнее сетки: левая колонка читается как отдельная
     панель, и названия машин выделяются не жирным шрифтом, а границей. */
  border-right: 1px solid var(--line);
  font-weight: 500; font-size: 11px; color: var(--text-dim);
  background: var(--chess-side);
}
table.chess thead th.place { z-index: 4; background: #fbfcfe; }
table.chess th.day.today, table.chess td.free.today { background: var(--accent-soft); }
table.chess td.free.weekend { background: #faf8f5; }

/* ─── главный экран в раскладке ВС: таблица во весь экран, панель кнопок справа */

/* Высота рабочей области. Вычитаем ровно то, что стоит над ней и под ней:
   шапка 44 + отступ страницы 12 сверху и 12 снизу + заголовок 22 + его отступ 10
   + рамка 2 ≈ 102, плюс небольшой запас. Раньше стояло 190 — под таблицей
   оставалась пустая полоса в треть экрана, а строки машин прятались под скролл.
   Обе колонки берут одну и ту же высоту, поэтому заканчиваются вровень. */
.vs { display: flex; gap: var(--gap); align-items: flex-start; --vs-h: calc(100vh - 116px); }
.vs > .vs-main { flex: 1; min-width: 0; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  height: var(--vs-h); display: flex; flex-direction: column; }
/* Таблица забирает всё, что осталось от подвала с легендой */
.vs-main .chess-wrap { flex: 1; min-height: 0; overflow: auto; }

/* Правая колонка живёт по высоте экрана и не листается: всё, что в ней есть,
   должно поместиться разом — иначе итоги дня уезжают за нижний край. Поэтому
   здесь всё на тон плотнее обычных форм: поля пониже, отступы меньше. */
.vs-side {
  width: 232px; flex: none; height: var(--vs-h);
  display: flex; flex-direction: column; gap: 3px; overflow-y: auto; overflow-x: hidden;
  font-size: 11.5px; scrollbar-width: thin;
}
.vs-side input, .vs-side select, .vs-side .btn {
  padding: 1px 7px; font-size: 11px; line-height: 1.2; min-height: 0;
}
/* Подпись о пользователе прижата к низу — панель заканчивается вровень с легендой.
   И прилипает к нижнему краю: в день с большой выручкой цифры в итогах шире,
   панель становится выше экрана — раньше в этом случае «кто работает» и кнопка
   смены пользователя уезжали за нижний край и найти их было негде. */
.vs-side .vs-user {
  margin-top: auto; position: sticky; bottom: 0;
  background: var(--bg); padding-top: 3px;
}

/* Ноутбук с невысоким экраном (а это большинство рабочих мест): ужимаем панель
   ещё на тон, чтобы итоги дня и подпись о пользователе помещались без прокрутки. */
@media (max-height: 900px) {
  .vs-side { font-size: 11px; gap: 3px; }
  .vs-side input, .vs-side select, .vs-side .btn { font-size: 10.5px; padding: 1px 6px; }
  .vs-btn { padding: 1px 8px; }
  .vs-line { font-size: 11px; line-height: 1.3; }
  .vs-period { padding: 3px; }
}
@media (max-height: 780px) {
  .vs-side { font-size: 10.5px; }
  .vs-line { font-size: 10.5px; line-height: 1.25; }
  .vs-box-head { font-size: 10px; }
  .vs-gap { margin: 1px 0; }
}

/* Шахматка — единственное, что листается. Как в ВС: страница стоит на месте,
   меню, кнопки и итоги всегда на виду, прокручивается только сама таблица. */
body.fixed { height: 100vh; overflow: hidden; }
body.fixed .page { height: calc(100vh - 44px); overflow: hidden; }

/* Блок периода серее остальных: он один задаёт, что видно на шахматке, и не
   должен теряться среди белых панелей. Поля дат внутри — ещё на тон темнее. */
.vs-period {
  display: grid; grid-template-columns: 22px 1fr; gap: 2px 4px; align-items: center;
  background: #eaeef4; border: 1px solid var(--line);
  border-radius: var(--radius); padding: 3px;
}
.vs-period label { color: var(--text-soft); }
.vs-period input, .vs-period select { width: 100%; }
.vs-period input { background: #dfe5ee; }
.vs-period select { background: #f4f7fa; }
.vs-period select, .vs-period .btn { grid-column: 1 / -1; }

.vs-nav { display: flex; gap: 3px; }
.vs-nav .btn { flex: 1; justify-content: center; }

.vs-actions {
  display: flex; flex-direction: column; gap: 0;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 3px;
}
.vs-gap { height: 1px; border-top: 1px solid var(--line-soft); margin: 1px 0; }

.vs-btn {
  display: flex; align-items: center; gap: 7px;
  padding: 1px 8px; border-radius: 4px;
  color: var(--text); text-decoration: none; white-space: nowrap;
}
.vs-btn:hover { background: var(--accent-soft); text-decoration: none; }
.vs-btn .ico { width: 16px; text-align: center; color: var(--text-soft); }
.vs-btn.need-sel { color: var(--text-dim); }
.vs-btn.need-sel.ready { color: var(--text); }

.vs-search { position: relative; }
.vs-search input { width: 100%; }
.vs-search .clear {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  color: var(--text-dim); text-decoration: none; font-size: 12px;
}

.vs-sel {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 2px 8px; font-size: 11px; min-height: 18px;
}
.vs-sel .hint { color: var(--text-dim); }

.vs-box {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1px 0;
}
.vs-box-head {
  padding: 2px 8px; font-weight: 600; font-size: 11px;
  color: var(--text-soft); border-bottom: 1px solid var(--line-soft); margin-bottom: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Строка сводки — подпись слева, число справа, всегда в одну строку. Суммы за
   хороший день длиннее подписи, и раньше число сваливалось под неё: блок итогов
   рос вдвое и выдавливал вниз всё, что под ним. Теперь переносов нет: подпись
   при нехватке места ужимается многоточием, число видно целиком. */
.vs-line {
  display: flex; justify-content: space-between; gap: 6px; align-items: baseline;
  padding: 0 8px; font-size: 11.5px; line-height: 1.45;
  color: var(--text-soft); text-decoration: none; white-space: nowrap;
}
.vs-line { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
a.vs-line:hover { background: var(--accent-soft); text-decoration: none; }
.vs-line b {
  color: var(--text); font-variant-numeric: tabular-nums;
  font-size: inherit; flex: none;
}
.vs-line.warn b { color: var(--danger); }
.vs-line.total { border-top: 1px solid var(--line-soft); margin-top: 1px; padding-top: 3px; }
.vs-line.total b { font-weight: 700; }

/* Итоги дня — последний блок панели. Раньше он листался внутри себя, и на низком
   экране менеджер видел «Наличными» без «Безналично» и «Всего»: три строки за
   прокруткой — это те самые цифры, ради которых в блок и смотрят. Поэтому блок
   не сжимаем и не листаем, а место под него отыгрываем плотностью строк выше. */
/* Внимание: класс .totals есть и в отчётах (строка итогов в подвале таблицы) —
   там он флексовый, с зазором 22px и крупными цифрами. В правой панели шахматки
   он этот зазор и размер утаскивал за собой: три строки итогов расползались на
   пол-экрана, а «Всего» уходило под нижний край. Поэтому здесь стиль возвращаем
   к обычным строкам сводки. */
.vs-side .vs-box.totals {
  flex: none; min-height: 0; overflow: visible;
  display: block; gap: 0;
}
.vs-side .vs-box.totals b { font-size: inherit; }

/* Кто работает и кнопка смены — внизу правой панели, как в ВС: в шапке это
   дублировалось трижды и съедало место у меню. */
.vs-user {
  font-size: 10.5px; color: var(--text-dim); padding: 0 2px; line-height: 1.2;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.vs-user b { display: block; color: var(--text-soft); font-size: 11px; }
.vs-user .btn { flex: none; height: 22px; font-size: 10.5px; }

/* Меню на свободной клетке: что ставим на машину — аренду, бронь или сервис */
.cell-menu {
  position: absolute; z-index: 30; min-width: 168px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 3px;
  box-shadow: 0 8px 24px rgba(20, 34, 56, .16);
}
.cell-menu[hidden] { display: none; }
.cell-menu a {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 9px; border-radius: 4px;
  font-size: 13px; color: var(--text); text-decoration: none; white-space: nowrap;
}
.cell-menu a:hover { background: var(--accent-soft); text-decoration: none; }
.cell-menu .ico { color: var(--accent); font-size: 12px; }

@media (max-width: 1100px) {
  .vs { flex-direction: column-reverse; }
  .vs-side { width: 100%; }
}

/* ─────────────────────────────────────── осмотр: ракурсы и схема кузова */

/* Плитка ракурсов. Ширина колонки под миниатюру телефона: карточку осмотра
   открывают у машины, и «снять» должно попадаться пальцем, а не курсором. */
.angles {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
}
.angle { display: flex; flex-direction: column; gap: 4px; }
.angle img {
  width: 100%; height: 92px; object-fit: cover;
  border: 1px solid var(--line); border-radius: var(--radius); background: #f7f9fc;
}
.angle .cap { font-size: 12px; color: var(--text-soft); line-height: 1.3; }
.angle .cap .hint { font-size: 11px; }
.angle .shot {
  display: flex; align-items: center; justify-content: center;
  height: 92px; border: 1px dashed var(--line); border-radius: var(--radius);
  color: var(--text-dim); background: #fbfcfe; cursor: pointer; font-size: 13px;
}
.angle .shot:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.angle.miss .cap { color: var(--text-dim); }
.angle form .btn { height: 24px; padding: 0 8px; font-size: 12px; }
.angle.done img { cursor: zoom-in; }

/* Снимки повреждения прямо в списке: маленькие, но щелчок открывает во весь экран */
.dmg-thumb {
  width: 64px; height: 48px; object-fit: cover; cursor: zoom-in;
  border: 1px solid var(--line); border-radius: 6px; background: #f7f9fc;
  margin-right: 4px; vertical-align: middle;
}

/* Подписи и журнал письма в карточке подписанного осмотра */
.signs { display: flex; gap: 18px; flex-wrap: wrap; margin-bottom: 12px; }
.sign { display: flex; flex-direction: column; gap: 4px; }
.sign img {
  width: 220px; height: 90px; object-fit: contain;
  border: 1px solid var(--line); border-radius: var(--radius); background: #fff;
}
.sign .cap { font-size: 12px; color: var(--text-soft); }
.sign.miss { color: var(--text-dim); }
.mail-log { width: 100%; border-collapse: collapse; font-size: 13px; }
.mail-log td { padding: 4px 8px 4px 0; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
.mail-log td.err { color: var(--danger, #c0392b); }
.sent-docs { margin: 4px 0 0; padding-left: 18px; font-size: 13px; }
.sent-docs li { margin-bottom: 2px; }
.sent-docs .hint { margin-left: 6px; }

/* Состояние осмотра в блоках «Выдача» и «Возврат» карточки аренды */
.hand-note {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 10px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: var(--radius);
  font-size: 13px;
}
.hand-note.done { background: #eaf7ee; border-color: #b7e0c2; color: #1c6b34; }
.hand-note.wait { background: #fff6e5; border-color: #f0dcb0; color: #8a6100; }
.hand-note.none { background: var(--bg-soft, #f7f8fa); color: var(--text-soft); }
.hand-note .btn { margin-left: auto; }

.scheme-wrap { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }
/* Схема — контейнер с позиционированием: метки ставятся долями от его размера */
.scheme {
  position: relative; width: 190px; height: 380px; flex: none;
  border: 1px solid var(--line-soft); border-radius: var(--radius); background: #fbfcfe;
}
.scheme-svg { width: 100%; height: 100%; display: block; }
.scheme-svg .body { fill: #eef2f7; stroke: #c3cdd9; stroke-width: 1.5; }
.scheme-svg .glass { fill: #dde5ee; }
.scheme-svg .roof { fill: #f7f9fc; stroke: #d5dde6; }
.scheme-svg .mirror { fill: #d5dde6; }
.scheme .pt {
  position: absolute; transform: translate(-50%, -50%);
  width: 20px; height: 20px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--danger); color: #fff; font-size: 11px; font-weight: 600;
  box-shadow: 0 1px 4px rgba(20, 34, 56, .3);
}
.scheme .pt.new { background: var(--accent); }
.scheme-side { flex: 1 1 320px; }
.damage-form { max-width: none; gap: 10px; }

/* ─────────────────────────────────────────────── отчёты */

.report-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; }
.report-card {
  display: flex; flex-direction: column; gap: 4px;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius);
  background: #fff; color: var(--text); text-decoration: none;
}
.report-card:hover { border-color: var(--accent); background: var(--accent-soft); }
.report-card b { font-size: 14px; }
.report-card.off { background: #fafbfc; color: var(--text-dim); }
.report-card.off:hover { border-color: var(--line); background: #fafbfc; }

/* Итоговая строка идёт отдельной таблицей — чтобы не уезжала при прокрутке списка */
table.grid.totals-row { border-top: 2px solid var(--line); }
table.grid.totals-row td { background: #f7f9fb; height: 34px; }

/* ─────────────────────────────────────────── документы и печатные формы */

/* Лист документа на экране: тот же вид, что уйдёт на принтер */
.doc-sheet {
  padding: 24px 28px; background: #fff; color: #000;
  font: 14px/1.5 "Times New Roman", Georgia, serif;
  max-height: 70vh; overflow: auto;
}
.doc-sheet p { margin: 0 0 8px; text-align: justify; }
.doc-sheet .doc-title { text-align: center; font-weight: 700; font-size: 16px; margin-bottom: 12px; }
.doc-sheet table { border-collapse: collapse; width: 100%; margin: 8px 0 12px; }
.doc-sheet table.doc-line td { vertical-align: top; padding: 2px 8px 2px 0; width: 50%; }
.doc-sheet table.doc-line td.right { text-align: right; }
.doc-sheet table.doc-grid th,
.doc-sheet table.doc-grid td { border: 1px solid #000; padding: 4px 6px; font-size: 13px; text-align: left; }
.doc-sheet table.doc-grid th { background: #f0f0f0; }
.doc-sheet .sign-line { display: inline-block; min-width: 160px; border-bottom: 1px solid #000; }

/* Шпаргалка подстановок рядом с текстом формы */
.var-list { max-height: 70vh; overflow: auto; font-size: 12px; }
.var-group { margin-bottom: 10px; }
.var-group b { display: block; margin-bottom: 4px; }
.var-row { display: flex; gap: 6px; align-items: baseline; padding: 1px 0; }
.var-row code {
  font-size: 11px; background: #f2f5f8; border: 1px solid var(--line-soft);
  border-radius: 4px; padding: 0 4px; white-space: nowrap;
}
.var-row span { color: var(--text-dim); }
textarea.code { font: 12px/1.5 ui-monospace, "SF Mono", Consolas, monospace; }
.checks { display: flex; flex-wrap: wrap; gap: 4px 16px; }

/* ─────────────────────────────────────────────── фотографии витрины */

/* Галерея в карточке машины: те же снимки, что уйдут на сайт и в модуль */
.photos { display: flex; flex-wrap: wrap; gap: 12px; }
.photos .photo {
  margin: 0; width: 200px; border: 1px solid var(--line-soft);
  border-radius: 8px; padding: 8px; background: #fff;
}
.photos .photo.main { border-color: var(--accent); }
.photos .photo img {
  width: 100%; height: 130px; object-fit: cover;
  border-radius: 6px; background: #f2f5f8; display: block;
}
.photos .photo figcaption {
  display: flex; align-items: center; gap: 6px; margin-top: 6px;
  font-size: 12px; min-height: 18px;
}

/* ── фильтры списков: период и сортировка (src/web/filters.js) ───────────── */
.toolbar .filter { display: inline-flex; align-items: center; gap: 6px; }
.toolbar .filter > span { color: #6b7a8c; font-size: 12px; }
/* Поля дат нужны только при «свой период» — иначе занимают полстроки зря */
.toolbar .period-dates { display: none; gap: 6px; }
.toolbar.custom-period .period-dates { display: inline-flex; }
/* Заголовок столбца — ссылка сортировки: щелчок сортирует, повторный разворачивает */
.grid th a.th-sort { color: inherit; text-decoration: none; display: block; }
.grid th a.th-sort:hover { color: #1f6feb; }
.grid th.sorted { color: #1f6feb; }

/* ─────────────────────────────────────────────── CRM: доска и диалоги */

/*
 * Доска воронки. Колонки прокручиваются вбок все вместе, карточки внутри
 * колонки — по вертикали: так на экран влезает вся воронка, а не первые три
 * стадии. Ширина колонки фиксированная — иначе стадия с одной карточкой
 * раздувается на пол-экрана.
 */
.board {
  display: flex; gap: 8px; align-items: stretch;
  flex: 1; min-height: 0; overflow-x: auto; padding-bottom: 6px;
}
.board .lane {
  width: 236px; flex: none; display: flex; flex-direction: column; min-height: 0;
  background: #e9edf3; border-radius: var(--radius);
}
.board .lane.over { background: var(--accent-soft); outline: 1px dashed var(--accent); }
.board .lane > header {
  padding: 7px 9px 6px; border-top: 3px solid #8b98a8;
  border-radius: var(--radius) var(--radius) 0 0; background: #f4f6fa;
  display: flex; align-items: baseline; gap: 6px;
}
.board .lane > header b { font-weight: 600; font-size: 12px; }
.board .lane > header i { font-style: normal; font-size: 11px; }
.board .lane > header span { margin-left: auto; color: var(--text-soft); font-size: 11px; white-space: nowrap; }
.board .lane-body { flex: 1; min-height: 0; overflow-y: auto; padding: 6px; display: flex; flex-direction: column; gap: 6px; }
.board .lane-won > header { background: #eaf6ee; }
.board .lane-lost > header { background: #fbeeea; }

.board .card {
  background: var(--panel); border: 1px solid var(--line-soft);
  border-radius: var(--radius); box-shadow: 0 1px 2px rgba(24, 41, 66, .06);
}
.board .card:hover { border-color: var(--accent); }
.board .card.dragging { opacity: .5; }
.board .card > a { display: block; padding: 7px 8px; color: inherit; }
.board .card > a:hover { text-decoration: none; }
.board .card-top { display: flex; gap: 6px; align-items: baseline; }
.board .card-top b { font-weight: 600; font-size: 12px; }
.board .card-top .sum { margin-left: auto; color: var(--ok); font-size: 12px; white-space: nowrap; }
.board .card-line { color: var(--text-soft); font-size: 12px; margin-top: 2px; }
.board .card-foot {
  display: flex; flex-wrap: wrap; gap: 4px 8px; margin-top: 5px;
  color: var(--text-dim); font-size: 11px;
}
.board .card-foot .wait { color: var(--warn); }
.hint.pad { padding: 8px; }
/* Предупреждение над живыми, но несохраняемыми полями карточки */
.hint.note {
  background: #fdf6e3; border: 1px solid #efdfae; border-radius: var(--radius);
  padding: 6px 10px; margin-bottom: 10px; color: #7a5c12;
}

/*
 * Полоса стадий в карточке обращения: тот же порядок, что колонки на доске.
 * Рабочие стадии делят ряд поровну и не переносятся — воронка читается одной
 * строкой слева направо, как в Б24; отказы спрятаны под кнопку справа.
 */
.stage-line { display: flex; align-items: stretch; gap: 6px; }
.stage-row { display: flex; flex: 1 1 auto; gap: 2px; min-width: 0; }
/* Каждая плашка живёт в своей форме — ширину делит форма, а не только кнопка */
.stage-cell { display: flex; flex: 1 1 0; min-width: 0; }
.stage-cell:has(.stage-step.on) { flex: 3 1 auto; }
.stage-row:hover .stage-cell:hover { flex: 4 1 auto; }
.stage-step {
  --st: #8b98a8;
  border: 1px solid var(--line); border-bottom: 3px solid var(--st); background: #fff;
  border-radius: var(--radius); padding: 4px 6px; font: inherit; font-size: 11px;
  color: var(--text-soft); cursor: pointer; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; flex: 1 1 0; min-width: 0; text-align: center;
}
/* Названия стадий длинные: под курсором плашка раздвигается и читается целиком */
.stage-row:hover .stage-step:hover { flex: 4 1 auto; }
.stage-step:hover { border-color: var(--st); color: var(--st); }
/* Пройденное — бледной заливкой того же цвета, текущее — залито целиком */
.stage-step.pass { background: color-mix(in srgb, var(--st) 14%, #fff); color: var(--text); }
/* Текущая стадия — залита цветом и шире соседей: её название видно целиком */
.stage-step.on {
  background: var(--st); border-color: var(--st); color: #fff; font-weight: 600;
  flex: 3 1 auto;
}

/* Отказы: их восемь штук, в ряд не лезут и нужны раз в день */
.stage-more { position: relative; flex: none; }
.stage-more > summary { list-style: none; display: block; width: max-content; }
.stage-more > summary::-webkit-details-marker { display: none; }
.stage-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 20; width: 240px;
  display: flex; flex-direction: column; gap: 3px; padding: 6px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 10px 30px rgba(20, 30, 44, .18);
}
.stage-menu .stage-step { text-align: left; flex: none; }

/* Кто взял обращение и кто продал — строкой под стадиями */
.panel-body.pad-top-0 { padding-top: 0; }
.stage-marks { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; font-size: 12px; }
.stage-marks .mark { display: inline-flex; align-items: center; gap: 6px; color: var(--text-soft); }
.stage-marks .mark b { color: var(--text-dim); font-weight: 500; }
.stage-marks .mark.set b { color: var(--text); font-weight: 600; }
.pick-crew { display: flex; flex-direction: column; gap: 6px; margin: 10px 0 4px; }
.pick-crew .btn { width: 100%; justify-content: flex-start; height: 32px; }

/*
 * Табло менеджеров над доской воронки: у кого сколько взято, продано и за
 * сколько отвечали. Висит на общем экране намеренно — показатель, который
 * видит только руководитель, соревнования не делает.
 */
.score-strip { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 10px; }
.score {
  display: flex; align-items: baseline; gap: 12px; text-decoration: none; color: var(--text-soft);
  background: var(--panel); border: 1px solid var(--line-soft); border-radius: 8px;
  padding: 6px 12px; font-size: 12px;
}
.score:hover { border-color: var(--accent); }
.score.on { border-color: var(--accent); background: var(--accent-soft); }
.score b { color: var(--text); font-size: 13px; }
.score i { font-style: normal; color: var(--text); font-weight: 600; }
/* Лидер по продажам — зелёной рамкой, без «победных» цветов в самой цифре */
.score.win { border-color: var(--ok); box-shadow: inset 0 0 0 1px var(--ok); }

/* Окно с вопросом: причина отказа и новое обращение. Своё, без библиотек */
.modal { display: none; position: fixed; inset: 0; background: rgba(20, 30, 44, .45); z-index: 50; }
.modal.open { display: flex; align-items: center; justify-content: center; }
.modal-box {
  background: var(--panel); border-radius: 8px; padding: 16px; width: 420px;
  box-shadow: 0 10px 40px rgba(20, 30, 44, .3);
}
.modal-box h2 { margin: 0 0 12px; font-size: 15px; }
.modal-foot { display: flex; gap: 8px; margin-top: 14px; }

/*
 * Окно диалогов: слева очередь, справа лента. Высота — во весь экран, потому
 * что переписку читают сверху вниз, а не прокруткой всей страницы.
 */
.dialogs {
  display: flex; gap: 8px; align-items: stretch;
  /* минус полоса каналов внизу: без этого её выдавливало за нижний край экрана */
  height: calc(100vh - 232px); min-height: 300px;
}
.dialog-list {
  width: 300px; flex: none; overflow-y: auto; background: var(--panel);
  border: 1px solid var(--line-soft); border-radius: var(--radius);
}
.dialog-row { display: block; padding: 8px 10px; border-bottom: 1px solid var(--line-soft); color: inherit; }
.dialog-row:hover { background: #f6f9ff; text-decoration: none; }
.dialog-row.on { background: var(--accent-soft); }
.dialog-top { display: flex; align-items: baseline; gap: 6px; }
.dialog-top b { font-weight: 600; font-size: 12px; }
.dialog-top .badge {
  margin-left: auto; background: var(--accent); color: #fff;
  border-radius: 9px; padding: 0 6px; font-size: 11px;
}
.dialog-sub { color: var(--text-dim); font-size: 11px; margin-top: 2px; }
.dialog-sub .wait { color: var(--warn); }
.dialog-last { color: var(--text-soft); font-size: 12px; margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.dialog-view {
  flex: 1; min-width: 0; display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--line-soft); border-radius: var(--radius);
}
.dialog-head { display: flex; align-items: baseline; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--line-soft); }
.dialog-head .dialog-actions { margin-left: auto; display: flex; gap: 6px; }
.feed { flex: 1; min-height: 0; overflow-y: auto; padding: 10px; background: #f7f9fc; }
.bubble { max-width: 68%; margin-bottom: 8px; padding: 7px 10px; border-radius: 10px; }
.bubble.in { background: #fff; border: 1px solid var(--line-soft); }
.bubble.out { background: var(--accent-soft); margin-left: auto; }
.bubble-text { white-space: pre-wrap; }
.bubble-foot { margin-top: 3px; color: var(--text-dim); font-size: 11px; }
.bubble-foot .err { color: var(--danger); }
.reply { display: flex; gap: 8px; padding: 8px; border-top: 1px solid var(--line-soft); align-items: flex-end; }
.reply textarea {
  flex: 1; resize: vertical; font: inherit; padding: 6px 8px;
  border: 1px solid var(--line); border-radius: var(--radius);
}

/*
 * Полоса каналов: кружок на канал рядом с поиском в диалогах и в списке
 * подключений. Цвет отвечает на один вопрос — можно ли этим ответить гостю
 * прямо сейчас. Жёлтого нет намеренно: «наполовину работает» менеджеру не
 * помогает, ошибка канала — это красный.
 */
.channel-strip {
  display: flex; align-items: center; gap: 4px 12px; flex-wrap: wrap;
  margin-top: 8px; padding: 7px 10px;
  background: var(--panel); border: 1px solid var(--line-soft); border-radius: var(--radius);
  font-size: 11px;
}
/* Подписи строк одной ширины — тогда каналы и расшифровка идут одной колонкой. */
.channel-strip .cs-title { color: var(--text-soft); font-weight: 600; min-width: 108px; }
/*
 * Расшифровка меток — отдельной строкой под каналами и от того же левого края.
 * Прижатая вправо, она читалась как продолжение последнего канала: «Сайт нет
 * live работает» — набор слов. У строки своя подпись, как у легенды шахматки.
 */
.channel-strip .cs-key {
  flex-basis: 100%; display: flex; align-items: center; gap: 4px 8px; flex-wrap: wrap;
  color: var(--text-dim);
}
.channel-strip .cs-key .pill { margin-left: 6px; }
.channel-strip .cs-key .pill:first-child { margin-left: 0; }
.channel-strip .ch {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--text-soft); white-space: nowrap;
}
a.ch:hover { color: var(--text); text-decoration: none; }
/* Маркер канала — метка словом, как на портале: «live» видно боковым зрением,
   а цветную точку приходится расшифровывать наведением. */
.pill {
  display: inline-block; flex: none;
  padding: 1px 7px; border-radius: 9px;
  font-size: 10px; font-weight: 600; line-height: 15px; letter-spacing: .2px;
  color: #fff; background: var(--danger);
}
.pill.live { background: #2e9e5b; }
.pill.err  { background: var(--warn); }
.pill.off  { background: var(--danger); }
.pill.soon { background: #c2ccd8; color: #5b6878; }

/* ── Права роли: массовые кнопки, счётчик и прибитая к низу кнопка сохранения.
   Прав под сотню и разделов девять — без этого настройка роли превращается в
   минуты кликов, а кнопка «Сохранить» уезжает за нижний край экрана, и человеку
   кажется, что каждый раздел надо сохранять отдельно. */
.perm-bar { border: 1px solid var(--line-soft); border-radius: 6px; margin-bottom: 14px; }
.perm-bar .perm-count { color: var(--text-soft); font-size: 12px; margin-right: 4px; }
.perm-bar .perm-count b { color: var(--text); font-size: 13px; }
.perm-bar .hint { margin-left: auto; }
/* Тот же приём нужен везде, где форма длиннее экрана: кнопка сохранения должна
   быть видна с любого места, иначе правку считают применённой, не нажав её. */
.perm-save, .save-bar {
  position: sticky; bottom: 0; z-index: 3;
  border-top: 1px solid var(--line-soft); border-bottom: 0;
  background: #fbfcfe;
  box-shadow: 0 -4px 10px rgba(28, 37, 48, .06);
}
.perm-save { justify-content: flex-end; }
.link-btn {
  border: 0; background: none; padding: 0 4px; cursor: pointer;
  color: var(--accent); font-size: 11px; font-weight: 500;
}
.link-btn:hover { text-decoration: underline; }
fieldset > legend .link-btn { margin-left: 2px; }

/* ── Карта парка (блок 20). Высота фиксированная: карта должна помещаться на
   экране вместе с началом таблицы — иначе «где машины» и «что за машина»
   приходится смотреть по очереди, прокруткой. */
.gps-map { height: clamp(420px, 62vh, 760px); border-radius: 6px; overflow: hidden; }
.gps-map.off {
  display: flex; align-items: center; justify-content: center;
  height: auto; min-height: 90px; padding: 24px;
  color: var(--text-soft); font-size: 13px; text-align: center;
  background: #f4f6f9;
}
.gps-map .leaflet-popup-content { font-size: 12px; line-height: 1.45; }

/* Скорость подписана прямо над едущей машиной: на карте важно увидеть движение
   одним взглядом, а не щёлкать по каждой точке. */
.gps-speed.leaflet-tooltip {
  padding: 1px 5px; border: 0; border-radius: 4px;
  background: #2e9e5b; color: #fff; font-size: 11px; font-weight: 600;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
}
.gps-speed.leaflet-tooltip-top::before { border-top-color: #2e9e5b; }

/* Госномер подписан под точкой — узнать машину, не тыкая в неё. У едущих
   подпись зелёная, чтобы движение читалось с одного взгляда. */
.gps-plate.leaflet-tooltip {
  padding: 0 4px; border: 0; border-radius: 3px; background: rgba(255, 255, 255, .85);
  color: #1f2a37; font-size: 11px; font-weight: 600; white-space: nowrap;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .2);
}
.gps-plate.moving.leaflet-tooltip { background: #2e9e5b; color: #fff; }
.gps-plate.leaflet-tooltip::before { display: none; }

/* Переключатель вида: по умолчанию карта показывает Калининградскую область,
   иначе одна уехавшая в Литву машина растягивает её на пол-Европы и весь парк
   собирается в один кружок. */
.gps-view {
  display: flex; overflow: hidden;
  border: 1px solid rgba(0, 0, 0, .2); border-radius: 4px;
  background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
}
.gps-view button {
  padding: 4px 9px; border: 0; border-left: 1px solid var(--line);
  background: #fff; color: var(--text-soft); font: inherit; font-size: 12px; cursor: pointer;
}
.gps-view button:first-child { border-left: 0; }
.gps-view button.on { background: var(--accent, #2f6fd0); color: #fff; }

/* Подпись под путём машины: чей путь показан и кнопка его убрать. */
.gps-note {
  padding: 4px 8px; border-radius: 4px;
  background: rgba(255, 255, 255, .92); color: #1f2a37; font-size: 12px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
}
.gps-note button {
  margin-left: 6px; padding: 2px 6px; border: 1px solid var(--line); border-radius: 3px;
  background: #fff; font: inherit; font-size: 11px; cursor: pointer;
}

/* 📍 в списке машин — навести карту на машину и показать её путь. */
.gps-locate {
  padding: 0 2px; border: 0; background: none; font-size: 13px; line-height: 1; cursor: pointer;
}
.gps-locate:hover { filter: brightness(1.2); }

.gps-legend { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; padding: 8px 2px 0; }
.gps-legend.legend-off > span { display: none; }
.gps-dot {
  display: inline-block; width: 10px; height: 10px; margin-right: 4px;
  border: 2px solid #fff; border-radius: 50%; box-shadow: 0 0 0 1px rgba(0, 0, 0, .15);
  vertical-align: -1px;
}
.gps-dot.moving { background: #2e9e5b; }
.gps-dot.idle   { background: #2f6fd0; }
.gps-dot.silent { background: #8a97a6; }

/* ── Поля с подсказками (public/suggest.js). Список рисуем поверх формы: если бы
   он раздвигал поля, форма прыгала бы при каждой букве. */
.suggest { position: relative; display: inline-flex; align-items: flex-start; gap: 6px; }
.suggest-list {
  position: absolute; top: 100%; left: 0; z-index: 40; min-width: 260px; max-width: 420px;
  max-height: 260px; overflow-y: auto; margin-top: 2px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 8px 20px rgba(28, 37, 48, .14);
}
.suggest-item { padding: 5px 9px; cursor: pointer; line-height: 1.35; }
.suggest-item + .suggest-item { border-top: 1px solid var(--line-soft); }
.suggest-item b { display: block; font-weight: 500; }
.suggest-item span { display: block; color: var(--text-dim); font-size: 11px; }
.suggest-item.on, .suggest-item:hover { background: var(--accent-soft); }
.suggest-empty { padding: 6px 9px; color: var(--text-dim); font-size: 12px; }
.suggest-add { height: 26px; white-space: nowrap; }
.suggest-new {
  position: absolute; top: 100%; left: 0; z-index: 41; width: 280px; margin-top: 2px;
  padding: 10px; display: flex; flex-direction: column; gap: 6px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 8px 20px rgba(28, 37, 48, .14);
}
/* Класс сильнее браузерного правила для [hidden] — без этой строки кнопка
   «Отмена» ничего не закрывает: атрибут ставится, а display: flex остаётся. */
.suggest-new[hidden] { display: none; }
.suggest-new-title { font-weight: 500; }
.suggest-new input { width: 100%; }
.suggest-new-foot { display: flex; justify-content: flex-end; gap: 6px; }
.suggest-new-err { color: var(--danger); font-size: 11px; min-height: 13px; }

/* ─────────────────────────────────────────────── помощь (обучалка)

   Кнопка «?» стоит в шапке рядом с профилем и ведёт в урок про открытый экран
   (src/web/layout.js). Круглая и без подписи: место в шапке дороже слова
   «Помощь», а знак вопроса в правом верхнем углу понимают все. */
.top .help-btn {
  flex: 0 0 auto;
  width: 26px; height: 26px; padding: 0;
  justify-content: center;
  border-radius: 50%;
  font-weight: 600;
}

.help-h { margin: 18px 0 8px; font-size: 14px; font-weight: 600; }

/* Карточки уроков: по три в ряд на большом экране, в один столбец на телефоне —
   помощь открывают и с телефона, стоя у машины. */
.help-list {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.help-card {
  display: block;
  padding: 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--text);
}
.help-card:hover { border-color: #b9c4d2; background: #f7f9fc; text-decoration: none; }
.help-card-title { font-weight: 600; margin-bottom: 4px; }
.help-card-about { color: var(--text-soft); font-size: 12px; }
.help-card-time { margin-top: 8px; color: var(--text-soft); font-size: 11px; }

/* Текст урока. Ширина ограничена: длинная строка через весь монитор читается
   плохо, а урок должны дочитывать до конца. */
.help-body { max-width: 760px; line-height: 1.55; }
.help-body h2 { margin: 18px 0 6px; font-size: 15px; font-weight: 600; }
.help-body h3 { margin: 14px 0 4px; font-size: 13px; font-weight: 600; }
.help-body h2:first-child, .help-body h3:first-child { margin-top: 0; }
.help-body p { margin: 8px 0; }
.help-body ul, .help-body ol { margin: 8px 0; padding-left: 22px; }
.help-body li { margin: 4px 0; }
.help-body code {
  padding: 1px 5px;
  background: var(--bg);
  border: 1px solid var(--line-soft);
  border-radius: 4px;
  font-size: 12px;
}
.help-body img { max-width: 100%; border: 1px solid var(--line); border-radius: var(--radius); }
/* Врезка «>» — то, на чём обжигаются: залог в кассе, осмотр задним числом. */
.help-note {
  margin: 12px 0;
  padding: 10px 12px;
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.help-next { margin-top: 12px; }

/* ─────────────────────────────────────── город на экране дозагрузки */
/*
 * Блок соседей живёт над очередью предложений. Текст в нём — с полями, а
 * таблицы во всю ширину панели, как на остальных экранах: разрывы цен читают
 * колонками, и лишние отступы по бокам только сужают их.
 */
.panel.city-board > h2, .panel.city-board > h3,
.panel.city-board > .hint, .panel.city-board > .msg { margin: 10px 12px; }
.panel.city-board > h2 { font-size: 14px; }
.panel.city-board > h3 { font-size: 13px; margin-top: 14px; }
.panel.city-board > :first-child { margin-top: 10px; }
.panel.city-board > :last-child { margin-bottom: 10px; }
.panel.city-board b.warn { color: var(--warn); }
.panel.city-board b.ok { color: var(--ok); }

/* ─────────────────────────────────────── план месяца на экране дозагрузки */
/*
 * Верхний блок экрана: цель, прогноз и связка шагов. Устроен так же, как блок
 * города, — поля у текста, таблица во всю ширину. Первая строка (сколько
 * заработали и сколько выходит к концу месяца) набрана крупнее остальных: это
 * та цифра, ради которой экран открывают, и искать её глазами не должны.
 */
.panel.month-plan > h2, .panel.month-plan > h3, .panel.month-plan > p,
.panel.month-plan > .hint, .panel.month-plan > .msg { margin: 10px 12px; }
.panel.month-plan > h2 { font-size: 14px; }
.panel.month-plan > :first-child { margin-top: 10px; }
.panel.month-plan > :last-child { margin-bottom: 10px; }
.panel.month-plan > p:first-of-type { font-size: 15px; }
.panel.month-plan b.warn { color: var(--warn); }
.panel.month-plan b.ok { color: var(--ok); }
.panel.month-plan .toolbar { border-bottom: 0; background: transparent; }
/* Поле цели и кнопка — одной строкой: форма в inline-block разъезжается. */
.panel.month-plan .toolbar form { display: inline-flex; gap: 8px; align-items: center; margin: 0; }
