/* Панель Версты.
 *
 * ── ПОЧЕМУ ОНА ВЫГЛЯДИТ ПЛОТНО, А НЕ ПРОСТОРНО ──────────────────────
 *
 * Это рабочий стол, а не витрина. Разбор десяти жалоб подряд — работа
 * глазами по строкам, и воздух между ними, красивый на снимке экрана,
 * заставляет прокручивать и терять место. Цвета взяты у приложения,
 * чтобы панель не выглядела чужой, но плотность здесь своя.
 */

:root {
  --canvas: #ffffff;
  --tint: #f2f4f8;
  --warm: #faf7f4;
  --ink: #0b0b0f;
  --muted: #6b6f76;
  --faint: #9aa0a6;
  --brand: #b2432d;
  --brand-tint: #fbede9;
  --hairline: #e6e8ec;
  --danger: #b93b31;
  --danger-tint: #fbebe9;
  --success: #2e8b62;
  --success-tint: #e4f2eb;
  --radius: 10px;
}

* { box-sizing: border-box; }

/* Скрытое обязано быть скрытым.
 *
 * `hidden` — правило браузера, и любое своё `display` его перебивает:
 * у `.gate` и `.modal` оно есть, и лист поверх страницы висел на
 * экране всегда, серой пеленой поверх входа. Отсюда `!important` —
 * тот редкий случай, когда он означает именно то, что написано. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font: 14px/1.45 -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
  background: var(--tint);
}

h1, h2, h3 { margin: 0 0 10px; font-weight: 650; }
h1 { font-size: 22px; }
h2 { font-size: 17px; }
h3 { font-size: 14px; }

a { color: var(--brand); }
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.error { color: var(--danger); }
.ok { color: var(--success); }
.spacer { flex: 1; }
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.nowrap { white-space: nowrap; }

/* ── Вход ───────────────────────────────────────────────────────── */

.gate {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 20px;
}

.gate .card {
  width: 320px;
  max-width: 100%;
  background: var(--canvas);
  border-radius: var(--radius);
  padding: 24px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .06), 0 8px 24px rgba(0, 0, 0, .06);
}

label {
  display: block;
  margin: 14px 0;
  font-size: 12px;
  color: var(--muted);
}

/* Галочки сюда не попадают.
 *
 * Общее правило «поле — это блок во всю ширину» верно для строк и чисел
 * и превращает галочку в полосу через весь лист, оторванную от своей
 * подписи. Ловится это только глазами: разметка при этом остаётся
 * правильной. */
input:not([type=checkbox]):not([type=radio]), select, textarea {
  display: block;
  width: 100%;
  margin-top: 4px;
  padding: 8px 10px;
  font: inherit;
  color: var(--ink);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: 8px;
}

input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--brand);
  outline-offset: -1px;
}

textarea { min-height: 70px; resize: vertical; }

input[type=checkbox] {
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--brand);
}

/* Подпись рядом с галочкой — строка, а не блок: иначе она уезжает
 * под неё и читается как подпись к следующему полю. */
label.row { display: flex; align-items: center; gap: 8px; }

button {
  font: inherit;
  padding: 8px 14px;
  color: #fff;
  background: var(--ink);
  border: 0;
  border-radius: 8px;
  cursor: pointer;
}

button:hover { opacity: .9; }
button:disabled { opacity: .45; cursor: default; }

button.quiet { color: var(--ink); background: var(--tint); }
button.good { background: var(--success); }
button.bad { background: var(--danger); }
button.link {
  color: var(--muted);
  background: none;
  padding: 4px;
  text-decoration: underline;
}

/* ── Каркас ─────────────────────────────────────────────────────── */

/* ── Колонка ──────────────────────────────────────────────────────
 *
 * Панель стоит по центру окна, а не прижата к левому краю.
 *
 * На широком мониторе прижатое влево содержимое означает, что глаз
 * ходит от левого края к правому через полтора метра пустоты, а голова
 * поворачивается вслед. Ширина колонки при этом ограничена: строка
 * таблицы во весь двадцатисемидюймовый экран не читается — взгляд
 * теряет строку на обратном ходе.
 *
 * Одна переменная на всю панель: шапка и содержимое обязаны стоять
 * по одной оси, а два числа в разных местах разъедутся на первой
 * же правке. */
:root { --column: 1180px; }

header {
  position: sticky;
  top: 0;
  z-index: 5;
  height: 48px;
  background: var(--canvas);
  border-bottom: 1px solid var(--hairline);
}

/* Шапка тянется во всю ширину, её содержимое — нет: иначе нижняя
 * черта обрывалась бы посреди экрана. */
.bar-inner {
  display: flex;
  gap: 16px;
  align-items: center;
  height: 100%;
  max-width: var(--column);
  margin: 0 auto;
  padding: 0 16px;
}

header b { color: var(--brand); }

/* Имя и «выйти» не сжимаются: сжимается полоса разделов. */
.bar-inner > b, #who, #signout { flex: none; white-space: nowrap; }

