/* Шрифты лежат рядом с приложением: сервер может стоять без исходящего доступа,
   и на отсутствие внешних ресурсов стоит тест. Подключены три подмножества —
   кириллица для интерфейса, латиница и расширенная латиница для VIN и марок. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url(/static/fonts/inter-cyrillic.woff2) format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url(/static/fonts/inter-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url(/static/fonts/inter-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/static/fonts/jetbrains-mono-cyrillic.woff2) format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/static/fonts/jetbrains-mono-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/static/fonts/jetbrains-mono-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Палитра и геометрия — из design/DESIGN.md. Несущее правило: синий означает
   действие, янтарь — предупреждение и предел ресурса. Красить янтарём обычные
   кнопки нельзя: метка обесценится там, где она правда нужна. */
:root {
  color-scheme: dark;
  --bg: #080d12;
  --bg-deep: #070b10;
  --surface: #111820;
  --surface-2: #151e27;
  --surface-3: #1a232e;
  --surface-deep: #0a1219;
  --text: #f2f6fa;
  --muted: #8e9ba9;
  --micro: #9eabb8;
  --line: #263544;
  --line-soft: #1b2935;
  --line-strong: #3a4a59;
  --line-action: #2f557a;
  --accent: #1772f2;
  --accent-hover: #2a80f6;
  --accent-ink: #ffffff;
  --accent-line: #3d91ff;
  --accent-edge: #4d9fff;
  --accent-soft: rgba(61, 145, 255, .16);
  --cyan: #66b8ff;
  --success: #1bb271;
  --success-strong: #1fcb86;
  --info: #0e84f4;
  --warning: #ffad05;
  --warning-text: #ffc200;
  --warning-icon: #ff9d02;
  --warning-border: rgba(255, 173, 5, .45);
  --warning-bg: rgba(255, 173, 5, .07);
  --danger: #ff7c7c;
  --track: #040d17;
  --grid-line: rgba(102, 184, 255, .005);
  --page-glow: rgba(30, 84, 128, .09);
  --chrome-bg: rgba(7, 13, 19, .78);
  --panel-edge: rgba(57, 77, 96, .92);
  --panel-fill: linear-gradient(145deg, rgba(16, 25, 34, .98), rgba(10, 17, 24, .98));
  /* Чертёжная графика экрана входа. Держим её в токенах: цвета там подобраны под
     тёмный фон, и на светлой теме подпись узла иначе становится тёмной на тёмном. */
  --tech-surface: #0b1721;
  --tech-border: #3f627e;
  --tech-ink: #6e91ad;
  --tech-index: #8693a0;
  --tech-node-bg: linear-gradient(180deg, rgba(13, 29, 43, .98), rgba(9, 17, 24, .98));
  --tech-node-border: #4ca8ed;
  --tech-node-fill: #101820;
  --tech-line: #b9c9d7;
  --tech-draw: #36536c;
  --tech-draw-accent: #4c82aa;
  --tech-dot: #4c82aa;
  --tech-glow: rgba(35, 119, 199, .42);
  --tech-grid: rgba(102, 184, 255, .12);
  --field-border: #46586a;
  --field-label: #d8e0e7;
  --field-lead: #b0bac4;
  --field-placeholder: #788593;
  --shadow: 0 24px 70px rgba(0, 0, 0, .38);
  --radius: 10px;
  --radius-sm: 5px;
  --radius-btn: 4px;
  --mono: "JetBrains Mono", ui-monospace, "Cascadia Mono", monospace;
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

/* Светлая тема каноном не утверждена и живёт как инженерная опция. Роли цветов
   в ней те же: primary остаётся синим, янтарь остаётся предупреждением. */
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f4f5f6;
  --bg-deep: #eceef1;
  --surface: #ffffff;
  --surface-2: #f8f9fa;
  --surface-3: #eef0f3;
  --surface-deep: #ffffff;
  --text: #191c20;
  --muted: #69717c;
  --micro: #69717c;
  --line: #dfe3e8;
  --line-soft: #e9ecf0;
  --line-strong: #c9ced5;
  --line-action: #b7c6d8;
  --accent: #1256b8;
  --accent-hover: #0f4a9f;
  --accent-ink: #ffffff;
  --accent-line: #1256b8;
  --accent-edge: #1256b8;
  --accent-soft: rgba(18, 86, 184, .18);
  --cyan: #1f6fa8;
  --success: #177b55;
  --success-strong: #177b55;
  --info: #1256b8;
  --warning: #9a5a00;
  --warning-text: #7d4900;
  --warning-icon: #9a5a00;
  --warning-border: rgba(154, 90, 0, .38);
  --warning-bg: #fff1da;
  --danger: #b32929;
  --track: #e4e7ec;
  --grid-line: transparent;
  --page-glow: transparent;
  --chrome-bg: rgba(255, 255, 255, .88);
  --panel-edge: #dfe3e8;
  --panel-fill: #ffffff;
  --tech-surface: #eef2f6;
  --tech-border: #b3c3d2;
  --tech-ink: #5d7488;
  --tech-index: #69717c;
  --tech-node-bg: #f4f7fa;
  --tech-node-border: #8fb4d4;
  --tech-node-fill: #ffffff;
  --tech-line: #8fa4b6;
  --tech-draw: #8ba0b4;
  --tech-draw-accent: #6f93b3;
  --tech-dot: #6f93b3;
  --tech-glow: rgba(35, 119, 199, 0);
  --tech-grid: rgba(18, 86, 184, .10);
  --field-border: #c9ced5;
  --field-label: #191c20;
  --field-lead: #69717c;
  --field-placeholder: #7a8290;
  --shadow: 0 20px 55px rgba(33, 38, 45, .10);
}

