/* ═══════════════════════════════════════════════════════════════════════════
   admin.css — Business Fleet UI

   Organised: fonts → tokens → reset → base → layout → primitives → utilities
   → responsive.

   ── Design direction ──────────────────────────────────────────────────────
   A data-heavy, operator-facing tool, so density is COMPACT: 13–14px body,
   ~40px table rows, 36px controls, borders rather than shadows.

   ── Brand ─────────────────────────────────────────────────────────────────
   Telekom Magenta (#E20074) is the one accent, and deliberately RARE: primary
   button, active nav item, focus rings, links, selected states — nowhere else.
   The neutral grey ramp carries everything else.

   ── Tokens ────────────────────────────────────────────────────────────────
   Every colour resolves through a semantic custom property, which is what makes
   dark mode a pure token swap — no component rule is theme-aware. NEVER
   hardcode a hex value below the token block.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────
   FONTS — self-hosted Inter (variable, 400–700).
   Split by unicode-range: a Latin-only page downloads just inter-latin.woff2
   (~48 KB); Cyrillic files load only when Cyrillic renders (names, "Патен
   налог").
───────────────────────────────────────────── */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('../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: 'Inter';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('../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 700;
    font-display: swap;
    src: url('../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 700;
    font-display: swap;
    src: url('../fonts/inter-cyrillic-ext.woff2') format('woff2');
    unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

/* ═════════════════════════════════════════════
   DESIGN TOKENS
═════════════════════════════════════════════ */
:root {
    /* ── Brand ramp — Telekom Magenta. 500 is the trademarked brand value. ── */
    --magenta-50:  #fef1f8;
    --magenta-100: #fdddee;
    --magenta-200: #fbbadb;
    --magenta-300: #f78cc2;
    --magenta-400: #ef4b9d;
    --magenta-500: #e20074;   /* Telekom Magenta */
    --magenta-600: #c20064;
    --magenta-700: #9e0052;
    --magenta-800: #7a0140;
    --magenta-900: #560130;

    /* ── Neutral ramp — Telekom grey, a touch cool so large flat fields don't
          read dead. Effectively neutral to the eye. ── */
    --grey-0:   #ffffff;
    --grey-25:  #fafafb;
    --grey-50:  #f5f5f7;
    --grey-100: #ededf0;
    --grey-200: #dfdfe4;
    --grey-300: #c7c7ce;
    --grey-400: #a4a4ad;
    --grey-500: #7c7c87;
    --grey-600: #6c6c76;
    --grey-700: #4b4b54;
    --grey-800: #383840;
    --grey-900: #26262c;
    --grey-950: #17171b;

    /* ── Surfaces ── */
    --color-canvas:         var(--grey-50);
    --color-surface:        var(--grey-0);
    --color-surface-raised: var(--grey-0);
    --color-surface-sunken: var(--grey-50);
    --color-surface-hover:  var(--grey-50);

    /* ── Text ──
       muted/subtle run darker than the raw grey ramp so 11–12px labels clear
       WCAG AA (4.5:1) on both card and canvas — grey-500 was 4.13:1. */
    --color-text:         var(--grey-900);
    --color-text-muted:   #5c5c66;
    --color-text-subtle:  #6f6f79;
    --color-text-inverse: var(--grey-0);

    /* ── Lines ── */
    --color-border:        var(--grey-200);
    --color-border-strong: var(--grey-300);
    --color-focus:         var(--magenta-500);
    --color-focus-ring:    rgba(226, 0, 116, 0.22);

    /* ── Intent: accent ── */
    --color-accent:          var(--magenta-500);
    --color-accent-hover:    var(--magenta-600);
    --color-accent-active:   var(--magenta-700);
    --color-accent-subtle:   var(--magenta-50);
    --color-accent-border:   var(--magenta-200);
    --color-accent-text:     var(--magenta-700);
    --color-on-accent:       #ffffff;

    /* ── Intent: status. Tempered vs web defaults — saturated status colours
          are unusable across 200 table rows. ── */
    --color-danger:         #c8242b;
    --color-danger-hover:   #a71d23;
    --color-danger-text:    #a01a20;
    --color-danger-subtle:  #fcecec;
    --color-danger-border:  #f2c9c9;

    --color-warning:        #b26a00;
    --color-warning-text:   #8a5200;
    --color-warning-subtle: #fdf3e3;
    --color-warning-border: #f0dcb2;

    --color-success:        #2f7d32;
    --color-success-hover:  #266628;
    --color-success-text:   #256428;
    --color-success-subtle: #ecf5ec;
    --color-success-border: #c5e0c6;

    --color-info:           #1063ad;
    --color-info-text:      #0c4c85;
    --color-info-subtle:    #eaf2fa;
    --color-info-border:    #c2d9ee;

    /* ── Elevation — used sparingly; borders do most of the separating. ── */
    --shadow-sm: 0 1px 2px rgba(23, 23, 27, 0.05);
    --shadow-md: 0 4px 12px rgba(23, 23, 27, 0.08);
    --shadow-lg: 0 16px 36px rgba(23, 23, 27, 0.14);

    /* ── Type scale — 11 / 12 / 13 / 14 / 16 / 20 / 24 / 30 ── */
    --text-2xs: 11px;
    --text-xs:  12px;
    --text-sm:  13px;
    --text-md:  14px;
    --text-lg:  16px;
    --text-xl:  20px;
    --text-2xl: 24px;
    --text-3xl: 30px;

    --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

    /* ── Spacing — 4px base ── */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 48px;
    --space-8: 64px;

    /* ── Radii — one small, one large, plus pill ── */
    --radius-sm:   6px;
    --radius-lg:   10px;
    --radius-full: 999px;

    /* ── Density (compact preset) ──
       Re-pointed wholesale at the touch breakpoint (RESPONSIVE › --bp-tab), so
       controls must read these instead of hardcoding heights — one override
       lifts every control, including those filter-select.js builds. */
    --control-h:    36px;
    --control-h-sm: 28px;
    --cell-pad-y:   10px;
    --cell-pad-x:   14px;
    --nav-h:        56px;
    --nav-link-h:   32px;   /* .navbar a — also derives the active underline */
    --tap-min:      44px;   /* minimum comfortable touch target */
    --content-max:  1280px;

    --transition: 0.15s ease;

    color-scheme: light;
}

/* ─────────────────────────────────────────────
   DARK — the same token names, re-pointed. Surfaces get LIGHTER as they rise
   (elevation is lightness, not shadow); canvas is never pure black; the accent
   and status colours are desaturated so they don't vibrate.
───────────────────────────────────────────── */
[data-theme="dark"] {
    --color-canvas:         #141417;
    --color-surface:        #1c1c21;
    --color-surface-raised: #24242b;
    --color-surface-sunken: #18181c;
    --color-surface-hover:  #2a2a32;

    --color-text:         #ededf0;
    --color-text-muted:   #a8a8b2;
    --color-text-subtle:  #8b8b96;   /* #82828d was 4.47:1 on a dark card — just under AA */
    --color-text-inverse: #17171b;

    --color-border:        #32323b;
    --color-border-strong: #45454f;
    --color-focus:         #e8479a;
    --color-focus-ring:    rgba(232, 71, 154, 0.28);

    /* Desaturated from #E20074 so it doesn't vibrate on dark, yet dark enough
       for the white button label to clear AA (4.58:1; #e23690 was 4.07).
       Hover/active deepen rather than brighten, keeping every state ≥4.5:1. */
    --color-accent:        #d82a84;
    --color-accent-hover:  #c91d76;
    --color-accent-active: #b41769;
    --color-accent-subtle: #35102380;
    --color-accent-border: #5c2142;
    --color-accent-text:   #f490c4;
    --color-on-accent:     #ffffff;

    --color-danger:         #d9534f;
    --color-danger-hover:   #e26c68;
    --color-danger-text:    #f09490;
    --color-danger-subtle:  #3a1c1c;
    --color-danger-border:  #5c2b2a;

    --color-warning:        #d99a2b;
    --color-warning-text:   #e8bb72;
    --color-warning-subtle: #362a15;
    --color-warning-border: #574429;

    --color-success:        #4c9c50;
    --color-success-hover:  #5cae60;
    --color-success-text:   #8ccb8f;
    --color-success-subtle: #1b2e1c;
    --color-success-border: #2e4a30;

    --color-info:           #4a92d6;
    --color-info-text:      #8fc0e8;
    --color-info-subtle:    #16283a;
    --color-info-border:    #2a4560;

    /* Shadows barely read on dark — keep them subtle and lean on borders. */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.45);
    --shadow-lg: 0 16px 36px rgba(0, 0, 0, 0.55);

    color-scheme: dark;
}

/* ═════════════════════════════════════════════
   RESET
═════════════════════════════════════════════ */
*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

button {
    font: inherit;
    color: inherit;
    background: none;
    border: none;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
}

img, svg { max-width: 100%; }

hr {
    border: none;
    border-top: 1px solid var(--color-border);
    margin: var(--space-4) 0;
}

/* Focus is visible EVERYWHERE — never remove an outline without replacing it. */
:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* ═════════════════════════════════════════════
   BASE
═════════════════════════════════════════════ */
body {
    font-family: var(--font-sans);
    font-size: var(--text-md);
    background: var(--color-canvas);
    color: var(--color-text);
    /* dvh follows collapsing mobile browser chrome; vh is the fallback. */
    min-height: 100vh;
    min-height: 100dvh;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4 {
    font-weight: 600;      /* heavier than 600 reads as marketing */
    line-height: 1.3;
    letter-spacing: -0.01em;
    color: var(--color-text);
}

a { color: var(--color-accent-text); }

/* Numeric columns, IDs and timestamps line up only with tabular figures. */
table, .tabular, time, .meta-value { font-variant-numeric: tabular-nums; }

/* ═════════════════════════════════════════════
   LAYOUT
═════════════════════════════════════════════ */

/* ── Navbar ──────────────────────────────────────────────────────────────
   Filled by renderNav() in panel.js — never hardcoded in a page. */
.navbar {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    display: flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0 var(--space-5);
    height: var(--nav-h);
    position: sticky;
    top: 0;
    z-index: 100;
}

.navbar .brand {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-weight: 600;
    font-size: var(--text-md);
    letter-spacing: -0.01em;
    color: var(--color-text);
    margin-right: var(--space-4);
    white-space: nowrap;
}

/* Brand mark — the T-Mobile logo, the same asset the tab favicon uses. It is
   a magenta-on-white bitmap, so it carries its own colour in both themes. */
.brand-mark {
    display: block;
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    object-fit: contain;
}

.navbar a {
    position: relative;
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: var(--text-sm);
    font-weight: 500;
    padding: 0 var(--space-3);
    height: var(--nav-link-h);
    display: inline-flex;
    align-items: center;
    border-radius: var(--radius-sm);
    white-space: nowrap;
    transition: background var(--transition), color var(--transition);
}

.navbar a:hover {
    background: var(--color-surface-hover);
    color: var(--color-text);
}

/* Tint AND accent bar — colour alone is not a sufficient signal. */
.navbar a.active {
    background: var(--color-accent-subtle);
    color: var(--color-accent-text);
    font-weight: 600;
}

/* Underline sits just above the navbar's 1px bottom border. Derived from the
   centred link's spare space, minus 1px to clear the border — same result as the
   old hardcoded -11px, but survives the drawer re-pointing --nav-link-h. */
.navbar a.active::after {
    content: "";
    position: absolute;
    left: var(--space-3);
    right: var(--space-3);
    bottom: calc(1px - (var(--nav-h) - var(--nav-link-h)) / 2);
    height: 2px;
    border-radius: 2px 2px 0 0;
    background: var(--color-accent);
}

/* Right-hand cluster: role chip, theme toggle, sign out. */
.nav-end {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
    padding-left: var(--space-3);
}

.nav-user {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-2);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    white-space: nowrap;
}

.nav-user strong {
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--color-text);
}