/* Разделов стало четырнадцать (лавка, 26.09.2026), и полоса перестала
 * помещаться в колонку: имя и «выйти» уезжали за край, а страница
 * получала прокрутку вбок. Теперь пункты плотнее, а если окно совсем
 * узкое — прокручивается сама полоса, а не вся страница. */
nav {
  display: flex;
  gap: 0;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}

nav a {
  flex: none;
  white-space: nowrap;
  padding: 5px 8px;
  border-radius: 7px;
  color: var(--muted);
  text-decoration: none;
}

nav a:hover { background: var(--tint); }
nav a.on { color: var(--ink); background: var(--tint); font-weight: 600; }

/* Отбор в журнале: выбранное отличается не только цветом, но и плотностью.
 * Цвет один и тот же у ссылки и у выбранного пункта читается плохо
 * при ярком свете и не читается вовсе теми, кто оттенок не различает. */
.row a.on {
  color: var(--ink);
  background: var(--tint);
  font-weight: 600;
  border-radius: 6px;
  padding: 2px 8px;
  text-decoration: none;
}

nav .count {
  display: inline-block;
  margin-left: 6px;
  padding: 0 6px;
  font-size: 11px;
  font-weight: 700;
  line-height: 16px;
  color: #fff;
  background: var(--brand);
  border-radius: 8px;
}

main { padding: 16px; max-width: var(--column); margin: 0 auto; }

/* ── Плитки и карточки ──────────────────────────────────────────── */

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 10px;
  margin-bottom: 18px;
}

.tile {
  padding: 12px 14px;
  background: var(--canvas);
  border-radius: var(--radius);
}

.tile .big { font-size: 26px; font-weight: 650; letter-spacing: -.5px; }
.tile .name { font-size: 12px; color: var(--muted); }
/* ── Спарклайны ──────────────────────────────────────────────────
 *
 * Линия без осей и подписей: она отвечает на «растёт или падает»
 * за полвзгляда, а точное значение читается числом над ней. Оси
 * превратили бы её в график, ради которого надо остановиться. */

.tile.trend { padding-bottom: 10px; }
.tile.trend .big { font-size: 22px; }
.tile .spark { display: block; margin: 6px 0 2px; width: 100%; height: 34px; }
.spark-line { stroke: var(--brand); stroke-width: 1.5; stroke-linejoin: round; }
.spark-area { fill: var(--brand-tint); }
.spark-dot { fill: var(--brand); }
.tile .faint { font-size: 11px; color: var(--muted); }

.tile.warn { background: var(--danger-tint); }
.tile.warn .big { color: var(--danger); }

.panel {
  background: var(--canvas);
  border-radius: var(--radius);
  padding: 14px;
  margin-bottom: 14px;
}

.bar { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
/* В строке отбора поля стоят рядом, а не растянуты во всю ширину.
 * Селектор повторяет `:not(...)` соседнего правила намеренно: без этого
 * то правило оказывается частнее и растягивает поле поиска на строку. */
.bar select,
.bar input:not([type=checkbox]):not([type=radio]) { width: auto; margin: 0; }

/* ── Строки очередей ────────────────────────────────────────────── */

.item {
  display: flex;
  gap: 12px;
  padding: 12px 0;
  border-top: 1px solid var(--hairline);
}

.item:first-child { border-top: 0; }
.item .body { flex: 1; min-width: 0; }
.item .title { font-weight: 600; }
.item .sub { font-size: 12px; color: var(--muted); }
.item .acts { display: flex; gap: 6px; align-items: flex-start; }

.photo {
  width: 96px;
  height: 96px;
  object-fit: cover;
  border-radius: 8px;
  background: var(--tint);
}

.avatar {
  width: 34px;
  height: 34px;
  object-fit: cover;
  border-radius: 50%;
  background: var(--tint);
}

.tag {
  display: inline-block;
  padding: 1px 7px;
  font-size: 11px;
  border-radius: 6px;
  background: var(--tint);
  color: var(--muted);
}

.tag.hot { background: var(--danger-tint); color: var(--danger); }
.tag.good { background: var(--success-tint); color: var(--success); }
.tag.brand { background: var(--brand-tint); color: var(--brand); }

/* ── Лавка ───────────────────────────────────────────────────────
 *
 * Цены — узкими полями с единицей справа: «449» в поле во всю ширину
 * теряется, и глаз ищет, где же цена. */

input.narrow:not([type=checkbox]) {
  display: inline-block;
  width: 96px;
  margin: 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.unit { margin-left: 6px; font-size: 12px; color: var(--muted); }
.small { font-size: 12px; }
table.knobs td { vertical-align: middle; }
tr.group td {
  padding-top: 14px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .4px;
  color: var(--faint);
  border-top: 0;
}
tr.group:hover { background: none; }

.banner { display: flex; gap: 14px; align-items: center; }
.banner .body { flex: 1; }
.banner h3 { margin-bottom: 4px; }
.banner p { margin: 0; }
.banner.warn { background: var(--danger-tint); }
.banner.warn h3 { color: var(--danger); }

.grid-hands {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
  gap: 22px 28px;
}
/* В каждом блоке один порядок: что → за что → кнопки. */
.grid-hands h3 { margin-bottom: 8px; }
.grid-hands input:not(.narrow), .grid-hands select { margin: 0 0 8px; }
.grid-hands .row + input { margin-top: 8px; }

details.panel summary { cursor: pointer; font-weight: 600; }

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

table { width: 100%; border-collapse: collapse; }
th, td { padding: 7px 8px; text-align: left; border-top: 1px solid var(--hairline); }
th { font-size: 11px; text-transform: uppercase; color: var(--faint); border-top: 0; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
tbody tr:hover { background: var(--warm); }
tr.off td { color: var(--faint); }

.empty { padding: 28px 0; text-align: center; color: var(--faint); }

/* ── Лист поверх ────────────────────────────────────────────────── */

.modal {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(11, 11, 15, .35);
}

.modal .sheet {
  width: min(680px, 100%);
  max-height: 88vh;
  overflow: auto;
  padding: 20px;
  background: var(--canvas);
  border-radius: 14px;
}

.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }

/* ── Сообщение о сделанном ──────────────────────────────────────── */

.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  z-index: 20;
  transform: translateX(-50%);
  padding: 10px 16px;
  color: #fff;
  background: var(--ink);
  border-radius: 999px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .2);
}