@media (prefers-color-scheme: light) {
  :root[data-theme="system"] {
    color-scheme: light;
    --bg: #f4f5f6; --bg-deep: #eceef1; --surface: #ffffff; --surface-2: #f8f9fa;
    --surface-3: #eef0f3; --surface-deep: #ffffff; --text: #191c20; --muted: #69717c;
    --micro: #69717c; --line: #dfe3e8; --line-soft: #e9ecf0; --line-strong: #c9ced5;
    --line-action: #b7c6d8; --accent: #1256b8; --accent-hover: #0f4a9f; --accent-ink: #ffffff;
    --accent-line: #1256b8; --accent-edge: #1256b8; --accent-soft: rgba(18, 86, 184, .18);
    --cyan: #1f6fa8; --success: #177b55; --success-strong: #177b55; --info: #1256b8;
    --warning: #9a5a00; --warning-text: #7d4900; --warning-icon: #9a5a00;
    --warning-border: rgba(154, 90, 0, .38); --warning-bg: #fff1da; --danger: #b32929;
    --track: #e4e7ec; --grid-line: transparent; --page-glow: transparent;
    --chrome-bg: rgba(255, 255, 255, .88); --panel-edge: #dfe3e8; --panel-fill: #ffffff;
    --tech-surface: #eef2f6; --tech-border: #b3c3d2; --tech-ink: #5d7488; --tech-index: #69717c;
    --tech-node-bg: #f4f7fa; --tech-node-border: #8fb4d4; --tech-node-fill: #ffffff;
    --tech-line: #8fa4b6; --tech-draw: #8ba0b4; --tech-draw-accent: #6f93b3; --tech-dot: #6f93b3;
    --tech-glow: rgba(35, 119, 199, 0); --tech-grid: rgba(18, 86, 184, .10);
    --field-border: #c9ced5; --field-label: #191c20; --field-lead: #69717c; --field-placeholder: #7a8290;
    --shadow: 0 20px 55px rgba(33, 38, 45, .10);
  }
}

* { box-sizing: border-box; }
html { min-width: 320px; background: var(--bg); }
body {
  margin: 0;
  min-height: 100vh;
  color: var(--text);
  background-color: var(--bg);
  /* Чертёжная сетка шагом 42px и мягкий блик — фон канона. Линии намеренно на
     грани видимости: они задают инженерный характер, а не рисунок. */
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px),
    radial-gradient(circle at 38% 48%, var(--page-glow), transparent 36%),
    linear-gradient(180deg, var(--bg) 0%, var(--bg-deep) 100%);
  background-size: 42px 42px, 42px 42px, 100% 100%, 100% 100%;
  background-attachment: fixed;
}
button, input, select { font: inherit; }
button, select { cursor: pointer; }
button:disabled, input:disabled, select:disabled { cursor: not-allowed; opacity: .55; }
a { color: inherit; }
.hidden { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.muted { color: var(--muted); line-height: 1.55; }
.compact { margin: 8px 0; font-size: 13px; }
.eyebrow { margin: 0 0 8px; color: var(--micro); font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: .16em; text-transform: uppercase; }
.mono { font-family: var(--mono); }
h1, h2, p { overflow-wrap: anywhere; }
h1 { margin: 0; font-size: clamp(26px, 3vw, 36px); line-height: 1.1; letter-spacing: -.03em; font-weight: 700; }
h2 { margin: 0; font-size: 20px; letter-spacing: -.015em; }

/* ── Экран входа ───────────────────────────────────────────────────────────
   Единственный экран, для которого есть утверждённый макет целиком: шапка со
   знаком, слева техническая идентичность, справа форма. Панель слева статична —
   декоративная анимация не должна притворяться загрузкой. */
.auth-view { min-height: 100vh; display: flex; flex-direction: column; }
.auth-topbar { display: flex; align-items: center; gap: 18px; min-height: 84px; padding: 0 30px; border-bottom: 1px solid var(--panel-edge); background: var(--chrome-bg); }
.auth-wordmark { font-size: clamp(20px, 2vw, 27px); font-weight: 700; letter-spacing: -.02em; }
.hex-mark { display: block; flex: 0 0 auto; width: 48px; height: 54px; }
.hex-mark svg { display: block; width: 100%; height: 100%; }
.mark-divider { flex: 0 0 auto; width: 1px; height: 30px; background: var(--line); }

.auth-workspace {
  flex: 1;
  width: 100%;
  max-width: 1440px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1.68fr) minmax(390px, 1fr);
  gap: 20px;
  padding: 36px 26px 28px;
}
.identity-panel, .login-panel {
  position: relative;
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--panel-edge);
  border-radius: var(--radius);
  background: var(--panel-fill);
}
.identity-panel { padding: clamp(30px, 4vw, 58px) clamp(20px, 2.4vw, 34px) 42px; }
.identity-grid {
  position: absolute;
  inset: 0;
  opacity: .14;
  background-image:
    linear-gradient(var(--tech-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--tech-grid) 1px, transparent 1px);
  background-size: 34px 34px;
}
.identity-content { position: relative; z-index: 2; height: 100%; display: flex; flex-direction: column; }
.identity-title-row { display: flex; align-items: center; gap: 22px; }
.title-rule { flex: 0 0 auto; width: 3px; height: 62px; border-radius: 999px; background: linear-gradient(180deg, transparent, var(--accent-line), transparent); }
.identity-title { margin: 0; font-size: clamp(28px, 2.9vw, 42px); line-height: 1.04; font-weight: 720; letter-spacing: -.035em; }
.micro-label { margin: clamp(22px, 3vw, 38px) 0 0; color: var(--micro); font-family: var(--mono); font-size: clamp(13px, 1.2vw, 17px); letter-spacing: .16em; }

