/* Рабочий инструмент: плотно, спокойно, читаемо.
   Моноширинный шрифт — для номеров и сумм, обычный для остального.

   Тема: по умолчанию следует за системной, но выбор человека сильнее. Он приезжает
   атрибутом `data-theme` на <html> — его ставит сервер по куке, поэтому страница
   сразу рисуется нужной и не мигает белым. Порядок правил важен:
   светлая на :root, тёмная по системной настройке (кроме случая, когда человек
   выбрал светлую), и тёмная по явному выбору — последней, чтобы перебивать систему. */

:root {
  color-scheme: light dark;

  --bg: #f4f6f8;
  --surface: #ffffff;
  --surface-2: #f8fafc;
  --line: #e2e8f0;
  --line-strong: #cbd5e1;

  --ink: #0f172a;
  --ink-2: #475569;
  --ink-3: #94a3b8;

  --accent: #2563eb;
  --accent-ink: #ffffff;
  --accent-soft: #eff6ff;
  --accent-line: #bfdbfe;

  --ok: #15803d;
  --ok-soft: #f0fdf4;
  --ok-line: #bbf7d0;

  --warn: #b45309;
  --warn-soft: #fffbeb;
  --warn-line: #fde68a;

  --err: #b91c1c;
  --err-soft: #fef2f2;
  --err-line: #fecaca;

  --radius: 10px;
  --radius-sm: 7px;
  --shadow: 0 1px 2px rgb(15 23 42 / .05), 0 1px 3px rgb(15 23 42 / .04);
  --shadow-lg: 0 4px 6px -1px rgb(15 23 42 / .07), 0 10px 20px -5px rgb(15 23 42 / .08);

  --mono: "DejaVu Sans Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0b1120;
    --surface: #131c2e;
    --surface-2: #1a2436;
    --line: #263349;
    --line-strong: #35435c;

    --ink: #e8edf5;
    --ink-2: #a4b1c4;
    --ink-3: #6b7c94;

    --accent: #60a5fa;
    --accent-ink: #0b1120;
    --accent-soft: #172554;
    --accent-line: #1e3a8a;

    --ok: #4ade80;
    --ok-soft: #10281a;
    --ok-line: #166534;

    --warn: #fbbf24;
    --warn-soft: #2a1f08;
    --warn-line: #78350f;

    --err: #f87171;
    --err-soft: #2b1212;
    --err-line: #7f1d1d;

    --shadow: 0 1px 2px rgb(0 0 0 / .35);
    --shadow-lg: 0 10px 25px -5px rgb(0 0 0 / .5);
  }
}

/* Явно выбранная тёмная тема — сильнее системной настройки. */
:root[data-theme="dark"] {
  --bg: #0b1120;
  --surface: #131c2e;
  --surface-2: #1a2436;
  --line: #263349;
  --line-strong: #35435c;

  --ink: #e8edf5;
  --ink-2: #a4b1c4;
  --ink-3: #6b7c94;

  --accent: #60a5fa;
  --accent-ink: #0b1120;
  --accent-soft: #172554;
  --accent-line: #1e3a8a;

  --ok: #4ade80;
  --ok-soft: #10281a;
  --ok-line: #166534;

  --warn: #fbbf24;
  --warn-soft: #2a1f08;
  --warn-line: #78350f;

  --err: #f87171;
  --err-soft: #2b1212;
  --err-line: #7f1d1d;

  --shadow: 0 1px 2px rgb(0 0 0 / .35);
  --shadow-lg: 0 10px 25px -5px rgb(0 0 0 / .5);
}


* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--ink);
  font: 14.5px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
}

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

::selection { background: var(--accent); color: var(--accent-ink); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* --- шапка ------------------------------------------------------------------------ */
.top {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .55rem 1.1rem;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(10px);
  border-bottom: 1px solid var(--line);
}

.brand {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-weight: 640;
  color: var(--ink);
  letter-spacing: -.01em;
  white-space: nowrap;
}
.brand:hover { text-decoration: none; }
.brand .mark {
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  border-radius: 7px;
  background: var(--accent);
  color: var(--accent-ink);
  font: 600 13px/1 var(--sans);
}

.top nav { display: flex; gap: .15rem; flex-wrap: wrap; }
.top nav a {
  display: inline-flex;
  align-items: center;
  gap: .38rem;
  padding: .34rem .68rem;
  border-radius: var(--radius-sm);
  color: var(--ink-2);
  font-weight: 500;
}
.top nav a:hover { background: var(--surface-2); color: var(--ink); text-decoration: none; }
.top nav a.on { background: var(--accent-soft); color: var(--accent); }

.top .spacer { margin-left: auto; }

.whoami {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding-left: .8rem;
  border-left: 1px solid var(--line);
}
.whoami .who { line-height: 1.25; text-align: right; }
.whoami .who b { display: block; font-weight: 560; font-size: 13px; }
.whoami .who span { color: var(--ink-3); font-size: 11.5px; }
.avatar {
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  font: 600 12px/1 var(--sans);
  color: var(--ink-2);
  /* Аватар стал ссылкой на свою учётку — подчёркивание и синева тут ни к чему. */
  text-decoration: none;
}

a.avatar:hover { border-color: var(--accent, var(--ink-2)); color: var(--ink); }

/* Картинка вместо буквы. `cover` обязателен: аватарка приходит квадратной, но
   кружок всё равно должен обрезать её, а не сплющить. */
.avatar img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }

/* --- Свой профиль --- */

.me-head { display: flex; gap: 1.2rem; align-items: center; flex-wrap: wrap; }
.me-avatar { display: grid; justify-items: center; gap: .5rem; }
.me-who { flex: 1 1 16rem; }
.me-who h2 { margin: 0 0 .2rem; }

.avatar-big {
  display: grid;
  place-items: center;
  width: 96px; height: 96px;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  font: 600 34px/1 var(--sans);
  color: var(--ink-2);
  overflow: hidden;
}
.avatar-big img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Настоящее поле файла спрятано, нажимают на подпись к нему — иначе кнопка
   выбора выглядит по-своему в каждом браузере. */
.me-avatar label.btn { cursor: pointer; }

/* --- Окно обрезки аватарки --- */

.crop {
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: var(--surface);
  color: var(--ink);
  padding: 1.1rem;
  max-width: min(92vw, 24rem);
}
.crop::backdrop { background: rgba(0, 0, 0, .55); }
.crop h2 { margin: 0 0 .2rem; font-size: 1.05rem; }
.crop .stage { margin: 0 0 .8rem; }

/* Кружок — это маска поверх квадратной канвы, а не форма самой канвы: рисовать
   удобнее в квадрате, а показывать надо то, что в итоге останется. */
.crop-view {
  position: relative;
  width: 320px; max-width: 100%;
  aspect-ratio: 1;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 12px;
  background: var(--surface-2);
  touch-action: none; /* иначе браузер уводит палец в прокрутку страницы */
}
.crop-view canvas { width: 100%; height: 100%; display: block; cursor: grab; }
.crop-view canvas:active { cursor: grabbing; }
.crop-view::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 999px rgba(0, 0, 0, .5);
  pointer-events: none;
}

.crop-zoom { display: flex; align-items: center; gap: .6rem; margin: .8rem 0 .2rem; }
.crop-zoom input[type=range] { flex: 1; }
.crop-zoom span { color: var(--ink-2); font-size: 1.1rem; }

.crop-buttons { display: flex; align-items: center; gap: .5rem; margin-top: .8rem; }
.crop-buttons .spacer { flex: 1; }
.crop-buttons form { margin: 0; }
.crop .note { font-size: 12px; margin: .5rem 0 0; }
.crop .note:empty { display: none; }

main { max-width: 1200px; margin: 0 auto; padding: 1.4rem 1.1rem 3rem; }

.foot {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 1.1rem 2.5rem;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  color: var(--ink-3);
  font-size: 12px;
}

/* --- стрелка «назад» --------------------------------------------------------------- */
.back {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  margin-bottom: .7rem;
  padding: .25rem .6rem .25rem .35rem;
  margin-left: -.35rem;          /* стрелка встаёт по левому краю заголовка */
  border-radius: var(--radius-sm);
  color: var(--ink-2);
  font-size: 13px;
  text-decoration: none;
}

.back:hover { background: var(--surface-2); color: var(--ink); text-decoration: none; }

.back .arrow {
  font-size: 15px;
  line-height: 1;
  transition: transform .12s ease;
}

.back:hover .arrow { transform: translateX(-2px); }

/* --- типографика ------------------------------------------------------------------ */
h1 { font-size: 22px; font-weight: 620; letter-spacing: -.02em; margin: 0 0 .25rem; }
h2 { font-size: 15px; font-weight: 600; margin: 1.6rem 0 .6rem; letter-spacing: -.01em; }
.sub { color: var(--ink-2); margin: 0 0 1.2rem; }
.stage { color: var(--ink-3); font-size: 12.5px; }

/* --- карточки и плитки ------------------------------------------------------------ */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem;
  margin-bottom: 1rem;
  box-shadow: var(--shadow);
}

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: .7rem;
  margin: 1rem 0 1.4rem;
}
.tile {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .8rem .9rem;
  box-shadow: var(--shadow);
}
.tile b {
  display: block;
  font: 620 21px/1.2 var(--mono);
  letter-spacing: -.02em;
  margin-bottom: .15rem;
}
.tile span { color: var(--ink-3); font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em; }