.toast.bad { background: var(--danger); }

@media (max-width: 720px) {
  nav { overflow-x: auto; }
  main { padding: 12px; }
  .bar-inner { padding: 0 12px; }
  .grid2 { grid-template-columns: 1fr; }

  /* Таблицы на узком экране не сжимаются, а прокручиваются вбок.
   *
   * Сжатие превращает пять колонок в пять столбцов по одному слову,
   * и читать их невозможно. Прокрутка отдаётся карточке, а не самой
   * таблице: `display: block` на таблице ломает выравнивание колонок,
   * и они перестают совпадать с шапкой. */
  .panel { overflow-x: auto; }
  .panel table { min-width: 520px; }

  /* Кнопки в строке переносятся, а не выдавливают содержимое за край. */
  .item { flex-wrap: wrap; }
  .acts { flex-wrap: wrap; }
}

/* ── Карта ──────────────────────────────────────────────────────── */

.map {
  height: 62vh;
  min-height: 360px;
  border-radius: 8px;
  overflow: hidden;
}

.map.small { height: 220px; min-height: 0; margin-bottom: 6px; }

/* Собственные подписи движка — латиницей и не в нашем духе. Оставлена
 * только атрибуция: она обязательна по лицензии ODbL. */
.maplibregl-ctrl-attrib { font-size: 10px; }

/* ── Привязка аутентификатора ─────────────────────────────────────
 *
 * QR приезжает разметкой SVG и растягивается по ширине карточки:
 * картинкой точками он мылился бы на экране с тройной плотностью,
 * а фотографируют его иногда прямо с монитора.
 *
 * Размер задан долей, а не числом: на узком экране карточка сама
 * становится уже, и жёсткие двести сорок точек вылезли бы за её край.
 * Соотношение сторон обязательно — без него высота считается по
 * содержимому, и до загрузки разметки на месте кода стоит пустая
 * полоска, от которой всё под ней прыгает. */

.qr {
  display: flex;
  justify-content: center;
  margin: 4px 0 10px;
}

.qr svg {
  /* Двести сорок точек на пятьдесят три модуля — это четыре с половиной
   * точки на модуль. Меньше — и камера, снимающая экран под углом,
   * начинает промахиваться; больше — карточка входа перестаёт помещаться
   * на ноутбуке. */
  width: 100%;
  max-width: 260px;
  height: auto;
  aspect-ratio: 1;
  /* Белая подложка обязательна: тёмный QR на тёмном фоне не читается
   * ни одной камерой, а тема панели может быть какой угодно. */
  background: #fff;
  padding: 8px;
  border-radius: var(--radius);
}

/* Ключ буквами — для тех, у кого не вышло сканировать. Моноширинным
 * и группами по четыре: строка из тридцати двух знаков подряд
 * вводится с ошибкой примерно всегда. */
.key {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 15px;
  letter-spacing: .5px;
  text-align: center;
  user-select: all;
  background: var(--canvas);
  border-radius: var(--radius);
  padding: 8px;
  margin: 0 0 12px;
}

.small { font-size: 12px; }

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

.state {
  display: flex;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--hairline);
}

.state:last-child { border-bottom: 0; }

.state-mark {
  width: 4px;
  border-radius: 2px;
  background: var(--hairline);
  flex: none;
}

.state.ok .state-mark { background: var(--success); }
/* Средний уровень — единственный, для которого в палитре цвета нет:
 * он не «хорошо» и не «плохо». Заводим один и здесь же, чтобы он был
 * рядом с местом, где нужен. */
.state.warn .state-mark { background: #c08a1e; }
.state.bad .state-mark { background: var(--danger); }

.state .body { flex: 1; }
.state .sub { font-size: 12px; color: var(--muted); margin-top: 2px; }

/* Карточка привязки шире остальных: в ней и код, и ключ, и объяснение.
 * Триста двадцать точек хватало форме из двух полей, а здесь текст
 * начинает переноситься по два слова в строку. */
.gate #enroll { width: 380px; }