.vin-rail { display: grid; grid-template-columns: repeat(17, minmax(0, 1fr)); gap: 6px; margin-top: 22px; }
.vin-cell-wrap { min-width: 0; }
.vin-cell {
  position: relative;
  height: clamp(56px, 7vw, 80px);
  display: grid;
  place-items: center;
  border: 1px solid var(--tech-border);
  border-radius: var(--radius-btn);
  color: var(--tech-ink);
  background-color: var(--tech-surface);
  /* Скобки стоят на всех четырёх углах ячейки: двумя псевдоэлементами больше
     двух углов не нарисовать, поэтому восемь фоновых слоёв — по две линии
     на угол. Псевдоэлементы у ячейки заняты быть не должны. */
  background-image:
    linear-gradient(currentColor, currentColor), linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor), linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor), linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor), linear-gradient(currentColor, currentColor);
  background-size: 7px 1px, 1px 7px, 7px 1px, 1px 7px, 7px 1px, 1px 7px, 7px 1px, 1px 7px;
  background-position:
    left 6px top 6px, left 6px top 6px,
    right 6px top 6px, right 6px top 6px,
    left 6px bottom 6px, left 6px bottom 6px,
    right 6px bottom 6px, right 6px bottom 6px;
  background-repeat: no-repeat;
}
.cell-cross {
  width: 13px;
  height: 13px;
  opacity: .35;
  background:
    linear-gradient(transparent 6px, currentColor 6px, currentColor 7px, transparent 7px),
    linear-gradient(90deg, transparent 6px, currentColor 6px, currentColor 7px, transparent 7px);
}
.vin-index { display: block; margin-top: 10px; color: var(--tech-index); font-family: var(--mono); font-size: clamp(10px, .95vw, 14px); text-align: center; }

.data-route { margin-top: clamp(26px, 3.4vw, 58px); display: grid; grid-template-columns: minmax(0, 186px) minmax(24px, 1fr) minmax(0, 186px) minmax(24px, 1fr) minmax(0, 186px); align-items: center; }
.route-node-shell { position: relative; min-width: 0; }
.route-glow { position: absolute; inset: -34px; opacity: .23; border-radius: 50%; background: radial-gradient(circle, var(--tech-glow), transparent 68%); pointer-events: none; }
.route-node-shell.terminal .route-glow { opacity: .15; }
.route-node {
  position: relative;
  z-index: 2;
  height: 70px;
  display: grid;
  place-items: center;
  border: 1px solid var(--tech-node-border);
  border-radius: var(--radius-sm);
  background: var(--tech-node-bg);
  color: var(--text);
  font-size: clamp(15px, 1.5vw, 22px);
  font-weight: 500;
}
.route-node-shell.terminal .route-node { border-color: var(--cyan); }
.route-line { width: 100%; height: 28px; overflow: visible; }
.route-line line { fill: none; stroke: var(--tech-line); stroke-width: 1.5; stroke-linecap: round; }
.route-line circle { fill: var(--tech-node-fill); stroke: var(--tech-line); stroke-width: 1.5; }

.circuit { margin-top: auto; padding-top: 26px; height: 172px; opacity: .64; }
.circuit svg { display: block; width: 100%; height: 146px; overflow: visible; }
.circuit-main { fill: none; stroke: var(--tech-draw); stroke-width: 1.2; }
.circuit-accent { fill: none; stroke: var(--tech-draw-accent); stroke-width: 1.3; }
.circuit-dashed { fill: none; stroke: var(--tech-draw); stroke-width: 1.2; stroke-dasharray: 7 5; }
.circuit-node { fill: var(--tech-node-fill); stroke: var(--tech-draw-accent); stroke-width: 1.2; }
.circuit-tick { stroke: var(--tech-draw); stroke-width: 1; }
.circuit-hatch { stroke: var(--tech-draw); stroke-width: 1; }
.circuit-dots { fill: var(--tech-dot); }

