/* Double E reporting platform — the one global stylesheet.
   Rules: docs/agent-context/site-rules.md, "Styling and themes".
   Examples of everything here: /style-guide/ (templates/core/style_guide.html).

   Layers:
     1. Primitives — the Double E Group brand palette. Components never use these.
     2. Tokens     — semantic names (surface, text, accent, status, chart…) with
                     a light and a dark value each. A theme is a set of token
                     overrides under html[data-theme="…"].
     3. Base       — element defaults.
     4. Components — tokens only below the marker; core/tests/test_style_guide.py
                     fails the suite on a colour literal there. */

/* === 1. Primitives ======================================================= */
/* The palette is the DEG USA Style Guide V1.2 (January 2025), pages 11–12,
   digital values as printed; core/tests/test_style_guide.py checks they stay
   so. Anything marked "derived" is a tint, shade or in-between step of a guide
   colour, added where the UI needs more than the guide lists (hover states,
   dark-theme surfaces, AA contrast for small text). */

:root {
    /* Corporate colours */
    --de-blue: #006BB6;          /* DEG Logo Blue (PMS 2175 C): the primary */
    --de-gray: #989899;          /* DEG Group Gray (Cool Gray 7 C) */
    --de-black: #241F21;         /* DEG Black (Neutral Black C) */
    --de-yellow: #FAE400;        /* DEG Safety Yellow (PMS 102 C): reserved, the colour bar only */

    /* Blacks and neutrals */
    --de-gray-dark: #3E3E3F;     /* Dark Gray (447 C) */
    --de-gray-mid: #828284;      /* Gray (877) */
    --de-gray-light: #B8B8B9;    /* Light Gray (Cool Gray 4) */
    --de-off-white: #E6E7E8;     /* Off White (7541 C) */
    --de-white: #FFFFFF;

    /* The navy that frames every page of the guide itself (sampled from the
       document; it is not in the palette table). */
    --de-navy: #174890;

    /* Derived */
    --de-blue-dark: #005A9A;     /* DEG Blue, darker: hover */
    --de-blue-tint: #E0EDF6;     /* DEG Blue at 12% on white: soft accent backgrounds */
    --de-blue-bright: #4DA6E6;   /* DEG Blue lifted for links on dark surfaces (5.2:1 on --de-black-2) */
    --de-blue-brighter: #7CBDEE; /* its hover */
    --de-blue-pale: #A9C4EA;     /* DEG Blue, pale: quiet text on the navy */
    --de-navy-deep: #113A77;     /* the navy, deeper: the sidebar's lower edge */
    --de-gray-text: #646466;     /* between Dark Gray and Gray: muted text at AA on Off White */
    --de-gray-line: #D2D2D3;     /* between Light Gray and Off White: borders */
    --de-gray-faint: #F2F2F3;    /* between Off White and White: table heads, hover rows */
    --de-black-2: #2D2829;       /* steps up from DEG Black: dark-theme surfaces */
    --de-black-3: #363132;
    --de-black-4: #433E3F;

    /* Status: not in the guide. Chosen for status, kept apart from the brand
       colours and the chart series; Safety Yellow is never a status colour. */
    --de-green: #2E8B72;
    --de-green-soft: #DFF3EC;
    --de-green-deep: #1F6B57;
    --de-green-bright: #7FD3B9;
    --de-amber: #D69A2D;
    --de-amber-soft: #FBF1DC;
    --de-amber-deep: #8A5E0C;
    --de-amber-bright: #F0C46A;
    --de-red: #C85A5A;
    --de-red-soft: #F8E4E4;
    --de-red-deep: #8F3A3A;
    --de-red-bright: #F09A9A;
    --de-steel: #4D9AC6;
    --de-steel-soft: #E1EFF7;
    --de-steel-deep: #2F6F94;
    --de-steel-bright: #8FCBEB;
    --de-purple: #6F58A8;        /* a fifth status colour (2026-10-23, Matt: no two actions share one); apart from the chart purple */
    --de-purple-soft: #ECE7F6;
    --de-purple-deep: #4A3880;   /* 8.2:1 on the soft tint */
    --de-purple-bright: #B9A7E6; /* 5.4:1 on the dark soft tint */

    /* Chart series, light and dark steps. Series 1 is DEG Logo Blue (dark: the
       same hue lifted into the dark lightness band). Validated 2026-10-02 for
       colour-vision separation between neighbours, lightness band, chroma and
       contrast on each surface (docs/agent-context/working-notes.md).
       Re-validate if changed. */
    --de-chart-blue: #006BB6;
    --de-chart-blue-dark: #3397DB;
    --de-chart-orange: #D0672A;
    --de-chart-orange-dark: #D6702F;
    --de-chart-teal: #2AA198;
    --de-chart-teal-dark: #2AA198;
    --de-chart-purple: #8A5FC7;
    --de-chart-purple-dark: #8F66CB;
    --de-chart-gold: #8C7A1E;
    --de-chart-gold-dark: #9C8A26;
    --de-chart-magenta: #C2508E;
    --de-chart-magenta-dark: #CC5E9B;
}

/* === 2. Tokens =========================================================== */

:root {
    color-scheme: light dark; /* "auto": follow the device */

    /* Avenir is the brand typeface (guide p. 13). It is a licensed font, so it
       is used where the device has it (macOS, iOS) and the stack falls back to
       the system sans elsewhere; nothing is downloaded. */
    --font-sans: Avenir, "Avenir Next", "Segoe UI", system-ui, -apple-system, Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-mono: Consolas, "Cascadia Mono", "SF Mono", Menlo, monospace;
    --radius: 10px;
    --radius-sm: 8px;
    --radius-pill: 999px;
    --sidebar-width: 272px; /* the drawer: room for the logo at full size beside its close button */

    /* Surfaces and text: Off White page, white surfaces; dark is DEG Black
       stepping up. Page titles wear DEG Blue, as every page of the guide does. */
    --bg: light-dark(var(--de-off-white), var(--de-black));
    --surface: light-dark(var(--de-white), var(--de-black-2));
    --surface-alt: light-dark(var(--de-gray-faint), var(--de-black-3));
    --border: light-dark(var(--de-gray-line), var(--de-black-4));
    --text: light-dark(var(--de-gray-dark), var(--de-off-white));
    --text-muted: light-dark(var(--de-gray-text), var(--de-gray-light));
    --text-heading: light-dark(var(--de-black), var(--de-white));
    --text-title: light-dark(var(--de-blue), var(--de-blue-bright));
    --text-on-accent: var(--de-white);

    /* Brand accent: buttons, links, active navigation */
    --accent: light-dark(var(--de-blue), var(--de-blue-bright));
    --accent-hover: light-dark(var(--de-blue-dark), var(--de-blue-brighter));
    --accent-soft: light-dark(var(--de-blue-tint), rgba(77, 166, 230, 0.18));
    --accent-soft-text: light-dark(var(--de-blue-dark), var(--de-blue-brighter));
    --focus: var(--accent);

    /* Sidebar: the guide's framing navy in both themes, the white logo on it */
    --sidebar-start: var(--de-navy);
    --sidebar-end: var(--de-navy-deep);
    --sidebar-text: rgba(255, 255, 255, 0.85);
    --sidebar-text-strong: var(--de-white);
    --sidebar-muted: var(--de-blue-pale);
    --sidebar-active: var(--de-blue);
    --sidebar-hover: rgba(255, 255, 255, 0.08);

    /* The colour bar (the guide's tri-colour Footer Graphic, p. 15): DEG Blue,
       Group Gray, Safety Yellow in equal thirds, this order, never changed. */
    --bar-1: var(--de-blue);
    --bar-2: var(--de-gray);
    --bar-3: var(--de-yellow);

    /* Status: reserved for status, always beside a text label */
    --success: var(--de-green);
    --success-soft: light-dark(var(--de-green-soft), rgba(46, 139, 114, 0.22));
    --success-text: light-dark(var(--de-green-deep), var(--de-green-bright));
    --warning: var(--de-amber);
    --warning-soft: light-dark(var(--de-amber-soft), rgba(214, 154, 45, 0.22));
    --warning-text: light-dark(var(--de-amber-deep), var(--de-amber-bright));
    --danger: var(--de-red);
    --danger-soft: light-dark(var(--de-red-soft), rgba(200, 90, 90, 0.22));
    --danger-text: light-dark(var(--de-red-deep), var(--de-red-bright));
    --info: var(--de-steel);
    --info-soft: light-dark(var(--de-steel-soft), rgba(77, 154, 198, 0.22));
    --info-text: light-dark(var(--de-steel-deep), var(--de-steel-bright));
    --expedite: var(--de-purple); /* a plan that exists but is late: the Shortage Report's Expedite PO */
    --expedite-soft: light-dark(var(--de-purple-soft), rgba(111, 88, 168, 0.25));
    --expedite-text: light-dark(var(--de-purple-deep), var(--de-purple-bright));
    --neutral-soft: var(--surface-alt);
    --neutral-text: var(--text-muted);

    /* Chart series: assigned in this order, never cycled; not status colours */
    --chart-1: light-dark(var(--de-chart-blue), var(--de-chart-blue-dark));
    --chart-2: light-dark(var(--de-chart-orange), var(--de-chart-orange-dark));
    --chart-3: light-dark(var(--de-chart-teal), var(--de-chart-teal-dark));
    --chart-4: light-dark(var(--de-chart-purple), var(--de-chart-purple-dark));
    --chart-5: light-dark(var(--de-chart-gold), var(--de-chart-gold-dark));
    --chart-6: light-dark(var(--de-chart-magenta), var(--de-chart-magenta-dark));
    --chart-grid: var(--border);
    --chart-track: var(--surface-alt);

    /* Elevation */
    --shadow-sm: light-dark(0 1px 2px rgba(36, 31, 33, 0.08), 0 1px 2px rgba(0, 0, 0, 0.4));
    --shadow-md: light-dark(0 8px 24px rgba(36, 31, 33, 0.16), 0 8px 24px rgba(0, 0, 0, 0.5));
    --shadow-sticky: light-dark(-10px 0 10px -10px rgba(36, 31, 33, 0.25), -10px 0 10px -10px rgba(0, 0, 0, 0.6));
    --backdrop: light-dark(rgba(36, 31, 33, 0.45), rgba(0, 0, 0, 0.6)); /* behind the open navigation drawer */

    /* The loading overlay (SRS-SITE-8): a dark scrim in both themes, the logo
       dim on it and its traces lit in DEG Blue lifted for dark surfaces.
       --loading-current is the one to change for another colour of current. */
    --loading-scrim: rgba(36, 31, 33, 0.84);
    --loading-text: var(--de-off-white);
    --loading-ghost: rgba(255, 255, 255, 0.14);
    --loading-ghost-lit: rgba(255, 255, 255, 0.32);
    --loading-current: var(--de-blue-bright);
}

