/* ANCOL CTIS web: the only stylesheet. Served from our own origin (plan §10.7): no inline style, no CDN, no web
   fonts. Every colour that means something comes with a word, so no state depends on colour alone.

   The look, on purpose: flat surfaces split by lines and space, one small corner radius, shadows only on what
   floats (menu, sheet, toast), sentence-case labels, status as a word with a small square, never a pill. Colour
   is for the wheels' states and for what needs someone; everything else is neutral (high-performance HMI, ISA-101).

   Contents: 1 tokens · 2 base · 3 app shell · 4 page parts · 5 controls · 6 data · 7 fleet · 8 live panel ·
   9 commands · 10 playback · 11 sign-in pages · 12 motion */

/* 1 ─ Tokens ─────────────────────────────────────────────────────────────────────────────────────────────── */
/* The app's palette (app/ui/theme/Color.kt): deep navy chrome and a cyan accent, steel-blue for quiet controls,
   so the state colours of the wheels stay the loudest thing on screen. */
:root {
  color-scheme: light dark;
  --bg: #f3f6fa;
  --surface: #ffffff;
  --surface-2: #f1f4f9;
  --hover: #e9eef4;
  --border: #dce3eb;
  --border-strong: #c0c7cf;
  --text: #171c22;
  --text-2: #40484f;
  --text-3: #5d6873;
  --accent: #00687a;
  --accent-hover: #00525f;
  --accent-soft: #dff4f8;
  --on-accent: #ffffff;
  --focus: #00839a;
  --steel-soft: #d6e4f7;
  --on-steel: #0a1d31;

  --ok: #157a3d;
  --ok-bg: #e6f4ea;
  --ok-line: #8fcca3;
  --attention: #9a5b00;
  --attention-bg: #fdf1dc;
  --attention-line: #e8b866;
  --alarm: #b4232a;
  --alarm-bg: #fde9e9;
  --alarm-line: #ec9a9d;
  --neutral: #5b6472;
  --neutral-bg: #eef0f3;
  --neutral-line: #ccd1d8;

  /* Wheel fills, as on the app (TireColors), a step deeper so white text on them stays readable. */
  --tire-ok: #23824a;
  --tire-inflating: #2b6cb0;
  --tire-deflating: #0a7f8c;
  --tire-holding: #6e52a0;
  --tire-attention: #e8a31b;
  --tire-on-attention: #2a1800;
  --tire-offline: #5b687c;
  --tire-alarm: #c62f2f;
  --tire-selected: #ffc400;
  --rig-bg: #e6ecf3;
  --rig-body: #f7f9fc;
  /* The vehicle drawing's lines and words: near black on light, so the plan reads at a glance on a bright screen. */
  --rig-line: #1f262e;
  --rig-ink: #171c22;

  --nav-bg: #0a1420;
  --nav-text: #b9c8d8;
  --nav-text-strong: #ffffff;
  --nav-hover: #14212f;
  --nav-active: #1b2938;
  --nav-muted: #7e93a6;

  --chart-1: #00687a; --chart-2: #c2410c; --chart-3: #15803d; --chart-4: #7c3aed; --chart-5: #2b6cb0;
  --chart-6: #be185d; --chart-7: #a16207; --chart-8: #475569;

  --radius: 0.375rem;
  --radius-sm: 0.25rem;
  --shadow: none;
  --shadow-pop: 0 0.625rem 1.75rem rgb(10 20 32 / 16%), 0 1px 0.1875rem rgb(10 20 32 / 8%);
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono", Consolas, monospace;
  --sidebar-width: 15.5rem;
  --tabbar-height: 3.75rem;
}

/* Dark: chosen in the account menu (data-theme="dark" on <html>, set by static/web/theme.js), or the system's
   choice while nothing is chosen. The two blocks hold the same tokens; tests/web/test_theme.py keeps them so. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0a1420;
    --surface: #101c2a;
    --surface-2: #14212f;
    --hover: #1b2938;
    --border: #22354a;
    --border-strong: #33475c;
    --text: #e0e7ef;
    --text-2: #b9c8d8;
    --text-3: #8da0b3;
    --accent: #56c8de;
    --accent-hover: #84d8e8;
    --accent-soft: #0e3540;
    --on-accent: #00363f;
    --focus: #56c8de;
    --steel-soft: #274b66;
    --on-steel: #dceaf7;

    --ok: #4cc47a;
    --ok-bg: #0f2a1e;
    --ok-line: #2a6a42;
    --attention: #f0aa45;
    --attention-bg: #2b2111;
    --attention-line: #7a5718;
    --alarm: #ff8a80;
    --alarm-bg: #33161b;
    --alarm-line: #87383b;
    --neutral: #a0afbf;
    --neutral-bg: #1b2938;
    --neutral-line: #33475c;

    --rig-bg: #0d1825;
    --rig-body: #14212f;
    --rig-line: #33475c;
    --rig-ink: #b9c8d8;

    --nav-bg: #050c14;
    --nav-hover: #101c2a;
    --nav-active: #1b2938;

    --chart-1: #56c8de; --chart-2: #fb923c; --chart-3: #4ade80; --chart-4: #a78bfa; --chart-5: #6aa1ff;
    --chart-6: #f472b6; --chart-7: #facc15; --chart-8: #94a3b8;

    --shadow: none;
    --shadow-pop: 0 0.75rem 2rem rgb(0 0 0 / 55%), 0 1px 0.1875rem rgb(0 0 0 / 40%);
  }
}
:root[data-theme="dark"] {
  --bg: #0a1420;
  --surface: #101c2a;
  --surface-2: #14212f;
  --hover: #1b2938;
  --border: #22354a;
  --border-strong: #33475c;
  --text: #e0e7ef;
  --text-2: #b9c8d8;
  --text-3: #8da0b3;
  --accent: #56c8de;
  --accent-hover: #84d8e8;
  --accent-soft: #0e3540;
  --on-accent: #00363f;
  --focus: #56c8de;
  --steel-soft: #274b66;
  --on-steel: #dceaf7;

  --ok: #4cc47a;
  --ok-bg: #0f2a1e;
  --ok-line: #2a6a42;
  --attention: #f0aa45;
  --attention-bg: #2b2111;
  --attention-line: #7a5718;
  --alarm: #ff8a80;
  --alarm-bg: #33161b;
  --alarm-line: #87383b;
  --neutral: #a0afbf;
  --neutral-bg: #1b2938;
  --neutral-line: #33475c;

  --rig-bg: #0d1825;
  --rig-body: #14212f;
  --rig-line: #33475c;
  --rig-ink: #b9c8d8;

  --nav-bg: #050c14;
  --nav-hover: #101c2a;
  --nav-active: #1b2938;

  --chart-1: #56c8de; --chart-2: #fb923c; --chart-3: #4ade80; --chart-4: #a78bfa; --chart-5: #6aa1ff;
  --chart-6: #f472b6; --chart-7: #facc15; --chart-8: #94a3b8;

  --shadow: none;
  --shadow-pop: 0 0.75rem 2rem rgb(0 0 0 / 55%), 0 1px 0.1875rem rgb(0 0 0 / 40%);
}
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

/* 2 ─ Base ───────────────────────────────────────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
/* Sizes are in rem (1rem = 16px at the browser's default), so the whole page grows with the root size: on wide
   screens it grows in steps, the way browser zoom would, instead of a small page in a sea of empty space. Below
   1680px nothing changes. Media conditions stay in px: they describe the screen, which the root size doesn't change. */