/* --- таблицы ---------------------------------------------------------------------- */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}
table { width: 100%; border-collapse: collapse; }
th, td { padding: .55rem .75rem; text-align: left; vertical-align: middle; }
thead th {
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .045em;
  color: var(--ink-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
tbody tr { border-top: 1px solid var(--line); }
tbody tr:first-child { border-top: none; }
tbody tr:hover { background: var(--surface-2); }
tfoot td, tfoot th { border-top: 1px solid var(--line); background: var(--surface-2); }
td.num, th.num { text-align: right; font-family: var(--mono); white-space: nowrap; font-variant-numeric: tabular-nums; }
th[data-sort] { cursor: pointer; user-select: none; }
th[data-sort]:hover { color: var(--ink); }

.plate {
  font: 600 14px/1 var(--mono);
  letter-spacing: .05em;
  white-space: nowrap;
}
.plate.big { font-size: 27px; letter-spacing: .06em; }

/* --- значки ------------------------------------------------------------------------ */
.tag {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: 11.5px;
  font-weight: 550;
  padding: .12rem .45rem;
  border-radius: 5px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.tag.draft { background: var(--warn-soft); color: var(--warn); border-color: var(--warn-line); }
.tag.confirmed { background: var(--ok-soft); color: var(--ok); border-color: var(--ok-line); }
.tag.err { background: var(--err-soft); color: var(--err); border-color: var(--err-line); }
.tag.info { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.tag.muted { background: var(--surface-2); color: var(--ink-3); border-color: var(--line); }

/* --- формы -------------------------------------------------------------------------- */
label { display: block; font-size: 12px; font-weight: 550; color: var(--ink-2); margin-bottom: .25rem; }
input, select, textarea {
  width: 100%;
  padding: .45rem .6rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  font: inherit;
  background: var(--surface);
  color: var(--ink);
  transition: border-color .12s, box-shadow .12s;
}
input:hover, select:hover { border-color: var(--ink-3); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
input.mono, td input.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
input::placeholder { color: var(--ink-3); }

.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: .8rem; }
.field.bad input { border-color: var(--err); background: var(--err-soft); }
.field .note { font-size: 11.5px; margin-top: .25rem; line-height: 1.4; }
.note.error { color: var(--err); }
.note.warning { color: var(--warn); }
.note.info { color: var(--ink-3); }
/* Снятое замечание не исчезает: оно объясняет, почему счёт когда-то пометили.
   Но и кричать ему больше незачем — приглушаем и перечёркиваем. */
.note.resolved { color: var(--ink-3); text-decoration: line-through; }

button, .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .35rem;
  padding: .45rem .9rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: 500 14px/1.4 var(--sans);
  cursor: pointer;
  transition: background .12s, border-color .12s, transform .06s;
}
button:hover, .btn:hover { background: var(--surface-2); border-color: var(--ink-3); text-decoration: none; }
button:active, .btn:active { transform: translateY(.5px); }
button.primary, .btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 550;
}
button.primary:hover, .btn.primary:hover { background: color-mix(in srgb, var(--accent) 86%, black); }
button.danger { color: var(--err); border-color: var(--err-line); }
button.danger:hover { background: var(--err-soft); border-color: var(--err); }
button.small, .btn.small { padding: .28rem .6rem; font-size: 12.5px; }
button:disabled { opacity: .55; cursor: not-allowed; }

.actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-top: 1.1rem; }
.toolbar { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-bottom: .9rem; }
.toolbar input[type=search] { max-width: 20rem; }
.inline-form { display: flex; gap: .35rem; align-items: center; }
.inline-form input, .inline-form select { min-width: 0; }

/* --- баннеры ------------------------------------------------------------------------ */
.banner {
  padding: .7rem .9rem;
  border-radius: var(--radius);
  margin-bottom: 1rem;
  border: 1px solid;
  font-size: 13.5px;
}
.banner b { display: block; margin-bottom: .15rem; }
.banner.error { background: var(--err-soft); border-color: var(--err-line); color: var(--err); }
.banner.warning { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }
.banner.ok { background: var(--ok-soft); border-color: var(--ok-line); color: var(--ok); }
.banner.info { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); }
.banner ul { margin: .35rem 0 0; padding-left: 1.15rem; }
.banner li { margin-top: .15rem; }

/* --- загрузка ------------------------------------------------------------------------ */
/* Сама зона `.drop` описана ниже, в разделе «зона загрузки и пустые состояния»:
   раньше она задавалась дважды — здесь рамка с фоном, а там отступы и флекс, —
   и правка в одном месте молча пропадала под вторым. */

.queue { list-style: none; margin: 1rem 0 0; padding: 0; }
.queue li {
  display: flex;
  align-items: baseline;
  gap: .7rem;
  padding: .55rem .8rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  margin-bottom: .4rem;
  flex-wrap: wrap;
  box-shadow: var(--shadow);
}
.queue .name { font-weight: 550; flex: 1 1 12rem; word-break: break-all; }
.queue li.running { border-left-color: var(--accent); }
.queue li.done { border-left-color: var(--ok); }
.queue li.error { border-left-color: var(--err); }
.queue li.duplicate { border-left-color: var(--warn); }

/* --- проверка счёта ------------------------------------------------------------------ */
.review { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: 1.1rem; align-items: start; }
.preview { position: sticky; top: 4rem; }
.preview img, .preview embed {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.raw {
  font-family: var(--mono);
  font-size: 12px;
  white-space: pre-wrap;
  max-height: 22rem;
  overflow: auto;
  line-height: 1.45;
}
details summary { cursor: pointer; color: var(--accent); font-size: 13px; }
details[open] summary { margin-bottom: .5rem; }

/* Пустое состояние. Их два вида, и путать их нельзя.
 *
 * Внутри карточки («Дублей нет», «Копий пока нет») это короткая реплика в ряду
 * других разделов — ей хватает серой строки, рамка вокруг каждой превратила бы
 * обслуживание в лоскутное одеяло.
 *
 * А пустая страница — это единственное, что человек видит, и ровно тот момент,
 * когда подсказка нужнее всего: почему пусто и что делать дальше. Поэтому у неё
 * своя рамка, воздух и ограниченная ширина — длинная строка через весь экран
 * читается хуже. */
.empty { color: var(--ink-3); padding: 2.5rem 1rem; text-align: center; line-height: 1.6; }
.card .empty { padding: 1.2rem .8rem; }

main > .empty {
  max-width: 34rem;
  margin: 1.5rem auto;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
}

/* Выход из пустоты — действие, а не просто ссылка в тексте. */
main > .empty .way-out {
  display: inline-block;
  margin-top: .8rem;
  padding: .4rem .9rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--accent);
}
main > .empty .way-out:hover { border-color: var(--accent); text-decoration: none; }

/* --- вход ---------------------------------------------------------------------------- */
.login-page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 1.5rem;
}
.login-card {
  width: 100%;
  max-width: 24rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 1.8rem;
  box-shadow: var(--shadow-lg);
}
.login-card .brand { justify-content: center; margin-bottom: .3rem; font-size: 17px; }
.login-card .org { text-align: center; color: var(--ink-3); font-size: 12.5px; margin-bottom: 1.5rem; }
.login-card .field { margin-bottom: .9rem; }
.login-card button { width: 100%; margin-top: .4rem; }

/* --- доступ -------------------------------------------------------------------------- */
.user-row td { vertical-align: middle; }
.session-list { list-style: none; margin: .3rem 0 0; padding: 0; font-size: 12px; color: var(--ink-3); }
.session-list li { display: flex; gap: .5rem; align-items: center; padding: .12rem 0; }
.role-pill { font-size: 11.5px; }

/* Правка машины спрятана в раскрывающийся блок: нужна редко, а места занимает много. */
.edit-vehicle summary { cursor: pointer; font-weight: 560; font-size: 14px; }
.edit-vehicle summary::marker { color: var(--ink-3); }
.edit-vehicle .sub { margin-top: .6rem; }

/* --- карточка учётной записи ------------------------------------------------------ */
/* Раньше это была таблица на девять колонок: выпадающие списки обрезались, а список
   сессий растягивал строку на пол-экрана. Карточка читается и на телефоне. */
.user-card { padding: 1rem 1.1rem; }

.user-head {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding-bottom: .8rem;
  border-bottom: 1px solid var(--line);
}

.user-name { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.user-name b { font-size: 15px; font-weight: 600; }
.user-state { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-left: auto; }
.user-head select { min-width: 11rem; }

/* Четыре блока настроек: на широком экране в ряд, на узком — друг под другом. */
.user-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 1rem 1.4rem;
  padding: .9rem 0;
}

.user-block { display: flex; flex-direction: column; gap: .35rem; align-items: flex-start; }

.user-block-title {
  font-size: 11px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.user-block .inline-form { flex-wrap: wrap; }
.user-block input[type="password"] { min-width: 9rem; }

.user-actions { border-top: 1px solid var(--line); padding-top: .8rem; margin-bottom: 0; }

/* Флажки разделов и компаний. Длинный список прокручивается внутри себя,
   чтобы карточка не растянулась. */
.ticks-form { display: flex; flex-direction: column; gap: .25rem; align-items: flex-start; }
.ticks { display: flex; flex-direction: column; gap: .15rem; }
.ticks.scrolling { max-height: 9rem; overflow-y: auto; padding-right: .5rem; }
.tick { display: flex; align-items: center; gap: .4rem; font-size: 12.5px; white-space: nowrap; }
.tick input { margin: 0; }
.ticks-form .stage { font-size: 11px; }

@media (max-width: 860px) {
  .review { grid-template-columns: 1fr; }
  .preview { position: static; }
  main { padding: 1rem .8rem 2rem; }
  .top { gap: .6rem; padding: .5rem .8rem; }
  h1 { font-size: 19px; }
}

/* --- панель фильтров --- */
.filters { padding: .85rem 1rem .95rem; }

/* Строка полей: поиск тянется, остальные держат свою ширину. Так на широком
   экране всё умещается в одну строку, а на узком спокойно переносится. */
.filters-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: .6rem .8rem;
}
.filters-row .field { flex: 1 1 12rem; min-width: 9rem; margin: 0; }
.filters-row .field.wide { flex: 2 1 16rem; }
.filters-row > button { flex: 0 0 auto; }