.nav-role {
    font-size: var(--text-2xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--color-text-subtle);
}

/* ── Mobile drawer scaffolding ────────────────────────────────────────────
   Inert on desktop; the real behaviour lives in RESPONSIVE › --bp-tab.
   renderNav() always emits these elements, so CSS alone decides bar vs drawer.

   display:contents drops the .nav-links wrapper from layout so its children stay
   direct .navbar flex items — that keeps .nav-end's margin-left:auto working. */
.nav-links { display: contents; }

.nav-toggle {
    display: none;
    width: var(--tap-min);
    height: var(--tap-min);
    margin-left: auto;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--color-text-muted);
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.nav-toggle:hover {
    background: var(--color-surface-hover);
    color: var(--color-text);
    border-color: var(--color-border-strong);
}

.nav-scrim { display: none; }

/* Scroll lock while the drawer is open. BOTH elements: iOS Safari honours
   overflow:hidden on <html>, not on <body> alone. */
html.nav-locked,
body.nav-locked { overflow: hidden; }

.theme-toggle {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text-muted);
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.theme-toggle:hover {
    background: var(--color-surface-hover);
    color: var(--color-text);
    border-color: var(--color-border-strong);
}

/* Sun shows in dark mode (click → light), moon in light mode (click → dark). */
.theme-toggle .icon-sun { display: none; }
[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

/* ── Page ────────────────────────────────────────────────────────────────── */
.container {
    max-width: var(--content-max);
    margin: var(--space-5) auto var(--space-7);
    padding: 0 var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.page-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin-bottom: var(--space-1);
}

.page-header h1 {
    font-size: var(--text-2xl);
    font-weight: 600;
    letter-spacing: -0.02em;
}

/* Section heading on a page that stacks several tables under one h1. */
.page-header h2 {
    font-size: var(--text-xl);
    font-weight: 600;
    letter-spacing: -0.01em;
    margin: 0;
    padding: 0;
    border: none;
}

/* Optional one-line description under a page title. */
.page-subtitle {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-top: 2px;
}

.header-actions {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
}

/* ═════════════════════════════════════════════
   PRIMITIVES
═════════════════════════════════════════════ */

/* ── Card ────────────────────────────────────────────────────────────────── */
.card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-5);
    box-shadow: var(--shadow-sm);
}