@media (min-width: 1680px) { html { font-size: 112.5%; } }
@media (min-width: 2000px) { html { font-size: 125%; } }
@media (min-width: 2400px) { html { font-size: 137.5%; } }
body {
  margin: 0;
  font: 0.9375rem/1.5 var(--font);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3 { margin: 0; line-height: 1.25; }
h1 { font-size: 1.375rem; font-weight: 650; letter-spacing: -0.01em; }
h2 { font-size: 0.9375rem; font-weight: 640; }
h3 { font-size: 0.8125rem; font-weight: 640; }
p { margin: 0 0 0.75rem; }
p:last-child { margin-bottom: 0; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }
code, pre, .mono { font-family: var(--mono); font-size: 0.92em; }
code { padding: 1px 0.3125rem; border-radius: 0.1875rem; background: var(--neutral-bg); overflow-wrap: anywhere; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 0.25rem; }
.icon { flex: none; width: 1.125rem; height: 1.125rem; }
.muted { color: var(--text-3); }
.num { font-variant-numeric: tabular-nums; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.skip { position: absolute; left: 0.5rem; top: -3rem; z-index: 50; padding: 0.5rem 0.75rem; border-radius: var(--radius-sm);
  background: var(--surface); box-shadow: var(--shadow-pop); }
.skip:focus { top: 0.5rem; }

/* 3 ─ App shell: sidebar on wide screens; top bar and bottom tab bar on phones ────────────────────────────── */
.app { min-height: 100vh; }
.sidebar { display: none; }
.page { min-width: 0; }
.content { width: 100%; max-width: 80rem; margin: 0 auto; padding: 1.25rem 1rem 3rem; container-type: inline-size; }
.has-tabbar .content { padding-bottom: calc(var(--tabbar-height) + 2.5rem + env(safe-area-inset-bottom)); }

.brand { display: inline-flex; align-items: center; gap: 0.625rem; color: var(--nav-text-strong); font-weight: 700;
  letter-spacing: 0.02em; }
.brand:hover { text-decoration: none; }
.brand-mark { width: 1.875rem; height: 1.875rem; flex: none; border-radius: 0.375rem; }
.brand-word { font-size: 0.9375rem; }
.brand-word span { font-weight: 450; color: var(--nav-muted); margin-left: 0.25rem; }

.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 0.75rem;
  min-height: 3.5rem; padding: 0.5rem 0.75rem 0.5rem 1rem;
  background: var(--nav-bg); color: var(--nav-text);
}
.topbar-home { display: inline-flex; flex: none; }
.topbar-home:hover { text-decoration: none; }
/* Where you are: the fleet (a way back to all fleets), "Platform" or "Fleets". */
.topbar-context { flex: 1; min-width: 0; display: flex; align-items: center; gap: 0.375rem;
  color: var(--nav-text-strong); font-size: 0.9375rem; font-weight: 650; }
.topbar-context > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar-context .icon { flex: none; width: 1rem; height: 1rem; color: var(--nav-muted); }
a.topbar-context:hover { color: var(--nav-text-strong); text-decoration: none; }
a.topbar-context:hover .icon { color: var(--nav-text-strong); }
/* The super admin's way to the platform on phones (the sidebar has it on wide screens). */
.topbar-button { display: inline-flex; flex: none; align-items: center; gap: 0.375rem; padding: 0.375rem 0.625rem;
  border: 1px solid #2b3540; border-radius: var(--radius-sm); color: var(--nav-text); font-size: 0.8125rem; font-weight: 600; }
.topbar-button .icon { width: 1.0625rem; height: 1.0625rem; color: var(--nav-muted); }
.topbar-button:hover { background: var(--nav-hover); color: var(--nav-text-strong); text-decoration: none; }
.topbar-button[aria-current="page"] { border-color: var(--accent); color: var(--nav-text-strong); }
.topbar-button[aria-current="page"] .icon { color: var(--accent); }
/* A page below a list (web/_topbar_back.html): its way back and its title instead of the logo and the fleet. */
.topbar-back { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 2.5rem; height: 2.5rem;
  margin-left: -0.5rem; border-radius: var(--radius-sm); color: var(--nav-text-strong); }
.topbar-back:hover { background: var(--nav-hover); text-decoration: none; }
.topbar-back .icon { width: 1.375rem; height: 1.375rem; }
.topbar-title { flex: 1; min-width: 0; display: flex; align-items: center; gap: 0.5rem; margin: 0;
  color: var(--nav-text-strong); font-size: 1.0625rem; font-weight: 700; }
.topbar-title > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar-title .plate { flex: none; border-color: #2b3540; color: var(--nav-text-strong); font-size: 0.8125rem; }
/* There, while the top bar shows (below 960px), the page leaves out its own crumb and title: one way back, one
   heading. The super admin's switch waits for the list page, which keeps the bar from crowding a long name. */
@media (max-width: 959px) {
  .page:has(.topbar-back) .topbar-button,
  .page:has(.topbar-back) .page-head .back-link,
  .page:has(.topbar-back) .page-head h1,
  .page:has(.topbar-back) .page-head--vehicle .title-crumb,
  .page:has(.topbar-back) .page-head--vehicle .title-crumb-sep,
  .page:has(.topbar-back) .page-head--vehicle .plate,
  .page:has(.topbar-back) .page-head--vehicle:not(:has(.tag)) { display: none; }
}

.tabbar {
  position: fixed; inset: auto 0 0; z-index: 20;
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  height: calc(var(--tabbar-height) + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--surface); border-top: 1px solid var(--border);
}
/* Icons on one line; a name too long for its share of the width ("Превозни средства") takes two lines. */
.tabbar .nav-link {
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 0.1875rem;
  padding: 0.5rem 2px 0.25rem; color: var(--text-3); font-size: 0.6875rem; font-weight: 560; line-height: 1.12; text-align: center;
}
.tabbar .nav-link .icon { flex: none; width: 1.375rem; height: 1.375rem; }
.tabbar .nav-link:hover { text-decoration: none; color: var(--text); }
.tabbar .nav-link[aria-current="page"] { color: var(--accent); }
.tabbar .nav-label { display: -webkit-box; max-width: 100%; overflow: hidden; overflow-wrap: anywhere;
  -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; }
/* A long section name has a short one for the bottom bar. */
.tabbar .nav-label--long, .sidebar .nav-label--short { display: none; }

@media (min-width: 960px) {
  .app { display: grid; grid-template-columns: var(--sidebar-width) minmax(0, 1fr); }
  .sidebar {
    position: sticky; top: 0; height: 100vh; overflow-y: auto;
    display: flex; flex-direction: column; gap: 0.25rem;
    padding: 1.125rem 0.75rem 0.75rem; background: var(--nav-bg); color: var(--nav-text);
  }
  .topbar, .tabbar { display: none; }
  .content, .has-tabbar .content { padding: 1.75rem 2rem 4rem; }
  h1 { font-size: 1.5rem; }
}

.sidebar .brand { padding: 2px 0.5rem 1.125rem; }
.nav-group { display: grid; gap: 2px; margin-bottom: 0.875rem; }
.nav-heading { padding: 0 0.625rem 0.375rem; font-size: 0.78125rem; font-weight: 600; color: var(--nav-muted); }
.sidebar .nav-link {
  position: relative; display: flex; align-items: center; gap: 0.625rem;
  padding: 0.5rem 0.625rem; border-radius: var(--radius-sm);
  color: var(--nav-text); font-size: 0.875rem; font-weight: 520;
}
.sidebar .nav-link:hover { background: var(--nav-hover); color: var(--nav-text-strong); text-decoration: none; }
.sidebar .nav-link[aria-current="page"] { background: var(--nav-active); color: var(--nav-text-strong); }
.sidebar .nav-link .icon { color: var(--nav-muted); }
.sidebar .nav-link[aria-current="page"] .icon, .sidebar .nav-link:hover .icon { color: var(--nav-text-strong); }

.fleet-switch { display: block; margin: 0 0 0.875rem; padding: 0.625rem; border: 1px solid #262e38; border-radius: var(--radius);
  color: var(--nav-text-strong); }
.fleet-switch:hover { background: var(--nav-hover); text-decoration: none; }
.fleet-switch--single:hover { background: none; }
.fleet-switch-label { display: flex; justify-content: space-between; font-size: 0.78125rem; font-weight: 500;
  color: var(--nav-muted); }
.fleet-switch-name { display: block; margin-top: 2px; font-weight: 640; overflow-wrap: anywhere; }
.sidebar-foot { margin-top: auto; padding-top: 0.75rem; border-top: 1px solid #222a33; }

/* Account menu: a <details>, so it opens and closes without any script. */
.menu { position: relative; }
.menu > summary { list-style: none; cursor: pointer; }
.menu > summary::-webkit-details-marker { display: none; }
.menu-trigger { display: flex; align-items: center; gap: 0.625rem; padding: 0.375rem 0.5rem; border-radius: var(--radius-sm);
  color: var(--nav-text); font-size: 0.84375rem; }
.menu-trigger:hover { background: var(--nav-hover); color: var(--nav-text-strong); }
.menu-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.avatar {
  display: inline-grid; place-items: center; flex: none; width: 1.875rem; height: 1.875rem; border-radius: 50%;
  background: var(--accent); color: var(--on-accent); font-size: 0.8125rem; font-weight: 700; text-transform: uppercase;
}
.menu-panel {
  position: absolute; z-index: 30; min-width: 13.75rem; padding: 0.375rem;
  background: var(--surface); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-pop);
}
.menu--up .menu-panel { bottom: calc(100% + 0.375rem); left: 0; right: 0; }
.menu--down .menu-panel { top: calc(100% + 0.375rem); right: 0; }
.menu--down .menu-name, .menu--down .menu-trigger > .icon { display: none; }
.menu-head { padding: 0.5rem 0.625rem 0.625rem; margin-bottom: 0.25rem; border-bottom: 1px solid var(--border); font-size: 0.8125rem;
  color: var(--text-3); overflow-wrap: anywhere; }
.menu-item {
  display: flex; align-items: center; gap: 0.625rem; width: 100%; padding: 0.5rem 0.625rem; border: 0; border-radius: var(--radius-sm);
  background: none; color: var(--text); font: inherit; font-size: 0.875rem; text-align: left; cursor: pointer;
}
.menu-item { justify-content: flex-start; }
.menu-item:hover { background: var(--hover); text-decoration: none; }
.menu-item .icon { color: var(--text-3); }
.menu-item[aria-current="page"] { color: var(--accent); }
.menu-item[aria-current="page"] .icon { color: var(--accent); }
/* The sections, in the menu of the phone's top bar only: the sidebar lists them on wide screens. */
.menu-nav { display: grid; margin-bottom: 0.25rem; padding-bottom: 0.25rem; border-bottom: 1px solid var(--border); }
.menu--up .menu-nav { display: none; }
.menu-heading { padding: 0.5rem 0.625rem 0.25rem; color: var(--text-3); font-size: 0.75rem; font-weight: 600; }
.menu-panel form { margin: 0.25rem 0 0; padding-top: 0.25rem; border-top: 1px solid var(--border); }
/* The colour theme switch: three small segments in the account menu. */
.theme-switch { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px; margin: 0.375rem 0.25rem 0.25rem;
  padding: 0.1875rem; border-radius: var(--radius-sm); background: var(--surface-2); }
.theme-switch[hidden] { display: none; }
.theme-switch button { min-height: 1.875rem; padding: 0.25rem 0.375rem; border: 1px solid transparent; border-radius: 0.1875rem; background: none;
  color: var(--text-2); font-size: 0.8125rem; }
.theme-switch button:hover { background: var(--hover); }
.theme-switch button[aria-pressed="true"] { border-color: var(--border); background: var(--surface); color: var(--text); }

/* The language switch: the same segments as the theme switch, in the account menu and under the sign-in card. */
.language-switch { margin: 0; }
.language-switch .theme-switch { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.menu-panel form.language-switch { margin: 0; padding: 0; border: 0; }
.language-switch--auth { width: 13.75rem; margin: 0.875rem auto 0; }

/* At the foot of the sidebar on wide screens, above the account (web/_preferences.html): the theme as three icons, the language as two codes, round
   pills on the navy sidebar. The sidebar's account menu leaves them out; the phone's menu keeps them. */
.sidebar-prefs { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0 0.5rem 0.625rem; }
.sidebar-prefs .theme-switch { margin: 0; padding: 2px; gap: 2px; border: 1px solid #262e38; border-radius: 62.4375rem;
  background: none; }
.sidebar-prefs .theme-switch--icons { grid-template-columns: repeat(3, 1.875rem); }
.sidebar-prefs .language-switch .theme-switch { grid-template-columns: repeat(2, 2.25rem); }
.sidebar-prefs .theme-switch button { display: grid; place-items: center; min-height: 1.625rem; height: 1.625rem; padding: 0;
  border: 0; border-radius: 62.4375rem; color: var(--nav-muted); font-size: 0.75rem; font-weight: 650; letter-spacing: 0.04em;
  cursor: pointer; }
.sidebar-prefs .theme-switch .icon { width: 0.9375rem; height: 0.9375rem; }
.sidebar-prefs .theme-switch button:hover { background: var(--nav-hover); color: var(--nav-text-strong); }
.sidebar-prefs .theme-switch button[aria-pressed="true"] { background: var(--nav-active); color: var(--nav-text-strong);
  box-shadow: inset 0 0 0 1px #33475c; }
.menu--up .theme-switch, .menu--up .language-switch { display: none; }

/* 4 ─ Page parts ─────────────────────────────────────────────────────────────────────────────────────────── */
.page-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 0.875rem 1.5rem;
  margin-bottom: 1.25rem; }
.page-head-main { min-width: 0; flex: 1 1 20rem; }
/* The way back to the page above, over the title: an arrow and that page's name. The negative margin lines the
   arrow up with the title while the hover background still has room around it. */
.back-link { display: inline-flex; align-items: center; gap: 0.375rem; margin: 0 0 0.5rem -0.5rem;
  padding: 0.25rem 0.625rem 0.25rem 0.375rem; border-radius: var(--radius-sm); color: var(--text-2); font-size: 0.875rem;
  font-weight: 560; }
.back-link:hover { background: var(--hover); color: var(--text); text-decoration: none; }
.back-link .icon { width: 1.125rem; height: 1.125rem; }
.title-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; }
.title-row h1 { overflow-wrap: anywhere; }
.page-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 1rem; margin: 0.5rem 0 0; color: var(--text-2);
  font-size: 0.875rem; }
.page-meta .icon { width: 1rem; height: 1rem; color: var(--text-3); }
.page-meta > span { display: inline-flex; align-items: center; gap: 0.375rem; }
.lede { max-width: 72ch; margin-top: 0.5rem; color: var(--text-2); }
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin: 0; }
.actions form { margin: 0; }

.stack { display: grid; gap: 1rem; }
.split { display: grid; gap: 1rem; align-items: start; }
@media (min-width: 1100px) {
  .split { grid-template-columns: minmax(0, 1fr) 22.5rem; }
}

.card { min-width: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); }
.card-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem 0.75rem;
  padding: 0.875rem 1rem; border-bottom: 1px solid var(--border); }
.card-head h2 { display: flex; align-items: center; gap: 0.5rem; }
.card-head p { width: 100%; margin: 0; color: var(--text-3); font-size: 0.84375rem; }
.card-body { padding: 1rem; }
@media (max-width: 479px) {
  .card-body { padding: 0.75rem; }
}
.card-foot { padding: 0.75rem 1rem; border-top: 1px solid var(--border); background: var(--surface-2);
  border-radius: 0 0 var(--radius) var(--radius); color: var(--text-3); font-size: 0.84375rem; }