/* Вторая строка — период и переключатель замечаний. Отделяем чертой, чтобы
   было видно: это уже не про то, что ищем, а про то, за какой срок. */
.filters-row.period {
  align-items: center;
  gap: .5rem .7rem;
  margin-top: .8rem;
  padding-top: .8rem;
  border-top: 1px solid var(--line);
}
.filters-row.period .row-label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Готовые периоды одной группой — сразу видно, какой выбран. */
.quick {
  display: inline-flex;
  flex-wrap: wrap;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface);
}
.quick-btn {
  padding: .34rem .7rem;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  border-left: 1px solid var(--line);
  white-space: nowrap;
}
.quick-btn:first-child { border-left: 0; }
.quick-btn:hover { background: var(--surface-2); color: var(--ink); text-decoration: none; }
.quick-btn.on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.quick-btn.on:hover { background: var(--accent); color: var(--accent-ink); }

.dates { display: inline-flex; align-items: center; gap: .35rem; }
.dates input { padding: .3rem .45rem; font-size: 13px; }
.dates .dash { color: var(--ink-3); }

/* Переключатель-таблетка: включённый виден с одного взгляда, в отличие от
   обычной галочки, которую в ряду полей легко не заметить. */
.toggle {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .3rem .7rem .3rem .55rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
  user-select: none;
  transition: background .12s, border-color .12s, color .12s;
}
.toggle:hover { border-color: var(--ink-3); background: var(--surface-2); }
.toggle input { width: auto; margin: 0; accent-color: var(--warn); }
.toggle.on {
  background: var(--warn-soft);
  border-color: var(--warn-line);
  color: var(--warn);
  font-weight: 550;
}

/* --- что применено и выгрузки --- */
.filters-state {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem .8rem;
  margin: .8rem 0 1rem;
}
.chips { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  max-width: 22rem;
  padding: .22rem .3rem .22rem .6rem;
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--ink);
  font-size: 12.5px;
  line-height: 1.5;
}
.chip b { font-weight: 600; color: var(--ink-2); }
.chip-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  color: var(--ink-3);
  font-size: 15px;
  line-height: 1;
}
.chip-x:hover { background: var(--err-soft); color: var(--err); text-decoration: none; }
.chip-reset { font-size: 12.5px; color: var(--ink-2); margin-left: .2rem; }
.chip-reset:hover { color: var(--err); }
.filters-state .exports { display: flex; gap: .4rem; flex-wrap: wrap; margin-left: auto; }

.field.checkbox { display: flex; align-items: flex-end; }
.field.checkbox label {
  display: flex;
  align-items: center;
  gap: .45rem;
  font-size: 14px;
  font-weight: 450;
  color: var(--ink);
  margin: 0 0 .45rem;
  cursor: pointer;
}
.field.checkbox input { width: auto; margin: 0; }

/* Перечень найденных работ бывает длинным. Показываем пару строк, остальное по
   наведению — иначе одна машина растягивает таблицу на пол-экрана. */
td.found-names {
  max-width: 18rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.filter-note {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .6rem 1rem;
  flex-wrap: wrap;
}
/* Метка на цветной плашке: фон у неё свой, иначе сливается с плашкой. */
.filter-note .chip { background: var(--surface); }
.filter-note .found-note { font-size: 12.5px; color: var(--ink-2); }

/* --- переключатели темы и языка ---------------------------------------------------- */
.prefs {
  display: flex;
  align-items: center;
  gap: .4rem;
}

.theme-switch {
  display: inline-flex;
  /* Не сжиматься: соседи по шапке отбирали ширину, а `overflow: hidden` молча
     срезал крайнюю кнопку — она оставалась видимой, но нажать её было нельзя. */
  flex: none;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface);
}

.theme-switch button {
  flex: none;
  border: 0;
  border-radius: 0;
  padding: .28rem .5rem;
  min-width: 1.9rem;
  font-size: 15px;
  line-height: 1.1;
  color: var(--ink-3);
  background: transparent;
  box-shadow: none;
}

.theme-switch button:hover { background: var(--surface-2); color: var(--ink-2); }
.theme-switch button.on { background: var(--accent-soft); color: var(--accent); }

select.lang {
  padding: .28rem 1.4rem .28rem .5rem;
  font-size: 12.5px;
  color: var(--ink-2);
}

/* Подпись для читалок с экрана: видеть её незачем, слышать — нужно. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* На узком экране предпочтения уезжают под навигацию, а не ломают шапку. */
/* --- узкий экран: телефон ------------------------------------------------------- */
/* Счета фотографируют и загружают с телефона, поэтому шапка обязана быть рабочей
   и там. В одну строку она не помещается: восемь пунктов меню наезжали на название
   и выталкивали блок пользователя за край экрана. Раскладываем в два ряда —
   сверху название и кнопки, снизу меню одной прокручиваемой полосой. */
@media (max-width: 720px) {
  .top {
    flex-wrap: wrap;
    gap: .5rem .7rem;
    padding: .5rem .8rem;
  }

  .top .brand { order: 1; }
  .top .spacer { display: none; }
  .prefs { order: 2; margin-left: auto; }
  .whoami { order: 3; }

  /* Меню — во второй ряд, во всю ширину. Не помещается — прокручивается вбок,
     а не переносится столбиком: столбик занимал пол-экрана. */
  .top nav {
    order: 4;
    width: 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    gap: .1rem;
    padding-bottom: .15rem;
    scrollbar-width: none;
  }

  .top nav::-webkit-scrollbar { display: none; }
  .top nav a { white-space: nowrap; }

  /* Имя и должность съедают ширину, а нужны меньше кнопки выхода. */
  .whoami .who { display: none; }

  /* Поля фильтра в один столбец: два в ряд на 375 точках нечитаемы. */
  .filters-row .field, .filters-row .field.wide { flex: 1 1 100%; }
  .filters-row > button { width: 100%; }

  /* Период: подпись строкой сверху, кнопки во всю ширину поровну — по ним
     попадают пальцем, а не курсором. */
  .filters-row.period { align-items: stretch; }
  .filters-row.period .row-label { width: 100%; }
  /* Четыре кнопки в ряд на 375 точках не читаются, а перенос флексом даёт
     кривое «3 + 1». Раскладываем сеткой 2x2: разделители рисует фон сквозь зазор. */
  .quick {
    width: 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1px;
    background: var(--line);
  }
  .quick-btn {
    text-align: center;
    padding: .5rem .3rem;
    border-left: 0;
    background: var(--surface);
  }
  .quick-btn.on { background: var(--accent); }
  .dates { width: 100%; }
  .dates input { flex: 1 1 0; min-width: 0; }
  .toggle { width: 100%; justify-content: center; padding: .45rem .7rem; }

  /* Выгрузки — своей строкой под метками, а не прижатыми вправо в обрез. */
  .filters-state .exports { margin-left: 0; width: 100%; }
  .filters-state .exports .btn { flex: 1 1 0; }
  .chip { max-width: 100%; }

  /* Таблицы шире экрана — прокручиваются внутри своей рамки, страница вбок не едет. */
  .table-wrap { margin-inline: -.8rem; padding-inline: .8rem; }

  .tiles { grid-template-columns: repeat(2, 1fr); }
}

/* --- выборочное удаление машин ---------------------------------------------------- */
/* Колонка отметок узкая и не участвует в сортировке: щелчок по ней не должен
   перестраивать таблицу под рукой у того, кто отмечает. */
/* Колонка отметок по умолчанию скрыта и появляется только в режиме выбора.
   В итоговой строке для неё есть своя пустая ячейка — поэтому при скрытии
   таблица не разъезжается и объединение ячеек пересчитывать не нужно. */
th.pick, td.pick { display: none; width: 2.2rem; text-align: center; padding-inline: .4rem; }
table.picking th.pick, table.picking td.pick { display: table-cell; }
th.pick input, td.pick input { width: auto; margin: 0; cursor: pointer; }

/* Пока идёт выбор, кнопка выглядит нажатой — видно, в каком режиме таблица. */
#pick-mode.on { background: var(--err-soft); border-color: var(--err); color: var(--err); }

/* Панель появляется только когда что-то отмечено, и липнет к низу экрана:
   выбирать приходится в длинной таблице, а кнопка нужна под рукой. */
.bulk {
  position: sticky;
  bottom: .8rem;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
  margin: .8rem 0;
  padding: .6rem .9rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}
.bulk-count { font-size: 13.5px; color: var(--ink-2); }
.bulk-count b { font-size: 16px; color: var(--ink); }
.bulk-status { font-size: 12.5px; color: var(--ink-2); margin-left: auto; }