/* The theme switch (core/static/core/site.js sets html[data-theme]). */
html[data-theme="light"] { color-scheme: light; }
html[data-theme="dark"] { color-scheme: dark; }
/* A future theme is a block like this — tokens only, no component changes:
   html[data-theme="contrast"] { --accent: …; --bg: …; } */

/* === 3. Base ============================================================= */

* { box-sizing: border-box; }

html, body { margin: 0; min-height: 100%; }

body {
    font-family: var(--font-sans);
    font-size: 15px;
    line-height: 1.5;
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
}

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

:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* The guide's hierarchy (p. 14), adapted to the screen: a page title is its
   "Subhead" (medium weight, DEG Blue); section headings are its "Headlines"
   (black weight, no oblique here). Capitals carry no extra tracking anywhere:
   the guide sets 0 tracking throughout. */
h1, h2, h3, h4 { margin: 0; color: var(--text-heading); line-height: 1.25; }
h1 { font-size: 30px; font-weight: 500; color: var(--text-title); }
h2 { font-size: 20px; font-weight: 700; }
h3 { font-size: 17px; font-weight: 600; }
h4 { font-size: 15px; font-weight: 600; }
p { margin: 0 0 12px; }
code, kbd { font-family: var(--font-mono); font-size: 0.92em; padding: 1px 5px; border-radius: 4px; background: var(--surface-alt); color: var(--text); }

/* === 4. Components (tokens only below this line) ========================= */

/* --- Utilities ---------------------------------------------------------- */

.muted { color: var(--text-muted); }
.small { font-size: 13px; }
.label {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--text-muted);
}
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}
.icon-sprite { display: none; } /* the inline icon sprite in base.html: symbols only, never laid out */
.icon { width: 20px; height: 20px; flex: 0 0 auto; }
.is-hidden { display: none !important; } /* set by script (hidden table columns, filtered-out rows); never in markup */

/* --- Layout shell ------------------------------------------------------- */

.shell { display: flex; min-height: 100vh; }

/* The sidebar is a drawer on every screen (Levin, 2026-10-22: the content gets
   the whole width). The top bar's menu button opens it over the page
   (site.js sets html.nav-open and unhides .nav-backdrop); the backdrop, its
   close button and Escape shut it. Closed, it is also invisible, so its
   links leave the tab order. */
.sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 40;
    width: var(--sidebar-width);
    max-width: 85vw;
    display: flex;
    flex-direction: column;
    padding: 22px 16px 20px;
    overflow-y: auto;
    color: var(--sidebar-text-strong);
    background: linear-gradient(180deg, var(--sidebar-start) 0%, var(--sidebar-end) 100%);
    box-shadow: var(--shadow-md);
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform 0.2s ease, visibility 0.2s;
}
.nav-open .sidebar { transform: none; visibility: visible; transition: transform 0.2s ease, visibility 0s; } /* visible at once on opening, so focus can move in */
.nav-backdrop { position: fixed; inset: 0; z-index: 39; background: var(--backdrop); }
.sidebar-head { display: flex; align-items: flex-start; gap: 8px; }
.sidebar-head .brand { flex: 1; min-width: 0; }
.nav-close {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    font-size: 22px;
    line-height: 1;
    color: var(--sidebar-text);
    background: transparent;
    cursor: pointer;
}
.nav-close:hover { color: var(--sidebar-text-strong); background: var(--sidebar-hover); }
@media (prefers-reduced-motion: reduce) { .sidebar { transition: none; } }

/* The top bar's menu button and the brand mark beside it (the favicon: the
   mark alone, white on DEG Blue), a link home while the drawer is shut. */
.menu-toggle {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text);
    background: var(--surface);
    cursor: pointer;
}
.menu-toggle:hover { background: var(--surface-alt); }
.menu-toggle svg { width: 22px; height: 22px; }
.topbar-mark { flex: 0 0 auto; display: block; }
.topbar-mark img { display: block; width: 32px; height: 32px; border-radius: var(--radius-sm); }

/* The white horizontal logo on the navy (guide p. 8: the white version is for
   dark backgrounds). Clear space is the width of the logo's "D" (p. 9), which
   the sidebar padding exceeds; never under 0.5 in (48px) high, so never under
   170px wide. Do not recolour, skew, shadow or lowercase it (p. 10). */
.brand { display: block; padding: 0 6px; }
.brand img { display: block; width: 100%; max-width: 196px; }

.nav { display: flex; flex-direction: column; gap: 4px; margin-top: 30px; }
.nav-link {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 14px;
    border-radius: var(--radius-sm);
    color: var(--sidebar-text);
    font-weight: 500;
    text-decoration: none;
}
.nav-link:hover { color: var(--sidebar-text-strong); background: var(--sidebar-hover); }
.nav-link.is-active { color: var(--sidebar-text-strong); background: var(--sidebar-active); }
.nav-link svg { width: 20px; height: 20px; flex: 0 0 20px; }
.nav-group { margin-top: 18px; padding: 0 14px 6px; font-size: 11px; text-transform: uppercase; color: var(--sidebar-muted); }

/* The colour bar: the guide's tri-colour Footer Graphic (p. 15) as the email
   signature uses it, a thin line anchoring the brand panel. Equal thirds of
   --bar-1/2/3, bleeding to the sidebar's edges; never reordered, never
   recoloured, and the only place Safety Yellow appears. */