.card--danger { border-color: var(--alarm-line); }
.card--danger .card-head { background: var(--alarm-bg); border-bottom-color: var(--alarm-line);
  border-radius: var(--radius) var(--radius) 0 0; }
.card--danger .card-head h2 { color: var(--alarm); }
.count { color: var(--text-3); font-size: 0.93em; font-weight: 500; font-variant-numeric: tabular-nums; }
.count--alarm { color: var(--alarm); font-weight: 650; }

.callout { display: flex; gap: 0.75rem; align-items: flex-start; padding: 0.75rem 0.875rem; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--surface-2); color: var(--text-2); font-size: 0.875rem; }
.callout > .icon { margin-top: 1px; }
.callout-body { flex: 1; min-width: 0; }
.callout strong { color: var(--text); }
.callout--attention { border-color: var(--attention-line); background: var(--attention-bg); }
.callout--attention > .icon { color: var(--attention); }
.callout--alarm { border-color: var(--alarm-line); background: var(--alarm-bg); }
.callout--alarm > .icon { color: var(--alarm); }
.callout--info { border-color: var(--border); background: var(--accent-soft); }
.callout--ok { border-color: var(--ok-line); background: var(--ok-bg); }
.callout--ok > .icon { color: var(--ok); }
.callout--info > .icon { color: var(--accent); }

.flashes { display: grid; gap: 0.5rem; margin-bottom: 1rem; }
.flash { padding: 0.625rem 0.875rem; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); font-size: 0.875rem; }
.flash--success { border-color: var(--ok-line); background: var(--ok-bg); }
.flash--error { border-color: var(--alarm-line); background: var(--alarm-bg); }
.flash--warning { border-color: var(--attention-line); background: var(--attention-bg); }
.flash--info { border-color: var(--border); background: var(--accent-soft); }

.empty { display: grid; justify-items: center; gap: 0.375rem; padding: 2rem 1rem; text-align: center; color: var(--text-3); }
.empty .icon { width: 1.75rem; height: 1.75rem; color: var(--text-3); }
.empty--ok .icon { color: var(--ok); }
.empty strong { color: var(--text); font-weight: 600; }

/* 5 ─ Controls ───────────────────────────────────────────────────────────────────────────────────────────── */
.btn, button {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  min-height: 2.25rem; padding: 0.4375rem 0.875rem; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text); font: inherit; font-size: 0.875rem; font-weight: 560; line-height: 1.2;
  text-align: center; cursor: pointer; white-space: nowrap;
}
.btn:hover, button:hover { background: var(--hover); text-decoration: none; }
.btn .icon, button .icon { width: 1rem; height: 1rem; }
.btn--primary { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
.btn--primary:hover { border-color: var(--accent-hover); background: var(--accent-hover); }
.btn--danger { border-color: var(--alarm); background: var(--alarm); color: #fff; }
.btn--danger:hover { filter: brightness(0.92); background: var(--alarm); }
.btn--danger-outline { border-color: var(--alarm-line); color: var(--alarm); }
.btn--danger-outline:hover { background: var(--alarm-bg); }
.btn--ghost { border-color: transparent; background: none; color: var(--text-2); }
.btn--sm { min-height: 2rem; padding: 0.3125rem 0.625rem; font-size: 0.8125rem; }
.btn--block { width: 100%; }
button.link { min-height: 0; padding: 0; border: 0; background: none; color: var(--accent); font-weight: 500; }
button.link:hover { background: none; text-decoration: underline; }
.inline-form { display: inline; margin: 0; }
.button-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.button-row form { margin: 0; }

/* Forms as Django renders them (form.as_div): one div per field with label, input, help text and errors. */
.form { display: grid; gap: 0.875rem; }
.form > div, .fields > div { display: grid; gap: 0.375rem; }
.form-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.fields--inline { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.75rem; }
.fields--inline > div { flex: 1 1 12.5rem; }
label { font-size: 0.84375rem; font-weight: 600; color: var(--text); }
input[type=email], input[type=password], input[type=text], input[type=number], input[type=datetime-local],
input[type=search], input[type=tel], input[type=url], select, textarea {
  width: 100%; min-height: 2.5rem; padding: 0.5rem 0.6875rem;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text); font: inherit; font-size: 1rem;
}
@media (min-width: 960px) {
  input[type=email], input[type=password], input[type=text], input[type=number], input[type=datetime-local],
  input[type=search], input[type=tel], input[type=url], select, textarea { font-size: 0.90625rem; }
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--focus);
  box-shadow: 0 0 0 0.1875rem var(--accent-soft); }
input[type=checkbox] { width: 1rem; height: 1rem; accent-color: var(--accent); }
div:has(> input[type=checkbox]) { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.helptext { color: var(--text-3); font-size: 0.8125rem; font-weight: 400; }
.errorlist { margin: 0; padding: 0.5rem 0.75rem; list-style: none; border-radius: var(--radius-sm);
  color: var(--alarm); background: var(--alarm-bg); font-size: 0.84375rem; }
.form > .errorlist, .form > ul.errorlist.nonfield { margin-bottom: 2px; }

/* Status words and tags */
.status {
  display: inline-flex; align-items: center; gap: 0.4375rem; color: var(--text-2); font-size: 0.84375rem; font-weight: 560;
  line-height: 1.4; white-space: nowrap;
}
.status::before { content: ""; width: 0.5rem; height: 0.5rem; border-radius: 2px; background: var(--neutral-line); flex: none; }
.status--ok::before { background: var(--ok); }
.status--attention { color: var(--attention); font-weight: 640; }
.status--alarm { color: var(--alarm); font-weight: 640; }
.status--attention::before, .status--alarm::before { background: currentColor; }
.status--pending::before { animation: pulse 1.4s ease-in-out infinite; }
.tag { display: inline-flex; align-items: center; padding: 1px 0.4375rem; border: 1px solid var(--border);
  border-radius: 0.25rem; background: var(--surface-2); color: var(--text-2); font-size: 0.75rem; font-weight: 560;
  white-space: nowrap; }
.plate { display: inline-flex; padding: 1px 0.4375rem; border: 1.5px solid var(--border-strong); border-radius: 0.25rem;
  font-family: var(--mono); font-size: 0.78125rem; font-weight: 650; letter-spacing: 0.04em; color: var(--text); }
.chip { display: inline-flex; align-items: center; gap: 0.375rem; padding: 0.1875rem 0.625rem; border-radius: var(--radius-sm);
  background: var(--accent-soft); color: var(--text); font-size: 0.8125rem; }


.chip .icon { width: 0.875rem; height: 0.875rem; }

/* 6 ─ Data: tables, details lists, timelines, pager ──────────────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.table th {
  padding: 0.5625rem 1rem; border-bottom: 1px solid var(--border); background: var(--surface-2);
  color: var(--text-3); font-size: 0.78125rem; font-weight: 600; text-align: left; white-space: nowrap;
}
.table td { padding: 0.6875rem 1rem; border-bottom: 1px solid var(--border); vertical-align: top; }
.table tbody tr:last-child td { border-bottom: 0; }
/* A row that opens something: its main link (.row-link) covers the whole row, so a click anywhere on it follows the
   link, while the row's other links and buttons stay above it and keep working. Only such rows react to the pointer. */
.table tbody tr:has(.row-link) { position: relative; cursor: pointer; }
.row-link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
tr:has(.row-link) :is(a:not(.row-link), button, input, select),
li:has(.row-link) :is(a:not(.row-link), button, input, select) { position: relative; z-index: 2; }
.table tbody tr:has(.row-link):hover td { background: var(--hover); }
tr:has(.row-link):hover .row-link, li:has(.row-link):hover .row-link { color: var(--accent); text-decoration: underline;
  text-underline-offset: 2px; }
.table .cell-primary { font-weight: 600; }
.table .cell-primary a { color: var(--text); }
.table .cell-primary a:hover { color: var(--accent); }
.table .cell-time { white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--text-2); }
.table .cell-num { text-align: right; font-variant-numeric: tabular-nums; }
.table .cell-wide { min-width: 13.75rem; color: var(--text-2); }
.table .cell-actions { text-align: right; white-space: nowrap; }
.table .cell-actions form { display: inline; margin: 0 0 0 0.375rem; }
.table td.empty-row { padding: 2rem 1rem; text-align: center; color: var(--text-3); }
.sub { display: block; margin-top: 2px; color: var(--text-3); font-size: 0.78125rem; font-weight: 400; }
.card > .table-wrap:last-child .table tbody tr:last-child td:first-child { border-bottom-left-radius: var(--radius); }

/* Below 720 px a table becomes a list of blocks: the column name sits left of each value (data-label). */
@media (max-width: 719px) {
  .table--stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .table--stack, .table--stack tbody, .table--stack tr, .table--stack td { display: block; width: 100%; }
  .table--stack tr { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); }
  .table--stack tbody tr:last-child { border-bottom: 0; }
  /* The label is a float in the left 38% (the cell's padding), and the cell contains it (flow-root), so a label that
     wraps (long in Bulgarian) makes its row taller instead of running into the next one. The float's margin and
     width are in % of the content box, which is the other 62%: hence the ratio. */
  .table--stack { --stack-label: 0.38; }
  .table--stack td { display: flow-root; padding: 0.1875rem 0 0.1875rem calc(var(--stack-label) * 100%); border: 0;
    text-align: left; min-height: 1.5rem; }
  .table--stack td::before {
    content: attr(data-label); float: left;
    margin-left: calc(var(--stack-label) / (1 - var(--stack-label)) * -100%);
    width: calc(var(--stack-label) / (1 - var(--stack-label)) * 100% - 0.75rem);
    color: var(--text-3); font-size: 0.78125rem; line-height: 1.75;
  }
  .table--stack td.cell-primary { padding-left: 0; padding-bottom: 0.375rem; font-size: 0.9375rem; }
  .table--stack td.cell-primary::before, .table--stack td.empty-row::before { content: none; }
  .table--stack td.empty-row { padding: 1.25rem 0; }
  .table--stack td.cell-num, .table--stack td.cell-actions { text-align: left; }
  .table--stack td.cell-actions { padding-left: 0; padding-top: 0.5rem; }
  .table--stack td.cell-actions form { margin: 0 0.375rem 0 0; }
  .table--stack tbody tr:has(.row-link):hover td { background: none; }
  .table--stack tbody tr:has(.row-link):hover { background: var(--hover); }
  /* The cells are positioned for their labels; the main link's cover must reach the row, not its own cell. */
  .table--stack td.cell-primary:has(.row-link) { position: static; }
}

.details { display: grid; gap: 0; margin: 0; }
.details > div { display: grid; grid-template-columns: minmax(6.875rem, 40%) 1fr; gap: 0.75rem; padding: 0.5625rem 0;
  border-bottom: 1px solid var(--border); font-size: 0.875rem; }
.details > div:first-child { padding-top: 0; }
.details > div:last-child { border-bottom: 0; padding-bottom: 0; }
.details dt { color: var(--text-3); }
.details dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

.timeline { margin: 0; padding: 0; list-style: none; }
.timeline li { position: relative; padding: 0 0 0.875rem 1.375rem; font-size: 0.875rem; }
.timeline li:last-child { padding-bottom: 0; }
.timeline li::before { content: ""; position: absolute; left: 0.25rem; top: 0.375rem; width: 0.5625rem; height: 0.5625rem; border-radius: 50%;
  border: 2px solid var(--border-strong); background: var(--surface); }
.timeline li::after { content: ""; position: absolute; left: 0.5rem; top: 1.0625rem; bottom: 0; width: 1px; background: var(--border); }
.timeline li:last-child::after { content: none; }
.timeline li.is-current::before { border-color: var(--ok); background: var(--ok); }
.timeline-title { font-weight: 600; }
.timeline-when { display: block; color: var(--text-3); font-size: 0.8125rem; font-variant-numeric: tabular-nums; }