.card h2 {
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text);
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

/* Card that holds a flush-to-the-edge table. */
.card-flush {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

/* Title bar for a .card-flush — the table's own heading + its actions. */
.card-flush-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--color-border);
}

.card-flush-header h2 {
    font-size: var(--text-md);
    font-weight: 600;
    margin: 0;
    padding: 0;
    border: none;
}

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    font-weight: 500;
    font-size: var(--text-sm);
    height: var(--control-h);
    padding: 0 var(--space-4);
    border-radius: var(--radius-sm);
    cursor: pointer;
    border: 1px solid transparent;
    text-decoration: none;
    white-space: nowrap;
    transition: background var(--transition), border-color var(--transition), color var(--transition);
}

.btn:disabled,
.btn[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
}

.btn-primary {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: var(--color-on-accent);
    font-weight: 600;
}
.btn-primary:hover:not(:disabled) {
    background: var(--color-accent-hover);
    border-color: var(--color-accent-hover);
}
.btn-primary:active:not(:disabled) { background: var(--color-accent-active); }

.btn-secondary {
    background: var(--color-surface);
    border-color: var(--color-border-strong);
    color: var(--color-text);
}
.btn-secondary:hover:not(:disabled) {
    background: var(--color-surface-hover);
    border-color: var(--color-text-subtle);
}

/* Ghost — tertiary actions (e.g. Cancel next to a submit). */
.btn-ghost {
    background: transparent;
    border-color: transparent;
    color: var(--color-text-muted);
}
.btn-ghost:hover:not(:disabled) {
    background: var(--color-surface-hover);
    color: var(--color-text);
}

.btn-danger {
    background: var(--color-danger-subtle);
    border-color: var(--color-danger-border);
    color: var(--color-danger-text);
}
.btn-danger:hover:not(:disabled) {
    background: var(--color-danger);
    border-color: var(--color-danger);
    color: #fff;
}

.btn-success {
    background: var(--color-success-subtle);
    border-color: var(--color-success-border);
    color: var(--color-success-text);
}
.btn-success:hover:not(:disabled) {
    background: var(--color-success);
    border-color: var(--color-success);
    color: #fff;
}

.btn-sm {
    height: var(--control-h-sm);
    padding: 0 var(--space-3);
    font-size: var(--text-xs);
}

/* A <summary> styled as a button — strip the native disclosure triangle. */
summary.btn { list-style: none; }
summary.btn::-webkit-details-marker { display: none; }
summary.btn::marker { content: ""; }

/* Danger zone — irreversible actions, fenced off from everything else. */
.danger-zone {
    margin-top: var(--space-5);
    padding: var(--space-4);
    border: 1px solid var(--color-danger-border);
    border-radius: var(--radius-sm);
    background: var(--color-danger-subtle);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    align-items: flex-start;
}

.danger-zone__title {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-danger-text);
}

.danger-zone p {
    font-size: var(--text-xs);
    color: var(--color-danger-text);
    line-height: 1.5;
}

/* Table-row action clusters (Details / Complete / Cancel) read as one group. */
.row-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
}

.row-actions .btn-sm {
    flex: 0 0 auto;
    min-width: 68px;
}

/* ── Forms ───────────────────────────────────────────────────────────────── */
.form-stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    max-width: 620px;
    margin: 0 auto;
}

.form-footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    padding-top: var(--space-4);
    margin-top: var(--space-2);
    border-top: 1px solid var(--color-border);
}

/* Label + control pair. The label text is the element's own text node. */
.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-muted);
}

.field-hint {
    font-size: var(--text-xs);
    font-weight: 400;
    text-transform: none;
    color: var(--color-text-subtle);
    line-height: 1.45;
}

/* Simple label + control row (e.g. "Name [input] [Create]"). */
.inline-form {
    display: flex;
    gap: var(--space-3);
    align-items: flex-end;
    flex-wrap: wrap;
}

/* ── Inputs ──────────────────────────────────────────────────────────────── */
input:not([type="checkbox"]):not([type="radio"]),
select,
textarea {
    font: inherit;
    font-size: var(--text-sm);
    color: var(--color-text);
    padding: 0 var(--space-3);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border-strong);
    background: var(--color-surface);
    outline: none;
    width: 100%;
    height: var(--control-h);
    transition: border-color var(--transition), box-shadow var(--transition);
}

textarea {
    height: auto;
    min-height: 84px;
    padding: var(--space-2) var(--space-3);
    line-height: 1.5;
    resize: vertical;
}

input::placeholder,
textarea::placeholder { color: var(--color-text-subtle); }

input:not([type="checkbox"]):not([type="radio"]):hover,
select:hover,
textarea:hover { border-color: var(--color-text-subtle); }

input:not([type="checkbox"]):not([type="radio"]):focus,
select:focus,
textarea:focus {
    border-color: var(--color-focus);
    box-shadow: 0 0 0 3px var(--color-focus-ring);
}

/* Disabled controls are styled EXPLICITLY — nothing left to the browser.
   `color` alone isn't enough: WebKit/Blink paint disabled text through
   -webkit-text-fill-color plus a dimming pass, invisible on light but a visible
   texture on dark. background-COLOR, not the shorthand, so the <select> chevron
   set below survives. */
input:disabled, select:disabled, textarea:disabled {
    background-color: var(--color-surface-sunken);
    color: var(--color-text-subtle);
    -webkit-text-fill-color: var(--color-text-subtle);
    opacity: 1;
    text-shadow: none;
    cursor: not-allowed;
}

input[type="checkbox"], input[type="radio"] {
    accent-color: var(--color-accent);
    cursor: pointer;
}

/* Native <select> — custom chevron to match the multiselect control. The stroke
   is set per theme because an SVG data-URI can't read a CSS variable. */
select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    cursor: pointer;
    padding-right: var(--space-6);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%237c7c87' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--space-3) center;
}

[data-theme="dark"] select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%2382828d' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* Multi-select (employee picker on create form) */
select.select-tall {
    height: 116px;
    padding-top: var(--space-2);
    padding-bottom: var(--space-2);
    background-image: none;
}

/* ── Filters ─────────────────────────────────────────────────────────────── */
.filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
}

.filters label {
    flex: 1 1 150px;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-muted);
}

/* Keeps every filter control on one row, wrapping only when too narrow. */
.filter-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
}

.filter-row .field {
    flex: 1 1 140px;
    min-width: 120px;
}

.filter-actions {
    display: flex;
    gap: var(--space-2);
    align-self: flex-end;
    flex: 0 0 auto;
    white-space: nowrap;
}

/* ── Date / time ─────────────────────────────────────────────────────────── */
.date-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface-sunken);
    overflow: hidden;
}