.color-bar {
    height: 6px;
    margin: auto -16px -20px;
    background: linear-gradient(90deg, var(--bar-1) 0 33.34%, var(--bar-2) 33.34% 66.67%, var(--bar-3) 66.67%);
}

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 0 28px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}
.topbar-title { min-width: 0; font-size: 24px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* the page title, the one h1 (Matt, 2026-10-22) */
.topbar-user { display: flex; align-items: center; gap: 14px; margin-left: auto; }
.topbar-user form { margin: 0; }
.user-name { font-weight: 500; }
a.user-name { color: var(--text); text-decoration: none; } /* the name leads to the profile page (SRS-USER-1) */
a.user-name:hover { color: var(--accent); text-decoration: underline; }

.content { flex: 1; width: 100%; min-width: 0; padding: 28px; } /* fills the window: the tables need the width (Matt, 2026-10-08) */

.footer {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 28px;
    border-top: 1px solid var(--border);
    font-size: 13px;
    color: var(--text-muted);
}

/* --- Page structure ----------------------------------------------------- */

.page-head { margin-bottom: 4px; }
/* A head with page-level actions on the right (the Shortage Report's Refresh): they wrap under the lead when narrow. */
.page-head-split { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 24px; }
.page-head-split .lead { flex: 1 1 420px; }
.page-head-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 0; }
.lead { margin: 0; font-size: 16px; color: var(--text-muted); }

.section { margin-top: 32px; }
.section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    margin: 0 0 14px;
}
.section-head h2 { margin: 0; }
.section-note { margin: -8px 0 16px; color: var(--text-muted); font-size: 14px; }

.toolbar { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; margin: 20px 0; }
.toolbar-end { margin-left: auto; }

.rules-head { margin: 28px 0 8px; font-size: 16px; }
.rules { margin: 0; padding-left: 20px; font-size: 14px; color: var(--text-muted); }
.rules li { margin: 4px 0; }

/* --- Buttons ------------------------------------------------------------ */

.btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    font: inherit;
    font-weight: 500;
    line-height: 1.3;
    text-decoration: none;
    cursor: pointer;
    color: var(--text);
    background: transparent;
}
.btn-primary { color: var(--text-on-accent); background: var(--accent); }
.btn-primary:hover { color: var(--text-on-accent); background: var(--accent-hover); }
.btn-ghost { color: var(--text); background: var(--surface); border-color: var(--border); }
.btn-ghost:hover { color: var(--text); background: var(--surface-alt); }
.btn-danger { color: var(--text-on-accent); background: var(--danger); }
.btn-danger:hover { color: var(--text-on-accent); filter: brightness(0.92); }
.btn-link { padding-left: 4px; padding-right: 4px; color: var(--accent); }
.btn-link:hover { color: var(--accent-hover); text-decoration: underline; }
.btn-sm { padding: 5px 11px; font-size: 13px; }
.btn[disabled], .btn.is-disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
.btn svg { width: 16px; height: 16px; }

/* --- Forms -------------------------------------------------------------- */

.field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--text-muted); }
.field > span:first-child, .field-label { font-weight: 500; }
.field input, .field select, .field textarea {
    padding: 7px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font: inherit;
    font-size: 14px;
    color: var(--text);
    background: var(--surface);
}
.field input:focus, .field select:focus, .field textarea:focus { outline: 2px solid var(--focus); outline-offset: 1px; border-color: var(--accent); }
.field textarea { min-height: 88px; resize: vertical; }
.field-help { font-size: 12px; color: var(--text-muted); }
.field.is-invalid input, .field.is-invalid select, .field.is-invalid textarea { border-color: var(--danger); }
.field-error { font-size: 12px; color: var(--danger-text); }
.check { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; color: var(--text); cursor: pointer; }
.check input { width: 16px; height: 16px; accent-color: var(--accent); margin: 0; }
.form-row { display: flex; flex-wrap: wrap; gap: 12px 16px; align-items: flex-end; }
/* A settings form (the profile page): as many 240px columns as fit, capped so
   the controls stay a readable width; the buttons take a row of their own. */
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px 20px; max-width: 760px; margin: 20px 0; }
.form-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.form-grid .form-actions { grid-column: 1 / -1; }
.table-wrap + .form-actions { margin-top: 16px; } /* a button row under a table keeps its distance (the profile's Sign out) */

/* --- Notices and toasts ------------------------------------------------- */

.notice {
    margin: 20px 0 0;
    padding: 12px 16px;
    border: 1px solid var(--border);
    border-left: 4px solid var(--info);
    border-radius: var(--radius);
    font-size: 14px;
    color: var(--text);
    background: var(--surface);
}
.notice strong { color: var(--text-heading); }
.notice + .table-wrap, .notice + .form-row, .notice + .notice { margin-top: 20px; } /* what follows a notice keeps its distance */
.notice-info { border-left-color: var(--info); background: var(--info-soft); }
.notice-success { border-left-color: var(--success); background: var(--success-soft); }
.notice-warning { border-left-color: var(--warning); background: var(--warning-soft); }
.notice-danger { border-left-color: var(--danger); background: var(--danger-soft); }

.toasts {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 100;
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: min(360px, calc(100vw - 40px));
}
.toast {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 12px 12px 16px;
    border: 1px solid var(--border);
    border-left: 4px solid var(--info);
    border-radius: var(--radius);
    font-size: 14px;
    color: var(--text);
    background: var(--surface);
    box-shadow: var(--shadow-md);
    animation: toast-in 180ms ease-out;
}
.toast-text { flex: 1; }
.toast-success { border-left-color: var(--success); }
.toast-warning { border-left-color: var(--warning); }
.toast-danger, .toast-error { border-left-color: var(--danger); }
.toast-close {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    font: inherit;
    font-size: 18px;
    line-height: 1;
    color: var(--text-muted);
    background: transparent;
    cursor: pointer;
}
.toast-close:hover { color: var(--text); background: var(--surface-alt); }
.toast.is-leaving { opacity: 0; transform: translateY(6px); transition: opacity 160ms, transform 160ms; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* --- Loading overlay (SRS-SITE-8) --------------------------------------- */
/* Covers the page while a marked form or link waits on the server (site.js,
   "Loading"); above the toasts and the drawer. The dim logo "charges", pulses
   of current run along its four traces. */
.loading-overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: grid;
    place-items: center;
    background: var(--loading-scrim);
    backdrop-filter: blur(4px);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}