.people { margin: 0; padding: 0; list-style: none; }
/* Adding a member: one row of fields at the top of the members' card, wrapping on a phone. */
.member-add { padding: 0.875rem 1rem; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.member-add-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.625rem 0.75rem; margin: 0; }
.member-add-form > div { display: grid; gap: 0.375rem; flex: 0 1 12.5rem; min-width: 0; }
.member-add-form > div:first-of-type { flex: 1 1 17.5rem; }
.member-add-form > button { min-height: 2.5rem; }
.member-add .helptext { margin: 0.5rem 0 0; }
@media (max-width: 599px) { .member-add-form > div, .member-add-form > button { flex: 1 1 100%; } }
.people li:has(.row-link) { position: relative; cursor: pointer; }
.people li:has(.row-link):hover { background: var(--hover); }
.people li { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.625rem 1rem; border-bottom: 1px solid var(--border); }
.people li:last-child { border-bottom: 0; }
.people-name { flex: 1; min-width: 0; overflow-wrap: anywhere; font-size: 0.875rem; }

.pager { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin-top: 1rem;
  color: var(--text-3); font-size: 0.84375rem; }
.pager-spacer { flex: 1; }

/* The Activity's filters: one row of chips per filter, the chosen one filled. Chips wrap; nothing scrolls sideways. */
.filters { display: grid; gap: 0.5rem; margin-bottom: 1rem; padding: 0.75rem 0.875rem; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow); }
.filter-row { display: flex; align-items: baseline; gap: 0.375rem 0.75rem; min-width: 0; }
.filter-name { flex: none; width: 3.25rem; color: var(--text-3); font-size: 0.8125rem; font-weight: 600; }
.filter-chips { display: flex; flex-wrap: wrap; gap: 0.375rem; min-width: 0; }
.filter-chip { display: inline-flex; align-items: center; gap: 0.375rem; min-height: 2rem; padding: 0.25rem 0.75rem;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--text-2);
  font-size: 0.84375rem; font-weight: 560; white-space: nowrap; }
.filter-chip:hover { text-decoration: none; border-color: var(--accent); color: var(--text); }
.filter-chip[aria-current="true"] { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
.filters-clear { display: inline-flex; align-items: center; gap: 0.25rem; justify-self: start; font-size: 0.8125rem; }
.filters-clear .icon { width: 0.875rem; height: 0.875rem; }
@media (max-width: 599px) {
  .filter-row { flex-direction: column; gap: 0.25rem; }
  .filter-name { width: auto; }
  .filter-chip { min-height: 1.875rem; padding: 0.1875rem 0.625rem; font-size: 0.8125rem; }
}
/* A row's category: a dot in the drawing's colours, next to its words. */
.cat { display: inline-block; flex: none; width: 0.5rem; height: 0.5rem; margin-right: 0.5rem; border-radius: 2px;
  background: var(--neutral-line); vertical-align: 1px; }
.filter-chip .cat { margin-right: 0; }
.cat--alarms { background: var(--tire-alarm); }
.cat--air { background: var(--tire-inflating); }
.cat--settings { background: var(--accent); }
.cat--access { background: var(--tire-holding); }
.cat--system { background: var(--tire-offline); }
.filter-chip[aria-current="true"] .cat { box-shadow: 0 0 0 2px var(--on-accent); }

/* 7 ─ Fleet: fleet cards, summary tiles, overview lines ──────────────────────────────────────────────────── */
/* "Your fleets": one row per fleet, the whole row one link. Phone: name and condition, then the vehicles' squares
   and the open alarms. Wide: columns under one header. */
.fleets-head, .fleets-row { display: grid; align-items: center; gap: 0.375rem 1rem;
  grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "name condition" "strip alarms"; }
.fleets-head { display: none; }
.fleets-row { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--text); }
.fleet-rows li:last-child .fleets-row { border-bottom: 0; border-radius: 0 0 var(--radius) var(--radius); }
.fleets-row:hover { background: var(--hover); text-decoration: none; }
.fleets-row:hover .fleet-row-go { color: var(--accent); }
.fleets-row-name { grid-area: name; min-width: 0; font-weight: 620; overflow-wrap: anywhere; }
.fleets-row-strip { grid-area: strip; display: flex; align-items: center; gap: 0.625rem; min-width: 0; font-size: 0.84375rem; }
.fleets-row-condition { grid-area: condition; justify-self: end; display: grid; justify-items: end; font-size: 0.84375rem; }
.fleets-row .fleet-row-alarms { grid-area: alarms; display: block; justify-self: end; }
.fleets-row .fleet-row-alarms:not(.has-alarms) { display: none; }
/* One square per vehicle in its overview's colour, most urgent first. */
.strip { display: flex; flex-wrap: wrap; gap: 0.1875rem; max-width: 13.75rem; }
.strip-cell { width: 0.625rem; height: 0.625rem; border-radius: 2px; background: var(--neutral-line); }
.strip-cell--ok { background: var(--tire-ok); }
.strip-cell--attention { background: var(--tire-attention); }
.strip-cell--alarm { background: var(--tire-alarm); }
.strip-cell--stale { background: var(--tire-offline); }
.strip-count { flex: none; color: var(--text-3); }
@container (min-width: 45rem) {
  .fleets-head, .fleets-row { grid-template-columns: minmax(11.25rem, 1.2fr) minmax(11.25rem, 1.4fr) 11.875rem 8.125rem 1rem;
    grid-template-areas: "name strip condition alarms go"; }
  .fleets-head { display: grid; padding: 0.5625rem 1rem; border-bottom: 1px solid var(--border); background: var(--surface-2);
    color: var(--text-3); font-size: 0.78125rem; font-weight: 600; }
  .fleets-row-condition { justify-self: start; justify-items: start; }
  .fleets-row .fleet-row-alarms, .fleets-row .fleet-row-alarms:not(.has-alarms) { display: block; justify-self: start; }
  .fleets-row .fleet-row-go { grid-area: go; display: inline-flex; }
}

/* The overview's counts: one line of words, coloured only when they say something is wrong. */
.fleet-summary { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: flex-end; gap: 0.5rem 1.5rem; }
.fleet-alarms { display: inline-flex; align-items: center; gap: 0.25rem; color: var(--text-2); font-size: 0.875rem; font-weight: 560; }
.fleet-alarms.has-alarms { color: var(--alarm); }
.fleet-alarms .icon { width: 0.9375rem; height: 0.9375rem; }

.age { white-space: nowrap; font-variant-numeric: tabular-nums; }
.age.is-stale, .is-stale { color: var(--attention); }
.alarm-link { display: inline-flex; align-items: center; gap: 0.375rem; font-weight: 650; color: var(--alarm); }

/* A glance at every wheel: axles left to right (cab first), the vehicle's left side at the bottom. */
.minimap { display: inline-flex; align-items: center; gap: 0.1875rem; padding: 0.1875rem 0; vertical-align: middle; }
.minimap-body { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.1875rem 0.3125rem; border: 1px solid var(--border-strong);
  border-radius: 0.25rem; }
.minimap-body:first-child { border-top-left-radius: 0.4375rem; border-bottom-left-radius: 0.4375rem; padding-left: 0.375rem; }
.minimap-axle { display: inline-flex; flex-direction: column-reverse; gap: 2px; }
.minimap-tire { display: block; width: 0.625rem; height: 0.375rem; border-radius: 1px; background: var(--tire-ok); }
.minimap-tire--inflating { background: var(--tire-inflating); }
.minimap-tire--deflating { background: var(--tire-deflating); }
.minimap-tire--holding { background: var(--tire-holding); }
.minimap-tire--attention { background: var(--tire-attention); }
.minimap-tire--offline { background: var(--tire-offline); }
.minimap-tire--alarm { background: var(--tire-alarm); }

/* The overview's vehicles: one row each, the whole row one link. Wide: columns under one header. Phone: the name
   and condition on the first line, the wheels, alarms and age on the second. */
.section-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.25rem 0.75rem;
  margin-bottom: 0.75rem; }
.section-head h2 { display: flex; align-items: center; gap: 0.5rem; font-size: 1rem; }
.fleet-rows { margin: 0; padding: 0; list-style: none; }
.fleet-head, .fleet-row { display: grid; align-items: center; gap: 0.375rem 1rem;
  grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "name status" "wheels age"; }
.fleet-head { display: none; }
.fleet-row { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--text); }
.fleet-rows li:last-child .fleet-row { border-bottom: 0; border-radius: 0 0 var(--radius) var(--radius); }
.fleet-row:hover { background: var(--hover); text-decoration: none; }
.fleet-row-name { grid-area: name; min-width: 0; font-weight: 620; overflow-wrap: anywhere; }
.fleet-row .status { grid-area: status; justify-self: end; }
.fleet-row-wheels { grid-area: wheels; display: flex; align-items: center; gap: 0.75rem; min-width: 0; font-size: 0.84375rem; }
.fleet-row-alarms { display: none; font-size: 0.84375rem; }
.fleet-row-alarms.has-alarms { color: var(--alarm); font-weight: 640; }
.fleet-row-age { grid-area: age; justify-self: end; color: var(--text-3); font-size: 0.8125rem; }
.fleet-row-go { display: none; color: var(--text-3); }
.fleet-row-go .icon { width: 1rem; height: 1rem; }
.fleet-row:hover .fleet-row-go { color: var(--accent); }
.fleet-row .minimap-tire { width: 0.8125rem; height: 0.5rem; }
.status--stale, .status--none { color: var(--text-3); }
@container (min-width: 45rem) {
  .fleet-head, .fleet-row { grid-template-columns: minmax(10rem, 1.4fr) 9.375rem minmax(7.5rem, 1fr) 8.125rem 6.25rem 1rem;
    grid-template-areas: "name status wheels alarms age go"; }
  .fleet-head { display: grid; padding: 0.5625rem 1rem; border-bottom: 1px solid var(--border); background: var(--surface-2);
    color: var(--text-3); font-size: 0.78125rem; font-weight: 600; }
  .fleet-row { padding: 0.625rem 1rem; }
  .fleet-row .status { justify-self: start; }
  .fleet-row-alarms { grid-area: alarms; display: block; }
  .fleet-row-age { justify-self: start; }
  .fleet-row-go { grid-area: go; display: inline-flex; }
}

/* 8 ─ Live panel: status, controls, the vehicle drawing, the side column ─────────────────────────────────── */
/* One grid, as the app's dashboard: the status, the tire mode switch, the drawing and the card under it (preset
   or Stop all), and beside them (below on narrow screens) the target panel and the last commands. The fragment
   reloaded every 2 s (.live) has no box of its own (display: contents), so its parts sit in the panel's grid
   next to the controls and the side column, which that reload never replaces. The last row takes any extra
   height of the side column, so the drawing never grows with it. */
.control { display: grid; grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "status" "modes" "rig" "foot" "looks" "side" "facts";
  grid-template-rows: auto auto auto auto auto auto 1fr;
  counter-reset: picked; }
.control > .live { display: contents; }
.control-head { grid-area: status; display: grid; gap: 0.75rem; padding: 0.875rem 1rem; border-bottom: 1px solid var(--border); }
.control > .live > .empty, .control > .live > .live-empty, .control > .live > .callout { grid-area: rig; }
.control > .live > .callout { margin: 1rem; }
.control .rig-wrap { grid-area: rig; padding: 1rem 1rem 0; }
.control .looks-wrap { grid-area: looks; align-self: start; padding: 0.875rem 1rem 1rem; }
.control:not(.control--commands) .looks-wrap { padding-top: 1rem; }
/* On a phone the controller's facts close the panel; with room, they sit right of the status. */
.control > .live > .live-facts { grid-area: facts; justify-content: center; padding: 0.75rem 1rem 1rem;
  border-top: 1px solid var(--border); }