.date-block {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
}

.date-block + .date-block { border-left: 1px solid var(--color-border); }

.date-block-label {
    font-size: var(--text-2xs);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.date-block .dt-input { background: var(--color-surface); }

.datetime-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2);
}

.dt-input { cursor: pointer; }

/* ── Table ───────────────────────────────────────────────────────────────── */
.table-wrapper {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}

thead th {
    padding: var(--space-2) var(--cell-pad-x);
    text-align: left;
    font-size: var(--text-2xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-muted);
    background: var(--color-surface-sunken);
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
    position: sticky;
    top: 0;
    z-index: 1;
}

tbody td {
    padding: var(--cell-pad-y) var(--cell-pad-x);
    color: var(--color-text);
    vertical-align: middle;
}

tbody tr { border-bottom: 1px solid var(--color-border); }
tbody tr:last-child { border-bottom: none; }
tbody tr:hover { background: var(--color-surface-hover); }

/* Right-align numeric columns; truncate long free text rather than wrapping. */
.num { text-align: right; font-variant-numeric: tabular-nums; }

.truncate {
    max-width: 260px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Pagination ──────────────────────────────────────────────────────────── */
.pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-3);
    flex-wrap: wrap;
}

.pager:empty { display: none; }

.pager .pager-info {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

.pager-btn { min-width: 64px; }
.pager-btn:disabled { opacity: 0.45; cursor: default; }

/* ── Badges — fixed status→intent map, defined once. ─────────────────────── */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 2px var(--space-2);
    border-radius: var(--radius-full);
    font-size: var(--text-2xs);
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
    border: 1px solid transparent;
}

.badge-overdue {
    background: var(--color-danger-subtle);
    color: var(--color-danger-text);
    border-color: var(--color-danger-border);
}

.badge-active {
    background: var(--color-success-subtle);
    color: var(--color-success-text);
    border-color: var(--color-success-border);
}

.badge-completed {
    background: var(--color-info-subtle);
    color: var(--color-info-text);
    border-color: var(--color-info-border);
}

.badge-canceled {
    background: var(--color-surface-sunken);
    color: var(--color-text-muted);
    border-color: var(--color-border);
}

.badge-pending {
    background: var(--color-warning-subtle);
    color: var(--color-warning-text);
    border-color: var(--color-warning-border);
}

/* ── Card grid (employees / organizations / vehicles) ────────────────────── */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: var(--space-3);
}

.card-grid .card {
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: 2px;
    transition: border-color var(--transition), box-shadow var(--transition);
}

.card-grid .card:hover {
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-md);
}

.card-grid .card h3 {
    font-size: var(--text-md);
    font-weight: 600;
    margin-bottom: var(--space-1);
}

.card-grid .card p {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    line-height: 1.5;
}

.card-grid .card .badge {
    margin-top: var(--space-2);
    align-self: flex-start;
}

.card-grid .card-overdue {
    border-color: var(--color-danger-border);
    background: var(--color-danger-subtle);
}

.card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
}

.card-actions form { display: inline-flex; }

/* ── Dashboard ───────────────────────────────────────────────────────────────
   The landing page for SUPERADMIN/ADMIN: a row of stat tiles above a two-column
   body — the queues that need someone on the left, at-a-glance panels on the
   right. Everything else on that page is an existing primitive (.card,
   .card-flush + table, .badge); these rules add only the tile and the layout. */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: var(--space-3);
}

.stat {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    /* The status modifiers below paint this edge. It is declared on the base
       tile so a neutral and an alerting tile have identical text boxes — only
       the colour changes, never the layout. */
    border-left-width: 3px;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

/* Tiles are links to the page that owns the number — the whole tile is the
   target, so the hover affordance is the card's, not an underline. */
a.stat {
    text-decoration: none;
    color: inherit;
    transition: border-color var(--transition), box-shadow var(--transition);
}

a.stat:hover {
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-md);
}

.stat-label {
    font-size: var(--text-2xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--color-text-subtle);
}

.stat-value {
    font-size: var(--text-3xl);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}

.stat-sub {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    line-height: 1.45;
}

/* A tile only takes on colour when its number is asking for someone's time —
   an overdue vehicle, a queue of pending requests. A dashboard where every
   tile is coloured says nothing. */
.stat-danger  { border-left-color: var(--color-danger); }
.stat-danger  .stat-value { color: var(--color-danger-text); }
.stat-warning { border-left-color: var(--color-warning); }
.stat-warning .stat-value { color: var(--color-warning-text); }

/* Body: queues left, panels right; one column below --bp-tab. */
.dash-cols {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: var(--space-4);
    align-items: start;
}

.dash-col {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
}

/* Fleet utilisation. Info, not accent: magenta stays reserved for the primary
   action and the active nav item. */
.meter {
    height: 8px;
    border-radius: var(--radius-full);
    background: var(--color-surface-sunken);
    border: 1px solid var(--color-border);
    overflow: hidden;
}

.meter > span {
    display: block;
    height: 100%;
    background: var(--color-info);
}

/* Label/number rows inside a panel — the compact alternative to a two-cell
   table when there is no column to align across rows. */
.stat-rows { display: flex; flex-direction: column; }

.stat-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--color-border);
    font-size: var(--text-sm);
}

.stat-row:last-child { border-bottom: none; }
.stat-row-label { color: var(--color-text-muted); }
.stat-row-value { font-weight: 600; font-variant-numeric: tabular-nums; }

/* Quick actions stack full-width in the side column, so their labels align. */
.quick-actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.quick-actions .btn { justify-content: flex-start; }

/* ── Modal ───────────────────────────────────────────────────────────────── */
.modal-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(23, 23, 27, 0.55);
    backdrop-filter: blur(3px);
    justify-content: center;
    align-items: center;
    padding: var(--space-4);
    z-index: 500;
}

.modal-overlay.open { display: flex; }

.modal-box {
    background: var(--color-surface-raised);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    width: 100%;
    max-width: 520px;
    max-height: 90vh;
    max-height: 90dvh;      /* vh would put the bottom under the URL bar */
    overflow-y: auto;
}

/* Wide variant — for the Past Reservations table (filters + full-width rows). */
.modal-box.modal-wide { max-width: 1100px; }

/* Narrow variant — short read-only detail panels. */
.modal-box.modal-sm { max-width: 420px; }

/* Title left, close/actions right — the default, so pages don't repeat it. */
.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--color-border);
}

.modal-header h2 {
    font-size: var(--text-lg);
    font-weight: 600;
    margin: 0;
}

.modal-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

.modal-close {
    width: 30px;
    height: 30px;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-xl);
    line-height: 1;
    color: var(--color-text-muted);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background var(--transition), color var(--transition);
}

.modal-close:hover {
    background: var(--color-surface-hover);
    color: var(--color-text);
}

.modal-body {
    padding: var(--space-5);
}

/* Footer action bar inside a modal / detail panel. */
.modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
}

/* ── Metadata grid — label above value, used on every details view. ──────── */
.meta-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}