.login-panel { display: flex; align-items: stretch; }
.login-card { width: 100%; display: flex; flex-direction: column; justify-content: center; padding: clamp(30px, 5vw, 76px) clamp(22px, 3vw, 42px); }
.login-card h2 { font-size: clamp(30px, 3vw, 40px); line-height: 1; letter-spacing: -.035em; }
.login-lead { margin: 25px 0 clamp(26px, 4vw, 60px); color: var(--field-lead); font-size: clamp(16px, 1.4vw, 19px); }
.field { margin-top: 31px; }
.field:first-of-type { margin-top: 0; }
.field label { display: block; margin-bottom: 11px; color: var(--field-label); font-size: clamp(14px, 1.2vw, 17px); font-weight: 500; }
.input-shell { position: relative; height: clamp(56px, 6vw, 76px); display: flex; align-items: center; border: 1px solid var(--field-border); border-radius: var(--radius-sm); background: var(--surface-deep); }
.input-shell:focus-within { border-color: var(--accent-line); box-shadow: 0 0 0 3px var(--accent-soft); }
.input-shell input { width: 100%; height: 100%; min-height: 0; padding: 0 23px; border: 0; outline: 0; border-radius: var(--radius-sm); color: var(--text); background: transparent; font-size: clamp(16px, 1.3vw, 20px); }
.input-shell input:focus { box-shadow: none; }
.input-shell input::placeholder { color: var(--field-placeholder); }
.input-shell.with-eye input { padding-right: 62px; }
.eye { position: absolute; right: 22px; display: grid; place-items: center; width: 30px; height: 30px; padding: 0; border: 0; background: transparent; color: var(--muted); }
.eye:hover { color: var(--accent-line); }
.eye svg { display: block; width: 28px; height: 19px; }
.eye-slash { display: none; }
.eye[aria-pressed="true"] .eye-slash { display: block; }
.submit { width: 100%; height: clamp(54px, 6vw, 66px); margin-top: clamp(24px, 3vw, 42px); border: 1px solid var(--accent-edge); border-radius: var(--radius-btn); color: #fff; background: var(--accent); font-size: clamp(17px, 1.4vw, 21px); font-weight: 650; letter-spacing: .01em; transition: background .15s ease; }
.submit:hover:not(:disabled) { background: var(--accent-hover); }
.submit:active:not(:disabled) { transform: translateY(1px); }

/* ── Общие контролы ───────────────────────────────────────────────────────── */
label { display: grid; gap: 8px; color: var(--muted); font-size: 13px; font-weight: 600; }
input, select { width: 100%; min-height: 43px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface-deep); color: var(--text); padding: 10px 12px; outline: none; }
input:focus, select:focus { border-color: var(--accent-line); box-shadow: 0 0 0 3px var(--accent-soft); }
input[aria-invalid="true"] { border-color: var(--danger); }
/* Отступ между полем и кнопкой нужен только там, где они стоят стопкой — в
   диалоге настроек. Общее правило `label + label` раньше било по соседним
   меткам в сетках и в шапке: второй столбец формы, фильтр статуса и кнопку
   «Выйти» оно сдвигало вниз на 18px относительно соседей. */
.dialog-card label + .button { margin-top: 16px; }
label small { color: var(--muted); font-weight: 450; line-height: 1.35; }
.button { min-height: 42px; border: 1px solid var(--line-action); border-radius: var(--radius-btn); padding: 9px 15px; background: transparent; color: var(--text); font-weight: 650; transition: transform .15s ease, border-color .15s ease, background .15s ease; }
.button:hover:not(:disabled), .icon-button:hover:not(:disabled) { border-color: var(--accent-line); }
.button:active:not(:disabled) { transform: translateY(1px); }
.button.primary { border-color: var(--accent-edge); background: var(--accent); color: var(--accent-ink); }
.button.primary:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-edge); }
.button.quiet { border-color: var(--line); }
.button.link { border: 0; min-height: auto; padding: 4px; background: transparent; color: var(--accent-line); }
.button.danger { color: var(--danger); }
.button.wide { width: 100%; }
.form-error { margin: 12px 0 0; color: var(--danger); font-size: 13px; line-height: 1.45; }

.loading-shell { min-height: 100vh; display: grid; place-content: center; justify-items: center; color: var(--muted); }
.spinner { width: 34px; height: 34px; border: 3px solid var(--line); border-top-color: var(--accent-line); border-radius: 50%; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Шапка приложения ─────────────────────────────────────────────────────── */
.app-chrome { position: sticky; top: 0; z-index: 20; background: var(--chrome-bg); border-bottom: 1px solid var(--line); backdrop-filter: blur(18px); }
.topbar { min-height: 68px; max-width: 1280px; margin: 0 auto; padding: 10px 24px; display: flex; align-items: center; justify-content: space-between; gap: 18px; }
.brand { display: inline-flex; align-items: center; gap: 14px; text-decoration: none; min-width: max-content; }
.brand-mark { display: block; flex: 0 0 auto; width: 32px; height: 36px; }
.brand-divider { flex: 0 0 auto; width: 1px; height: 26px; background: var(--line); }
.brand b { display: block; font-size: 17px; font-weight: 700; letter-spacing: -.02em; }
.topbar-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; min-width: 0; }
.container-picker { display: flex; align-items: center; gap: 8px; min-width: 0; }
.container-picker span { white-space: nowrap; }
/* Длинное имя контейнера native-select обрезал по краю без многоточия —
   «…23.06.2026 · 2» вместо «· 26», и это читалось как неверное число. Chrome
   рисует ellipsis на select, если попросить явно. */