.control-side { grid-area: side; display: grid; align-content: start; gap: 1.125rem; min-width: 0; padding: 1rem;
  border-top: 1px solid var(--border); background: var(--surface-2); }
.control:not(:has(.wheel-pick, .command-log)) .control-side { display: none; }
.control:not(:has(.wheel-pick)) .target-panel { display: none; }
/* With room, the facts sit on the right of the status line, across the whole panel (they share its grid area). */
@media (min-width: 600px) {
  .control { grid-template-areas: "status" "modes" "rig" "foot" "looks" "side";
    grid-template-rows: auto auto auto auto auto 1fr; }
  .control > .live > .live-facts { grid-area: status; justify-self: end; align-self: center; justify-content: flex-end;
    max-width: 70%; padding: 0 1rem; border-top: 0; text-align: right; }
}
/* One column (phones): the target panel is the docked card, there only while wheels are selected. */
@container (max-width: 39.9375rem) {
  .control:not(:has(.wheel-pick:checked)) .target-panel { display: none; }
  .control:not(:has(.wheel-pick:checked, .command-log)) .control-side { display: none; }
}
/* Room for two columns (tablets and up): the side column beside the mode switch and the drawing. The drawing is
   about 350px wide, so a tablet in portrait already has room; the column grows from 260px to 320px, or takes the
   width set by dragging the line between the columns (--side-width, set and remembered by commands.js). */
@container (min-width: 40rem) {
  .control:has(.wheel-pick, .command-log) {
    grid-template-columns: minmax(0, 1fr) var(--side-width, clamp(16.25rem, 36%, 20rem));
    grid-template-rows: auto auto auto auto 1fr;
    grid-template-areas: "status status" "modes side" "rig side" "foot side" "looks side"; }
  .control-side { position: relative; border-top: 0; border-left: 1px solid var(--border);
    border-radius: 0 0 var(--radius) 0; }
  .target-panel { position: sticky; top: 1rem; }
  .side-resizer:not([hidden]) { display: block; }
}
/* The line between the columns, as a handle: a wide invisible grip over the border, which lights up on hover,
   focus or drag. Without the script it stays hidden (and so does nothing). */
.side-resizer { display: none; position: absolute; z-index: 3; top: 0; bottom: 0; left: -0.4375rem; width: 0.875rem;
  cursor: col-resize; touch-action: none; }
.side-resizer::after { content: ""; position: absolute; top: 0; bottom: 0; left: 0.375rem; width: 2px;
  background: transparent; transition: background 0.12s ease; }
.side-resizer:hover::after, .side-resizer:focus-visible::after, .side-resizer.is-dragging::after {
  background: var(--accent); }
.side-resizer:focus-visible { outline: none; }
.control.is-resizing { cursor: col-resize; user-select: none; }

.live { display: grid; gap: 1rem; }
.live-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.375rem 1rem; }
.freshness { display: inline-flex; align-items: center; gap: 0.5rem; margin: 0; color: var(--ok); font-weight: 640;
  font-size: 0.875rem; }
.freshness::before { content: ""; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: currentColor;
  animation: pulse 2s ease-in-out infinite; }
.freshness.is-stale { color: var(--attention); }
.freshness.is-stale::before { animation: none; }
.freshness--still { color: var(--text); }
.freshness--still::before { background: var(--accent); animation: none; }
.live-source { color: var(--text-3); font-size: 0.8125rem; }
.live-empty { margin: 0; padding: 1.75rem 1rem; text-align: center; color: var(--text-3); }

/* The controller's own facts, quietly: they matter when something is off, and then they say so in colour. */
.live-facts { display: flex; flex-wrap: wrap; gap: 2px 1.125rem; margin: 0; color: var(--text-3); font-size: 0.8125rem; }
.live-facts > div { display: inline-flex; align-items: center; gap: 0.3125rem; }
.live-facts dt::after { content: ":"; }
.live-facts dd { display: inline-flex; align-items: center; gap: 0.25rem; margin: 0; color: var(--text-2); font-weight: 560; }
.live-facts .icon { width: 0.875rem; height: 0.875rem; }
.live-facts .is-off dd { color: var(--attention); }

/* Above the drawing: the tire mode switch as on the app (current mode filled), and the alarms to acknowledge. */
.mode-bar { grid-area: modes; display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center; gap: 0.625rem 0.75rem; padding: 1rem 1rem 0; }
.mode-bar:not(:has(form, p)) { display: none; }
.mode-bar form { margin: 0; }
.mode-bar > .mode-switch { grid-column: 2; }
.mode-bar > form:not(.mode-switch) { grid-column: 3; justify-self: end; }
.mode-bar > .control-note { grid-column: 1 / -1; }
.mode-switch { display: inline-flex; align-items: center; }
.segmented { display: inline-flex; gap: 0.1875rem; padding: 0.1875rem; border: 1px solid var(--border-strong);
  border-radius: var(--radius); background: var(--surface-2); }
.segment { display: inline-flex; align-items: center; justify-content: center; min-width: 7.75rem; min-height: 2.375rem;
  padding: 0.375rem 1.125rem; border: 0; border-radius: var(--radius-sm); background: none; color: var(--text-2);
  font-size: 0.9375rem; font-weight: 600; }
button.segment:hover { background: var(--hover); color: var(--text); }
.segment.is-current { background: var(--accent); color: var(--on-accent); }
.pill-button { min-height: 2.5rem; gap: 0.5rem; padding: 0.375rem 0.875rem; }
.pill-button--alarm { border-color: var(--alarm-line); background: var(--alarm-bg); color: var(--alarm); font-weight: 650; }
.pill-button--alarm:hover { border-color: var(--alarm); background: var(--alarm-bg); }
.control-note { display: flex; align-items: flex-start; gap: 0.5rem; margin: 0; padding: 0.5rem 0.75rem;
  border-radius: var(--radius-sm); background: var(--attention-bg); color: var(--text-2); font-size: 0.84375rem; }
.control-note .icon { width: 1rem; height: 1rem; margin-top: 2px; color: var(--attention); }
.control-note strong { color: var(--text); }
@media (max-width: 599px) {
  .mode-bar { grid-template-columns: minmax(0, 1fr); }
  .mode-bar > .mode-switch, .mode-bar > form:not(.mode-switch) { grid-column: 1; justify-self: stretch; }
  .segmented { flex: 1; min-width: 0; }
  .segment { flex: 1; min-width: 0; }
  .pill-button { width: 100%; }
}

/* Under the drawing, one wide card as on the app: the preset in Automatic, Stop all in Manual. */
.foot-bar { grid-area: foot; align-self: start; padding: 1rem 1rem 0; }
.foot-bar:not(:has(form)) { display: none; }
.foot-bar form { max-width: 38.75rem; margin: 0 auto; }
.foot-button { width: 100%; min-height: 3rem; justify-content: center; gap: 0.625rem; padding: 0.5rem 1.125rem;
  border-radius: var(--radius-sm); font-size: 0.9375rem; white-space: normal; }
.foot-button .icon { width: 1.25rem; height: 1.25rem; }
.foot-value { font-weight: 650; }
.foot-label { opacity: 0.8; font-size: 0.875rem; font-weight: 500; }
.foot-note { font-size: 0.8125rem; font-weight: 500; opacity: 0.85; }
.foot-note::before { content: "· "; }
.foot-button--preset { border-color: var(--border-strong); background: var(--surface); color: var(--text); }
.foot-button--preset:hover { border-color: var(--accent); background: var(--surface); }
.foot-button--preset.is-active .foot-value { color: var(--accent); }

/* The same settings as plain facts, where nothing can be changed (no permission, playback). */
.state-facts { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0; }
.state-facts > div { display: flex; align-items: baseline; gap: 0.5rem; padding: 0.375rem 0.75rem; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface-2); }
.state-facts dt { color: var(--text-2); font-size: 0.8125rem; }
.state-facts dd { margin: 0; font-weight: 650; }
.state-facts .is-alarm { border-color: var(--alarm-line); background: var(--alarm-bg); }
.state-facts .is-alarm dd { color: var(--alarm); }

/* The vehicle seen from above, front at the top, drawn as a plan in thin lines on the panel itself: one outline
   per truck or trailer, one row per axle, the compressor's tank inside the outline it belongs to. */
.rig-wrap, .looks-wrap { display: grid; gap: 0.875rem; min-width: 0; align-content: start; }
.rig { display: grid; gap: 1rem; justify-items: center; padding: 0.375rem 0; }
/* Each outline is as wide as its widest axle or tank, never wider than the panel: no empty chassis. */
.rig-body { position: relative; display: grid; gap: 1.375rem; width: fit-content; min-width: min(100%, 20rem);
  max-width: 100%; padding: 2.5rem 1.25rem 1.375rem;
  border: 1.5px solid var(--rig-line); border-radius: 0.625rem; background: var(--rig-body); }
.rig-body:first-child { border-top-left-radius: 2.5rem; border-top-right-radius: 2.5rem; padding-top: 3.25rem; }
/* The cab's windscreen. */
.rig-body:first-child::after { content: ""; position: absolute; top: 0.75rem; left: 30%; right: 30%; height: 0.375rem;
  border-radius: 0.375rem 0.375rem 2px 2px; background: var(--rig-line); opacity: 0.7; }
.rig-body + .rig-body::before { content: ""; position: absolute; top: -1.125rem; left: 50%; width: 2px; height: 1rem;
  margin-left: -1px; background: var(--rig-line); }
.rig-label { position: absolute; top: 1.25rem; left: 0; right: 0; text-align: center; color: var(--rig-ink);
  font-size: 0.78125rem; font-weight: 650; }
.rig-body:first-child .rig-label { top: 1.875rem; }
.rig-body + .rig-body .rig-label { top: 1rem; }
/* As wide as its own wheels and centred, so its line never shows past them when the outline is wider. */
.axle { position: relative; justify-self: center; max-width: 100%; display: grid;
  grid-template-columns: minmax(0, 1fr) 2.25rem minmax(0, 1fr); align-items: center;
  gap: 0.75rem; }
.axle::before { content: ""; position: absolute; left: 1rem; right: 1rem; top: 50%; height: 0.1875rem; margin-top: -1.5px;
  background: var(--rig-line); }
/* Two classes: the axle side holds the wheels' checkboxes, and the form rule for a div with a checkbox
   (section 5) would otherwise wrap twin wheels onto two lines. */
.axle > .axle-side { position: relative; display: flex; flex-wrap: nowrap; align-items: stretch; gap: 0.375rem; min-width: 0; }
.axle-side--left { justify-content: flex-end; }
.axle-hub { position: relative; display: grid; place-items: center; width: 2rem; height: 2rem; border-radius: 50%;
  border: 1.5px solid var(--rig-line); background: var(--surface); color: var(--rig-ink); font-size: 0.78125rem; font-weight: 650; }
button.axle-hub { min-height: 2rem; padding: 0; cursor: pointer; }
button.axle-hub:hover { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }

/* A wheel: flat, filled with its tone like the app's tiles, dark sidewalls left and right, and always a word for any
   colour other than "fine". Selected wheels keep their fill and get a yellow ring and a tick. */