.loading-overlay.is-active { opacity: 1; visibility: visible; transition: opacity 0.25s ease; }
.loading-box { display: flex; flex-direction: column; align-items: center; gap: 20px; padding: 0 16px; text-align: center; }
.loading-mark { width: min(28vw, 150px); height: auto; overflow: visible; }
.loading-message { margin: 0; color: var(--loading-text); font: 500 16px/1.4 var(--font-sans); letter-spacing: 0.04em; }
.loading-ghost { fill: var(--loading-ghost); animation: loading-charge 2.4s ease-in-out infinite; }
.loading-trace {
    fill: none;
    stroke: var(--loading-current);
    stroke-width: 3.5;
    stroke-linecap: round;
    stroke-linejoin: round;
    filter: drop-shadow(0 0 4px var(--loading-current)) drop-shadow(0 0 10px var(--loading-current));
    animation: loading-run 2.4s linear infinite;
}
.loading-trace-outer { stroke-dasharray: 9 41; } /* two pulses chase round the outside */
.loading-trace-left { stroke-dasharray: 14 86; animation-duration: 1.6s; }
.loading-trace-right { stroke-dasharray: 14 86; animation-duration: 1.6s; animation-direction: reverse; }
.loading-trace-centre { stroke-dasharray: 18 32; animation-duration: 1.2s; }
@keyframes loading-run { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
@keyframes loading-charge { 0%, 100% { fill: var(--loading-ghost); } 50% { fill: var(--loading-ghost-lit); } }
/* Trial variants of the overlay (2026-10-28, to choose one): data-variant on
   .loading-overlay, set by the style guide's demo buttons; without it, the
   pulses above. The losers are deleted once one is chosen. */
.loading-level-fill, .loading-scan-glow, .loading-scan-line, .loading-bar { display: none; }

/* Draw: the mark is drawn line by line like a blueprint, fills, starts again. */
.loading-overlay[data-variant="draw"] .loading-trace { stroke-dasharray: 100 100; animation: loading-draw 3.2s ease-in-out infinite; }
.loading-overlay[data-variant="draw"] .loading-ghost { animation: loading-draw-fill 3.2s ease-in-out infinite; }
@keyframes loading-draw {
    0% { stroke-dashoffset: 100; opacity: 1; }
    55%, 85% { stroke-dashoffset: 0; opacity: 1; }
    100% { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes loading-draw-fill {
    0%, 50% { fill: var(--loading-ghost); }
    70%, 85% { fill: var(--loading-current); }
    100% { fill: var(--loading-ghost); }
}

/* Fill: the mark fills from the bottom like a level gauge. */
.loading-overlay[data-variant="fill"] .loading-trace { display: none; }
.loading-overlay[data-variant="fill"] .loading-level-fill {
    display: inline;
    fill: var(--loading-current);
    filter: drop-shadow(0 0 6px var(--loading-current));
    animation: loading-level-fade 2.8s ease-in-out infinite;
}
.loading-overlay[data-variant="fill"] .loading-level { animation: loading-rise 2.8s ease-in-out infinite; }
@keyframes loading-rise { 0% { transform: translateY(357px); } 70%, 100% { transform: translateY(0); } }
@keyframes loading-level-fade { 0%, 85% { opacity: 1; } 100% { opacity: 0; } }

/* Scan: a bright line sweeps the dim mark, like an inspection scanner. */
.loading-overlay[data-variant="scan"] .loading-trace { display: none; }
.loading-overlay[data-variant="scan"] .loading-ghost { animation: none; }
.loading-overlay[data-variant="scan"] .loading-scan-glow { display: inline; fill: var(--loading-current); }
.loading-overlay[data-variant="scan"] .loading-scan-line {
    display: inline;
    fill: var(--loading-current);
    filter: drop-shadow(0 0 4px var(--loading-current)) drop-shadow(0 0 12px var(--loading-current));
}
.loading-overlay[data-variant="scan"] .loading-scan-band,
.loading-overlay[data-variant="scan"] .loading-scan-line { animation: loading-scan 1.8s ease-in-out infinite alternate; }
@keyframes loading-scan { from { transform: translateY(0); } to { transform: translateY(309px); } }

/* Quiet: the mark breathes, a thin bar runs under the line. */
.loading-overlay[data-variant="quiet"] .loading-trace { display: none; }
.loading-overlay[data-variant="quiet"] .loading-ghost { animation: none; fill: var(--loading-ghost-lit); }
.loading-overlay[data-variant="quiet"] .loading-mark { animation: loading-breathe 2.8s ease-in-out infinite; }
.loading-overlay[data-variant="quiet"] .loading-bar {
    display: block;
    position: relative;
    width: 160px;
    height: 3px;
    border-radius: 3px;
    background: var(--loading-ghost);
    overflow: hidden;
}
.loading-bar::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 40%;
    border-radius: inherit;
    background: var(--loading-current);
    animation: loading-bar 1.4s ease-in-out infinite;
}
@keyframes loading-breathe { 0%, 100% { opacity: 0.55; transform: scale(0.97); } 50% { opacity: 1; transform: scale(1); } }
@keyframes loading-bar { from { transform: translateX(-100%); } to { transform: translateX(250%); } }

/* Harden: the core lights, then the inner walls, then the outer shell
   closes and sets solid, like armour going on. */
.loading-overlay[data-variant="harden"] .loading-trace {
    stroke-dasharray: 100 100;
    animation-duration: 4.8s;
    animation-timing-function: ease-in-out;
    animation-direction: normal;
}
.loading-overlay[data-variant="harden"] .loading-trace-centre {
    stroke-dasharray: none;
    fill: var(--loading-current);
    animation-name: loading-harden-core;
}
.loading-overlay[data-variant="harden"] .loading-trace-left,
.loading-overlay[data-variant="harden"] .loading-trace-right { animation-name: loading-harden-walls; }
.loading-overlay[data-variant="harden"] .loading-trace-outer { animation-name: loading-harden-shell; }
.loading-overlay[data-variant="harden"] .loading-ghost { animation: loading-harden-set 4.8s ease-in-out infinite; }
@keyframes loading-harden-core {
    0% { opacity: 0; fill-opacity: 0; }
    15%, 88% { opacity: 1; fill-opacity: 0.6; }
    100% { opacity: 0; fill-opacity: 0; }
}
@keyframes loading-harden-walls {
    0%, 18% { stroke-dashoffset: 100; opacity: 1; }
    40%, 88% { stroke-dashoffset: 0; opacity: 1; }
    100% { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes loading-harden-shell {
    0%, 40% { stroke-dashoffset: 100; stroke-width: 3.5; opacity: 1; }
    68% { stroke-dashoffset: 0; stroke-width: 3.5; }
    74% { stroke-dashoffset: 0; stroke-width: 8; }
    80%, 88% { stroke-dashoffset: 0; stroke-width: 5; opacity: 1; }
    100% { stroke-dashoffset: 0; stroke-width: 5; opacity: 0; }
}
@keyframes loading-harden-set {
    0%, 66% { fill: var(--loading-ghost); }
    74% { fill: var(--loading-text); }
    82%, 88% { fill: var(--loading-ghost-lit); }
    100% { fill: var(--loading-ghost); }
}

/* Seal: the core glows while the shell closes round it from both sides and
   flashes where the two ends meet. */
.loading-overlay[data-variant="seal"] .loading-trace-left,
.loading-overlay[data-variant="seal"] .loading-trace-right { display: none; }
.loading-overlay[data-variant="seal"] .loading-trace-centre {
    stroke-dasharray: none;
    fill: var(--loading-current);
    animation: loading-seal-core 1.6s ease-in-out infinite alternate;
}
.loading-overlay[data-variant="seal"] .loading-trace-outer { animation: loading-seal-shell 4s ease-in-out infinite; }
.loading-overlay[data-variant="seal"] .loading-ghost { animation: loading-seal-flash 4s ease-in-out infinite; }
@keyframes loading-seal-core { from { fill-opacity: 0.25; } to { fill-opacity: 0.7; } }
@keyframes loading-seal-shell {
    0% { stroke-dasharray: 0 100 0; stroke-width: 3.5; opacity: 1; }
    60% { stroke-dasharray: 50 0 50; stroke-width: 3.5; }
    66% { stroke-dasharray: 50 0 50; stroke-width: 8; }
    75%, 88% { stroke-dasharray: 50 0 50; stroke-width: 4.5; opacity: 1; }
    100% { stroke-dasharray: 50 0 50; stroke-width: 4.5; opacity: 0; }
}
@keyframes loading-seal-flash {
    0%, 58% { fill: var(--loading-ghost); }
    66% { fill: var(--loading-text); }
    80%, 88% { fill: var(--loading-ghost-lit); }
    100% { fill: var(--loading-ghost); }
}
@media (prefers-reduced-motion: reduce) {
    .loading-trace { animation: none; stroke-dasharray: none; opacity: 0.6; }
    .loading-ghost { animation-duration: 4s; }
    .loading-overlay[data-variant] *, .loading-bar::before { animation: none !important; }
}

/* --- Pills (status labels) ---------------------------------------------- */

.pill {
    display: inline-block;
    padding: 3px 10px;
    border-radius: var(--radius-pill);
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
    color: var(--neutral-text);
    background: var(--neutral-soft);
}
.pill-success { color: var(--success-text); background: var(--success-soft); }
.pill-warning { color: var(--warning-text); background: var(--warning-soft); }
.pill-danger { color: var(--danger-text); background: var(--danger-soft); }
.pill-info { color: var(--info-text); background: var(--info-soft); }
.pill-accent { color: var(--accent-soft-text); background: var(--accent-soft); }
.pill-expedite { color: var(--expedite-text); background: var(--expedite-soft); }
.pill-neutral { color: var(--neutral-text); background: var(--neutral-soft); } /* the base look, named, for a status that is a pause (On hold) */

/* --- Cards and tiles ---------------------------------------------------- */

.tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 18px;
    margin: 26px 0 32px;
}
.tile {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 18px 20px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 4px solid var(--accent);
    border-radius: var(--radius);
}
.tile-label { font-size: 12px; font-weight: 600; text-transform: uppercase; color: var(--text-muted); }
.tile strong { font-size: 18px; color: var(--text-heading); }
.tile-note { font-size: 14px; color: var(--text-muted); }

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 18px;
}
.card {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 18px 20px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
/* Icon and title share one row, with the status as a small caption under the
   title; the description gets the card's full width below. No badges. */
.card-head { display: flex; align-items: center; gap: 12px; }
.card-title { flex: 1; min-width: 0; }
.card-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 40px;
    width: 40px;
    height: 40px;
    border-radius: var(--radius);
    color: var(--accent-soft-text);
    background: var(--accent-soft);
}
.card-icon svg { width: 20px; height: 20px; }
.card h3 { margin: 0; line-height: 1.3; }
.card h3 a { color: inherit; text-decoration: none; }
.card h3 a:hover { color: var(--accent); }
.card-status {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--text-muted);
}
.card-status-preview { color: var(--accent); }
.card-planned .card-icon { color: var(--text-muted); background: var(--surface-alt); }
/* A card that leads somewhere is clickable as a whole: the title's link is
   stretched over the card with a pseudo-element, so the markup keeps one
   link (the title) and the keyboard focus stays on it. Nothing else inside
   such a card may be a link. */
.card-link { position: relative; cursor: pointer; }
.card-link h3 a::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius); }
.card-link:hover { border-color: var(--accent); }
.card-link:hover h3 a { color: var(--accent); }
.card-link:focus-within { outline: 2px solid var(--focus); outline-offset: 2px; }
.card-link h3 a:focus-visible { outline: none; } /* the card shows the focus ring instead */
.card p { margin: 0; font-size: 14px; line-height: 1.5; color: var(--text-muted); }