.container-picker select { width: min(280px, 26vw); text-overflow: ellipsis; }
.theme-picker select { width: 152px; }
.icon-button { width: 42px; height: 42px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: transparent; color: var(--text); font-size: 18px; }
.tabs { max-width: 1280px; margin: 0 auto; padding: 0 24px; display: flex; gap: 24px; overflow-x: auto; scrollbar-width: none; }
.tabs button { position: relative; min-height: 46px; border: 0; padding: 0 1px; background: transparent; color: var(--muted); font-weight: 650; white-space: nowrap; }
.tabs button[aria-selected="true"] { color: var(--text); }
.tabs button[aria-selected="true"]::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--accent-line); }
.count-badge { display: inline-grid; place-items: center; min-width: 20px; height: 20px; margin-left: 4px; padding: 0 5px; border-radius: 99px; background: var(--surface-3); font-family: var(--mono); font-size: 11px; }

/* ── Экраны ───────────────────────────────────────────────────────────────── */
.main { max-width: 1280px; margin: 0 auto; padding: 42px 24px 80px; }
.page-heading { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 28px; }
.page-heading .muted { margin: 10px 0 0; max-width: 720px; }
.page-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.panel { min-width: 0; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); padding: 22px; }
.panel-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; margin-bottom: 18px; }
.metric-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 14px; }
.metric { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); padding: 21px; }
.metric span, .metric small { display: block; color: var(--muted); }
.metric span { font-size: 13px; font-weight: 650; }
.metric strong { display: block; margin: 14px 0 8px; font-size: 34px; }
.metric small { font-size: 12px; }
.metric.success strong { color: var(--success); }
.metric.attention strong { color: var(--warning); }
.overview-grid { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(280px, .65fr); gap: 14px; }
.attention-list { display: grid; gap: 8px; }
.attention-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px; padding: 13px 0; border-top: 1px solid var(--line-soft); }
.attention-item:first-child { border-top: 0; }
.attention-item b, .attention-item small { display: block; }
.attention-item small { margin-top: 4px; color: var(--muted); font-family: var(--mono); font-size: 12px; }
.download-panel { display: flex; flex-direction: column; align-items: flex-start; }
.download-panel .muted { flex: 1; }
.download-icon { display: grid; place-items: center; width: 44px; height: 44px; margin-bottom: 22px; border-radius: 8px; background: var(--surface-3); color: var(--accent-line); font-size: 24px; }
.empty { margin: 24px 0 0; color: var(--muted); text-align: center; }

.workflow-grid { display: grid; grid-template-columns: minmax(0, 1fr) 300px; align-items: start; gap: 14px; }
.workflow-main { grid-column: 1; }
.workflow-summary { grid-column: 2; position: sticky; top: 142px; }
.form-grid { display: grid; grid-template-columns: minmax(0, 1fr) 186px; gap: 14px; margin-bottom: 16px; }
.field-shell { position: relative; display: block; }
.vin-field input { font-family: var(--mono); font-size: 18px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; padding-right: 44px; }
/* Галка появляется только на полном допустимом VIN: это подтверждение ввода, а
   не украшение, и до семнадцатого символа подтверждать нечего. */
.vin-valid { position: absolute; top: 50%; right: 13px; width: 20px; height: 20px; margin-top: -10px; color: var(--success); pointer-events: none; }
.vin-valid svg { display: block; width: 100%; height: 100%; }
/* Степпер предела: одна рамка, сегменты разделены линиями, число по центру.
   Поле остаётся числовым — с клавиатуры значение вводится напрямую. */
.stepper { display: grid; grid-template-columns: 42px minmax(0, 1fr) 42px; align-items: stretch; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface-deep); overflow: hidden; }
.stepper:focus-within { border-color: var(--accent-line); box-shadow: 0 0 0 3px var(--accent-soft); }
.stepper input { min-height: 41px; border: 0; border-radius: 0; background: transparent; text-align: center; font-family: var(--mono); font-weight: 700; appearance: textfield; -moz-appearance: textfield; }
.stepper input:focus { box-shadow: none; }
.stepper input::-webkit-outer-spin-button, .stepper input::-webkit-inner-spin-button { appearance: none; margin: 0; }
.stepper-step { border: 0; background: transparent; color: var(--muted); font-size: 19px; line-height: 1; }
.stepper-step:first-child { border-right: 1px solid var(--line); }
.stepper-step:last-child { border-left: 1px solid var(--line); }
.stepper-step:hover:not(:disabled) { color: var(--text); background: var(--surface-3); }
.heading-aside { display: flex; align-items: center; gap: 16px; }
/* Тормозной диск — единственная предметная графика экрана узлов: тонкая линия,
   без заливки и анимации. Вектора в поставке макетов не было, нарисован здесь. */
.rotor-mark { display: block; flex: 0 0 auto; width: 76px; height: 76px; opacity: .55; }
.rotor-mark svg { display: block; width: 100%; height: 100%; fill: none; stroke: var(--tech-draw-accent); stroke-width: 1; }
@media (max-width: 680px) { .rotor-mark { display: none; } }
.notice { border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px; line-height: 1.45; }
.notice.info { display: flex; gap: 10px; margin-bottom: 20px; color: var(--muted); font-size: 13px; }
.notice.info::before { content: "i"; flex: 0 0 auto; display: grid; place-items: center; width: 17px; height: 17px; margin-top: 1px; border: 1px solid var(--accent-line); border-radius: 50%; color: var(--accent-line); font-family: var(--mono); font-size: 11px; font-weight: 700; }
.notice.warning { display: flex; gap: 11px; border-color: var(--warning-border); background: var(--warning-bg); color: var(--warning-text); }
/* Треугольник-иконка канона: янтарь предупреждает и больше нигде не встречается. */
.notice.warning::before { content: ""; flex: 0 0 auto; width: 0; height: 0; margin-top: 4px; border-left: 8px solid transparent; border-right: 8px solid transparent; border-bottom: 14px solid var(--warning-icon); }
.candidate-list { display: grid; gap: 10px; }
.candidate-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px; align-items: center; padding: 15px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface-2); }
.candidate-card h3 { margin: 0 0 9px; font-size: 16px; }
.candidate-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; color: var(--muted); font-size: 12px; }
/* Территория — главный различитель одинаковых названий: у Cadillac CTS Sedan
   каталог отдаёт две карточки, где отличается только она. Поэтому чип, а не
   мелкая серая подпись в общем ряду. */