.wheel {
  --fill: var(--tire-ok);
  --ink: #ffffff;
  position: relative; display: grid; align-content: center; justify-items: center; gap: 1px;
  flex: 0 1 8rem; width: 8rem; min-width: 0; min-height: 7.625rem; padding: 0.625rem 0.8125rem; isolation: isolate;
  border-radius: 0.375rem; color: var(--ink); text-align: center; line-height: 1.2; background: var(--fill);
  box-shadow: inset 0.375rem 0 0 rgb(0 0 0 / 24%), inset -0.375rem 0 0 rgb(0 0 0 / 24%);
}
.wheel-position { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.6875rem;
  font-weight: 600; opacity: 0.85; text-transform: capitalize; }
.wheel-pressure { font-size: clamp(1.25rem, 5vw, 1.8125rem); font-weight: 700; line-height: 1.05;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.wheel-unit { font-size: 0.5em; font-weight: 650; letter-spacing: 0; opacity: 0.85; }
.wheel-temp { margin-top: 2px; font-size: 0.84375rem; font-variant-numeric: tabular-nums; opacity: 0.9; }
/* On a narrow phone a twin axle leaves about 60 px per wheel: the unit then wraps under the number. */
.wheel-pressure, .wheel-temp { overflow-wrap: anywhere; }
/* Up to two lines, so "Pressure low" or "Sensor offline" reads whole on a narrow wheel. */
.wheel-flag { display: -webkit-box; max-width: 100%; margin-top: 0.1875rem; padding: 1px 0.3125rem; border-radius: 0.1875rem;
  background: rgb(0 0 0 / 22%); font-size: 0.6875rem; font-weight: 650; line-height: 1.2; overflow: hidden; overflow-wrap: anywhere; -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; line-clamp: 2; }
/* Every loop animates only transform or opacity, which the browser moves without repainting the wheel.
   Air flowing: chevrons slide through a still, faded window (.wheel-flow), one chevron step (22 px) per loop. */
.wheel-flow { display: none; position: absolute; inset: 0 24%; z-index: -1; overflow: hidden; pointer-events: none;
  -webkit-mask-image: linear-gradient(transparent, #000 30%, #000 70%, transparent);
  mask-image: linear-gradient(transparent, #000 30%, #000 70%, transparent); }
.wheel--inflating .wheel-flow, .wheel--deflating .wheel-flow { display: block; }
.wheel-flow::before {
  content: ""; position: absolute; inset: -1.375rem 0 0;
  --chevron: rgb(255 255 255 / 17%);
  background:
    linear-gradient(to bottom right, transparent 40%, var(--chevron) 40% 60%, transparent 60%) left top / 50% 1.375rem repeat-y,
    linear-gradient(to bottom left, transparent 40%, var(--chevron) 40% 60%, transparent 60%) right top / 50% 1.375rem repeat-y;
  animation: flow-up 1.8s linear infinite;
}
.wheel--deflating .wheel-flow::before {
  background:
    linear-gradient(to bottom left, transparent 40%, var(--chevron) 40% 60%, transparent 60%) left top / 50% 1.375rem repeat-y,
    linear-gradient(to bottom right, transparent 40%, var(--chevron) 40% 60%, transparent 60%) right top / 50% 1.375rem repeat-y;
  animation-name: flow-down;
}
/* Holding breathes and an alarm glows: a light layer, or a red ring, fading in and out over the fill. */
.wheel--holding::before, .wheel--alarm::before { content: ""; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit; opacity: 0; pointer-events: none; animation: glow 2s ease-in-out infinite; }
.wheel--holding::before { background: rgb(255 255 255 / 15%); }
.wheel--alarm::before { box-shadow: 0 0 0 0.25rem rgb(198 47 47 / 35%); animation-duration: 1.6s; }
.wheel--inflating { --fill: var(--tire-inflating); }
.wheel--deflating { --fill: var(--tire-deflating); }
.wheel--holding { --fill: var(--tire-holding); }
.wheel--attention { --fill: var(--tire-attention); --ink: var(--tire-on-attention); }
.wheel--attention .wheel-flag { background: rgb(255 255 255 / 35%); }
.wheel--offline { --fill: var(--tire-offline); }
.wheel--alarm { --fill: var(--tire-alarm); }

/* Selection: the wheel is the label of a checkbox kept out of sight but focusable and counted. */
.wheel-pick { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none; }
.wheel-pick:checked { counter-increment: picked; }
label.wheel { cursor: pointer; font-weight: inherit; -webkit-user-select: none; user-select: none;
  transition: filter 0.12s ease; }
label.wheel:hover { filter: brightness(1.08); }
.wheel-pick:focus-visible + .wheel { outline: 0.1875rem solid var(--focus); outline-offset: 0.1875rem; }
.wheel-pick:checked + .wheel { outline: 0.1875rem solid var(--tire-selected); outline-offset: 0.1875rem; }
.wheel-pick:checked + .wheel::after { content: "\2713"; position: absolute; top: -0.5625rem; right: -0.5625rem; display: grid;
  place-items: center; width: 1.25rem; height: 1.25rem; border-radius: 0.1875rem; background: var(--tire-selected); color: #2a1800;
  font-size: 0.75rem; font-weight: 800; }
@media (max-width: 599px) {
  .rig { padding: 0.75rem 0.375rem; }
  .rig-body { padding-left: 0.375rem; padding-right: 0.375rem; gap: 1.125rem; }
  .axle { grid-template-columns: minmax(0, 1fr) 1.625rem minmax(0, 1fr); gap: 0.25rem; }
  .axle-hub, button.axle-hub { width: 1.625rem; height: 1.625rem; min-height: 1.625rem; font-size: 0.65625rem; }
  .axle > .axle-side { gap: 0.25rem; }
  .wheel { min-height: 5.75rem; padding: 0.5rem 0.5rem; border-radius: 0.3125rem;
    box-shadow: inset 0.25rem 0 0 rgb(0 0 0 / 24%), inset -0.25rem 0 0 rgb(0 0 0 / 24%); }
  .wheel-position { display: none; }
  .wheel-temp { font-size: 0.75rem; }
  .wheel { padding-left: 0.25rem; padding-right: 0.25rem; }
  .wheel-flag { padding: 0 0.1875rem; font-size: 0.625rem; overflow-wrap: normal; }
}

/* The compressor and its tank: a centred card across the chassis, its name on top, the tank pressure large, the rest
   in small words under it. contain: inline-size keeps its words from widening the vehicle's outline, and the note line
   keeps its height when empty, so the card keeps its size as the compressor starts, runs and rests. While it runs, a
   light sweeps along its top edge. */
.tank { position: relative; display: grid; justify-items: center; gap: 0.1875rem; margin: 0; padding: 0.875rem 1rem 0.625rem;
  overflow: hidden; contain: inline-size; border: 1.5px solid var(--rig-line); border-radius: 0.625rem;
  background: var(--surface); text-align: center; }
.tank-head { display: inline-flex; align-items: center; gap: 0.375rem; color: var(--rig-ink); }
.tank-icon { display: grid; place-items: center; width: 1.125rem; height: 1.125rem; }
.tank-icon svg { width: 100%; height: 100%; }
.tank-label { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; }
.tank-pressure { font-size: 1.875rem; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em; }
.tank-unit { color: var(--rig-ink); font-size: 0.5em; font-weight: 650; letter-spacing: 0; }
.tank-meta, .tank-notes { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 2px 0.875rem;
  color: var(--rig-ink); font-size: 0.78125rem; font-variant-numeric: tabular-nums; }
.tank-notes { min-height: 1.5em; }
.tank-alarm { color: var(--alarm); font-size: 0.78125rem; font-weight: 680; }
.tank.is-running { border-color: var(--accent); }
.tank.is-running .tank-head { color: var(--accent); }
.tank.is-running .status::before { animation: pulse 1.4s ease-in-out infinite; }
.tank.is-running::before { content: ""; position: absolute; top: 0; left: 0; width: 40%; height: 0.1875rem; pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  animation: tank-sweep 1.8s ease-in-out infinite; }
/* After the running look: a problem outranks it. */
.tank--attention { border-color: var(--attention); background: var(--attention-bg); }
.tank--alarm { border-color: var(--alarm); background: var(--alarm-bg); }
.tank--alarm .tank-pressure { color: var(--alarm); }
@media (max-width: 599px) {
  .tank { padding: 0.75rem 0.625rem 0.5rem; }
  .tank-pressure { font-size: 1.625rem; }
}

.legend { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.25rem 0.875rem; margin: 0; padding: 0; list-style: none;
  color: var(--rig-ink); font-size: 0.75rem; }
.legend li { display: inline-flex; align-items: center; gap: 0.375rem; }
.legend li::before { content: ""; width: 0.625rem; height: 0.625rem; border-radius: 2px; background: var(--tire-ok); }
.legend .legend--inflating::before { background: var(--tire-inflating); }
.legend .legend--deflating::before { background: var(--tire-deflating); }
.legend .legend--holding::before { background: var(--tire-holding); }
.legend .legend--attention::before { background: var(--tire-attention); }
.legend .legend--offline::before { background: var(--tire-offline); }
.legend .legend--alarm::before { background: var(--tire-alarm); }
.legend .legend--selected::before { background: none; box-shadow: inset 0 0 0 0.15625rem var(--tire-selected); }

/* Only the wheels the controller flags are listed in words, under the drawing: the others say all on it. */
.side-label { margin: 0 0 0.5rem; color: var(--text); font-size: 0.84375rem; font-weight: 640; }
.section-label { margin-bottom: 0.625rem; color: var(--text); font-size: 0.84375rem; font-weight: 640; }
.look-list { margin: 0; padding: 0; list-style: none; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); }
.look { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 0.75rem; padding: 0.5625rem 0.75rem;
  border-bottom: 1px solid var(--border); font-size: 0.84375rem; }
.look:last-child { border-bottom: 0; }
.look-place { font-weight: 640; }
.look-place::before { content: ""; display: inline-block; width: 0.5rem; height: 0.5rem; margin-right: 0.5rem; border-radius: 2px;
  background: var(--attention); }
.look--alarm .look-place::before { background: var(--alarm); }
.look-what { grid-column: 1; color: var(--text-2); }
.look--alarm .look-what { color: var(--alarm); font-weight: 600; }
.look-values { grid-column: 2; grid-row: 1 / span 2; align-self: center; color: var(--text-3); font-size: 0.78125rem; text-align: right; }
@media (max-width: 599px) {
  .look { grid-template-columns: minmax(0, 1fr); }
  .look-values { grid-column: 1; grid-row: auto; text-align: left; }
}

/* 9 ─ Commands: the target panel, the sheet, the notice, the command list ─────────────────────────────────── */
/* The target panel never covers the drawing: beside it on wide screens; on phones, once a wheel is selected, a
   card docked at the bottom like the app's action card, leaving the wheels above it free to tap. */
.side-panel { display: grid; gap: 0.75rem; padding: 1rem; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); box-shadow: var(--shadow); }
.side-panel-title { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9375rem; }
.side-panel-title .icon { color: var(--accent); }
.target-form { display: grid; gap: 0.625rem; margin: 0; }
.target-fields { display: grid; gap: 0.625rem; }
.control:not(:has(.wheel-pick:checked)) .target-fields { opacity: 0.45; pointer-events: none; }
.control:not(:has(.wheel-pick:checked)) .pick-summary button { visibility: hidden; }
.pick-summary { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; font-weight: 640; }
.pick-count { font-variant-numeric: tabular-nums; }
.pick-count::before { content: counter(picked); }
.input-unit { position: relative; }
.input-unit input { padding-right: 3.5rem; }
.input-unit-label { position: absolute; top: 50%; right: 0.875rem; transform: translateY(-50%); color: var(--text-3);
  font-size: 0.9375rem; font-weight: 650; pointer-events: none; }
.input-big { min-height: 3.5rem; font-size: 1.625rem; font-weight: 700; font-variant-numeric: tabular-nums; }
/* Manual: Stop for the selected wheels, under the target and set apart by a line (fleet/_stop.html). Like the target,
   it waits for a selection; while a target is being confirmed it steps aside. */
.stop-slot:not(:has(button)) { display: none; }
.stop-slot { display: grid; gap: 0.375rem; padding-top: 0.75rem; border-top: 1px solid var(--border); }
.stop-slot .helptext { margin: 0; }
.control:not(:has(.wheel-pick:checked)) .stop-slot { opacity: 0.45; pointer-events: none; }
.target-panel:has(.confirm-step) .stop-slot { display: none; }
@container (max-width: 39.9375rem) {
  .control:has(.wheel-pick:checked) .target-panel {
    position: fixed; z-index: 15; left: 0.75rem; right: 0.75rem; bottom: calc(0.75rem + env(safe-area-inset-bottom));
    max-height: 70vh; overflow-y: auto; box-shadow: var(--shadow-pop); border-color: var(--border-strong);
  }
  .control:has(.wheel-pick:checked) .target-panel .helptext { display: none; }
  .control:has(.wheel-pick:checked) { margin-bottom: 7.5rem; }
  /* Docked, it stays two lines high so the wheels above stay in view: the selection across the top, then the
     value, Review and Stop as one row of equal height. The boxes between the panel and those controls (the step
     area, the form, its fields, the Stop slot) step out of the layout (display: contents), so all of them are
     cells of the panel's one grid. A confirmation, when it fills the step area, takes the whole width. The
     heading and the label stay for screen readers. */
  .control:has(.wheel-pick:checked) .target-panel {
    grid-template-columns: minmax(0, 1fr) auto auto; grid-template-areas: "picked picked picked" "value go stop";
    gap: 0.5rem; padding: 0.625rem 0.75rem;
  }
  .control:has(.wheel-pick:checked) .target-panel > .side-panel-body,
  .control:has(.wheel-pick:checked) .target-panel .target-form,
  .control:has(.wheel-pick:checked) .target-panel .target-fields,
  .control:has(.wheel-pick:checked) .target-panel > .stop-slot { display: contents; }
  .control:has(.wheel-pick:checked) .target-panel .side-panel-title,
  .control:has(.wheel-pick:checked) .target-fields > label {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  /* A confirmation or a refusal in the step area: one column of its own, and Stop steps aside. */
  .control:has(.wheel-pick:checked) .target-panel:has(> .side-panel-body > :not(.target-form)) {
    grid-template-columns: minmax(0, 1fr); grid-template-areas: none;
  }
  .control:has(.wheel-pick:checked) .target-panel:has(> .side-panel-body > :not(.target-form)) > .stop-slot { display: none; }
  /* Any error takes a whole row of its own, below the controls (auto-placed). */
  .control:has(.wheel-pick:checked) .target-panel .errorlist { grid-column: 1 / -1; margin: 0; }
  .control:has(.wheel-pick:checked) .pick-summary { grid-area: picked; }
  .control:has(.wheel-pick:checked) .target-fields .input-unit { grid-area: value; }
  .control:has(.wheel-pick:checked) .target-panel .input-big { height: 3rem; min-height: 0; font-size: 1.375rem; }
  .control:has(.wheel-pick:checked) .target-fields button[type="submit"],
  .control:has(.wheel-pick:checked) .stop-slot button {
    width: auto; height: 3rem; min-height: 0; padding-block: 0; padding-inline: 1rem; white-space: nowrap;
  }
  .control:has(.wheel-pick:checked) .target-fields button[type="submit"] { grid-area: go; }
  .control:has(.wheel-pick:checked) .stop-slot button { grid-area: stop; }
}
@media (max-width: 959px) {
  .has-tabbar .control:has(.wheel-pick:checked) .target-panel { bottom: calc(var(--tabbar-height) + 0.625rem + env(safe-area-inset-bottom)); }
}

/* The sheet: an HTML popover for the short confirmation of every other command; centred on wide screens, from the
   bottom on phones. */
.sheet {
  width: min(28.75rem, calc(100vw - 2rem)); max-height: calc(100vh - 3rem); overflow-y: auto; margin: auto; padding: 0;
  border: 1px solid var(--border); border-radius: 0.5rem; background: var(--surface); color: var(--text);
  box-shadow: var(--shadow-pop);
}
.sheet::backdrop { background: rgb(5 12 20 / 45%); }
.sheet:has(.confirm-step) { width: min(23.75rem, calc(100vw - 2rem)); }
.sheet-head { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; justify-content: space-between;
  gap: 0.75rem; padding: 0.875rem 0.875rem 0.75rem 1.25rem; border-bottom: 1px solid var(--border); background: var(--surface); }
.sheet-head h2 { font-size: 1.0625rem; }
.sheet-body { padding: 1.125rem 1.25rem 1.25rem; }
@media (max-width: 599px) {
  .sheet { width: 100%; max-width: none; max-height: 88vh; margin: auto 0 0; border-radius: 0.625rem 0.625rem 0 0;
    border-bottom: 0; padding-bottom: env(safe-area-inset-bottom); }
}
.btn--icon { min-height: 2.25rem; width: 2.25rem; padding: 0; }
.btn--icon .icon { width: 1.125rem; height: 1.125rem; }
.choices { display: grid; gap: 0.5rem; }
.choices--grid { grid-template-columns: repeat(auto-fill, minmax(6.875rem, 1fr)); }
.choice { justify-content: flex-start; min-height: 3rem; padding: 0.625rem 0.875rem; text-align: left; white-space: normal;
  font-size: 0.90625rem; }
.choices--grid .choice { justify-content: center; text-align: center; }
.choice:hover { border-color: var(--accent); background: var(--accent-soft); }
.helptext + .choices, .helptext + .button-row { margin-top: 0.75rem; }

/* A confirmation is short and centred: what will be sent, any warning, and the buttons. */
.confirm-step { display: grid; gap: 0.75rem; text-align: center; }
.confirm-step .callout { text-align: left; }
.confirm-step .button-row { justify-content: center; }
.confirm-what { margin: 0; padding: 0.875rem 1rem; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2); font-size: 1rem; font-weight: 650; }
.confirm-details { margin: -0.25rem 0 0; padding: 0; list-style: none; color: var(--text-2); font-size: 0.875rem; }
/* A target or a Stop in parts: what kind of command, the pressure large, then the wheels as chips. */
.confirm-what--parts { display: grid; gap: 0.25rem; font-size: inherit; font-weight: inherit; }
.confirm-headline { margin: 0; color: var(--text-2); font-size: 0.8125rem; font-weight: 650; letter-spacing: 0.02em; }
.confirm-what--stop .confirm-headline { color: var(--alarm); font-size: 0.9375rem; }
.confirm-value { margin: 0; color: var(--text); font-size: 1.75rem; font-weight: 750; line-height: 1.15; }
.confirm-wheels { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.375rem; margin: 0.375rem 0 0; padding: 0;
  list-style: none; }
.confirm-wheels li { padding: 0.1875rem 0.625rem; border: 1px solid var(--border-strong); border-radius: 62.4375rem;
  background: var(--surface); color: var(--text); font-size: 0.84375rem; font-weight: 600; }
.confirm-step .button-row { margin-top: 2px; }
.confirm { max-width: 35rem; }

/* The presets sheet (command_steps/preset.html): one card per preset, every wheel's target drawn as a small vehicle
   (_preset_card.html). Tapping a card blurs it and lays Apply, Edit and Delete over it; the blurred card itself lets
   taps through, so tapping it again closes the actions. The active preset is marked by the accent. */
.preset-list { display: grid; gap: 0.5rem; margin: 0 0 0.75rem; padding: 0; list-style: none; }
.preset { position: relative; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.preset.is-active { border-color: var(--accent); background: var(--accent-soft); }
.preset-card { position: relative; }
.preset-summary { display: grid; gap: 0.5rem; padding: 0.625rem 0.75rem 0.75rem; list-style: none; }
.preset-summary::-webkit-details-marker { display: none; }
summary.preset-summary { cursor: pointer; }
summary.preset-summary:hover { background: color-mix(in srgb, var(--accent-soft) 45%, transparent); }
summary.preset-summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.preset-head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.5rem; min-width: 0; }
.preset-number { display: inline-grid; place-items: center; min-width: 1.375rem; height: 1.375rem; padding: 0 0.375rem;
  border-radius: 0.6875rem; background: var(--surface-2); color: var(--text-2); font-size: 0.75rem; font-weight: 700; }
.preset.is-active .preset-number { background: var(--accent); color: var(--on-accent); }
.preset-name { font-size: 0.9375rem; overflow-wrap: anywhere; }
/* The small vehicle: one row per axle, its hub centred under the others, so the wheels line up as on the drawing. */
.preset-rig { display: grid; gap: 0.3125rem; width: fit-content; max-width: 100%; margin: 0 auto; }
.preset-axle { position: relative; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 0.5rem; }
.preset-axle::before { content: ""; position: absolute; left: 0.5rem; right: 0.5rem; top: 50%; height: 2px; margin-top: -1px;
  background: var(--border-strong); }
.preset-side { position: relative; display: flex; gap: 0.25rem; }
.preset-side--left { justify-content: flex-end; }
.preset-value { min-width: 2.875rem; padding: 0.1875rem 0.375rem; border: 1px solid var(--border-strong); border-radius: 0.3125rem;
  background: var(--surface); color: var(--text); font-size: 0.8125rem; font-weight: 650; text-align: center; }
.preset-hub { position: relative; display: grid; place-items: center; width: 1.25rem; height: 1.25rem; border-radius: 50%;
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--text-3); font-size: 0.65625rem;
  font-weight: 700; }
/* The actions over a tapped card. Only the buttons take taps; the rest falls through to the card, which closes. */
.preset-overlay { position: absolute; inset: 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  align-content: center; gap: 0.5rem; padding: 0.5rem; background: color-mix(in srgb, var(--surface) 72%, transparent);
  -webkit-backdrop-filter: blur(0.375rem); backdrop-filter: blur(0.375rem); pointer-events: none; animation: preset-in 0.15s ease-out; }
.preset-overlay form { margin: 0; pointer-events: auto; }
.preset-overlay button { min-width: 6rem; box-shadow: var(--shadow-pop); }
.preset-overlay button:not(.btn--primary) { background: var(--surface); }
.preset-card[open] > summary .preset-rig { opacity: 0.6; }
@keyframes preset-in { from { opacity: 0; } to { opacity: 1; } }
@media (max-width: 599px) {
  .preset-value { min-width: 2.5rem; padding: 0.1875rem 0.25rem; font-size: 0.78125rem; }
  .preset-overlay button { min-width: 0; padding-left: 0.75rem; padding-right: 0.75rem; }
}
.tag--accent { border-color: var(--accent); color: var(--text); }
.tag--attention { border-color: var(--attention-line); background: var(--attention-bg); color: var(--attention); }
/* The preset form (command_steps/preset_edit.html): the name, then one row per axle with a small field per wheel. */
.preset-form { display: grid; gap: 0.875rem; }
.preset-name-field { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 0.25rem 0.625rem; }
.preset-name-field .errorlist { grid-column: 2; margin: 0; }
.preset-form .button-row { justify-content: center; }
.preset-wheels { display: grid; gap: 0.5rem; margin: 0; padding: 0; border: 0; }
.preset-wheels legend { margin-bottom: 2px; padding: 0; font-size: 0.84375rem; font-weight: 650; }
.preset-wheels .helptext { margin: 0 0 0.25rem; }
.preset-axle-row { display: grid; grid-template-columns: 3.625rem minmax(0, 1fr); align-items: end; gap: 0.625rem;
  padding: 0.5rem 0.625rem; border-radius: var(--radius-sm); background: var(--surface-2); }
.preset-axle-name { padding-bottom: 0.5625rem; color: var(--text-2); font-size: 0.8125rem; font-weight: 650; }
.preset-axle-wheels { display: grid; grid-template-columns: repeat(auto-fit, minmax(4.5rem, 1fr)); gap: 0.375rem; }
.preset-wheel { display: grid; gap: 0.1875rem; min-width: 0; }
.preset-wheel label { overflow: hidden; color: var(--text-3); font-size: 0.71875rem; font-weight: 600; text-overflow: ellipsis;
  white-space: nowrap; }
.preset-wheel input { width: 100%; min-width: 0; padding-left: 0.375rem; padding-right: 0.375rem; text-align: center;
  font-variant-numeric: tabular-nums; }
.preset-wheel .errorlist { margin: 0; font-size: 0.75rem; }
@media (max-width: 599px) {
  .preset-axle-row { grid-template-columns: minmax(0, 1fr); gap: 0.25rem; }
  .preset-axle-name { padding-bottom: 0; }
  .preset-axle-wheels { grid-template-columns: repeat(auto-fit, minmax(3.75rem, 1fr)); }
}

/* The notice after a command is stored: short, at the bottom, gone by itself; the answer itself shows under
   Commands, because it comes later and matters more. */
.toast-region { position: fixed; z-index: 40; left: 50%; bottom: 1.5rem; width: min(27.5rem, calc(100vw - 2rem));
  transform: translateX(-50%); pointer-events: none; }
@media (max-width: 959px) {
  .has-tabbar .toast-region { bottom: calc(var(--tabbar-height) + 0.75rem + env(safe-area-inset-bottom)); }
}
.toast { display: flex; align-items: flex-start; gap: 0.75rem; padding: 0.75rem 1rem; border-radius: 0.375rem;
  background: #0a1420; color: #ffffff; box-shadow: var(--shadow-pop); animation: toast 6s ease forwards; }
.toast > .icon { margin-top: 1px; color: #4cc47a; }
.toast p { display: grid; gap: 2px; margin: 0; font-size: 0.875rem; }
.toast span { color: #b9c8d8; font-size: 0.8125rem; }

.commands:empty { display: none; }
.command-log { display: grid; margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--border); }
.command-log li { display: grid; gap: 0.25rem; padding: 0.625rem 0; border-bottom: 1px solid var(--border); }
.command-what { font-size: 0.84375rem; font-weight: 600; overflow-wrap: anywhere; }
.command-log .status { justify-self: start; white-space: normal; }
.command-meta { color: var(--text-3); font-size: 0.75rem; overflow-wrap: anywhere; }

/* The vehicle's pages as tabs under its title. */
.details-page { display: grid; gap: 1rem; align-items: start; }
@container (min-width: 53.75rem) { .details-page { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
.details-page > :only-child { grid-column: 1 / -1; }
.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr)); gap: 0.75rem 1.25rem; margin: 0; }
/* Same header height in both cards, with or without a button in it. */
.details-page .card-head { min-height: 3.875rem; }
.facts dt { color: var(--text-3); font-size: 0.8125rem; }
.facts dd { margin: 0.1875rem 0 0; font-weight: 620; overflow-wrap: anywhere; }
.plain-list { display: grid; gap: 0.375rem; margin: 0; padding: 0; list-style: none; font-size: 0.875rem; }
.plain-list li { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.25rem 0.75rem; }
.archive-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem 1rem; margin: 0; }
.form > .fields--inline { display: flex; }
.fields--inline > .form-actions { flex: 0 0 auto; }
.tabs { display: flex; gap: 0.25rem; margin: -0.375rem 0 1.25rem; border-bottom: 1px solid var(--border); overflow-x: auto;
  scrollbar-width: none; }
.page-head--vehicle { margin-bottom: 0.875rem; }
.page-head--vehicle .title-row { gap: 0.25rem 0.5rem; }
.title-crumb-sep { display: inline-flex; }
.title-crumb-sep .icon { width: 1rem; height: 1rem; color: var(--text-3); }
.title-crumb { display: inline-flex; align-items: center; color: var(--text-3); font-size: 0.9375rem; font-weight: 560; }
.title-crumb .icon { display: none; width: 1.375rem; height: 1.375rem; }
/* On phones the bottom bar already says "Vehicles": the way back is an arrow before the name. */
@media (max-width: 599px) {
  .title-crumb { margin-left: -0.25rem; padding: 0.25rem; border-radius: var(--radius-sm); color: var(--text-2); }
  .title-crumb:hover { background: var(--hover); }
  .title-crumb .icon { display: block; }
  .title-crumb > span, .title-crumb-sep { display: none; }
}
.tab-short { display: none; }
.tab-lede { display: flex; align-items: center; gap: 0.375rem; margin: -0.375rem 0 1rem; color: var(--text-3); font-size: 0.84375rem; }
.tab-lede .icon { width: 0.9375rem; height: 0.9375rem; }
.tab-bar-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem 1rem;
  margin: -0.375rem 0 1rem; }