.meta-grid:last-child { margin-bottom: 0; }

/* Small uppercase heading that groups a set of fields inside a panel. */
.section-label {
    font-size: var(--text-2xs);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-subtle);
    margin-bottom: var(--space-2);
}

.meta-label {
    display: block;
    font-size: var(--text-2xs);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-subtle);
}

.meta-value {
    margin-top: var(--space-1);
    font-size: var(--text-sm);
    color: var(--color-text);
    word-break: break-word;
}

/* ── Employee list / row (reservation details) ───────────────────────────── */
.employee-list {
    display: flex;
    flex-direction: column;
}

.employee-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--color-border);
    font-size: var(--text-sm);
}

.employee-row:last-of-type { border-bottom: none; }

.add-employee-row {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
    display: flex;
    align-items: flex-end;
    gap: var(--space-3);
}

.add-employee-row label {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-muted);
}

/* ── Multi-select (searchable, chip-based) + combobox ────────────────────── */
.multiselect { position: relative; }

.multiselect-control {
    min-height: var(--control-h);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    padding: var(--space-1) var(--space-3);
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    transition: border-color var(--transition), box-shadow var(--transition);
}

.multiselect-control:hover { border-color: var(--color-text-subtle); }

.multiselect-control:focus-within,
.multiselect-control.open {
    border-color: var(--color-focus);
    box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.ms-chevron {
    flex: 0 0 auto;
    margin-left: auto;
    color: var(--color-text-subtle);
    transition: transform var(--transition), color var(--transition);
}

.multiselect-control.open .ms-chevron {
    transform: rotate(180deg);
    color: var(--color-accent);
}

.chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    flex: 1 1 auto;
    min-width: 0;
    padding: 3px 0;
}

.ms-placeholder {
    color: var(--color-text-subtle);
    font-size: var(--text-sm);
    font-weight: 400;
    text-transform: none;
    align-self: center;
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    background: var(--color-accent-subtle);
    border: 1px solid var(--color-accent-border);
    color: var(--color-accent-text);
    font-size: var(--text-xs);
    font-weight: 500;
    text-transform: none;
    padding: 2px 4px 2px var(--space-2);
    border-radius: var(--radius-full);
    white-space: nowrap;
}

.chip button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border: none;
    background: transparent;
    cursor: pointer;
    color: var(--color-accent-text);
    font-size: var(--text-md);
    line-height: 1;
    padding: 0;
    border-radius: 50%;
}

.chip button:hover { background: var(--color-accent-border); }

.chip-overflow {
    background: var(--color-surface-sunken);
    border-color: var(--color-border);
    color: var(--color-text-muted);
}

.multiselect-panel {
    position: absolute;
    top: calc(100% + var(--space-1));
    left: 0;
    right: 0;
    z-index: 30;
    background: var(--color-surface-raised);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.multiselect-panel[hidden] { display: none; }

.multiselect-search {
    height: 32px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border-strong);
    font: inherit;
    font-size: var(--text-sm);
    background: var(--color-surface-sunken);
    color: var(--color-text);
    width: 100%;
}

.multiselect-search:hover { border-color: var(--color-text-subtle); }

.multiselect-search:focus {
    outline: none;
    border-color: var(--color-focus);
    background: var(--color-surface);
    box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.multiselect-actions {
    display: flex;
    gap: var(--space-2);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--color-border);
}

.link-btn {
    display: inline-flex;
    align-items: center;
    background: transparent;
    border: 1px solid var(--color-border);
    outline: none;
    color: var(--color-text-muted);
    font-size: var(--text-2xs);
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-full);
    transition: background var(--transition), border-color var(--transition), color var(--transition);
}

.link-btn:hover {
    background: var(--color-accent-subtle);
    border-color: var(--color-accent-border);
    color: var(--color-accent-text);
}

.multiselect-list {
    list-style: none;
    margin: 0;
    padding: 2px;
    overflow-y: auto;
    max-height: 224px;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.multiselect-list li {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: var(--text-sm);
    font-weight: 400;
    text-transform: none;
    color: var(--color-text);
    transition: background var(--transition);
}

.multiselect-list li:hover { background: var(--color-surface-hover); }

.multiselect-list li.ms-selected {
    background: var(--color-accent-subtle);
    font-weight: 500;
    color: var(--color-accent-text);
}

.multiselect-list li input[type="checkbox"] {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    margin: 0;
}

.ms-empty {
    color: var(--color-text-subtle);
    font-size: var(--text-xs);
    padding: var(--space-2) var(--space-1);
    text-align: center;
    cursor: default;
}

.ms-empty:hover { background: transparent; }

/* Department (group) filter select inside the multiselect panel. */
.multiselect-group-filter {
    height: 32px;
    font-size: var(--text-sm);
}

/* Secondary detail (name · email) shown after a list item's main label. */
.ms-subtitle {
    color: var(--color-text-subtle);
    font-weight: 400;
}

/* Combobox — single-select variant of filter-select.js. */
.combo { position: relative; }

.combo-input { height: var(--control-h); background: var(--color-surface); }

.combo-list {
    position: absolute;
    top: calc(100% + var(--space-1));
    left: 0;
    right: 0;
    z-index: 30;
    background: var(--color-surface-raised);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-1);
    max-height: 240px;
}

.combo-list[hidden] { display: none; }

/* ── Toasts ──────────────────────────────────────────────────────────────── */
#toastContainer {
    position: fixed;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    z-index: 9999;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding-top: var(--space-4);
    width: min(92vw, 420px);
    pointer-events: none;
}

.toast {
    pointer-events: auto;
    width: 100%;
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-lg);
    border: 1px solid var(--color-border);
    background: var(--color-surface-raised);
    box-shadow: var(--shadow-lg);
    position: relative;
    overflow: hidden;
    opacity: 0;
    transform: translateY(-140%);
    transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.35s ease;
}

.toast--show { transform: translateY(0); opacity: 1; }
.toast--hide { animation: toast-slide-out 0.3s ease forwards; }

@keyframes toast-slide-out {
    to { transform: translateY(-140%); opacity: 0; }
}

.toast--error {
    background: var(--color-danger-subtle);
    border-color: var(--color-danger-border);
    color: var(--color-danger-text);
}

.toast--success {
    background: var(--color-success-subtle);
    border-color: var(--color-success-border);
    color: var(--color-success-text);
}

.toast__icon {
    flex-shrink: 0;
    font-size: var(--text-lg);
    line-height: 1.25;
    font-weight: 700;
}

.toast__body { flex: 1; min-width: 0; }

.toast__title {
    font-weight: 600;
    font-size: var(--text-sm);
    margin-bottom: 1px;
}

.toast__msg {
    font-size: var(--text-xs);
    color: var(--color-text);
    word-wrap: break-word;
}

.toast__close {
    flex-shrink: 0;
    background: transparent;
    border: none;
    color: inherit;
    font-size: var(--text-lg);
    line-height: 1;
    cursor: pointer;
    padding: 0 2px;
    opacity: 0.7;
}
.toast__close:hover { opacity: 1; }