.chip-region { display: inline-flex; align-items: center; gap: 8px; padding: 3px 10px; border: 1px solid var(--line-action); border-radius: 6px; color: var(--text); font-size: 12px; }
.chip-region b { color: var(--accent-line); font-family: var(--mono); font-size: 15px; font-weight: 700; letter-spacing: .04em; }
.chip-option { display: inline-flex; padding: 3px 8px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface-3); color: var(--text); font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: .06em; }
.match-wrap { position: relative; display: inline-flex; }
.match-chip { display: inline-flex; align-items: center; gap: 7px; min-height: 26px; padding: 3px 10px; border: 1px solid var(--line-action); border-radius: 99px; background: transparent; color: var(--text); font-size: 12px; font-weight: 650; }
.match-chip b { font-family: var(--mono); }
.match-chip::after { content: "i"; display: grid; place-items: center; width: 15px; height: 15px; border: 1px solid var(--accent-line); border-radius: 50%; color: var(--accent-line); font-family: var(--mono); font-size: 10px; font-weight: 700; }
.match-chip[aria-expanded="true"] { border-color: var(--accent-line); }
/* Разбор совпадения: карточка с выноской к самому чипу. Всплывает по клику, а
   не по наведению — на телефоне наведения нет. */
.match-popover { position: absolute; z-index: 30; top: calc(100% + 10px); left: 0; width: max(260px, 100%); padding: 15px 16px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-2); box-shadow: var(--shadow); }
.match-popover::before { content: ""; position: absolute; top: -6px; left: 22px; width: 10px; height: 10px; border-left: 1px solid var(--line); border-top: 1px solid var(--line); background: var(--surface-2); transform: rotate(45deg); }
.match-popover h4 { margin: 0 0 12px; font-size: 13px; font-weight: 650; }
.match-popover dl { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 9px 14px; margin: 0; font-size: 12px; }
.match-popover dt { color: var(--muted); }
.match-popover dd { margin: 0; font-family: var(--mono); text-align: right; white-space: nowrap; }
.match-popover dd.miss { color: var(--muted); }
.match-popover dt.total, .match-popover dd.total { margin-top: 3px; padding-top: 12px; border-top: 1px solid var(--line); color: var(--text); font-weight: 700; }
.match-caveat { display: flex; gap: 9px; margin: 13px 0 0; color: var(--warning-text); font-size: 12px; line-height: 1.4; }
.match-caveat::before { content: ""; flex: 0 0 auto; width: 0; height: 0; margin-top: 3px; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 11px solid var(--warning-icon); }
/* На узком экране разбор встаёт в поток под чипом, а не всплывает над карточкой.
   Замер на живых данных, 390px: чип стоял на left 135, попап шириной 260 давал
   правый край 395 при вьюпорте 390. Виноваты длинные названия комплектаций —
   на коротких стендовых чип переносился на свою строку и вылета не было.
   Порог тот же, на котором раскладка и так схлопывается в столбец. */
@media (max-width: 900px) {
  .match-wrap { display: block; width: 100%; }
  .match-popover { position: static; width: auto; margin-top: 10px; box-shadow: none; }
  .match-popover::before { display: none; }
}
.node-toolbar, .machine-toolbar { display: flex; align-items: center; gap: 10px; }
.search-field { flex: 1; min-width: 170px; }
.nodes-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); max-height: 540px; overflow: auto; border-top: 1px solid var(--line); }
.node-option { position: relative; display: flex; align-items: flex-start; gap: 11px; min-width: 0; padding: 11px 8px 11px 10px; border-bottom: 1px solid var(--line-soft); color: var(--text); font-size: 13px; font-weight: 500; }
/* Отмеченная строка получает вертикальную акцентную полосу слева. Там, где
   :has не поддерживается, полосы просто нет — сам выбор от этого не страдает. */