.tab-bar-row .tab-lede { display: block; margin: 0; }
.tab { display: inline-flex; align-items: center; gap: 0.5rem; margin-bottom: -1px; padding: 0.625rem 0.875rem;
  border-bottom: 2px solid transparent; color: var(--text-2); font-size: 0.875rem; font-weight: 600; white-space: nowrap; }
.tab .icon { width: 1.0625rem; height: 1.0625rem; color: var(--text-3); }
.tab:hover { color: var(--text); text-decoration: none; border-bottom-color: var(--border-strong); }
.tab[aria-current="page"] { color: var(--accent); border-bottom-color: var(--accent); }
.tab[aria-current="page"] .icon { color: var(--accent); }
/* On phones: icon over a short name, all tabs sharing the width. After the base rules, so they win. */
@media (max-width: 599px) {
  .tabs { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 0; overflow: visible; }
  .tab { flex-direction: column; justify-content: center; gap: 0.1875rem; padding: 0.5rem 2px 0.5625rem; font-size: 0.71875rem; }
  .tab .icon { width: 1.25rem; height: 1.25rem; }
  .tab-long { display: none; }
  .tab-short { display: inline; }
  /* A label longer than its share of the width ends in an ellipsis instead of running into the next tab. */
  .tab { min-width: 0; }
  .tab > span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* 10 ─ Playback ─────────────────────────────────────────────────────────────────────────────────────────── */
.window { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.75rem; margin: 0; }
.window > div { display: grid; gap: 0.375rem; flex: 1 1 12.5rem; }
.chart { min-height: 15rem; display: grid; place-items: center; color: var(--text-3); font-size: 0.875rem; }
.chart.is-drawn { display: block; }
.chart .uplot { font-family: var(--font); color: var(--text-2); }
.chart .u-legend { font-size: 0.78125rem; }
.chart .u-legend .u-marker { border-radius: 2px; }
.player { display: flex; align-items: center; gap: 0.875rem; padding: 0.75rem 1rem; border-top: 1px solid var(--border); }
.player button { flex: none; min-width: 5.75rem; }
.player input[type=range] { flex: 1; min-width: 0; accent-color: var(--accent); height: 1.75rem; }

/* 11 ─ Sign-in pages ─────────────────────────────────────────────────────────────────────────────────────── */
.auth { display: grid; min-height: 100vh; place-items: center; padding: 2rem 1rem; }
.auth-col { width: 100%; max-width: 26.25rem; }
.auth-brand { display: flex; justify-content: center; margin-bottom: 1.5rem; }
.auth-brand .brand { color: var(--text); }
.auth-brand .brand-word span { color: var(--text-3); }
.auth-card { padding: 1.75rem 1.5rem; }
/* An error page shown before sign-in sits in the sign-in card: its own card frame would double up. */
.auth-card .card { border: 0; box-shadow: none; background: none; }
.auth-card .card-body { padding: 0; }
@media (min-width: 480px) { .auth-card { padding: 2rem; } }
.auth-card h1 { font-size: 1.3125rem; margin-bottom: 0.375rem; }
.auth-card .lede { margin: 0 0 1.25rem; font-size: 0.90625rem; }
.auth-card .form button[type=submit]:not(.link) { width: 100%; min-height: 2.625rem; }
.auth-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem 1rem; margin-top: 1.125rem; font-size: 0.875rem; }
.auth-foot { margin-top: 1.5rem; text-align: center; color: var(--text-3); font-size: 0.78125rem; }
.steps { display: grid; gap: 1.125rem; margin: 0 0 1.25rem; padding: 0; list-style: none; counter-reset: step; }
.steps > li { position: relative; padding-left: 2.25rem; counter-increment: step; font-size: 0.90625rem; }
.steps > li { padding-left: 1.625rem; }
.steps > li::before { content: counter(step) "."; position: absolute; left: 0; top: 0; color: var(--text-3);
  font-weight: 650; font-variant-numeric: tabular-nums; }