.toast__progress {
    position: absolute;
    left: 0;
    bottom: 0;
    height: 3px;
    width: 100%;
    background: currentColor;
    opacity: 0.4;
}

/* ── States: empty, loading, error ───────────────────────────────────────── */

/* Empty state — names what's missing and offers the fix. Spans the full card
   grid so it isn't mistaken for a card. */
.empty-state {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-7) var(--space-5);
    text-align: center;
    background: var(--color-surface);
    border: 1px dashed var(--color-border-strong);
    border-radius: var(--radius-lg);
}

.empty-state__icon {
    font-size: var(--text-2xl);
    line-height: 1;
    color: var(--color-text-subtle);
}

.empty-state__title {
    font-size: var(--text-md);
    font-weight: 600;
    color: var(--color-text);
}

.empty-state__msg {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    max-width: 46ch;
}

.empty-state .btn { margin-top: var(--space-2); }

/* Table-cell variant, for an empty <tbody>. */
.empty-cell {
    text-align: center;
    color: var(--color-text-muted);
    padding: var(--space-6) var(--space-4) !important;
    font-size: var(--text-sm);
}

/* Skeleton — shaped like the content it replaces, not a spinner. */
.skeleton {
    display: block;
    border-radius: var(--radius-sm);
    background: linear-gradient(
        90deg,
        var(--color-surface-sunken) 25%,
        var(--color-surface-hover) 37%,
        var(--color-surface-sunken) 63%
    );
    background-size: 400% 100%;
    animation: skeleton-shimmer 1.4s ease infinite;
}

.skeleton-text { height: 12px; margin: var(--space-2) 0; }
.skeleton-text:nth-child(even) { width: 70%; }

@keyframes skeleton-shimmer {
    0%   { background-position: 100% 50%; }
    100% { background-position: 0 50%; }
}

/* Inline "Loading…" line, for surfaces too small for a skeleton. */
.loading-text {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

/* Persistent inline messaging. */
.alert {
    display: flex;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
    background: var(--color-surface-sunken);
    font-size: var(--text-sm);
    color: var(--color-text);
}

.alert-warning {
    background: var(--color-warning-subtle);
    border-color: var(--color-warning-border);
    color: var(--color-warning-text);
}

.alert-danger {
    background: var(--color-danger-subtle);
    border-color: var(--color-danger-border);
    color: var(--color-danger-text);
}

.alert-info {
    background: var(--color-info-subtle);
    border-color: var(--color-info-border);
    color: var(--color-info-text);
}

/* ── Login splash (login.html) ───────────────────────────────────────────── */
.splash-page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    min-height: 100dvh;
    background: var(--color-canvas);
}

.splash {
    text-align: center;
    padding: var(--space-6) var(--space-5);
    max-width: 420px;
}

.splash-status {
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text);
    letter-spacing: -0.01em;
}

.splash-detail {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-top: var(--space-2);
    line-height: 1.55;
}

.splash-brand {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-6);
    font-size: var(--text-lg);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--color-text);
}

/* The splash wordmark is a step larger than the navbar's; so is its mark. */
.splash-brand .brand-mark {
    width: 28px;
    height: 28px;
}

.spinner {
    width: 34px;
    height: 34px;
    margin: 0 auto var(--space-4);
    border: 3px solid var(--color-border);
    border-top-color: var(--color-accent);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* Terminal (error) state hides the spinner — there is no manual way forward. */
.splash.stopped .spinner { display: none; }
.splash.stopped #status { color: var(--color-danger-text); }

/* ── Audit log: login-details modal ──────────────────────────────────────── */
.login-details-link {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-accent-text);
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.login-details-link:hover { color: var(--color-accent-hover); }

.login-detail-list {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-2) var(--space-5);
    margin: 0;
    font-size: var(--text-sm);
    align-items: baseline;
}

.login-detail-list dt {
    color: var(--color-text-muted);
    font-weight: 600;
    font-size: var(--text-xs);
}

.login-detail-list dd {
    margin: 0;
    color: var(--color-text);
}

.login-detail-when {
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
    margin-bottom: var(--space-4);
}

/* ── Range calendar (range-picker.js) ────────────────────────────────────── */
/* The width MUST be definite, not `max-width`. The `margin: 0 auto` below is a
   cross-axis auto margin inside `.field`'s column flexbox, which suppresses
   `stretch` and sizes the box to fit-content — so the calendar used to grow
   sideways with the summary text, and taller too (`.cal-day` is 1/1). */
.cal-range {
    width: 340px;
    max-width: 100%;
    margin: 0 auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-3);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
    user-select: none;
}

.cal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--space-2);
}

.cal-nav-group {
    display: flex;
    gap: var(--space-1);
}

/* Empty grid cell (leading offset before day 1) — holds its column so the days
   line up under the correct weekday, but shows nothing and isn't clickable. */
.cal-blank { aspect-ratio: 1 / 1; }

.cal-title {
    font-size: var(--text-md);
    font-weight: 600;
    color: var(--color-text);
}

.cal-nav {
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-lg);
    line-height: 1;
    color: var(--color-text-muted);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition), color var(--transition);
}

.cal-nav:hover {
    background: var(--color-surface-hover);
    border-color: var(--color-border-strong);
    color: var(--color-text);
}

.cal-weekdays,
.cal-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}

.cal-weekdays { margin-bottom: var(--space-1); }

.cal-weekdays span {
    text-align: center;
    font-size: var(--text-2xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-subtle);
    padding: 2px 0;
}

.cal-day {
    aspect-ratio: 1 / 1;
    display: flex;
    align-items: center;
    justify-content: center;
    font: inherit;
    font-size: var(--text-sm);
    font-variant-numeric: tabular-nums;
    color: var(--color-text);
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background var(--transition), color var(--transition);
}

.cal-day:hover:not(.is-disabled):not(.is-selected) { background: var(--color-surface-hover); }
.cal-day.is-muted { color: var(--color-text-subtle); }
.cal-day.is-today { box-shadow: inset 0 0 0 1px var(--color-accent-border); }
.cal-day.is-disabled { color: var(--color-border-strong); cursor: default; }

/* range span (days strictly between start and end) */
.cal-day.in-range {
    background: var(--color-accent-subtle);
    color: var(--color-accent-text);
    border-radius: 0;
}

/* endpoints */
.cal-day.is-selected {
    background: var(--color-accent);
    color: var(--color-on-accent);
    font-weight: 600;
}