.node-option:has(input:checked)::before { content: ""; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px; border-radius: 2px; background: var(--accent-line); }
.node-option input { flex: 0 0 auto; width: 22px; height: 22px; min-height: 0; margin: 0; padding: 0; appearance: none; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface-deep); }
.node-option input:checked { border-color: var(--accent); background: var(--accent); }
.node-option input:checked::after { content: ""; display: block; width: 5px; height: 10px; margin: 3px auto 0; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.node-option input:focus-visible { outline: 0; border-color: var(--accent-line); box-shadow: 0 0 0 3px var(--accent-soft); }
.node-option span { min-width: 0; }
/* Размер узла показывается только при повторном сборе той же машины — это
   измерение прошлого прогона, а не оценка. До первого сбора колонки нет. */
.node-option .node-size { margin-left: auto; padding-left: 12px; color: var(--muted); font-family: var(--mono); font-size: 12px; white-space: nowrap; }
.status-legend { margin: 22px 0 0; padding-top: 18px; border-top: 1px solid var(--line-soft); }
.status-legend ul { display: grid; gap: 9px; margin: 0; padding: 0; list-style: none; }
.status-legend li { display: flex; align-items: center; gap: 12px; color: var(--muted); font-size: 12px; line-height: 1.4; }
.status-legend .status { flex: 0 0 auto; min-width: 108px; justify-content: center; }

.selection-number { display: flex; align-items: baseline; gap: 10px; }
.selection-number strong { font-size: 48px; line-height: 1; font-weight: 700; }
.selection-number span { color: var(--muted); font-size: 19px; }
.budget { display: grid; gap: 9px; margin: 26px 0 12px; }
.budget-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; color: var(--muted); font-size: 12px; }
.budget-head b { color: var(--text); font-family: var(--mono); font-weight: 700; }
.budget > strong { font-size: 20px; font-weight: 650; }
.budget > strong b { color: var(--accent-line); }
/* Полоса расхода: процент печатается текстом внутри заливки, а не только её
   шириной. На узкой заливке подпись не помещается и выносится вправо. */
.budget-track { position: relative; display: block; height: 28px; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-btn); background: var(--track); }
.budget-track em { position: absolute; top: 0; bottom: 0; left: 0; display: flex; align-items: center; justify-content: flex-end; width: 0; background: var(--accent); transition: width .25s ease; }
.budget-track em span { padding: 0 9px; color: #fff; font-family: var(--mono); font-size: 12px; font-weight: 700; font-style: normal; }
.budget-track em.narrow { overflow: visible; }
.budget-track em.narrow span { position: absolute; left: 100%; padding: 0 0 0 9px; color: var(--muted); }
.budget.over .budget-track em { background: var(--danger); }
.budget-reserve { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.45; }
.budget-reserve b { color: var(--success-strong); font-family: var(--mono); font-weight: 700; }
.budget.over .budget-reserve b { color: var(--danger); }
.progress { display: block; height: 8px; overflow: hidden; border-radius: 99px; background: var(--track); }
.progress i { display: block; width: 0; height: 100%; background: var(--accent); transition: width .25s ease; }
.run-metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin: 20px 0; }
.run-metrics div { padding: 16px; border-radius: 8px; background: var(--surface-2); }
.run-metrics span, .run-metrics strong { display: block; }
.run-metrics span { color: var(--muted); font-size: 12px; }
.run-metrics strong { margin-top: 9px; font-family: var(--mono); font-size: 24px; font-weight: 700; }

.machine-toolbar { flex-wrap: wrap; margin-bottom: 18px; }
.machine-toolbar .search-field { margin-left: auto; max-width: 330px; }
.segmented { display: inline-flex; padding: 3px; border: 1px solid var(--line); border-radius: 6px; background: var(--surface-2); }
.segmented button { min-height: 34px; border: 0; border-radius: var(--radius-btn); padding: 6px 11px; background: transparent; color: var(--muted); font-weight: 650; }
.segmented button[aria-pressed="true"] { background: var(--surface-3); color: var(--text); }
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 13px 10px; border-top: 1px solid var(--line-soft); text-align: left; vertical-align: middle; }
th { border-top: 0; color: var(--muted); font-size: 12px; font-weight: 600; }
td { font-size: 13px; }
.machine-title { display: grid; gap: 5px; }
.machine-title small, .mono { color: var(--muted); font-family: var(--mono); font-size: 12px; }
.machine-title small { letter-spacing: .06em; }
.machine-actions { display: flex; justify-content: flex-end; gap: 6px; flex-wrap: wrap; }
.machine-actions .button { min-height: 34px; padding: 6px 10px; font-size: 12px; }
/* Бейджи статусов: пилюля с точкой, цвет несёт смысл. «Не готово» жёлтое, а не
   серое — метка должна мозолить глаз, иначе клиент её не заметит. */
.status { display: inline-flex; align-items: center; gap: 7px; min-height: 25px; border: 1px solid currentColor; border-radius: 99px; padding: 3px 10px; background: transparent; color: var(--muted); font-size: 11px; font-weight: 700; white-space: nowrap; }
.status::before { content: ""; flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
.status.done { color: var(--success); }
.status.partial { color: var(--info); }
.status.new { color: var(--warning); }
.status.collecting { color: var(--cyan); }
.status.failed { color: var(--danger); }
.machine-cards { display: none; }

dialog { width: min(520px, calc(100vw - 28px)); max-height: calc(100vh - 28px); border: 0; padding: 0; border-radius: var(--radius); background: transparent; color: var(--text); }
dialog::backdrop { background: rgba(0, 0, 0, .62); backdrop-filter: blur(3px); }
.dialog-card { width: 100%; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); padding: clamp(22px, 4vw, 32px); box-shadow: var(--shadow); }
.dialog-card hr { margin: 26px 0; border: 0; border-top: 1px solid var(--line); }
.toast { position: fixed; z-index: 50; right: 22px; bottom: 22px; max-width: min(420px, calc(100vw - 32px)); padding: 13px 16px; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--surface-3); box-shadow: var(--shadow); font-size: 13px; }