/* --- Stat tiles (KPI row) ----------------------------------------------- */

.kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 18px;
    margin: 0 0 22px;
}
.kpi {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 16px 20px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 4px solid var(--accent);
    border-radius: var(--radius);
}
.kpi-label { font-size: 12px; font-weight: 600; text-transform: uppercase; color: var(--text-muted); }
.kpi-value {
    font-size: 32px;
    font-weight: 700;
    line-height: 1.15;
    color: var(--text-heading);
    font-variant-numeric: tabular-nums;
}
.kpi-value-text { font-size: 20px; line-height: 1.4; } /* a date or a word in the value's place, so it does not wrap */
.kpi-delta { font-size: 13px; color: var(--text-muted); }
.kpi-success { border-left-color: var(--success); }
.kpi-warning { border-left-color: var(--warning); }
.kpi-danger { border-left-color: var(--danger); }
.kpi-info { border-left-color: var(--info); }
.kpi-expedite { border-left-color: var(--expedite); }

/* --- Tooltips ----------------------------------------------------------- */
/* A short explanation shown while the element is hovered or has keyboard
   focus: the class has-tip and the text in data-tip, on any element (a
   data table's header carrying its column's long description, SRS-SITE-6).
   The bubble hangs under the element's left edge; tip-end hangs it from the
   right edge (a column pinned at the right, so it stays inside the
   scrolling wrap); is-static shows it in flow under the text (the style
   guide; inline elements only, not a table cell). It is a ::before so the
   element's ::after stays free (the sort arrow); being out of flow, it
   never inherits a header's dotted underline. */
.has-tip { position: relative; }
.has-tip::before {
    content: attr(data-tip);
    position: absolute;
    left: 0;
    top: calc(100% + 6px);
    z-index: 20;
    width: max-content;
    max-width: 320px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-md);
    font-size: 13px;
    font-weight: 400;
    line-height: 1.4;
    letter-spacing: 0;
    text-align: left;
    text-transform: none;
    white-space: normal;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.12s;
}
.has-tip:hover::before, .has-tip:focus-visible::before, .has-tip.is-static::before { opacity: 1; visibility: visible; }
.has-tip.tip-end::before { left: auto; right: 0; }
.has-tip.is-static { display: inline-flex; flex-direction: column-reverse; align-items: flex-start; } /* the ::before comes first in flow; reversed, it sits under the text */
.has-tip.is-static::before { position: static; margin-top: 8px; box-shadow: none; }

/* --- Tables ------------------------------------------------------------- */

.table-wrap { overflow-x: auto; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }
.data-table { width: 100%; border-collapse: collapse; font-size: 13.5px; white-space: nowrap; }
.data-table th, .data-table td {
    padding: 8px 10px;
    border-bottom: 1px solid var(--border);
    text-align: left;
    vertical-align: top;
}
.data-table th {
    position: sticky;
    top: 0;
    background: var(--surface-alt);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--text-muted);
}
.data-table tbody tr:last-child td { border-bottom: 0; }
.data-table tbody tr:hover td { background: var(--surface-alt); }
.data-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.data-table .key { font-weight: 600; color: var(--text-heading); }
/* A facts list (the profile's account section): two columns, label then value,
   the label column as narrow as its longest label, the whole no wider than a form. */
.table-wrap.facts { max-width: 760px; }
.table-wrap.facts td.key { width: 1%; white-space: nowrap; padding-right: 40px; }
.data-table .wrap { white-space: normal; min-width: 220px; }
.data-table .col-description { white-space: normal; min-width: 220px; }
/* A clipped column (Column(clip=True), the Shortage Report's description,
   2026-10-23: purchasing's laptops need the width): the header and the cells
   carry .clip, which frees them of col-description's wrapping width, and the
   cell's text sits in a .clip-text cut at --clip-width with an ellipsis (an
   inline block, because a table cell ignores max-width). The whole value is
   the cell's tip (has-tip / data-tip, as on headers), shown over the cell so
   it reads as the cell opening out and never hangs below the table, where
   the scrolling wrap would clip it; a body cell's bubble is display: none
   until hovered, because an out-of-flow box that is merely invisible still
   adds scroll space to the wrap. A short date (MM-DD) carries its full date
   the same way, without the clip. */
.data-table .clip { min-width: 0; white-space: nowrap; }
.data-table .clip-text { display: inline-block; max-width: var(--clip-width, 12ch); overflow: hidden; text-overflow: ellipsis; vertical-align: bottom; }
.data-table td.has-tip::before { display: none; top: -1px; left: -1px; min-width: calc(100% + 2px); }
.data-table td.has-tip:hover::before { display: block; }
.data-table td.col-action.has-tip::before { left: auto; right: -1px; } /* the pinned column: the bubble grows leftwards, into the table */
.data-table .col-part_number { font-weight: 600; color: var(--text-heading); }
.data-table .empty { padding: 28px; text-align: center; color: var(--text-muted); }
/* The action is what the reader acts on: pinned to the right edge while the
   other columns scroll. */
.data-table .col-action {
    position: sticky;
    right: 0;
    background: var(--surface);
    box-shadow: var(--shadow-sticky);
}
.data-table th.col-action { background: var(--surface-alt); z-index: 1; }
.data-table tbody tr:hover td.col-action { background: var(--surface-alt); }
/* A sticky head (2026-10-27, purchasing lost the column names scrolling down
   the Shortage Report): .table-wrap.sticky-head scrolls both ways inside a
   box no taller than the window (or --sticky-head-max), and the whole thead,
   header row and filter row together, stays at its top. The thead sticks, not
   each th, or both rows would stack at top 0. A collapsed border scrolls away
   with the table, so the head's bottom line is an inset shadow. Phones get
   cards and the page's own scroll instead. */
.table-wrap.sticky-head { max-height: var(--sticky-head-max, calc(100dvh - 48px)); overflow: auto; }
.table-wrap.sticky-head thead { position: sticky; top: 0; z-index: 2; }
.table-wrap.sticky-head thead th { top: auto; }
.table-wrap.sticky-head thead tr:last-child th { box-shadow: inset 0 -1px 0 var(--border); }
.table-wrap.sticky-head thead tr:last-child th.col-action { box-shadow: var(--shadow-sticky), inset 0 -1px 0 var(--border); }
.table-caption { margin: 8px 2px 0; font-size: 13px; color: var(--text-muted); }

/* Cards: when a table's own box is narrow (a phone; Levin, 2026-10-22), each
   row becomes a card with no sideways scrolling. The first cell is the
   card's title, the Action sits beside it, the description runs full width,
   and every other cell is "label over value" in as many auto-sized columns
   as fit. Labels come from data-label, which site.js copies from the
   header. Sortable headers become a strip of sort chips; the filter row
   folds away (the toolbar's search and quick filter stay). A container
   query, not a media query, so a narrow box anywhere gets cards. */