.confirm-dialog {
  max-width: 34rem;
  width: calc(100% - 2rem);
  padding: 1.2rem 1.3rem 1rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-lg);
}
.confirm-dialog::backdrop { background: rgb(15 23 42 / .45); }
.confirm-dialog h2 { margin: 0 0 .3rem; font-size: 17px; }
.confirm-dialog .sub { margin: 0 0 .8rem; }

/* Список того, что исчезнет. Прокручивается: отметить могут и три машины, и сорок,
   а диалог не должен вырастать за пределы экрана. */
.confirm-body {
  max-height: 15rem;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.confirm-line {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  padding: .35rem .6rem;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
}
.confirm-line:last-child { border-bottom: 0; }
.confirm-line b { font-family: var(--mono); }
.confirm-line .right { margin-left: auto; white-space: nowrap; color: var(--ink-2); }

/* Пробег визита — рядом с датой счёта. Приглушённый: это справка, а не событие,
   в отличие от жёлтой метки «проверьте». */
.tag.km {
  background: var(--surface-2);
  border-color: var(--line-strong);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* --- технический паспорт ----------------------------------------------------------- */
/* Графы бланка: подпись слева, значение справа. Колонок столько, сколько влезает —
   на телефоне одна, на широком экране три. */
.pass-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 0 1.4rem;
}
.pass-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .8rem;
  padding: .4rem 0;
  border-bottom: 1px solid var(--line);
  font-size: 13.5px;
}
.pass-row span { color: var(--ink-2); }
.pass-row b { text-align: right; font-variant-numeric: tabular-nums; }

/* --- тендеры ---------------------------------------------------------------------- */
/* Полоса слева задаёт цвет по оценке: список просматривают глазами сверху вниз,
   и решение принимают по ней, а не по названию. */
.tender { border-left: 4px solid var(--line-strong); margin-bottom: .9rem; }
.tender.good { border-left-color: var(--ok); }
.tender.mid { border-left-color: var(--warn); }
.tender.bad { border-left-color: var(--err); }

.tender-head { display: flex; align-items: flex-start; gap: 1rem; }
.tender-main { flex: 1; min-width: 0; }
.tender-main h2 { margin: 0 0 .2rem; font-size: 15.5px; line-height: 1.35; }
.tender-main p { margin: 0 0 .25rem; }
.tender-facts { font-size: 13px; }

/* Оценка — самое крупное на карточке: за ней и приходят. */
.score { text-align: center; min-width: 4.4rem; }
.score b { display: block; font-size: 26px; line-height: 1; font-variant-numeric: tabular-nums; }
.score b span { font-size: 14px; font-weight: 400; }
.score b.waiting { color: var(--ink-3); }
.score-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-3); }
.tender.good .score b { color: var(--ok); }
.tender.mid .score b { color: var(--warn); }
.tender.bad .score b { color: var(--err); }

.verdict { margin: .7rem 0; padding-left: .7rem; border-left: 2px solid var(--line); }
.risks { margin: .6rem 0 0; padding-left: 1.1rem; font-size: 12.5px; color: var(--ink-2); }
.risks li { margin-bottom: .2rem; }

/* Правый край карточки тендера: метка «под своего» и кнопка копирования. */
.tender-side { display: flex; flex-direction: column; align-items: flex-end; gap: .4rem; }
.tender-side .btn.done { background: var(--ok-soft); border-color: var(--ok-line); color: var(--ok); }

/* Прицеп на карточке тягача: номер крупно, рядом марка из техпаспорта. */
.trailer-card h2 {
  margin: 0 0 .5rem;
  font-size: 1rem;
}

.trailer-card p {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
  margin: 0;
}

.trailer-card .sub {
  margin: 0;
}

.row-links {
  margin-top: .8rem !important;
}


/* --- находки комплексной проверки --------------------------------------------- */

/* Слева цветная полоса по важности: список читают сверху вниз и глазами ищут
   красное, а не вчитываются в каждый заголовок. */
.finding {
  border-left: 3px solid var(--line-strong);
  padding: 8px 0 8px 12px;
  margin: 10px 0;
}

.finding.error { border-left-color: var(--err); }
.finding.warning { border-left-color: var(--warn); }
.finding.info { border-left-color: var(--line-strong); }

.finding.error .finding-title { color: var(--err); }
.finding.warning .finding-title { color: var(--warn); }

.finding-title { font-weight: 600; }

.finding-hint {
  font-size: 0.9em;
  opacity: 0.75;
  margin-top: 2px;
}

.finding-example {
  font-size: 0.88em;
  opacity: 0.9;
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}

#checkup-result { margin-top: 6px; }

/* Решение по тендеру: кнопки-статусы в правом углу карточки. Активная — как
   выбранный источник в фильтре, чтобы язык подсветки был один. */
.decide { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .35rem; }
.decide .btn.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }


/* --- тема «Звёздное небо» ------------------------------------------------------
 *
 * Третья тема наравне со светлой и тёмной: тот же набор переменных, поэтому все
 * страницы получают её бесплатно, ничего не переписывая.
 *
 * Небо нарисовано двумя закреплёнными слоями на псевдоэлементах `body` — ни
 * одного лишнего узла в разметке. Звёзды это `radial-gradient`, собранные в
 * плитку и размноженные `repeat`: браузер рисует плитку один раз и дальше только
 * копирует её. Мерцает лишь верхний слой, и мерцает **прозрачностью** — такую
 * анимацию видеокарта делает сама, без перерисовки страницы.
 *
 * Читаемость важнее вида: это таблицы, в которые смотрят весь день. Поэтому под
 * карточками стоит почти непрозрачная подложка, небо просвечивает только по
 * полям страницы, а цифры остаются на спокойном фоне.
 */

:root[data-theme="stars"] {
  color-scheme: dark;

  --bg: #05060f;
  --surface: #101632;
  --surface-2: #151d3d;
  --line: #253063;
  --line-strong: #384788;

  --ink: #eaeeff;
  --ink-2: #a9b4dd;
  --ink-3: #6f7aa8;

  --accent: #8fb6ff;
  --accent-ink: #060a1c;
  --accent-soft: #16204a;
  --accent-line: #2c3d7e;

  --ok: #6ee7b7;
  --ok-soft: #0c2a24;
  --ok-line: #14614b;

  --warn: #fcd34d;
  --warn-soft: #2a2109;
  --warn-line: #7c5910;

  --err: #fda4a4;
  --err-soft: #2c1220;
  --err-line: #7e2545;

  --shadow: 0 1px 2px rgb(0 0 0 / .5);
  --shadow-lg: 0 10px 30px -8px rgb(0 0 0 / .7);

  /* Свечение вокруг активных элементов — единственное украшение, которое тема
     добавляет сверх палитры. Держим переменной, чтобы правился в одном месте. */
  --glow: 0 0 12px rgb(143 182 255 / .35);
}

/* Дальнее небо: туманности и два неподвижных слоя звёзд.
   `fixed` и с запасом за края — при прокрутке слой не перерисовывается. */