.qr { display: block; width: 12.5rem; height: 12.5rem; margin: 0.625rem 0; padding: 0.625rem; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: #fff; }
/* A page about one small thing (a phone, adding one): one centred column, not stretched across a wide screen. */
.page-narrow { max-width: 45rem; margin-inline: auto; }
/* The phone's setup code: the QR code and the same code as text, centred, the facts below a line. */
.setup-code { display: grid; justify-items: center; gap: 0.625rem; text-align: center; }
.setup-code .qr { width: 15rem; max-width: 100%; height: auto; margin: 0; }
.setup-code p { margin: 0; }
.setup-code-text { font-family: var(--mono); font-size: 1.375rem; font-weight: 650; letter-spacing: 0.06em; }
.setup-code-facts { border-top: 1px solid var(--border); }
.codes { display: grid; grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr)); gap: 0.375rem 1rem; margin: 0;
  padding: 0.875rem 1rem; border: 1px dashed var(--border-strong); border-radius: var(--radius-sm); background: var(--surface-2);
  font-family: var(--mono); font-size: 0.875rem; }
/* The sign-in pages' one icon above the title: the icon alone, in the page's colour, no tile behind it. */
.big-icon { display: block; margin-bottom: 0.75rem; color: var(--accent); }
.big-icon .icon { width: 1.75rem; height: 1.75rem; }
.big-icon--alarm { color: var(--alarm); }
.big-icon--ok { color: var(--ok); }

/* 12 ─ Motion ───────────────────────────────────────────────────────────────────────────────────────────── */
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@keyframes flow-up { from { transform: translateY(1.375rem); } to { transform: none; } }
@keyframes flow-down { from { transform: none; } to { transform: translateY(1.375rem); } }
@keyframes glow { 50% { opacity: 1; } }
/* The light is 40 % of the card's width: from just left of the card to just past its right edge. */
@keyframes tank-sweep { from { transform: translateX(-100%); } to { transform: translateX(250%); } }
@keyframes toast {
  0% { opacity: 0; transform: translateY(0.75rem); }
  6%, 85% { opacity: 1; transform: none; }
  100% { opacity: 0; visibility: hidden; }
}
@keyframes toast-still { 0% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  /* The notice must still go away: shown in full, then gone, without moving. */
  .toast { animation: toast-still 6s step-end forwards !important; }
}

/* Storage page: one bar per row, scaled to the largest row of its table. */
.usage-meter { display: block; width: 100%; min-width: 6rem; height: 0.6rem; }