.table-wrap { container: table-wrap / inline-size; }
@container table-wrap (max-width: 600px) {
    .data-table, .data-table thead, .data-table tbody { display: block; }
    .data-table .col-filter-row, .data-table thead tr:not(:has(.sortable)), .data-table thead th:not(.sortable) { display: none; }
    .data-table thead tr { display: flex; gap: 6px; padding: 10px 12px; overflow-x: auto; border-bottom: 1px solid var(--border); background: var(--surface-alt); }
    .data-table thead th, .data-table thead th.col-action { position: static; flex: 0 0 auto; padding: 4px 10px; border: 1px solid var(--border); border-radius: var(--radius-pill); background: var(--surface); box-shadow: none; }
    .data-table thead .col-description, .data-table thead .wrap { min-width: 0; }
    .data-table tbody tr {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
        gap: 8px 14px;
        padding: 12px 14px;
        border-bottom: 1px solid var(--border);
    }
    .data-table tbody tr:last-child { border-bottom: 0; }
    .data-table tbody tr:hover { background: var(--surface-alt); }
    .data-table tbody td, .data-table tbody tr:hover td, .data-table tbody tr:hover td.col-action {
        min-width: 0;
        padding: 0;
        border: 0;
        text-align: left;
        white-space: normal;
        overflow-wrap: anywhere;
        background: transparent;
    }
    .data-table tbody td::before { content: attr(data-label); display: block; font-size: 11px; font-weight: 600; text-transform: uppercase; color: var(--text-muted); }
    .data-table tbody td.has-tip::before { position: static; display: block; width: auto; min-width: 0; max-width: none; padding: 0; border: 0; background: transparent; box-shadow: none; opacity: 1; visibility: visible; } /* a tipped cell's bubble is its label here: the card shows the whole value anyway */
    .data-table tbody td:first-child { grid-column: 1 / -1; font-size: 15px; font-weight: 600; color: var(--text-heading); }
    .data-table tbody tr:has(> .col-action) td:first-child { grid-column: 1 / -2; }
    .data-table tbody .col-action { position: static; grid-row: 1; grid-column: -2 / -1; justify-self: end; box-shadow: none; }
    .data-table tbody .num { text-align: left; }
    .data-table tbody .col-description, .data-table tbody .wrap { grid-column: 1 / -1; min-width: 0; }
    .data-table tbody .clip-text { display: inline; max-width: none; white-space: normal; } /* a card has the room: nothing is clipped */
    .data-table tbody td:first-child::before, .data-table tbody .col-action::before, .data-table tbody .col-description::before, .data-table tbody td[colspan]::before { content: none; }
    .data-table tbody td[colspan] { grid-column: 1 / -1; font-size: 13px; font-weight: 400; color: var(--text-muted); } /* a note row or the empty state, not a card title */
}

/* The table toolset (SRS-SITE-3; recipe in docs/agent-context/tables.md,
   behaviour in tables.js): the toolbar's search and count, sortable headers,
   the filter row, the Columns picker and its panel, view tabs, the match pill
   and the pager. Markup comes from templates/tables/*.html. */

.table-search { min-width: 200px; }
.table-scope { min-width: 170px; } /* a page-level choice beside the search (the facility, SRS-USER-2); its select is a .col-filter so it submits on change */
.table-count { align-self: flex-end; padding-bottom: 9px; }
.toolbar .btn-link.btn-sm { align-self: flex-end; padding-bottom: 7px; }
.toolbar .table-quick-filter { align-self: flex-end; }

.data-table th.sortable { cursor: pointer; user-select: none; }
.data-table th.sortable:hover, .data-table th.sortable:focus-visible { color: var(--text); }
.data-table th.sortable::after { content: "\2195"; display: inline-block; margin-left: 4px; opacity: 0.4; } /* an atomic inline: a has-tip header's dotted underline stops before the arrow */
.data-table th.sort-asc::after { content: "\25B2"; opacity: 1; }
.data-table th.sort-desc::after { content: "\25BC"; opacity: 1; }
/* A header with a long description: dotted, the cue that hovering tells more.
   While hovered or focused it stacks above the other sticky headers (the
   filter row, the pinned action column at 1), or they would cover its tip. */
.data-table th.has-tip { text-decoration: underline dotted; text-decoration-color: var(--text-muted); text-underline-offset: 3px; }
.data-table th.has-tip:hover, .data-table th.has-tip:focus-visible { z-index: 2; }
.data-table .col-filter-row th { padding: 6px 8px; font-weight: 400; text-transform: none; }
.data-table .col-filter-row .col-filter { width: 100%; min-width: 64px; } /* the box fits its column instead of widening it */
.col-filter {
    width: 100%;
    min-width: 90px;
    padding: 4px 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font: inherit;
    font-size: 13px;
    text-transform: none;
    color: var(--text);
    background: var(--surface);
}
.col-filter:focus { outline: 2px solid var(--focus); outline-offset: 1px; border-color: var(--accent); }

/* The Columns picker: the button family on one right-aligned line (the panel
   anchors to the group), the drop-down panel, and its sections. */
.col-picker { position: relative; display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.col-picker-panel {
    display: none;
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    z-index: 20; /* above the pinned action column, below the toasts */
    min-width: 240px;
    max-height: 440px;
    overflow-y: auto;
    padding: 10px 12px;
    text-align: left;
    font-size: 13px;
    font-weight: 400;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
}
.col-picker-panel.is-open { display: block; }
.col-picker-panel.is-static { display: block; position: static; width: max-content; max-width: 100%; box-shadow: none; } /* the style guide shows it open, in flow */
.col-picker-actions { display: flex; gap: 6px; padding-bottom: 10px; margin-bottom: 8px; border-bottom: 1px solid var(--border); }
.col-picker-actions .btn { flex: 1; justify-content: center; }
.col-picker-views { padding-bottom: 10px; margin-bottom: 8px; border-bottom: 1px solid var(--border); }
.col-picker-views-head { margin-bottom: 6px; font-size: 12px; font-weight: 600; text-transform: uppercase; color: var(--text-muted); white-space: nowrap; }
.col-picker-views-actions { display: flex; flex-wrap: wrap; gap: 4px 14px; }
.col-picker-views-btn, .col-picker-match-toggle, .col-picker-more {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: 13px;
    color: var(--accent);
    cursor: pointer;
    white-space: nowrap;
}
.col-picker-views-btn:hover, .col-picker-match-toggle:hover, .col-picker-more:hover { color: var(--accent-hover); text-decoration: underline; }
.col-picker-views-btn.is-armed { color: var(--danger-text); font-weight: 600; }
.col-picker-form { display: none; margin-top: 8px; }
.col-picker-form.is-open { display: block; }
.col-picker-form-actions { display: flex; gap: 6px; margin-top: 6px; }
.col-picker-form-actions .btn { flex: 1; justify-content: center; }
.col-picker-input {
    width: 100%;
    padding: 5px 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font: inherit;
    font-size: 13px;
    color: var(--text);
    background: var(--surface);
}
.col-picker-input:focus { outline: 2px solid var(--focus); outline-offset: 1px; border-color: var(--accent); }
.col-picker-match-toggle { display: block; width: 100%; padding-bottom: 10px; margin-bottom: 8px; border-bottom: 1px solid var(--border); text-align: left; color: var(--text-muted); }
.col-picker-match-toggle.is-open { color: var(--accent); }
.col-picker-match { display: none; padding-bottom: 10px; margin-bottom: 8px; border-bottom: 1px solid var(--border); }
.col-picker-match.is-open { display: block; }
.col-picker-results { max-height: 180px; margin-top: 6px; overflow-y: auto; }
.col-picker-result { display: flex; align-items: center; gap: 8px; padding: 5px 6px; border-radius: 6px; cursor: pointer; white-space: nowrap; }
.col-picker-result:hover, .col-picker-result:focus-visible { background: var(--surface-alt); }
.col-picker-result-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.col-picker-result-badge { flex: 0 0 auto; padding: 1px 7px; border: 1px solid var(--border); border-radius: var(--radius-pill); font-size: 11px; text-transform: uppercase; color: var(--text-muted); }
.col-picker-result-badge.has-view { color: var(--success-text); border-color: currentColor; }
.col-picker-result-apply { flex: 0 0 auto; font-size: 11px; font-weight: 600; text-transform: uppercase; color: var(--accent); }
.col-picker-empty { padding: 4px 2px; color: var(--text-muted); white-space: normal; }
.col-picker-more { display: block; width: 100%; padding-top: 4px; text-align: center; }
.col-picker-list { display: flex; flex-direction: column; gap: 2px; }
.col-picker-item { display: flex; align-items: center; gap: 8px; padding: 3px 0; cursor: pointer; white-space: nowrap; }
.col-picker-item input { width: 15px; height: 15px; margin: 0; accent-color: var(--accent); cursor: pointer; }

/* Named views: the tab strip next to the Columns button, from two views on. */
.col-view-tabs { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.col-view-tabs[hidden] { display: none; }
.btn-ghost.is-active { color: var(--accent-soft-text); background: var(--accent-soft); border-color: transparent; }

/* The match pill: visible while previewing a colleague's layout, with both
   exits at hand, so the reader cannot forget they are on someone else's view. */
/* The toolbar pill: a labelled group of small actions in one outlined
   capsule. Two uses: the match pill (.col-match-pill, tables.js shows it
   while previewing a colleague's layout) and the settings pill
   (.toolbar-settings, in the middle of the toolbar: the page's settings
   links and the Column names page, SRS-SITE-6). Buttons and links share
   .toolbar-pill-btn. */
.toolbar-pill, .col-match-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 4px 3px 10px;
    border: 1px solid var(--accent);
    border-radius: var(--radius-pill);
    font-size: 12px;
    color: var(--accent-soft-text);
    background: var(--accent-soft);
    white-space: nowrap;
}
.col-match-pill[hidden] { display: none; }
.toolbar-pill-btn, .col-match-pill-btn {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    font: inherit;
    font-size: 11px;
    color: var(--text);
    background: var(--surface);
    text-decoration: none;
    cursor: pointer;
}
.toolbar-pill-btn:hover, .col-match-pill-btn:hover { color: var(--accent); border-color: var(--accent); }
.col-match-pill-btn[data-match-keep] { color: var(--success-text); border-color: currentColor; }
/* Both auto margins share the free space, so the settings pill sits midway
   between the left-hand controls and the right-hand group; it lines up with
   the small buttons' middle. */
.toolbar-settings { margin-left: auto; align-self: flex-end; margin-bottom: 3px; }

.pager { display: flex; align-items: center; gap: 8px; margin-top: 12px; font-size: 13px; }
.pager-link { display: inline-flex; padding: 5px 11px; border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); background: var(--surface); text-decoration: none; }
.pager-link:hover { color: var(--text); background: var(--surface-alt); }
.pager-link.is-disabled { opacity: 0.5; pointer-events: none; }
.pager-info { color: var(--text-muted); }