.cal-day.is-start { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.cal-day.is-end { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.cal-day.is-start.is-end { border-radius: var(--radius-sm); }

.cal-times {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

.cal-time-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    font-size: var(--text-2xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
}

/* Popover form of the range calendar (audit-log date-range filter): a readonly
   field in the filter row opens the same calendar in a floating panel, so the
   row keeps its one-line height. */
.cal-field { position: relative; }

.cal-popover {
    display: none;
    position: absolute;
    top: calc(100% + var(--space-1));
    left: 0;
    z-index: 60;
}

.cal-popover.open { display: block; }

.cal-popover .cal-range {
    width: 320px;
    max-width: none;
    margin: 0;
    box-shadow: var(--shadow-lg);
}

/* The summary is the one part whose content grows — empty, then one line, then
   two once both ends are picked. Reserve both lines up front so it can't push
   the calendar taller mid-selection. Keep `height`, not `min-height`. */
.cal-summary {
    margin-top: var(--space-3);
    height: 34px;               /* exactly 2 × line-height below */
    line-height: 17px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-muted);
    text-align: center;
}

/* Single-date mode (createDayPicker) prints one short day that cannot wrap. */
.cal-range--single .cal-summary { height: 17px; }

/* ═════════════════════════════════════════════
   UTILITIES
   Small, token-backed helpers that replace what used to be inline styles.
   Anything colour-related MUST come from here (or a primitive) so dark mode
   keeps working.
═════════════════════════════════════════════ */
.text-muted   { color: var(--color-text-muted); }
.text-subtle  { color: var(--color-text-subtle); }
.text-danger  { color: var(--color-danger-text); }
.text-success { color: var(--color-success-text); }
.text-warning { color: var(--color-warning-text); }
.text-accent  { color: var(--color-accent-text); }

.text-xs { font-size: var(--text-xs); }
.text-sm { font-size: var(--text-sm); }
.text-lg { font-size: var(--text-lg); }

.font-normal { font-weight: 400; }
.font-medium { font-weight: 500; }
.font-semibold { font-weight: 600; }

/* Table-cell inputs that shouldn't stretch to the full column width. */
.input-narrow { max-width: 170px; }
.mono { font-family: var(--font-mono); font-size: var(--text-xs); }
.nowrap { white-space: nowrap; }

/* Flex helpers — the handful of arrangements pages actually repeat. */
.row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.row-between {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

.row-end {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
}

.row-bottom {
    display: flex;
    align-items: flex-end;
    gap: var(--space-3);
}

.row-wrap { flex-wrap: wrap; }

.stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.grow { flex: 1; }

.mt-2 { margin-top: var(--space-2); }
.mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); }
.mb-2 { margin-bottom: var(--space-2); }
.mb-3 { margin-bottom: var(--space-3); }
.mb-4 { margin-bottom: var(--space-4); }

.full-span { grid-column: 1 / -1; }
.hidden { display: none !important; }

/* ═════════════════════════════════════════════
   RESPONSIVE

   Three breakpoints, one job each. Custom properties are illegal in a @media
   prelude, so the values are literals — these names are the contract:

     --bp-lap    1120px   NAV: links collapse into a side drawer. An admin's 9
                          links (Dashboard joined them) plus brand and user
                          cluster measure ~1080px, so a horizontal bar overflows
                          below 1120. Adding a link? Re-measure and raise this —
                          and panel.js's matchMedia, which must match.
     --bp-tab     900px   TOUCH: density tokens re-point to touch sizes.
                          Deliberately NOT the nav number — a 1000px window is
                          still a mouse and doesn't want 44px rows.
     --bp-phone   760px   LAYOUT COLLAPSE: tables become stacked cards, filters
                          go single-column, modals become bottom sheets.

   Keep the blocks in descending order so the narrower one wins without
   !important. Adding a breakpoint? Name it here and say what it owns.

   ⚠ All of this is dead code without the viewport meta in
   templates/panel/fragments/prefix.html — mobile browsers otherwise lay out at
   a ~980px virtual viewport. Do not remove that tag.
═════════════════════════════════════════════ */
/* ── --bp-lap: the nav becomes a side drawer ───────────────────────────────
   Moving .nav-end into the drawer also keeps the theme toggle and Sign Out
   reachable — on a scrolling bar, margin-left:auto resolved against the SCROLL
   width and parked them past the right edge. */
@media (max-width: 1120px) {
    .navbar { padding: 0 var(--space-4); }

    .nav-toggle { display: inline-flex; }

    .nav-links {
        position: fixed;
        top: var(--nav-h);
        right: 0;
        bottom: 0;
        width: min(82vw, 320px);
        z-index: 101;
        display: flex;
        flex-direction: column;
        gap: var(--space-1);
        padding: var(--space-4);
        background: var(--color-surface);
        border-left: 1px solid var(--color-border);
        box-shadow: var(--shadow-lg);
        overflow-y: auto;
        overscroll-behavior: contain;
        transform: translateX(100%);
        /* visibility, not just transform, is what takes the links out of the
           tab order while closed — load-bearing. The 0.22s delay holds it until
           the slide-out finishes. */
        visibility: hidden;
        transition: transform 0.22s ease, visibility 0s linear 0.22s;
    }

    .navbar.nav-open .nav-links {
        transform: none;
        visibility: visible;
        transition: transform 0.22s ease, visibility 0s;
    }

    .navbar a {
        font-size: var(--text-md);
        justify-content: flex-start;
    }

    /* In a vertical list the underline reads as a separator — use a leading
       accent rule instead. */
    .navbar a.active::after { content: none; }
    .navbar a.active {
        box-shadow: inset 3px 0 0 var(--color-accent);
        padding-left: calc(var(--space-3) + 3px);
    }

    .nav-end {
        margin-left: 0;
        margin-top: auto;               /* pinned to the bottom of the drawer */
        padding-left: 0;
        padding-top: var(--space-4);
        border-top: 1px solid var(--color-border);
        flex-wrap: wrap;
        gap: var(--space-3);
    }
    .nav-user { display: inline-flex; }
    .nav-end .btn { flex: 1 1 auto; }

    .nav-scrim {
        display: none;
        position: fixed;
        inset: var(--nav-h) 0 0 0;      /* leaves the bar itself tappable */
        z-index: 90;
        background: rgba(23, 23, 27, 0.45);
    }
    .navbar.nav-open .nav-scrim { display: block; }
}

/* ── --bp-tab: touch density ───────────────────────────────────────────── */
@media (max-width: 900px) {
    /* Re-point the density tokens instead of hardcoding .btn/input heights —
       hardcoding leaves token-driven controls (.multiselect-control,
       .combo-input) stuck at 36px while their sibling inputs grow. */
    :root {
        --control-h:    44px;
        --control-h-sm: 36px;
        --cell-pad-y:   12px;
        --nav-link-h:   44px;
    }

    /* Controls that don't read a density token. */
    .theme-toggle,
    .modal-close { width: var(--tap-min); height: var(--tap-min); }

    .cal-nav { width: 40px; height: 40px; }
    /* .cal-blank must match .cal-day: the grid pads to a fixed 6 rows, and a
       shorter trailing row of blanks makes the height month-dependent. */
    .cal-day,
    .cal-blank { min-height: 40px; }        /* aspect-ratio:1/1 → ~34px at 375 */

    .chip { padding: 3px 3px 3px var(--space-3); }
    .chip button { width: 24px; height: 24px; }

    .link-btn { min-height: 36px; padding: var(--space-2) var(--space-3); }
    .pager-btn { min-width: 96px; }
    .toast__close { width: 36px; height: 36px; }
    .login-details-link { display: inline-block; padding: var(--space-2) 0; }

    /* These override the shared input height, so the token re-point misses them. */
    .multiselect-search,
    .multiselect-group-filter { height: 40px; }

    /* Dashboard: the side column stops being a side and falls under the queues.
       Its panels are summaries, so they read fine at full width. */
    .dash-cols { grid-template-columns: 1fr; }
}

/* ── --bp-phone: layout collapse ───────────────────────────────────────── */
@media (max-width: 760px) {
    .container {
        margin: var(--space-4) auto var(--space-6);
        padding: 0 var(--space-4);
        gap: var(--space-3);
    }

    .card { padding: var(--space-4); }
    .card-flush-header { padding: var(--space-4); }

    /* These three are real grids. */
    .date-row,
    .datetime-pair,
    .cal-times { grid-template-columns: 1fr; }

    /* Stacked filters are full-width, so match the field rather than keep the
       fixed 320px, which overflows at 320w. */
    .cal-popover { right: 0; }
    /* Still definite, just viewport-bounded: `width: auto` in an absolutely
       positioned popover shrink-to-fits and resizes with the summary text. */
    .cal-popover .cal-range { width: min(320px, calc(100vw - 32px)); }

    /* .filters and .filter-row are FLEX (see FORMS) — stack them accordingly;
       grid-template-columns would be inert here. */
    .filters,
    .filter-row {
        flex-direction: column;
        align-items: stretch;
    }
    .filters label,
    .filter-row .field { flex: 1 1 auto; }
    .filter-actions { align-self: stretch; }
    .filter-actions .btn { flex: 1 1 0; }

    /* Flex/grid items default to min-width:auto, and <input type="time"> has a
       wide intrinsic minimum that pushes these containers past the viewport. */
    .filters > *,
    .filter-row > *,
    .cal-times > * { min-width: 0; }
    .filter-row .field { min-width: 0; }    /* base rule sets 120px */

    .date-block + .date-block {
        border-left: none;
        border-top: 1px solid var(--color-border);
    }

    .meta-grid { grid-template-columns: 1fr; }
    .card-grid { grid-template-columns: 1fr; }

    .modal-header, .modal-body { padding: var(--space-4); }

    /* ── Modals become bottom sheets ────────────────────────────────────
       A centred box puts its actions mid-screen and its top under the notch;
       anchoring to the bottom keeps buttons in thumb reach. */
    .modal-overlay {
        align-items: flex-end;
        padding: 0;
    }
    .modal-box,
    .modal-box.modal-sm,
    .modal-box.modal-wide {
        max-width: 100%;
        max-height: 88vh;
        max-height: 88dvh;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
        border-left: none;
        border-right: none;
        border-bottom: none;
    }

    /* position:absolute with no flip-up logic, so near the bottom of a form
       they'd open into nothing. Cap to the viewport so they scroll instead. */
    .multiselect-panel,
    .combo-list {
        max-height: 50vh;
        max-height: 50dvh;
        overflow-y: auto;
    }

    /* ── Tables become stacked cards ────────────────────────────────────
       A 10-column table can't survive a 375px viewport, and side-scrolling
       hides the Actions column. Each <tr> becomes a card, each cell showing its
       column name from the data-label that panel.js's labelTableCells() stamps
       on. Opt out with class="table-keep". */
    .table-wrapper { overflow-x: visible; }   /* nothing left to scroll */

    table:not(.table-keep) { display: block; width: 100%; }

    /* ::before renders the headings per-cell now. Also neutralises the sticky
       `thead th`, which would stick to the wrong container. */
    table:not(.table-keep) > thead { display: none; }

    table:not(.table-keep) > tbody { display: block; }

    table:not(.table-keep) > tbody > tr {
        display: block;
        padding: var(--space-3) var(--space-4);
        border-bottom: 1px solid var(--color-border);
    }
    table:not(.table-keep) > tbody > tr:last-child { border-bottom: none; }
    /* Row hover is a pointer affordance; on touch it just sticks after a tap. */
    table:not(.table-keep) > tbody > tr:hover { background: transparent; }

    /* flex, not grid: cell values are often several inline nodes
       ("Ana P. <span>+2 more</span>"), and flex lays them out in source order
       without whitespace nodes becoming phantom items. Leave justify-content
       alone — space-between flings the trailing fragment to the right edge. */
    table:not(.table-keep) > tbody > tr > td {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        column-gap: var(--space-3);
        row-gap: var(--space-1);
        padding: var(--space-1) 0;
        border: none;
        text-align: left;          /* undo .num */
        white-space: normal;       /* undo .nowrap — no column to protect now */
        min-width: 0;
    }

    table:not(.table-keep) > tbody > tr > td::before {
        content: attr(data-label);
        flex: 0 0 38%;
        max-width: 38%;
        font-size: var(--text-2xs);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        color: var(--color-text-muted);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Unlabelled cell → render value-only rather than an empty 38% gutter. */
    table:not(.table-keep) > tbody > tr > td:not([data-label])::before,
    table:not(.table-keep) > tbody > tr > td[data-label=""]::before { content: none; }

    /* Placeholder-only cells, flagged by labelTableCells(). */
    table:not(.table-keep) > tbody > tr > td.cell-empty { display: none; }

    /* Full-width message rows keep their own centred treatment. */
    table:not(.table-keep) > tbody > tr > td.empty-cell {
        display: block;
        text-align: center;
    }
    table:not(.table-keep) > tbody > tr > td.empty-cell::before { content: none; }
    table:not(.table-keep) > tbody > tr:has(> .empty-cell) { padding: 0; }

    /* Action clusters get their own full-width line under the label. */
    table:not(.table-keep) > tbody > tr > td > .row-actions {
        flex: 1 1 100%;
        margin-top: var(--space-2);
        gap: var(--space-2);
    }
    /* The base rule's min-width:68px + flex:0 0 auto puts a 212px floor on three
       buttons in one cell, with no way to shrink. */
    .row-actions .btn-sm {
        flex: 1 1 auto;
        min-width: 0;
        height: var(--control-h);
    }

    /* Long free text has a whole card row to itself now. */
    .truncate {
        max-width: 100%;
        white-space: normal;
        overflow: visible;
    }
}

/* ═════════════════════════════════════════════
   MOTION
═════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }

    .toast { transform: none; }
    .toast--show { transform: none; }
    .toast--hide { animation: none; opacity: 0; }
    .skeleton { animation: none; }
}

/* ═════════════════════════════════════════════
   PRINT — travel orders get printed from the details view.
═════════════════════════════════════════════ */
@media print {
    .navbar, .header-actions, .card-actions, .row-actions,
    .pager, #toastContainer, .modal-overlay { display: none !important; }

    body { background: #fff; color: #000; }
    .card, .card-flush { border: 1px solid #ccc; box-shadow: none; }
}