/* Ниже опорной ширины макета левая панель входа не помещается: 17 ячеек рейки
   становятся нечитаемой кашей. Макетов для узких экранов не существует, поэтому
   панель убирается целиком, а форма остаётся ровно такой же. */
@media (max-width: 1080px) {
  .auth-workspace { grid-template-columns: minmax(0, 1fr); max-width: 620px; align-content: center; }
  .identity-panel { display: none; }
}

@media (max-width: 900px) {
  .topbar { align-items: flex-start; }
  .topbar-actions { flex-wrap: wrap; }
  .container-picker { order: 2; width: 100%; }
  .container-picker select { width: 100%; }
  .theme-picker select { width: 130px; }
  .overview-grid, .workflow-grid { grid-template-columns: 1fr; }
  /* Когда панели встают в столбик, книга должна быть первой: ради неё клиент и
     заходит. Иначе кнопка «Скачать» уезжает почти на два экрана вниз, под
     список «Что требует внимания». */
  .download-panel { order: -1; }
  .workflow-main, .workflow-summary { grid-column: 1; }
  .workflow-summary { position: static; }
  .nodes-list { grid-template-columns: 1fr; }
}

@media (max-width: 680px) {
  /* Только на узких экранах: Safari на iOS зумит страницу при фокусе поля мельче
     16px. На десктопе это правило ломало макетные компактные контролы — селекты
     в шапке распухали и «Системная тема» переставала помещаться, — поэтому оно
     живёт здесь, а не в общих стилях. */
  input, select, textarea { font-size: 16px; }
  .auth-topbar { min-height: 64px; padding: 0 18px; gap: 14px; }
  .hex-mark { width: 36px; height: 40px; }
  .mark-divider { height: 24px; }
  .auth-workspace { padding: 18px; }
  .topbar { padding: 10px 14px; flex-wrap: wrap; }
  .brand-divider, .container-picker > span { display: none; }
  .brand-mark { width: 28px; height: 32px; }
  .brand b { font-size: 15px; }
  .topbar-actions {
    width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-areas: "theme settings logout" "container container container";
  }
  .container-picker { grid-area: container; width: 100%; }
  #settings-open { grid-area: settings; }
  .theme-picker { grid-area: theme; min-width: 0; }
  .theme-picker select { width: 100%; }
  #logout { grid-area: logout; }
  .tabs { padding: 0 14px; gap: 22px; }
  .main { padding: 28px 14px 64px; }
  .page-heading { align-items: flex-start; flex-direction: column; }
  .page-heading > .button { width: 100%; }
  /* На телефоне клиент заходит ровно за файлом. Поднимаем панель книги сразу под
     заголовок — выше плиток и блока внимания, — чтобы «Скачать .xlsx» попадала на
     первый экран, а не пряталась за метриками и списком проблем. */
  #view-overview { display: flex; flex-direction: column; }
  #view-overview .page-heading { order: 0; }
  #view-overview .overview-grid { order: 1; }
  #view-overview .metric-grid { order: 2; }
  .metric-grid { grid-template-columns: 1fr 1fr; }
  .metric:first-child { grid-column: 1 / -1; }
  .metric { padding: 16px; }
  .panel { padding: 17px; }
  .form-grid { grid-template-columns: 1fr; }
  .node-toolbar { align-items: stretch; flex-wrap: wrap; }
  .node-toolbar .search-field { flex-basis: 100%; }
  .run-metrics { grid-template-columns: 1fr; }
  .machine-toolbar { align-items: stretch; }
  .machine-toolbar .search-field { order: 3; flex-basis: 100%; max-width: none; }
  .segmented { flex: 1; }
  .segmented button { flex: 1; }
  .table-wrap { display: none; }
  .machine-cards { display: grid; gap: 10px; }
  .machine-card { padding: 15px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface-2); }
  .machine-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
  .machine-card .mono { display: block; margin: 8px 0 13px; }
  .machine-card-stats { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-bottom: 14px; color: var(--muted); font-size: 12px; }
  .machine-actions { justify-content: flex-start; }
  .candidate-card { grid-template-columns: 1fr; }
  .candidate-card .button { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* Справочник. Список правится по одному и вставляется пачкой — оба способа
   клиент просил явно, поэтому они рядом, а не в разных местах экрана. */
.glossary-add { display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.glossary-single { flex: 1 1 280px; }
.glossary-single input { width: 100%; }
.glossary-bulk { flex-basis: 100%; }
.glossary-bulk summary { cursor: pointer; color: var(--muted); font-size: 13px; font-weight: 650; }
.glossary-bulk textarea { width: 100%; margin: 10px 0; font-family: var(--mono); font-size: 12px; }
.glossary-list { display: grid; gap: 6px; margin: 12px 0 0; padding: 0; list-style: none; }
.glossary-list li { display: flex; align-items: center; justify-content: space-between; gap: 10px; border: 1px solid var(--line-soft); border-radius: var(--radius-btn); padding: 7px 8px 7px 12px; font-size: 13px; }
.glossary-list li span { overflow-wrap: anywhere; }
/* Сводка неприменённого. Панель существует, только когда есть что применять:
   пустая плашка «изменений нет» приучает её не замечать. */
.glossary-diff { display: grid; gap: 6px; margin: 12px 0 0; padding: 0; list-style: none; color: var(--muted); font-size: 13px; }