/* The site map's path and view columns read as code. */
.mono, .data-table .col-path, .data-table .col-view { font-family: var(--font-mono); font-size: 12px; }

/* --- Segmented control and collapsible groups ---------------------------- */
/* A .segmented control switches between shapes of one thing (the site map's
   Table / Groups). A .group is a <details> per area with a <summary> head and
   a list of rows; site.js's live filter (data-live-filter) and the
   expand / collapse buttons (data-details-toggle) drive them. */

.segmented { display: inline-flex; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); }
.segmented a { padding: 6px 14px; font-size: 13px; font-weight: 500; color: var(--text-muted); text-decoration: none; }
.segmented a + a { border-left: 1px solid var(--border); }
.segmented a:hover { color: var(--text); background: var(--surface-alt); }
.segmented .is-active, .segmented .is-active:hover { color: var(--accent-soft-text); background: var(--accent-soft); }

.groups { display: flex; flex-direction: column; gap: 8px; }
.group { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }
.group-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    border-radius: var(--radius);
    font-weight: 600;
    color: var(--text-heading);
    list-style: none;
    cursor: pointer;
    user-select: none;
}
.group-head::-webkit-details-marker { display: none; }
.group-head::before { /* the chevron: turns when the group opens */
    content: "";
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    margin: 0 2px 2px 0;
    border-right: 2px solid var(--text-muted);
    border-bottom: 2px solid var(--text-muted);
    transform: rotate(-45deg);
    transition: transform 120ms;
}
.group[open] > .group-head::before { transform: rotate(45deg); margin-bottom: 4px; }
.group[open] > .group-head { border-radius: var(--radius) var(--radius) 0 0; }
.group-head:hover { background: var(--surface-alt); }
.group-mount { color: var(--text-muted); font-weight: 400; }
.group-count { margin-left: auto; padding: 2px 10px; border-radius: var(--radius-pill); font-size: 12px; font-weight: 600; color: var(--text-muted); background: var(--surface-alt); }
.group-body { border-top: 1px solid var(--border); }
.group-list { margin: 0; padding: 0; list-style: none; }
.group-row {
    display: grid;
    grid-template-columns: minmax(200px, 1fr) minmax(180px, 1fr) auto;
    gap: 2px 16px;
    align-items: baseline;
    padding: 9px 16px;
    font-size: 14px;
}
.group-row + .group-row { border-top: 1px solid var(--border); }
.group-row:hover { background: var(--surface-alt); }
.group-row .pill { justify-self: start; }
.group-row-title a { font-weight: 500; text-decoration: none; }
.group-row-title a:hover { text-decoration: underline; }
.group-path { color: var(--text-muted); }
.group-row-note { grid-column: 1 / -1; }

/* --- Charts ------------------------------------------------------------- */
/* Series colours are --chart-1 … --chart-6 in that order; status colours are
   never series. One axis per chart; a legend from two series; a table beside
   every chart. Data-driven values arrive as custom properties set inline
   (style="--value: 62%; --series: var(--chart-1)") — the one sanctioned use
   of a style attribute.
   Chart.js charts (SRS-SITE-7) are templates/core/_chart.html, drawn by
   core/static/core/charts.js; .charts lays several out side by side. */

.chart { margin: 0; padding: 18px 20px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }
.chart-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px 16px; margin-bottom: 14px; }
.chart-title { margin: 0; font-size: 15px; }
.chart-subtitle { margin: 2px 0 0; font-size: 13px; color: var(--text-muted); }
.chart-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 0; padding: 0; list-style: none; font-size: 13px; color: var(--text-muted); }
.chart-legend li { display: inline-flex; align-items: center; gap: 6px; }
.legend-swatch { width: 10px; height: 10px; border-radius: 3px; background: var(--series, var(--chart-1)); }
.legend-swatch.legend-line { width: 16px; height: 0; border-radius: 0; background: none; border-top: 2px solid var(--series, var(--chart-1)); } /* the key of a line series */
.legend-swatch.legend-dashed { border-top-style: dashed; } /* a target or a forecast */

.charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr)); gap: 16px; } /* a dashboard's charts, two or more a row on a wide screen */
.chart-canvas { position: relative; height: 280px; } /* Chart.js fills this box; the height is the chart's */
.chart-canvas-short { height: 200px; }
.chart-canvas-tall { height: 380px; }
.chart-numbers { margin-top: 12px; font-size: 13px; }
.chart-numbers > summary { width: fit-content; cursor: pointer; color: var(--accent); }
.chart-numbers > summary:hover { color: var(--accent-hover); }
.chart-numbers .table-wrap { margin-top: 8px; }

/* The token probe: charts.js reads the canvas colours from these spans,
   so the canvas follows the tokens and the theme like everything else. */
.chart-probe { position: absolute; width: 0; height: 0; overflow: hidden; visibility: hidden; }
.chart-probe [data-token="chart-1"] { color: var(--chart-1); }
.chart-probe [data-token="chart-2"] { color: var(--chart-2); }
.chart-probe [data-token="chart-3"] { color: var(--chart-3); }
.chart-probe [data-token="chart-4"] { color: var(--chart-4); }
.chart-probe [data-token="chart-5"] { color: var(--chart-5); }
.chart-probe [data-token="chart-6"] { color: var(--chart-6); }
.chart-probe [data-token="chart-grid"] { color: var(--chart-grid); }
.chart-probe [data-token="text"] { color: var(--text); }
.chart-probe [data-token="text-muted"] { color: var(--text-muted); }
.chart-probe [data-token="text-heading"] { color: var(--text-heading); }
.chart-probe [data-token="surface"] { color: var(--surface); }
.chart-probe [data-token="border"] { color: var(--border); }

.bars { display: flex; flex-direction: column; gap: 8px; }
.bar-row { display: grid; grid-template-columns: 90px 1fr 56px; align-items: center; gap: 12px; font-size: 13px; }
.bar-label { color: var(--text-muted); }
.bar-track { height: 14px; border-radius: 4px; background: var(--chart-track); overflow: hidden; }
.bar { height: 100%; width: var(--value, 0%); border-radius: 0 4px 4px 0; background: var(--series, var(--chart-1)); }
.bar-value { text-align: right; font-variant-numeric: tabular-nums; color: var(--text); }