:root[data-theme="stars"] body::before {
  content: "";
  position: fixed;
  inset: -8%;
  z-index: -3;
  pointer-events: none;
  background-color: var(--bg);
  background-image:
    /* Млечный Путь — рыхлая полоса наискось. Одна она делает для ощущения
       глубины больше, чем два десятка звёзд: небу нужна не только россыпь,
       но и то, вокруг чего она собрана. */
    linear-gradient(107deg,
      transparent 30%,
      rgb(140 160 255 / .07) 42%,
      rgb(190 175 255 / .11) 50%,
      rgb(140 160 255 / .07) 58%,
      transparent 70%),
    radial-gradient(58% 42% at 12% 8%, rgb(70 50 150 / .30) 0, transparent 70%),
    radial-gradient(52% 38% at 88% 14%, rgb(22 96 140 / .26) 0, transparent 72%),
    radial-gradient(64% 48% at 74% 92%, rgb(96 36 110 / .22) 0, transparent 74%),
    /* Две далёкие галактики: размытые эллипсы вполсилы. Глазу нужно за что-то
       зацепиться на дальнем плане, иначе он читает фон как плоскую заливку. */
    radial-gradient(7% 2.6% at 31% 26%, rgb(206 214 255 / .13) 0, transparent 100%),
    radial-gradient(5% 3.4% at 79% 62%, rgb(226 206 255 / .11) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 476px 468px, rgb(255 255 255 / .8) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 468px 120px, rgb(255 233 205 / .8) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 506px 396px, rgb(214 205 255 / .9) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 355px 28px, rgb(255 255 255 / .9) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 471px 96px, rgb(255 255 255 / .65) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 459px 8px, rgb(255 255 255 / .8) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 245px 450px, rgb(255 255 255 / .65) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 148px 187px, rgb(214 205 255 / .65) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 71px 231px, rgb(255 255 255 / .8) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 472px 55px, rgb(198 219 255 / .9) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 7px 305px, rgb(198 219 255 / .65) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 108px 405px, rgb(255 233 205 / .8) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 373px 436px, rgb(255 233 205 / .9) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 345px 412px, rgb(255 255 255 / .65) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 465px 77px, rgb(255 255 255 / .8) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 414px 488px, rgb(198 219 255 / .65) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 73px 372px, rgb(198 219 255 / .65) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 90px 31px, rgb(214 205 255 / .9) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 103px 47px, rgb(214 205 255 / .8) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 307px 340px, rgb(255 233 205 / .8) 0, transparent 100%),
    radial-gradient(1.6px 1.6px at 204px 362px, rgb(198 219 255 / .9) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 318px 332px, rgb(255 255 255 / .65) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 110px 274px, rgb(255 255 255 / .65) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 362px 163px, rgb(255 233 205 / .8) 0, transparent 100%),
    radial-gradient(1px 1px at 126px 99px, rgb(255 255 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 241px 181px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 249px 59px, rgb(198 219 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 224px 310px, rgb(214 205 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 210px 215px, rgb(255 255 255 / .7) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 23px 216px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 255px 90px, rgb(255 255 255 / .3) 0, transparent 100%),
    radial-gradient(1px 1px at 43px 62px, rgb(255 255 255 / .3) 0, transparent 100%),
    radial-gradient(1px 1px at 188px 124px, rgb(214 205 255 / .3) 0, transparent 100%),
    radial-gradient(1px 1px at 273px 177px, rgb(255 255 255 / .3) 0, transparent 100%),
    radial-gradient(1px 1px at 59px 103px, rgb(255 255 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 154px 21px, rgb(198 219 255 / .3) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 237px 154px, rgb(255 233 205 / .7) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 188px 294px, rgb(255 255 255 / .7) 0, transparent 100%),
    radial-gradient(1px 1px at 68px 168px, rgb(214 205 255 / .7) 0, transparent 100%),
    radial-gradient(1px 1px at 96px 25px, rgb(255 255 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 185px 315px, rgb(198 219 255 / .3) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 63px 291px, rgb(255 255 255 / .3) 0, transparent 100%),
    radial-gradient(1px 1px at 228px 265px, rgb(255 255 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 66px 13px, rgb(198 219 255 / .7) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 144px 52px, rgb(198 219 255 / .55) 0, transparent 100%),
    radial-gradient(1px 1px at 109px 193px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 71px 229px, rgb(198 219 255 / .3) 0, transparent 100%),
    radial-gradient(1px 1px at 229px 195px, rgb(255 255 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 182px 123px, rgb(255 233 205 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 178px 303px, rgb(198 219 255 / .55) 0, transparent 100%),
    radial-gradient(1px 1px at 103px 250px, rgb(198 219 255 / .3) 0, transparent 100%),
    radial-gradient(1px 1px at 106px 143px, rgb(255 233 205 / .55) 0, transparent 100%),
    radial-gradient(1px 1px at 237px 125px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1px 1px at 36px 244px, rgb(255 255 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 274px 68px, rgb(198 219 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 161px 24px, rgb(255 233 205 / .3) 0, transparent 100%),
    radial-gradient(1px 1px at 309px 28px, rgb(255 233 205 / .55) 0, transparent 100%),
    radial-gradient(1px 1px at 202px 167px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1px 1px at 173px 24px, rgb(255 255 255 / .7) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 280px 37px, rgb(255 255 255 / .3) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 133px 29px, rgb(198 219 255 / .7) 0, transparent 100%),
    radial-gradient(1px 1px at 91px 121px, rgb(255 233 205 / .4) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 25px 40px, rgb(255 233 205 / .3) 0, transparent 100%),
    radial-gradient(1px 1px at 64px 21px, rgb(198 219 255 / .4) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 133px 96px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1px 1px at 91px 254px, rgb(198 219 255 / .3) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 253px 278px, rgb(214 205 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 128px 64px, rgb(255 255 255 / .7) 0, transparent 100%),
    radial-gradient(1px 1px at 99px 292px, rgb(214 205 255 / .7) 0, transparent 100%),
    radial-gradient(1px 1px at 143px 303px, rgb(214 205 255 / .4) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 246px 313px, rgb(255 233 205 / .7) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 48px 83px, rgb(255 255 255 / .3) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 89px 115px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 237px 78px, rgb(255 255 255 / .3) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 79px 66px, rgb(255 255 255 / .4) 0, transparent 100%),
    radial-gradient(1px 1px at 295px 100px, rgb(255 255 255 / .55) 0, transparent 100%);
  background-size:
    auto, auto, auto, auto, auto, auto,
    520px 520px,
    320px 320px;
  background-repeat:
    no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, repeat, repeat;
}

/* Ближние звёзды — крупнее и мерцают. Отдельным слоем, чтобы анимация трогала
   только его: перекрашивать всё небо ради нескольких огоньков незачем. */
:root[data-theme="stars"] body::after {
  content: "";
  position: fixed;
  inset: -8%;
  z-index: -2;
  pointer-events: none;
  background-image: radial-gradient(2.4px 2.4px at 751px 191px, rgb(255 255 255 / .95) 0, transparent 100%),
    radial-gradient(2.4px 2.4px at 711px 38px, rgb(198 219 255 / .95) 0, transparent 100%),
    radial-gradient(2.4px 2.4px at 748px 382px, rgb(255 233 205 / .95) 0, transparent 100%),
    radial-gradient(2px 2px at 63px 3px, rgb(255 233 205 / .95) 0, transparent 100%),
    radial-gradient(2.4px 2.4px at 318px 57px, rgb(255 233 205 / .95) 0, transparent 100%),
    radial-gradient(2px 2px at 658px 74px, rgb(255 255 255 / .95) 0, transparent 100%),
    radial-gradient(2px 2px at 91px 102px, rgb(214 205 255 / .95) 0, transparent 100%),
    radial-gradient(2.4px 2.4px at 259px 127px, rgb(255 255 255 / .85) 0, transparent 100%),
    radial-gradient(2.4px 2.4px at 478px 167px, rgb(255 255 255 / .95) 0, transparent 100%),
    radial-gradient(2px 2px at 530px 2px, rgb(198 219 255 / .95) 0, transparent 100%),
    radial-gradient(2.4px 2.4px at 186px 749px, rgb(198 219 255 / .95) 0, transparent 100%),
    radial-gradient(2px 2px at 712px 606px, rgb(255 255 255 / .95) 0, transparent 100%);
  background-size: 760px 760px;
  background-repeat: repeat;
  animation: star-twinkle 7s ease-in-out infinite;
}

/* Сияние вдоль верхнего края. Держится выше содержимого и не доходит до таблиц:
   цвет и движение там, где есть воздух, а над цифрами — спокойный фон.

   Живёт на слое метеоров, а не на шапке. У шапки `backdrop-filter`, а он делает
   её точкой отсчёта для всего, что внутри с `position: fixed` — сияние тогда
   попадает в её слой и туманит содержимое сверху вместо того, чтобы лежать
   под ним. Проверено на живой странице. */
:root[data-theme="stars"] .meteors::before {
  content: "";
  position: absolute;
  top: -12vh;
  left: -10vw;
  right: -10vw;
  height: 58vh;
  pointer-events: none;
  background:
    radial-gradient(48% 100% at 20% 0%, rgb(56 130 220 / .30) 0, transparent 66%),
    radial-gradient(44% 92% at 58% 4%, rgb(24 170 156 / .22) 0, transparent 68%),
    radial-gradient(50% 96% at 86% 0%, rgb(140 70 220 / .26) 0, transparent 66%);
  filter: blur(30px);
  animation: aurora-sway 38s ease-in-out infinite alternate;
}

@keyframes aurora-sway {
  0% { transform: translate3d(-3%, 0, 0) scaleY(1); opacity: .85; }
  100% { transform: translate3d(3%, 0, 0) scaleY(1.16); opacity: 1; }
}

/* Глубина при прокрутке: дальний слой отстаёт от ближнего, и небо перестаёт быть
   плоской картинкой. Прокрутка ведёт анимацию напрямую (`scroll()`), поэтому
   обработчиков на прокрутку нет вовсе — всё считает браузер на своей стороне.
   Где такой временной шкалы нет, небо просто остаётся неподвижным. */
@supports (animation-timeline: scroll()) {
  /* Свойства расписаны по одному не для красоты. В краткой записи `animation`
     длительность обнуляется в ноль, а шкале прокрутки нужна `auto` — иначе
     анимация считается завершённой сразу и слой не двигается вовсе. И шкалу
     приходится называть явно (`root block`): по умолчанию она ищет ближайшего
     прокручиваемого предка, а у закреплённого слоя его нет. */
  :root[data-theme="stars"] body::before {
    animation-name: sky-far;
    animation-duration: auto;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: scroll(root block);
  }

  :root[data-theme="stars"] .meteors::after {
    animation-name: sky-mid;
    animation-duration: auto;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: scroll(root block);
  }

  :root[data-theme="stars"] body::after {
    animation-name: star-twinkle, sky-near;
    animation-duration: 7s, auto;
    animation-timing-function: ease-in-out, linear;
    animation-iteration-count: infinite, 1;
    animation-fill-mode: none, both;
    animation-timeline: auto, scroll(root block);
  }
}

@keyframes sky-far { to { transform: translate3d(0, -2.5%, 0); } }
@keyframes sky-mid { to { transform: translate3d(0, -4.5%, 0); } }
@keyframes sky-near { to { transform: translate3d(0, -7%, 0); } }

@keyframes star-twinkle {
  0%, 100% { opacity: .45; }
  50% { opacity: 1; }
}

/* Небо просвечивает по полям, но не сквозь данные: под таблицей подложка почти
   непрозрачная. Полупрозрачная карточка выглядит нарядно ровно до тех пор, пока
   в ней не нужно прочитать столбец цифр. */
:root[data-theme="stars"] .card,
:root[data-theme="stars"] .banner,
:root[data-theme="stars"] .finding {
  background: rgb(16 22 50 / .93);
}

/* Тонкая светлая полоска по верхней кромке — будто панель освещена сверху.
   На плоском тёмном фоне это единственное, что отличает «прямоугольник краски»
   от «предмета в пространстве», и стоит оно одной строки без перерисовок. */
:root[data-theme="stars"] .card,
:root[data-theme="stars"] .tile {
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / .06),
    0 1px 2px rgb(0 0 0 / .5),
    0 12px 30px -14px rgb(4 6 20 / .9);
}

/* Плитки со сводными числами — то, на что смотрят первым. Едва заметная
   подсветка сверху делает их главными на странице, не крича. */
:root[data-theme="stars"] .tile {
  background:
    linear-gradient(180deg, rgb(30 40 88 / .55) 0, rgb(16 22 50 / .93) 42%);
  border-color: var(--line);
}

:root[data-theme="stars"] .top {
  background: rgb(8 11 28 / .82);
  border-bottom-color: var(--line);
}

:root[data-theme="stars"] thead th,
:root[data-theme="stars"] tfoot td,
:root[data-theme="stars"] tfoot th {
  background: rgb(21 29 61 / .96);
}

:root[data-theme="stars"] tbody tr:hover {
  background: rgb(30 40 84 / .96);
}

/* Значок раздела и кнопка светятся — тонко, только там, где взгляд и так стоит. */
:root[data-theme="stars"] .top nav a.on,
:root[data-theme="stars"] .theme-switch button.on {
  box-shadow: var(--glow);
}

:root[data-theme="stars"] .brand .mark {
  box-shadow: var(--glow);
}

/* Уважаем настройку «меньше движения»: для кого-то мерцание — не украшение,
   а помеха. Небо при этом остаётся, замирает только мерцание. */
@media (prefers-reduced-motion: reduce) {
  :root[data-theme="stars"] body::after {
    animation: none;
    opacity: .8;
  }
}


/* --- метеоры ------------------------------------------------------------------
 *
 * Шесть росчерков, идущих вразнобой: разной длины, с разной скоростью и с разных
 * высот. Ровный строй одинаковых полосок читался бы как заставка, а вразнобой —
 * как небо.
 *
 * Слой лежит под содержимым и обрезан по краям, чтобы улетающая полоска не
 * растягивала страницу и не поднимала полосу прокрутки. Каждый метеор — один
 * `transform`: видеокарта двигает готовый слой, страница не перерисовывается.
 * Поэтому шесть стоят почти столько же, сколько один.
 */

.meteors { display: none; }

:root[data-theme="stars"] .meteors {
  display: block;
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;

  /* Виньетка: к краям кадра темнее. Приём старый как фотография — затемнённая
     рамка отодвигает центр вглубь, и плоская картинка перестаёт быть плоской.
     Лежит поверх звёзд, но под содержимым. */
  background:
    radial-gradient(122% 92% at 50% 42%, transparent 52%, rgb(2 3 10 / .55) 100%);
}

/* Третий слой звёзд — средний по дальности. Двух слоёв на параллакс мало:
   при двух глаз читает «передний и задний», при трёх — глубину. */
:root[data-theme="stars"] .meteors::after {
  content: "";
  position: absolute;
  inset: -8%;
  pointer-events: none;
  background-image: radial-gradient(1.4px 1.4px at 121px 73px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 432px 81px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 146px 577px, rgb(255 233 205 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 180px 38px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 98px 415px, rgb(214 205 255 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 6px 561px, rgb(198 219 255 / .45) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 141px 551px, rgb(255 255 255 / .45) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 208px 14px, rgb(214 205 255 / .55) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 47px 105px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 127px 570px, rgb(255 255 255 / .7) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 388px 257px, rgb(255 255 255 / .45) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 117px 76px, rgb(198 219 255 / .45) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 565px 470px, rgb(255 255 255 / .7) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 38px 570px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 43px 438px, rgb(255 255 255 / .45) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 110px 10px, rgb(255 255 255 / .45) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 93px 537px, rgb(214 205 255 / .45) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 178px 174px, rgb(198 219 255 / .45) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 324px 453px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 150px 252px, rgb(255 233 205 / .7) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 246px 470px, rgb(255 233 205 / .55) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 199px 612px, rgb(198 219 255 / .45) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 503px 584px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.2px 1.2px at 264px 369px, rgb(255 233 205 / .55) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 204px 495px, rgb(255 255 255 / .45) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 332px 542px, rgb(255 233 205 / .55) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 486px 364px, rgb(198 219 255 / .45) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 484px 443px, rgb(255 255 255 / .45) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 175px 486px, rgb(255 255 255 / .55) 0, transparent 100%),
    radial-gradient(1.4px 1.4px at 116px 4px, rgb(198 219 255 / .7) 0, transparent 100%);
  background-size: 640px 640px;
  background-repeat: repeat;
}

:root[data-theme="stars"] .meteors i {
  position: absolute;
  left: -18vw;
  height: 1.5px;
  width: 190px;
  background: linear-gradient(90deg, transparent, rgb(207 224 255 / .75) 55%, #fff);
  filter: drop-shadow(0 0 6px rgb(160 200 255 / .8));
  opacity: 0;
  animation: meteor 30s linear infinite;
}

/* Каждому свой рост, своя высота и своё время выхода. Задержки разведены по
   пять секунд — примерно столько между росчерками и получается.

   Высоты собраны в верхней половине не случайно: летят они под углом вниз, и
   начатый низко уходит за нижний край, едва показавшись. */
:root[data-theme="stars"] .meteors i:nth-child(1) { top: -6vh; width: 200px; animation-delay: 0s; }
:root[data-theme="stars"] .meteors i:nth-child(2) { top: 20vh; width: 140px; animation-delay: 5s;
  animation-duration: 26s; }
:root[data-theme="stars"] .meteors i:nth-child(3) { top: 7vh; width: 230px; animation-delay: 10s; }
:root[data-theme="stars"] .meteors i:nth-child(4) { top: 34vh; width: 120px; animation-delay: 15s;
  animation-duration: 34s; }
:root[data-theme="stars"] .meteors i:nth-child(5) { top: 14vh; width: 175px; animation-delay: 20s; }
:root[data-theme="stars"] .meteors i:nth-child(6) { top: 27vh; width: 155px; animation-delay: 25s;
  animation-duration: 28s; }

@keyframes meteor {
  0% { transform: rotate(32deg) translate3d(0, 0, 0); opacity: 0; }
  1% { opacity: .9; }
  5% { transform: rotate(32deg) translate3d(132vw, 0, 0); opacity: 0; }
  100% { transform: rotate(32deg) translate3d(132vw, 0, 0); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  :root[data-theme="stars"] .meteors { display: none; }
}

/* --- «Автопарк» в звёздной теме -------------------------------------------------
 *
 * Главная рабочая страница, и потому единственная, которую наряжаем отдельно.
 * Всё добавленное здесь либо помогает читать таблицу, либо не мешает ей: строка
 * под курсором светится — по ней проще вести взглядом на широком экране.
 */

:root[data-theme="stars"] body[data-page="vehicles"] h1,
:root[data-theme="stars"] body[data-page^="fleet"] h1 {
  text-shadow: 0 0 22px rgb(143 182 255 / .35);
}

/* Сводные плитки — то, на что смотрят первым. Свечение по краю делает их
   главными на странице, не трогая сами числа. */
:root[data-theme="stars"] body[data-page="vehicles"] .tile,
:root[data-theme="stars"] body[data-page^="fleet"] .tile {
  border-color: rgb(70 92 172 / .7);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / .08),
    0 0 22px -6px rgb(90 130 255 / .35),
    0 12px 30px -14px rgb(4 6 20 / .9);
}

:root[data-theme="stars"] body[data-page="vehicles"] .tile b,
:root[data-theme="stars"] body[data-page^="fleet"] .tile b {
  text-shadow: 0 0 18px rgb(143 182 255 / .4);
}

/* Госномер — единственное, что на этой странице ищут глазами. Лёгкое свечение
   помогает найти строку, не делая текст менее чётким. */
:root[data-theme="stars"] body[data-page="vehicles"] .plate,
:root[data-theme="stars"] body[data-page^="fleet"] .plate {
  text-shadow: 0 0 14px rgb(143 182 255 / .45);
}

/* Строка под курсором подсвечивается полосой слева направо — как луч, идущий
   по строке. На таблице в семьдесят строк это заметно помогает не сбиться. */
:root[data-theme="stars"] body[data-page="vehicles"] tbody tr:hover,
:root[data-theme="stars"] body[data-page^="fleet"] tbody tr:hover {
  background: linear-gradient(
    90deg,
    rgb(44 60 130 / .95) 0,
    rgb(32 44 96 / .95) 45%,
    rgb(24 33 74 / .95) 100%
  );
  box-shadow: inset 2px 0 0 var(--accent);
}


/* --- иерархия в списке машин --------------------------------------------------
 *
 * На странице было семьдесят семь строк, и все числа в них выглядели одинаково:
 * повторяющееся «AZNUR» весило столько же, сколько итоговая сумма. Здесь всё
 * ровно об этом — что должно бросаться в глаза, а что уйти в фон.
 *
 * Через переменные, поэтому светлая и тёмная темы получают то же самое.
 */

/* Итог — то, ради чего в эту таблицу смотрят. Он и должен читаться первым:
   в разметке он уже в <b>, здесь добавляем размер и полный контраст. */
#fleet td[data-total] b {
  font-size: 14px;
  color: var(--ink);
}

/* Промежуточные суммы — вспомогательные, им незачем спорить с итогом. */
#fleet td[data-subtotal],
#fleet td[data-vat] {
  color: var(--ink-2);
}

/* Название заказчика повторяется в каждой строке. Это не данные, а фон:
   читают его редко, а места занимает как полноценный столбец. */
#fleet td.stage {
  font-size: 11.5px;
  letter-spacing: .03em;
  opacity: .72;
}

/* Разделители тоньше: на семидесяти строках сплошная сетка утомляет, а строку
   от строки отделяет и одного намёка достаточно. */
#fleet tbody tr { border-top-color: color-mix(in srgb, var(--line) 60%, transparent); }

/* Липкой шапки здесь нет намеренно. У `.table-wrap` горизонтальная прокрутка,
   а она делает контейнер точкой отсчёта для `sticky`: шапка прилипала бы к его
   верху, который уезжает вместе со страницей, — то есть ни к чему. Заставить её
   работать можно, ограничив таблицу по высоте и прокручивая внутри, но это уже
   меняет поведение страницы, а не её вид. Проверено на живой странице. */

/* Шапка столбцов отделена от данных чуть заметнее: на длинном списке взгляд
   возвращается к ней, и она должна находиться сразу. */
#fleet thead th {
  border-bottom: 1px solid var(--line-strong);
  padding-top: .7rem;
  padding-bottom: .7rem;
}

/* --- плитки: главное число --------------------------------------------------- */

/* Из пяти плиток одна главная — общая сумма. Остальные её слагаемые и счётчики,
   и одинаковый вес всех пяти скрывал это. */
.tiles .tile:last-child b { color: var(--accent); }
.tiles .tile:last-child {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
}

/* Счётчики штук — не деньги, и мельче: так взгляд сразу отделяет одно от другого. */
.tiles .tile:nth-child(1) b,
.tiles .tile:nth-child(2) b { font-size: 18px; color: var(--ink-2); }

/* --- поля ввода --------------------------------------------------------------- */

/* Поле — углубление, а не ещё одна карточка поверх карточки. Разница небольшая,
   но именно она отличает «форму» от «россыпи прямоугольников». */
.filters input,
.filters select {
  background: color-mix(in srgb, var(--bg) 55%, var(--surface));
  box-shadow: inset 0 1px 2px rgb(0 0 0 / .06);
}

.filters input:focus,
.filters select:focus {
  background: var(--surface);
}

/* --- кнопки выгрузки ----------------------------------------------------------- */

/* «Удалить» стояло вплотную к выгрузкам и весило столько же. Отодвигаем и
   красим на наведении: необратимое действие не должно быть похоже на «скачать». */
.toolbar #pick-mode { margin-right: .35rem; }
.toolbar #pick-mode:hover {
  border-color: color-mix(in srgb, var(--err) 55%, var(--line-strong));
  color: var(--err);
}


/* --- хронология обслуживания ----------------------------------------------------
 *
 * Лента по оси времени вместо стопки одинаковых карточек. Ось слева, на ней
 * точки визитов; между точками подписано, сколько прошло. Ради этой подписи всё
 * и затевалось: двадцать две даты подряд не показывают, что машина полгода
 * молчала, а потом трижды за месяц приезжала.
 */

/* Три числа, от которых зависит вся геометрия ленты. Держим их переменными и
   считаем от них: когда ось и точка на ней заданы порознь, они расходятся —
   так и вышло, точка встала мимо линии на полтора пикселя. */
.timeline {
  --pad: 1.6rem;   /* отступ ленты слева */
  --axis: .38rem;  /* где проходит ось от края ленты */
  --dot: 9px;      /* поперечник точки визита */

  list-style: none;
  margin: 0;
  padding: 0 0 0 var(--pad);
  position: relative;
}

/* Сама ось. Гаснет к концу: история не обрывается, она просто уходит в прошлое. */
.timeline::before {
  content: "";
  position: absolute;
  left: var(--axis);
  /* Начинается ровно в середине первой точки, а не выше неё. Иначе над первым
     визитом торчал огрызок линии в пустоту — именно он и читался как «криво». */
  top: calc(.8rem + .55em + var(--dot) / 2);
  bottom: 0;
  width: 1px;
  background: linear-gradient(180deg,
    var(--line-strong) 0,
    var(--line) 72%,
    transparent 100%);
}

.timeline .visit {
  --visit-pad-y: .8rem;

  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--visit-pad-y) .9rem;
  margin-bottom: .55rem;
  box-shadow: var(--shadow);
}

/* Точка визита. Середина точки садится ровно на середину оси, а сама она
   встаёт напротив строки с датой, а не посреди карточки.

   Отсчёт идёт от левого края карточки, поэтому вычитаем отступ ленты: так
   положение остаётся верным, каким бы ни был отступ на узком экране. */
.timeline .visit::before {
  content: "";
  position: absolute;
  left: calc(var(--axis) + .5px - var(--pad) - var(--dot) / 2);
  top: calc(var(--visit-pad-y, .8rem) + .55em);
  width: var(--dot);
  height: var(--dot);
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--line-strong);
}

/* Непроверенный счёт видно прямо на оси — не надо читать все карточки подряд. */
.timeline .visit.flagged::before {
  border-color: var(--warn);
  background: var(--warn);
}

.visit-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .3rem .6rem;
}

.visit-date {
  font: 600 13.5px/1.2 var(--mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.visit-no { font-size: 13px; }

/* Сумма визита прижата вправо: по ней ведут взглядом сверху вниз, сравнивая
   поездки между собой, и для этого числа должны стоять в столбик. */
.visit-sum {
  margin-left: auto;
  font: 600 15px/1.2 var(--mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.visit-who {
  margin: .3rem 0 .55rem;
  font-size: 12px;
  color: var(--ink-3);
}

/* Счёт с единственной обобщённой строкой — не таблица на пять столбцов, а
   одна строка: подпись слева, число справа. */
.visit-lone {
  display: flex;
  align-items: baseline;
  gap: .8rem;
  padding: .5rem .65rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: 13px;
}
.visit-lone span { color: var(--ink-2); }
.visit-lone b {
  margin-left: auto;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

.visit-source { margin: .55rem 0 0; font-size: 12.5px; }

/* Промежуток между визитами. Это подпись на оси, а не карточка: она должна
   читаться как пауза, а не как ещё одно событие. */
.timeline .gap {
  position: relative;
  margin-top: .1rem;
  padding: .1rem 0 .45rem;
  font-size: 11.5px;
  color: var(--ink-3);
  letter-spacing: .02em;
}

.timeline .gap span {
  display: inline-block;
  padding: .05rem .5rem;
  border-radius: 99px;
  background: var(--bg);
}

@media (max-width: 720px) {
  .visit-sum { margin-left: 0; width: 100%; }
}


/* --- зона загрузки и пустые состояния --------------------------------------------
 *
 * Страница загрузки — главный ежедневный экран, и он был на две трети пуст:
 * узкая полоса вверху и чернота до подвала. Здесь про то, чтобы у него
 * появилась середина.
 */

.drop {
  border: 2px dashed var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 2.9rem 1.2rem 2.4rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .1rem;
  text-align: center;
  color: var(--ink-2);
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.drop:hover { border-color: var(--accent); }
.drop.over { border-color: var(--accent); background: var(--accent-soft); }

/* Значок задаёт зоне центр. Без него прямоугольник читается как «поле ввода»,
   а не как «сюда кладут файлы». */
.drop-mark {
  width: 46px;
  height: 46px;
  margin-bottom: .55rem;
  color: var(--ink-3);
  transition: color .15s, transform .15s;
}

.drop:hover .drop-mark { color: var(--accent); }
.drop.over .drop-mark { color: var(--accent); transform: translateY(-3px); }

.drop b { display: block; color: var(--ink); font-size: 17px; font-weight: 600; margin: 0; }
.drop-hint { font-size: 13px; color: var(--ink-2); }

/* Подсказка про сшитый файл — про то, о чём иначе не догадаться: месяц одним
   PDF кидать можно. */
.drop-note {
  margin-top: .75rem;
  font-size: 12px;
  color: var(--ink-3);
  max-width: 34rem;
}

/* Состояние «всё разобрано». Это хорошая новость, и она должна читаться как
   хорошая новость, а не как серая строчка посреди пустоты. */
.allclear {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .15rem;
  padding: 2.6rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink-2);
}

.allclear svg { width: 40px; height: 40px; color: var(--ok); margin-bottom: .5rem; }
.allclear b { color: var(--ink); font-size: 15px; }
.allclear span { font-size: 13px; color: var(--ink-3); }

/* --- ход разбора ------------------------------------------------------------------ */

/* Полоса под строкой задачи. Занимает всю ширину, поэтому в `flex-wrap` идёт
   отдельной строкой — счётчик страниц и полоса не должны толкаться. */
.queue .bar {
  flex: 1 0 100%;
  height: 3px;
  margin-top: .45rem;
  border-radius: 99px;
  background: var(--line);
  overflow: hidden;
}

.queue .bar i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 99px;
  background: var(--accent);
  transition: width .35s ease;
}

/* Когда считать нечего — полоса бежит сама. Рисовать выдуманные проценты хуже,
   чем честно показать, что работа идёт, а сколько её осталось, неизвестно. */
.queue .bar.unknown i {
  width: 35%;
  animation: bar-run 1.4s ease-in-out infinite;
}

@keyframes bar-run {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(320%); }
}

@media (prefers-reduced-motion: reduce) {
  .queue .bar.unknown i { animation: none; width: 100%; opacity: .5; }
}


/* --- значки разделов --------------------------------------------------------------
 *
 * Значок помогает найти нужный пункт боковым зрением, но подписи не заменяет:
 * «Тендеры» и «Журнал» одной картинкой не различить. Поэтому он приглушён —
 * это подсказка, а не главное в пункте.
 */

.top nav .ico {
  flex: 0 0 auto;
  opacity: .62;
  transition: opacity .12s;
}

.top nav a:hover .ico,
.top nav a.on .ico { opacity: 1; }

/* На узком экране подписи прячутся, и меню из девяти слов превращается в ряд
   значков — тогда они уже несут смысл сами, и приглушать их нельзя. */
@media (max-width: 900px) {
  .top nav a span { display: none; }
  .top nav a { padding: .38rem .5rem; }
  .top nav .ico { opacity: .85; width: 19px; height: 19px; }
}


/* --- узкий экран: таблица машин становится карточками --------------------------
 *
 * Тринадцать столбцов в горизонтальной прокрутке на телефоне не читаются: пока
 * доедешь до суммы, потеряешь, чья она. Поэтому каждая строка разворачивается в
 * карточку, а названия столбцов подставляются подписями к значениям.
 *
 * Подписи приезжают из `data-label` в разметке, а не дублируются здесь: иначе
 * они разошлись бы с шапкой при первой же правке — и остались бы без перевода.
 *
 * Всё заперто внутри медиазапроса: на широком экране таблица остаётся таблицей.
 */

@media (max-width: 720px) {
  /* Только обёртка автопарка. Раньше здесь стоял общий `.table-wrap`, и вместе
     с автопарком прокрутку теряли все остальные таблицы сайта — состав работ в
     карточке машины обрезался вместо того, чтобы прокручиваться. */
  .fleet-wrap { overflow-x: visible; border: none; background: none; box-shadow: none; }

  #fleet, #fleet tbody, #fleet tr, #fleet td { display: block; width: auto; }

  /* Шапка и подвал не нужны: столбцов больше нет, а итоги показывают плитки. */
  #fleet thead, #fleet tfoot { display: none; }

  #fleet tr {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow);
    padding: .1rem .2rem .3rem;
    margin-bottom: .55rem;
  }

  #fleet td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: .34rem .7rem;
    border: none;
    text-align: right;
  }

  #fleet td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    color: var(--ink-3);
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: .04em;
    text-align: left;
  }

  /* Госномер — заголовок карточки: во всю ширину, крупно и без подписи. */
  #fleet td[data-plate] {
    justify-content: flex-start;
    padding: .5rem .7rem .35rem;
    border-bottom: 1px solid var(--line);
    margin-bottom: .2rem;
    font-size: 15px;
  }
  #fleet td[data-plate]::before { content: none; }

  /* Пустые ячейки на телефоне только занимают место. Замечаний нет — строки нет. */
  #fleet td:empty { display: none; }

  /* Отметка для удаления остаётся, но уходит в правый верхний угол карточки. */
  #fleet td.pick {
    float: right;
    padding: .5rem .7rem 0;
  }
  #fleet td.pick::before { content: none; }

  /* Итог на карточке — самое крупное число, как и в таблице. */
  #fleet td[data-total] b { font-size: 15px; }
}


/* --- узкий экран: остальные таблицы ---------------------------------------------
 *
 * Их в карточки не разворачиваем — в них по три-пять столбцов, и прокрутки вбок
 * достаточно. Но место экономим: отступы уже, а служебные столбцы прячем.
 */

@media (max-width: 720px) {
  .table-wrap { -webkit-overflow-scrolling: touch; }
  .table-wrap th, .table-wrap td { padding: .45rem .5rem; }

  /* Состав работ в карточке машины. Номер строки на телефоне не нужен —
     строки и так идут по порядку, а место он занимает. */
  .visit .table-wrap th:first-child,
  .visit .table-wrap td:first-child { display: none; }

  /* Название работы занимает столько, сколько есть, и переносится. */
  .visit .table-wrap td:nth-child(2) { min-width: 8rem; white-space: normal; }

  /* Лента жмётся к краю: полтора сантиметра отступа на узком экране — роскошь.
     Меняем только числа — положение точки посчитается от них само. */
  .timeline { --pad: .95rem; --axis: .22rem; }
  .timeline .visit { --visit-pad-y: .65rem; padding-left: .55rem; padding-right: .55rem; }
}


/* --- узкий экран: поля и карточка тендера ----------------------------------------
 *
 * Две вещи, которые на телефоне мешали каждый день.
 */

@media (max-width: 720px) {
  /* Safari на iOS увеличивает всю страницу, когда палец попадает в поле со
     шрифтом мельче 16px, и обратно сам не возвращает — после каждого ввода
     страницу приходится отщипывать пальцами. Базовый кегль сайта 14,5px, поля
     наследуют его, поэтому здесь задаём ровно 16: это не про читаемость, а про
     то, чтобы браузер оставил масштаб в покое. Больше всего достаётся проверке
     счёта — там полей больше десятка. */
  input, select, textarea { font-size: 16px; }

  /* Карточка тендера собрана в три колонки: оценка, суть, кнопки справа. На
     телефоне третья колонка сжимала середину до пары слов, а пять кнопок
     решения вставали в узкий столбик по правому краю. Переносим их вниз во всю
     ширину: оценка и название остаются в первой строке, решения — во второй. */
  .tender-head { flex-wrap: wrap; gap: .7rem; }
  .score { min-width: 3.6rem; }
  .score b { font-size: 23px; }

  .tender-side {
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    width: 100%;
    gap: .4rem;
  }

  /* Кнопки делят строку поровну и дорастают до размера, в который попадает
     палец: 36px — общепринятый минимум для касания. */
  .decide { width: 100%; justify-content: flex-start; }
  .decide .btn { flex: 1 1 5.5rem; min-height: 36px; }

  /* Переключатели источника и решения — во всю ширину, иначе они жмутся к
     подписи слева и половина строки пропадает впустую. */
  .filters-row.period { align-items: stretch; }
  .filters-row.period .quick { width: 100%; }
  .filters-row.period .quick-btn { flex: 1 1 auto; text-align: center; min-height: 34px; line-height: 22px; }
}


/* --- печать ------------------------------------------------------------------------
 *
 * По машинам есть настоящий PDF-отчёт, а вот обслуживание, журнал и тендеры взять
 * на бумагу нечем — их печатают прямо из браузера. Без этих правил на лист уходят
 * шапка, фильтры, кнопки и тёмный фон во всю страницу.
 *
 * Палитру не переписываем по месту, а переопределяем переменные: тогда светлыми
 * становятся сразу все страницы и все три темы, включая звёздную.
 */

@media print {
  @page { margin: 1.5cm; }

  :root,
  :root[data-theme="dark"],
  :root[data-theme="stars"] {
    --bg: #fff;
    --surface: #fff;
    --surface-2: #fff;
    --ink: #000;
    --ink-2: #333;
    --ink-3: #555;
    --line: #ccc;
    --line-strong: #999;
  }

  body { background: #fff; color: #000; }

  /* Всё, что нажимают, на бумаге бессмысленно. */
  .top, .foot, .prefs, .meteors, .filters, .filters-state,
  .actions, .decide, .exports, .drop, button, .btn {
    display: none !important;
  }

  main { padding: 0; max-width: none; }

  /* Тень на бумаге превращается в серую грязь, рамки достаточно. */
  .card, .tender { box-shadow: none; border: 1px solid var(--line); }

  /* Строку таблицы и карточку не режем между листами. */
  tr, .card, .tender, .visit, .finding { break-inside: avoid; }

  /* Шапка длинной таблицы повторяется на каждом листе — иначе со второго листа
     непонятно, что за столбцы. */
  thead { display: table-header-group; }

  /* Ссылка на бумаге бесполезна, если не видно, куда она ведёт. Печатаем адрес
     рядом — но только у внешних: внутренние («/vehicles/77AL499») ничего не дают. */
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 10px;
    color: #555;
    word-break: break-all;
  }
}


/* --- клиенты ---------------------------------------------------------------------
 *
 * Карточка клиента: сверху имя и счётчики, подробности — за раскрытием. Клиентов
 * будет много, и разворачивать каждого целиком значит получить ту же простыню,
 * от которой мы уходим в ленте тендеров.
 */

.client-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }
.client-head h2 { margin: 0 0 .2rem; font-size: 15.5px; }
/* Отключённый клиент виден, но приглушён: его данные на месте, входа у него нет. */
.client-card.off { opacity: .6; }

/* Поля в строке подхватывают общий `.inline-form` выше по файлу. */
.inline-form input, .inline-form select { flex: 1 1 8rem; }

/* --- Дозаполнение пробелов --- */

/* Поле узкое намеренно: в него вписывают шесть цифр, а широкое поле в таблице
   уводит взгляд и мешает бежать глазами по столбцу. */
.gaps .gap-input { width: 9rem; max-width: 100%; }
.gaps .gap-state { width: 2rem; text-align: center; }
.gaps tr.gap-done .gap-state { color: var(--ok, #2e7d32); }
.gaps tr.gap-failed .gap-state { color: var(--err); }
/* Заполненную строку приглушаем, а не прячем: исчезающая из-под курсора строка
   сбивает счёт, и непонятно, сохранилось ли. */
.gaps tr.gap-done { opacity: .55; }