.chart-svg { display: block; width: 100%; max-width: 900px; height: auto; }
.chart-svg .axis-label { font-size: 12px; }
.chart-svg .grid { stroke: var(--chart-grid); stroke-width: 1; }
.chart-svg .axis-label { fill: var(--text-muted); }
.chart-svg .series { fill: none; stroke: var(--series, var(--chart-1)); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart-svg .marker { fill: var(--series, var(--chart-1)); stroke: var(--surface); stroke-width: 2; }

/* --- Dashboards (SRS-DASH-1) -------------------------------------------- */
/* A dashboard (templates/dashboards/, dashboards.js) is a twelve-column grid
   of widgets: a tile takes a sixth of the width (six to a row, as a .kpis row
   does), a chart or a list a quarter (-s), a half (-m) or the whole (-l); the
   reader chooses in Customize mode, which shows each widget's handle. A
   laptop gives a tile a quarter and a small widget a half; a phone gives a
   tile half the width and everything else all of it. */

.dash-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 16px; margin: 0 0 24px; }
.dash-item { position: relative; display: flex; flex-direction: column; grid-column: span 6; min-width: 0; }
.dash-item-tile { grid-column: span 2; }
.dash-item-s { grid-column: span 3; }
.dash-item-m { grid-column: span 6; }
.dash-item-l { grid-column: span 12; }
.dash-item > .kpi, .dash-item > .chart, .dash-item > .widget { flex: 1 1 auto; }
/* A tile, and a widget with nothing to draw or list, keep their own height:
   stretched to a chart's row they were mostly empty space (Matt, 2026-10-29).
   The tiles' floor keeps a row of tiles level when their notes wrap unevenly. */
.dash-item-tile, .dash-item-empty { align-self: start; }
.dash-item-tile .kpi { min-height: 150px; }
.dash-toolbar { margin-top: 16px; }
.dash-stamp { align-self: flex-end; padding-bottom: 9px; }
.dash-tools { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.dash-edit-actions { display: inline-flex; gap: 8px; }
.dash-edit-actions[hidden] { display: none; }
.dash-help { margin: -8px 0 12px; }

/* A tile that leads to its report: the stat tile as a link. */
a.kpi { text-decoration: none; color: inherit; }
.kpi-link:hover { border-color: var(--accent); }
.kpi-link:hover .kpi-label { color: var(--accent); }
.kpi-link:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* A list widget; an empty or failed one says why in one muted line. */
.widget { padding: 18px 20px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }
.widget-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px 16px; margin-bottom: 12px; }
.widget-title { margin: 0; font-size: 15px; }
.widget-more { font-size: 13px; }
.widget .table-wrap { margin: 0; }
.widget .data-table th, .widget .data-table td { padding: 7px 10px; }
.widget-empty-text { margin: 0; font-size: 14px; color: var(--text-muted); }
.widget-error { border-color: var(--danger); }

/* Customize mode: a handle over each widget (drag, size, move, hide), the
   dragged widget faded, the hidden widgets in a tray under the grid. */
.dash-handle { display: none; }
.is-customizing .dash-handle {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px 4px 10px;
    margin-bottom: 6px;
    border: 1px dashed var(--accent);
    border-radius: var(--radius-sm);
    font-size: 12px;
    color: var(--accent-soft-text);
    background: var(--accent-soft);
    cursor: grab;
}
.dash-handle-grip { letter-spacing: -2px; opacity: 0.7; }
.dash-handle-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.dash-sizes button { padding: 2px 8px; border: 0; font: inherit; font-size: 11px; font-weight: 600; color: var(--text-muted); background: var(--surface); cursor: pointer; }
.dash-sizes button + button { border-left: 1px solid var(--border); }
.dash-sizes button:hover { color: var(--text); background: var(--surface-alt); }
.dash-sizes .is-active, .dash-sizes .is-active:hover { color: var(--accent-soft-text); background: var(--accent-soft); }
.dash-handle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font: inherit;
    font-size: 13px;
    color: var(--text);
    background: var(--surface);
    cursor: pointer;
}
.dash-handle-btn:hover { color: var(--accent); border-color: var(--accent); }
.is-customizing .dash-item { outline: 1px dashed var(--border); outline-offset: 4px; border-radius: var(--radius); }
.is-customizing .dash-item.is-dragging { opacity: 0.5; }
.is-customizing .kpi-link, .is-customizing .widget-more { cursor: default; }
.dash-tray { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 10px 12px; margin: 0 0 24px; border: 1px dashed var(--border); border-radius: var(--radius); background: var(--surface-alt); }
.dash-tray[hidden] { display: none; }
.dash-tray-label { font-size: 12px; font-weight: 600; text-transform: uppercase; color: var(--text-muted); }
.dash-tray-btn { padding: 4px 10px; border: 1px solid var(--border); border-radius: var(--radius-pill); font: inherit; font-size: 13px; color: var(--text); background: var(--surface); cursor: pointer; }
.dash-tray-btn:hover { color: var(--accent); border-color: var(--accent); }
.dash-tray-btn[hidden] { display: none; }

@media (max-width: 1100px) {
    .dash-item-tile { grid-column: span 3; }
    .dash-item-s { grid-column: span 6; }
}
@media (max-width: 640px) {
    .dash-grid { gap: 10px; }
    .dash-item-tile { grid-column: span 6; }
    .dash-item-s, .dash-item-m { grid-column: span 12; }
}

/* --- Style guide only --------------------------------------------------- */

.subnav { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 16px 0 8px; font-size: 14px; }
.subnav a { text-decoration: none; }
.guide-section { padding-top: 12px; margin-top: 24px; border-top: 1px solid var(--border); }
.guide-section > h2 { margin-bottom: 4px; }
.guide-section > h4 { margin: 14px 0 8px; }
.guide-note { margin: 0 0 14px; font-size: 14px; color: var(--text-muted); }
.example { padding: 18px 20px; background: var(--surface); border: 1px dashed var(--border); border-radius: var(--radius); }
.example + .example { margin-top: 14px; }
.chart-use { margin: 8px 2px 0; } /* the line under each chart example: when to use that kind */
.example-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.example-narrow { max-width: 380px; } /* a phone-width box: a table inside turns into cards */
.swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.swatch { display: flex; flex-direction: column; gap: 6px; }
.swatch-chip { height: 44px; border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--swatch); }
.swatch-name { font-family: var(--font-mono); font-size: 12px; color: var(--text-muted); }
.swatch-note { font-size: 12px; color: var(--text-muted); }
.logo-example { display: inline-block; padding: 24px 28px; border-radius: var(--radius); background: var(--sidebar-start); }
.logo-example img { display: block; width: 196px; }
.bar-example { height: 6px; background: linear-gradient(90deg, var(--bar-1) 0 33.34%, var(--bar-2) 33.34% 66.67%, var(--bar-3) 66.67%); }
.type-sample { display: grid; grid-template-columns: 180px 1fr; gap: 8px 16px; align-items: baseline; }
.type-sample code { justify-self: start; }
.icon-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.icon-item { display: flex; align-items: center; gap: 10px; font-family: var(--font-mono); font-size: 12px; color: var(--text-muted); }
.icon-item svg { width: 20px; height: 20px; color: var(--accent-soft-text); }

/* --- Small screens ------------------------------------------------------ */

@media (max-width: 860px) {
    .topbar, .content, .footer { padding-left: 16px; padding-right: 16px; }
    .content { padding-top: 20px; }
    .topbar-title { font-size: 19px; }
    .type-sample { grid-template-columns: 1fr; }
    .bar-row { grid-template-columns: 70px 1fr 48px; }
    /* The Columns panel becomes a sheet along the bottom edge instead of a drop-down that would run off the side. */
    .col-picker-panel { position: fixed; left: 16px; right: 16px; top: auto; bottom: 16px; max-height: 70vh; }
    .col-picker-panel.is-static { position: static; }
    .group-row { grid-template-columns: 1fr; gap: 2px; }
}

/* Phones: the top bar keeps the menu, the title (on two lines if it needs
   them) and the user's name (the way to the profile, which holds the theme
   and Sign out since 2026-10-23); the stat tiles go two to a row, smaller. */
@media (max-width: 640px) {
    .topbar { height: auto; min-height: 56px; gap: 10px; padding-top: 8px; padding-bottom: 8px; }
    .topbar-mark { display: none; }
    .user-name { font-size: 14px; }
    .topbar-title { font-size: 18px; line-height: 1.2; white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
    .topbar-user { gap: 8px; }
    .topbar-user .btn { padding: 6px 10px; }
    .lead { font-size: 15px; }
    .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin-bottom: 16px; }
    .kpi { padding: 10px 12px; border-left-width: 3px; }
    .kpi-label { font-size: 11px; }
    .kpi-value { font-size: 24px; }
    .kpi-value-text { font-size: 16px; }
    .toolbar { gap: 10px; margin: 14px 0; }
    .table-search { min-width: 0; flex: 1 1 100%; }
    .table-wrap.sticky-head { max-height: none; } /* cards: the page scrolls, not the table */
    .footer { flex-direction: column; gap: 4px; }
}
