/* ============================================================================
   fsi.css — canonical FSI design system, generated from the Fleet UI Kit.
   Source of truth: the "Fleet UI Kit" Claude Design project (tokens + components).
   Shared verbatim across FSI apps. Namespaced .fleet-* components for standalone
   apps; .fsi-* aliases for Bootstrap-layered apps. Dark mode via dual selectors.
   ============================================================================ */

/* Fleet UI Kit v1.3.0 "FSI Brand Standard" tokens, taken from the canonical
   ~/Repos/fleet-ui-kit/tokens.css. The design handoff shipped a v1.2.0 copy;
   its :root is byte-identical to v1.3.0's, so this adopts the canonical
   source rather than a snapshot that will drift.

   This retires the pre-v1.0 palette (#2563eb accent, #f8fafc canvas) that
   this file still carried. */
:root {
  /* Neutrals — FSI light standard */
  --bg: #f2f2f2;        /* app canvas (FSI light section gray) */
  --surface: #ffffff;   /* cards / panels (FSI white) */
  --border: #d8d8d8;    /* hairlines (FSI #cccccc/#d8d8d8) */
  --text: #111111;      /* headings / primary text (FSI near-black) */
  --text-muted: #555555;/* body / secondary text (FSI gray) */

  /* Brand accent — FSI blue ramp */
  --accent: #426ab3;        /* FSI Blue — official swatch (kit v1.5.0) */
  --accent-hover: #001c54;  /* FSI Navy */
  --accent-subtle: #eef3fb; /* light tint of brand blue */
  --accent-muted: #bfd0eb;  /* FSI Mist */

  /* Link colour. Separate from --accent because the dark accent reaches only
     3.2:1 on the dark surface; in light the brand blue passes at 5.2:1. */
  --link: var(--accent);
  --link-strong: var(--accent-hover);  /* text on --accent-subtle / emphasis */

  /* Operational status (unchanged — semantic states, not brand) */
  --success: #16a34a;   /* Active / OK */
  --warning: #d97706;   /* Idle / attention */
  --danger:  #dc2626;   /* Offline / error */
  --info:    #0891b2;   /* Maintenance / info */

  /* ---- Status surfaces (v1.2.0) ----
     THE RULE: fills are translucent, never opaque pastels, so the fill tracks
     the page underneath it — pale over white in light, deep over navy in dark.
     Only the LABEL flips per theme (see the dark blocks below); the -tint and
     -border values are identical in both themes and must stay that way.

     Until v1.2.0 these values were hardcoded rgba() literals inside
     12-badges / 14-data-table / 15-alerts, which is why three components
     drifted apart. Every status surface now routes through these tokens.

     Light labels are deliberately DARKER than the raw semantic hue above
     (#166534 vs #16a34a): on a 12% tint over white the raw hue is too light
     to read. Adopted from FSI_POD's local fork, whose names these are. */
  --success-tint:   rgba(22, 163, 74, .12);
  --success-border: rgba(22, 163, 74, .35);
  --success-label:  #166534;

  --warning-tint:   rgba(217, 119, 6, .14);  /* .14, not .12 — amber is the weakest hue */
  --warning-border: rgba(217, 119, 6, .38);
  --warning-label:  #92400e;

  --danger-tint:    rgba(220, 38, 38, .12);
  --danger-border:  rgba(220, 38, 38, .35);
  --danger-label:   #991b1b;

  --info-tint:      rgba(8, 145, 178, .12);
  --info-border:    rgba(8, 145, 178, .35);
  --info-label:     #155e75;

  --neutral-tint:   rgba(85, 85, 85, .10);
  --neutral-border: var(--border);
  --neutral-label:  var(--text-muted);

  /* Radius */
  --radius-sm: 6px;
  --radius: 10px;
  --radius-full: 9999px;  /* v1.2.0 — pills; was hardcoded in badges/pills */

  /* Spacing scale */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;

  /* Layout — page container width (Fleet UI Kit v1.6.0). Fluid between the
     1240px baseline every app already used and 1800px, validated on
     FSI-welcome-landing's calendar page. Before this, the page-wrapper's
     max-width was a literal hardcoded per app, and had drifted to three
     different values (1240 / 1100 / 980px) across the suite. Reference this
     token from a wrapper's max-width instead of a literal. */
  --container-max: clamp(1240px, 92vw, 1800px);

  /* Density — table cell / list row padding (fleet-ui-kit v1.7.0). One pair for
     every table and list row in the suite; 11x14 is the former 12x16 at ~90%.
     Reference these from th / td / row rules, never a literal padding. */
  --cell-py: 11px;
  --cell-px: 14px;

  /* Type scale */
  --text-xs: 12px;
  --text-sm: 14px;
  --text-base: 16px;
  --text-lg: 18px;
  --text-xl: 24px;
  --text-2xl: 32px;

  /* Type — FSI: Lato for body/UI, Bebas Neue for display headings */
  --font: 'Lato', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-display: 'Bebas Neue', 'Oswald', 'Arial Narrow', Impact, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Elevation (neutral-black based, matching FSI #111) */
  --shadow: 0 1px 2px rgba(17, 17, 17, .06), 0 1px 3px rgba(17, 17, 17, .1);
  --shadow-lg: 0 4px 6px -1px rgba(17, 17, 17, .08), 0 10px 15px -3px rgba(17, 17, 17, .1);
}

/* Dark mode — dual selectors for Bootstrap 5 (data-bs-theme) and custom (data-theme). */
:root[data-bs-theme='dark'],
:root[data-theme='dark'] {
  --bg: #030f26;
  --surface: #0a1c3d;
  --border: #16305e;
  --text: #eaf1fa;
  --text-muted: #9fb6d8;

  --accent: #426ab3;
  --accent-hover: #4586c6;
  --accent-subtle: #0f2247;
  --accent-muted: #bfd0eb;
  --link: #6ea8e6;   /* 6.7:1 on --surface */
  --link-strong: #6ea8e6;

  /* Only the LABEL flips. The -tint and -border values are deliberately NOT
     overridden here -- a translucent fill already reads correctly over the
     navy surface, and overriding it would break the one-fill-two-themes
     property the pattern rests on (Fleet UI Kit v1.2.0). */
  --success-label: #86efac;
  --warning-label: #fcd34d;
  --danger-label:  #fca5a5;
  --info-label:    #67e8f9;
  --neutral-label: #9fb6d8;
  --neutral-tint:  rgba(191, 208, 235, .12);

  --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 1px 3px rgba(0, 0, 0, .4);
  --shadow-lg: 0 4px 6px -1px rgba(0, 0, 0, .4), 0 10px 15px -3px rgba(0, 0, 0, .5);
}

/* ---------------------------------------------------------------- Base ---- */
* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--text-base);
  color: var(--text);
  background: var(--bg);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3, h4 { color: var(--text); line-height: 1.2; margin: 0 0 var(--space-3); }

.mono { font-family: var(--font-mono); }
.muted { color: var(--text-muted); }
.text-right { text-align: right; }
.eyebrow {
  font-size: var(--text-xs); font-weight: 600; text-transform: uppercase;
  letter-spacing: .05em; color: var(--text-muted);
}

.app-main { max-width: var(--container-max); margin: 0 auto; padding: var(--space-6) var(--space-4) var(--space-12); }

/* ------------------------------------------------------------- Top nav ---- */
.app-nav {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow);
  position: sticky; top: 0; z-index: 40;
}
.app-nav__inner {
  max-width: var(--container-max); margin: 0 auto;
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
}
.app-nav__brand {
  font-weight: 700; font-size: var(--text-lg); color: var(--text);
  display: inline-flex; align-items: center; gap: var(--space-2);
}
.app-nav__brand:hover { text-decoration: none; }
.app-nav__brand .mark {
  width: 26px; height: 26px; border-radius: var(--radius-sm);
  background: linear-gradient(135deg, var(--accent), var(--accent-hover));
  color: #fff; font-size: var(--text-xs); font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center; flex: none;
}
.app-nav__links { display: flex; align-items: center; gap: var(--space-1); }
.app-nav__spacer { flex: 1; }
.app-nav__link {
  font-size: var(--text-sm); font-weight: 500; color: var(--text-muted);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
}
.app-nav__link:hover { background: var(--neutral-tint); color: var(--text); text-decoration: none; }
.app-nav__link.is-active { color: var(--link); background: var(--accent-subtle); font-weight: 600; }

/* ---------------------------------------------------------- Page header --- */
.page-header {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-6);
}
.page-title { font-size: var(--text-2xl); font-weight: 700; letter-spacing: -.01em; margin: 0 0 var(--space-1); }
.page-subtitle { color: var(--text-muted); margin: 0; }
.section-title { font-size: var(--text-lg); font-weight: 600; margin: 0 0 var(--space-3); }

/* ------------------------------------------------------------- Buttons ---- */
.fleet-btn {
  font-family: inherit; font-weight: 600; font-size: var(--text-sm);
  padding: 10px 16px; border-radius: var(--radius-sm); border: 1px solid transparent;
  cursor: pointer; display: inline-flex; align-items: center; gap: var(--space-2);
  line-height: 1; transition: background .12s, border-color .12s, filter .12s;
}
.fleet-btn:hover { text-decoration: none; }
.fleet-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.fleet-btn--sm { font-size: var(--text-xs); padding: 7px 12px; }
.fleet-btn--lg { font-size: 15px; padding: 12px 20px; }
.fleet-btn--primary { background: var(--accent); color: #fff; }
.fleet-btn--primary:hover { background: var(--accent-hover); }
.fleet-btn--secondary { background: var(--surface); color: var(--text); border-color: var(--border); }
.fleet-btn--secondary:hover { background: var(--neutral-tint); }
.fleet-btn--ghost { background: transparent; color: var(--link); }
.fleet-btn--ghost:hover { background: var(--accent-subtle); }
.fleet-btn--danger { background: var(--danger); color: #fff; }
.fleet-btn--danger:hover { filter: brightness(.94); }
.fleet-btn:disabled, .fleet-btn.is-disabled { opacity: .5; cursor: not-allowed; }

/* -------------------------------------------------------------- Cards ----- */
.fleet-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden;
}
.fleet-card__header {
  padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  font-weight: 600;
}
.fleet-card__body { padding: var(--space-4); }

/* --------------------------------------------------------- Stat cards ----- */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--space-4); }
.stat-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 18px 20px; position: relative; overflow: hidden;
}
.stat-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--accent); }
.stat-card.is-ok::before { background: var(--success); }
.stat-card.is-warn::before { background: var(--warning); }
.stat-card.is-bad::before { background: var(--danger); }
.stat-card__label { font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: .03em; color: var(--text-muted); }
.stat-card__value { font-size: var(--text-2xl); font-weight: 700; margin: var(--space-2) 0 var(--space-1); letter-spacing: -.01em; }
.stat-card__trend { font-size: 13px; font-weight: 600; display: inline-flex; align-items: center; gap: 4px; }
.stat-card__trend.up { color: var(--success); }
.stat-card__trend.down { color: var(--danger); }
.stat-card__trend.flat { color: var(--text-muted); }

/* -------------------------------------------------------- Data table ------ */
.fleet-table-wrap {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow); overflow: auto;
}
.fleet-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.fleet-table thead th {
  text-align: left; font-size: var(--text-xs); font-weight: 600; text-transform: uppercase;
  letter-spacing: .03em; color: var(--text-muted); padding: var(--cell-py) var(--cell-px);
  background: var(--neutral-tint); border-bottom: 1px solid var(--border); white-space: nowrap;
}
.fleet-table tbody td, .fleet-table tbody th { padding: var(--cell-py) var(--cell-px); border-bottom: 1px solid var(--border); text-align: left; }
.fleet-table tbody tr:last-child td, .fleet-table tbody tr:last-child th { border-bottom: none; }
.fleet-table tbody tr:hover td, .fleet-table tbody tr:hover th { background: var(--neutral-tint); }
.fleet-table .num { text-align: right; font-family: var(--font-mono); color: var(--text-muted); }
.fleet-table .unit { font-family: var(--font-mono); font-weight: 600; }

/* Grid variant: dense, sticky first column, status-tinted cells */
.fleet-table--grid { white-space: nowrap; }
.fleet-table--grid thead th { position: sticky; top: 0; z-index: 2; }
.fleet-table--grid .sticky-col { position: sticky; left: 0; z-index: 1; background: var(--surface); white-space: normal; min-width: 17rem; max-width: 22rem; }
.fleet-table--grid thead .sticky-col { z-index: 3; background: var(--neutral-tint); }
.fleet-table--grid td { text-align: center; font-variant-numeric: tabular-nums; }
.cell--low { background: var(--danger-tint) !important; color: var(--danger-label); font-weight: 600; }
.cell--missing { background: var(--warning-tint) !important; color: var(--warning-label); font-weight: 600; }
.cell--untracked { color: var(--text-muted); opacity: .65; }
.row--low > * { background: var(--danger-tint); }
.row--missing > * { background: var(--warning-tint); }

/* ------------------------------------------------------- Badges / pills --- */
.fleet-badge {
  display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-xs); font-weight: 600;
  padding: 4px 10px; border-radius: var(--radius-full); border: 1px solid transparent;
}
.fleet-badge .dot { width: 6px; height: 6px; border-radius: 50%; }
.fleet-badge.is-ok { color: var(--success-label); background: var(--success-tint); border-color: var(--success-border); }
.fleet-badge.is-ok .dot { background: var(--success); }
.fleet-badge.is-missing { color: var(--warning-label); background: var(--warning-tint); border-color: var(--warning-border); }
.fleet-badge.is-missing .dot { background: var(--warning); }
.fleet-badge.is-low { color: var(--danger-label); background: var(--danger-tint); border-color: var(--danger-border); }
.fleet-badge.is-low .dot { background: var(--danger); }
.fleet-badge.is-info { color: var(--info-label); background: var(--info-tint); border-color: var(--info-border); }
.fleet-badge.is-info .dot { background: var(--info); }
.fleet-badge.is-muted { color: var(--text-muted); background: var(--neutral-tint); border-color: var(--border); }
.fleet-badge.is-muted .dot { background: var(--text-muted); }

/* --------------------------------------------------------------- Alerts --- */
.fleet-alert {
  display: flex; gap: var(--space-3); padding: 13px 16px; border-radius: var(--radius);
  border: 1px solid; font-size: var(--text-sm); line-height: 1.45; margin-bottom: var(--space-3);
}
.fleet-alert__icon { flex: 0 0 20px; font-weight: 700; }
.fleet-alert__body strong { display: block; margin-bottom: 2px; }
.fleet-alert.is-info { background: var(--info-tint); border-color: var(--info-border); color: var(--text); }
.fleet-alert.is-info .fleet-alert__icon { color: var(--info); }
.fleet-alert.is-ok, .fleet-alert.is-success { background: var(--success-tint); border-color: var(--success-border); color: var(--text); }
.fleet-alert.is-ok .fleet-alert__icon, .fleet-alert.is-success .fleet-alert__icon { color: var(--success); }
.fleet-alert.is-warn, .fleet-alert.is-warning { background: var(--warning-tint); border-color: var(--warning-border); color: var(--text); }
.fleet-alert.is-warn .fleet-alert__icon, .fleet-alert.is-warning .fleet-alert__icon { color: var(--warning); }
.fleet-alert.is-bad, .fleet-alert.is-danger { background: var(--danger-tint); border-color: var(--danger-border); color: var(--text); }
.fleet-alert.is-bad .fleet-alert__icon, .fleet-alert.is-danger .fleet-alert__icon { color: var(--danger); }

/* ----------------------------------------------------------- Form fields -- */
.fleet-field { margin-bottom: var(--space-4); }
.fleet-field label { display: block; font-size: 13px; font-weight: 600; margin-bottom: 6px; }
.fleet-field .hint { font-size: var(--text-xs); color: var(--text-muted); margin-top: 6px; }
.fleet-field .err { font-size: var(--text-xs); color: var(--danger); margin-top: 6px; }
.fleet-input, .fleet-field input, .fleet-field select, .fleet-field textarea {
  width: 100%; font-family: inherit; font-size: var(--text-sm); padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text); outline: none;
}
.fleet-field input:focus, .fleet-field select:focus, .fleet-field textarea:focus, .fleet-input:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-subtle);
}
.fleet-field input::placeholder { color: #94a3b8; }
.fleet-field.is-invalid input { border-color: var(--danger); }
.fleet-field input:disabled { background: var(--neutral-tint); color: var(--text-muted); cursor: not-allowed; }

/* --------------------------------------------------------------- Legend --- */
.legend { display: flex; flex-wrap: wrap; gap: var(--space-4); font-size: var(--text-xs); color: var(--text-muted); margin: var(--space-2) 0 var(--space-3); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend .swatch { width: 14px; height: 14px; border: 1px solid var(--border); border-radius: 3px; }
.legend .swatch.low { background: var(--danger-tint); }
.legend .swatch.missing { background: var(--warning-tint); }
.legend .swatch.untracked { background: var(--neutral-tint); }

/* --------------------------------------------- Legacy .fsi-* compat aliases -
   Consumed by Bootstrap-layered FSI apps (e.g. fsi_STRUCTURE_EXAMPLE). Styled
   with Fleet tokens so those apps inherit the Fleet look without template edits. */
.fsi-navbar { background: var(--surface); border-bottom: 1px solid var(--border); box-shadow: var(--shadow); }
.fsi-navbar__container { display: flex; align-items: center; gap: var(--space-4); }
.fsi-navbar__brand { font-weight: 700; color: var(--text); }
.fsi-navbar__menu .nav-link { color: var(--text-muted); }
.fsi-navbar__menu .nav-link:hover { color: var(--text); }
.fsi-display { font-weight: 700; letter-spacing: -.01em; }

.fsi-button-primary, .fsi-primary-btn { background: var(--accent); border: 1px solid var(--accent); color: #fff; font-weight: 600; border-radius: var(--radius-sm); }
.fsi-button-primary:hover, .fsi-button-primary:focus, .fsi-primary-btn:hover, .fsi-primary-btn:focus { background: var(--accent-hover); border-color: var(--accent-hover); color: #fff; }
.fsi-button-secondary, .fsi-secondary-btn { background: var(--surface); border: 1px solid var(--border); color: var(--text); font-weight: 600; border-radius: var(--radius-sm); }
.fsi-button-secondary:hover, .fsi-button-secondary:focus, .fsi-secondary-btn:hover, .fsi-secondary-btn:focus { background: var(--neutral-tint); color: var(--text); }
.fsi-nav-action { background: transparent; border: 1px solid var(--border); color: var(--text-muted); border-radius: var(--radius-sm); }
.fsi-nav-action:hover { background: var(--neutral-tint); color: var(--text); }
/* Keyboard focus indicator (WCAG 2.4.7) on the legacy button classes. */
.fsi-button-primary:focus-visible, .fsi-primary-btn:focus-visible,
.fsi-button-secondary:focus-visible, .fsi-secondary-btn:focus-visible,
.fsi-nav-action:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.fsi-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }
.fsi-badge, .fsi-badge-success, .fsi-badge-primary {
  display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-xs); font-weight: 600;
  padding: 4px 10px; border-radius: var(--radius-full); border: 1px solid transparent;
}
.fsi-badge { color: var(--text-muted); background: var(--neutral-tint); border-color: var(--border); }
.fsi-badge-success { color: var(--success-label); background: var(--success-tint); border-color: var(--success-border); }
.fsi-badge-primary { color: var(--info-label); background: var(--info-tint); border-color: var(--info-border); }
.fsi-section-title { font-size: var(--text-lg); font-weight: 600; }
.fsi-text-success { color: var(--success); }
.fsi-text-danger { color: var(--danger); }

/* Map Bootstrap contextual alerts onto Fleet status chips for .fsi-* apps. */
.alert.alert-success { background: var(--success-tint); border-color: var(--success-border); color: var(--success-label); }
.alert.alert-danger { background: var(--danger-tint); border-color: var(--danger-border); color: var(--danger-label); }
.alert.alert-warning { background: var(--warning-tint); border-color: var(--warning-border); color: var(--warning-label); }
.alert.alert-info { background: var(--info-tint); border-color: var(--info-border); color: var(--info-label); }

/* Map Bootstrap form controls onto Fleet tokens so inputs stay consistent
   (notably in dark mode) in .fsi-* apps that use standard Bootstrap fields. */
.form-control, .form-select, .form-check-input {
  background-color: var(--surface); color: var(--text); border-color: var(--border);
}
.form-control:focus, .form-select:focus, .form-check-input:focus {
  background-color: var(--surface); color: var(--text);
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-subtle);
}
.form-control::placeholder { color: var(--text-muted); opacity: .7; }

/* ==========================================================================
   ADMIN CONSOLE (fsi-lobby) — Fleet UI Kit v1.3.0, design handoff Part 2.

   Everything below is ADDITIVE: no rule above this banner was renamed or
   removed, because twenty-odd admin templates -- and every other FSI app that
   ships this file -- consume them. Only tokens are used: no literal hex that a
   token already covers, and every status fill is a translucent --*-tint so it
   tracks the surface underneath it in both themes.

   Read this section as the contract for the five admin screens. Where a Fleet
   component already existed (.fleet-card, .fleet-table, .fleet-badge,
   .fleet-alert, .fleet-btn, .stat-card, .app-nav__*), the screens REUSE it;
   what follows is only what those components did not already cover.
   ========================================================================== */

/* -------------------------------------------- Shell / host-page bridge ----
   templates/admin/base.html renders the whole console inside
   templates/base.html's `content` block, which sits in a Bootstrap
   `.container`. `.admin-shell` is the marker that lets the console take the
   full width and replace the Bootstrap navbar with the Fleet top nav, without
   editing base.html -- which the login, help and error screens still use as-is.

   :has() is the mechanism: it is the only way a descendant can restyle its own
   ancestors. Where it is unsupported the console renders inside the container
   with the old navbar still above it -- plainer, never broken. */
.admin-shell { display: block; }

body:has(.admin-shell) > nav.fsi-navbar { display: none; }

/* main.container.py-4 -- Bootstrap's padding utilities are !important, so the
   reset has to be too. The shell supplies its own gutters. */
body:has(.admin-shell) > main.container {
  max-width: none; width: 100%;
  padding: 0 !important;
}

/* div.container.mt-3 -- base.html's flash-message strip. Aligned to the shell's
   1240 inner (1240 + 2 x 16 gutter), and given breathing room only when it
   actually holds an alert; empty, it collapses to nothing above the nav. */
body:has(.admin-shell) > div.container { max-width: 1272px; margin-top: 0 !important; }
body:has(.admin-shell) > div.container:has(.alert) { padding-top: var(--space-4); }
body:has(.admin-shell) > footer { max-width: 1272px; margin: 0 auto; }

@supports not selector(:has(*)) {
  .admin-shell { margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); }
}

/* ------------------------------------------------ Top nav -- Lobby brand ---
   Reuses .app-nav / .app-nav__inner / .app-nav__spacer above. Only the brand
   lockup differs from the kit default: a solid accent chip (not the kit's
   gradient) next to "Lobby" set in the display face. */
.app-nav__brand--lobby {
  font-family: var(--font-display); font-size: 26px; font-weight: 400;
  letter-spacing: .06em; color: var(--link-strong); gap: 10px;
}
.app-nav__brand--lobby:hover { color: var(--link-strong); text-decoration: none; }
.app-nav__brand--lobby .mark {
  background: var(--accent); font-family: var(--font); letter-spacing: 0;
}

/* Right-hand utility cluster. Declared a row explicitly: Bootstrap's
   .navbar-nav is a column until a .navbar-expand-* ancestor turns it, and this
   cluster has none. */
.app-nav__utils {
  display: flex; flex-direction: row; align-items: center; gap: var(--space-2);
  list-style: none; margin: 0; padding: 0;
}

/* ------------------------------------------------- Facility scope chip ----
   Static until a view passes the Locations the signed-in account may scope to.
   .app-scope__select is the drop-in for that day: the chrome lives on the
   wrapper, so swapping the <span> for a <select> does not change the shell. */
.app-scope {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: var(--text-sm); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 6px 12px; background: var(--surface); white-space: nowrap;
}
.app-scope__label { color: var(--text-muted); }
.app-scope__value { font-weight: 700; }
.app-scope__caret { font-size: 11px; color: var(--text-muted); }
.app-scope:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-subtle); }
.app-scope__select {
  font: inherit; font-weight: 700; color: var(--text); background: transparent;
  border: 0; padding: 0; outline: none; max-width: 200px;
}

/* ------------------------------------------------------------ User chip --- */
.app-user {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: inherit; font-size: var(--text-sm); color: var(--text-muted);
  background: transparent; border: 0; padding: 4px 6px 4px 4px;
  border-radius: var(--radius-full); cursor: pointer; line-height: 1.2;
}
.app-user:hover { background: var(--neutral-tint); color: var(--text); }
.app-user:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.app-user__avatar {
  width: 30px; height: 30px; border-radius: var(--radius-full);
  background: var(--accent-subtle); color: var(--link-strong);
  font-weight: 700; font-size: var(--text-xs); flex: none;
  display: inline-flex; align-items: center; justify-content: center;
}
.app-user__email { max-width: 22ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-user__menu {
  border-color: var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); font-size: var(--text-sm); min-width: 240px;
}
.app-user__name { font-weight: 700; color: var(--text); }
@media (max-width: 720px) { .app-user__email, .app-scope__label { display: none; } }

/* --------------------------------------------------- Console body grid ---- */
.admin-layout {
  max-width: 1240px; width: 100%; margin: 0 auto;
  padding: var(--space-6) var(--space-4) var(--space-12);
  display: grid; grid-template-columns: 200px 1fr; gap: var(--space-6);
  align-items: start;
}
/* min-width:0 lets a wide table scroll inside its own wrapper instead of
   stretching the grid column and pushing the sidebar off-screen. */
.admin-main { min-width: 0; }
@media (max-width: 860px) { .admin-layout { grid-template-columns: 1fr; } }

/* Bootstrap-grid compatibility. Until this change the console's content sat in
   a `.col-lg-10`, whose 12px of gutter padding cancelled the negative margins
   of any `.row` a screen opened with. The Fleet grid cell has none, so a
   legacy screen's row would hang 12px past every card beside it -- the kind of
   break no test catches. Restore the inset only for the screens that still
   open with a row, rather than padding .admin-main and insetting the rebuilt
   Fleet screens by 12px as well. */
.admin-main:has(> .row) {
  padding-left: calc(var(--bs-gutter-x, 1.5rem) * .5);
  padding-right: calc(var(--bs-gutter-x, 1.5rem) * .5);
}

/* ---------------------------------------------------------- Side nav ------
   .fsi-admin-nav is the pre-existing class -- admin/base.html and
   help/_base.html both carry it and neither was ever styled. It is grouped
   into the same rule rather than aliased in a second one, so the two cannot
   drift apart. */
.side-nav, .fsi-admin-nav {
  display: flex; flex-direction: column; gap: 2px; align-self: start;
}
.side-nav__link, .fsi-admin-nav .nav-link {
  font-size: var(--text-sm); font-weight: 400; color: var(--text-muted);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
}
.side-nav__link:hover, .fsi-admin-nav .nav-link:hover {
  background: var(--neutral-tint); color: var(--text); text-decoration: none;
}
.side-nav__link:focus-visible, .fsi-admin-nav .nav-link:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.side-nav__link.is-active, .fsi-admin-nav .nav-link.active {
  font-weight: 700; color: var(--link-strong); background: var(--accent-subtle);
}

/* -------------------------------------------------- Page header pattern ---
   Scoped to .admin-shell so the console's display H1 does not change
   .page-title for the other FSI apps that ship this same file. */
.admin-shell .page-title {
  font-family: var(--font-display); font-size: 40px; font-weight: 400;
  letter-spacing: .03em; line-height: 1; margin: 0;
}
.admin-shell .page-subtitle { font-size: var(--text-sm); margin: var(--space-1) 0 0; }
.page-title__count { color: var(--link); }
.page-header__actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.page-back { font-size: 13px; font-weight: 700; color: var(--link); display: inline-block; }

/* ------------------------------------------------------ Layout helpers ---- */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
.grid-main-side { display: grid; grid-template-columns: 1.6fr 1fr; gap: var(--space-4); }
.grid-span-all { grid-column: 1 / -1; }
@media (max-width: 900px) {
  .grid-2, .grid-main-side { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------- Stat cards (add) ----
   .stat-card, its 4px left status bar, .stat-card__label and
   .stat-card__value already exist above and are unchanged. These are the
   console's additions: the dashboard grid ratio, the display-face number, and
   stat cards that are links. */
.stat-grid--dash { grid-template-columns: 1.6fr 1fr 1fr 1fr; }
@media (max-width: 1000px) { .stat-grid--dash { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px) { .stat-grid--dash { grid-template-columns: 1fr; } }

a.stat-card { display: block; color: var(--text); }
a.stat-card:hover { text-decoration: none; box-shadow: var(--shadow-lg); }
a.stat-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.stat-card__value--display {
  font-family: var(--font-display); font-size: 64px; font-weight: 400;
  letter-spacing: 0; line-height: 1; margin: var(--space-2) 0 var(--space-1);
}
.stat-card__value--ok { color: var(--success-label); }
.stat-card__value--warn { color: var(--warning-label); }
.stat-card__value--bad { color: var(--danger-label); }
.stat-card__qualifier { font-size: var(--text-base); font-weight: 400; color: var(--text-muted); }
.stat-card__note { font-size: 13px; color: var(--text-muted); }
.stat-card__note--strong { font-weight: 700; }
.stat-card.is-info::before { background: var(--info); }

/* -------------------------------------------------- Filter / chip row -----
   The search field flexes; the chips are links, because a filter is a URL --
   shareable, bookmarkable, and the back button works. */
.filter-row {
  display: flex; align-items: center; gap: var(--space-2);
  flex-wrap: wrap; margin-bottom: var(--space-3);
}
.filter-row__search { flex: 1; min-width: 260px; }
.search-field {
  display: flex; align-items: center; gap: var(--space-2);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); padding: 0 12px;
}
.search-field:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-subtle); }
.search-field__icon { color: var(--text-muted); flex: none; }
.search-field input {
  flex: 1; min-width: 0; font-family: inherit; font-size: var(--text-sm);
  border: 0; outline: none; background: transparent; color: var(--text);
  padding: 9px 0;
}
.filter-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 700; padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border); border-radius: var(--radius-full);
  background: var(--surface); color: var(--text-muted); white-space: nowrap;
}
.filter-chip:hover { background: var(--neutral-tint); color: var(--text); text-decoration: none; }
.filter-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.filter-chip.is-active { border-color: var(--accent); background: var(--accent-subtle); color: var(--link-strong); }
.filter-chip__count { font-weight: 400; color: var(--text-muted); }
.filter-chip.is-active .filter-chip__count { color: var(--link-strong); }

/* ---------------------------------------------------------- Tab row ------- */
.fleet-tabs {
  display: flex; gap: 0; flex-wrap: wrap;
  border-bottom: 1px solid var(--border); margin-bottom: var(--space-4);
  font-size: var(--text-sm); font-weight: 700;
}
.fleet-tabs__tab {
  padding: 10px var(--space-4); color: var(--text-muted);
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap;
}
.fleet-tabs__tab:hover { color: var(--text); text-decoration: none; }
.fleet-tabs__tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.fleet-tabs__tab.is-active { color: var(--link-strong); border-bottom-color: var(--accent); }
.fleet-tabs__count { font-weight: 400; }

/* ------------------------------------------------------ Front-desk card ---
   One card per open visit whose host was not told. The 4px left border is the
   severity: danger = a delivery that failed, warning = one that was never
   going to send (a configuration fault, not a bounce). Neutral is the
   fallback, so a card without a state modifier still looks deliberate. */
.desk-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
@media (max-width: 900px) { .desk-grid { grid-template-columns: 1fr; } }

.desk-card {
  background: var(--surface); border: 1px solid var(--border);
  border-left: 4px solid var(--neutral-border);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px 20px;
}
.desk-card.is-bad { border-color: var(--danger-border); border-left-color: var(--danger); }
.desk-card.is-warn { border-color: var(--warning-border); border-left-color: var(--warning); }
.desk-card.is-info { border-color: var(--info-border); border-left-color: var(--info); }
.desk-card__top { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-3); }
.desk-card__kicker {
  font-size: var(--text-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; color: var(--text-muted);
}
.desk-card.is-bad .desk-card__kicker { color: var(--danger-label); }
.desk-card.is-warn .desk-card__kicker { color: var(--warning-label); }
.desk-card.is-info .desk-card__kicker { color: var(--info-label); }
.desk-card__name { font-size: 22px; font-weight: 700; margin-top: var(--space-1); line-height: 1.2; }
.desk-card__meta { font-size: var(--text-sm); color: var(--text-muted); }
.desk-card__meta strong { color: var(--text); }
.desk-card__elapsed {
  font-family: var(--font-display); font-size: 40px; line-height: 1;
  color: var(--text-muted); flex: none;
}
.desk-card.is-bad .desk-card__elapsed { color: var(--danger-label); }
.desk-card.is-warn .desk-card__elapsed { color: var(--warning-label); }
.desk-card.is-info .desk-card__elapsed { color: var(--info-label); }
.desk-card__reason {
  margin: 14px 0; padding: 10px 12px; border-radius: var(--radius-sm);
  font-size: 13px; background: var(--neutral-tint);
}
.desk-card.is-bad .desk-card__reason { background: var(--danger-tint); }
.desk-card.is-warn .desk-card__reason { background: var(--warning-tint); }
.desk-card.is-info .desk-card__reason { background: var(--info-tint); }
.desk-card__actions { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; }

/* ------------------------------------------------- Needs-attention rows ---
   [pill][text][link], one row per thing the front desk has to do. */
.attn-list { display: flex; flex-direction: column; }
.attn-row {
  display: flex; align-items: center; gap: 14px;
  padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--border);
}
.attn-row:last-child { border-bottom: none; }
.attn-row__text { flex: 1; font-size: var(--text-sm); }
.attn-row__link {
  font-size: var(--text-xs); font-weight: 700; color: var(--link);
  padding: 7px 12px; border-radius: var(--radius-sm); white-space: nowrap;
}
.attn-row__link:hover { background: var(--accent-subtle); text-decoration: none; }

/* --------------------------------------------------------- Bar meter ------
   Horizontal percentage bars (check-out rate). The track is the neutral tint
   so it reads on both surfaces; the fill carries the judgement. */
.meter-list { display: flex; flex-direction: column; gap: 10px; font-size: 13px; }
.meter-row { display: grid; grid-template-columns: 120px 1fr 44px; gap: 10px; align-items: center; }
.meter { display: block; height: 8px; background: var(--neutral-tint); border-radius: var(--radius-full); overflow: hidden; }
.meter__fill { display: block; height: 100%; background: var(--success); border-radius: inherit; }
.meter__fill.is-warn { background: var(--warning); }
.meter__fill.is-bad { background: var(--danger); }
.meter__value { text-align: right; font-weight: 700; }

/* ------------------------------------------------------ Definition list ---
   The visit-detail cards: a fixed label column, so two cards side by side line
   their rows up with each other. */
.fleet-dl {
  margin: 0; padding: var(--space-2) var(--space-4);
  display: grid; grid-template-columns: 150px 1fr; font-size: var(--text-sm);
}
.fleet-dl dt { color: var(--text-muted); padding: var(--space-2) 0; border-bottom: 1px solid var(--border); }
.fleet-dl dd { margin: 0; padding: var(--space-2) 0; border-bottom: 1px solid var(--border); }
.fleet-dl dt:last-of-type, .fleet-dl dd:last-of-type { border-bottom: none; }
@media (max-width: 560px) {
  .fleet-dl { grid-template-columns: 1fr; }
  .fleet-dl dt { border-bottom: none; padding-bottom: 0; }
}

/* ------------------------------------------------------------- Avatars ---- */
.avatar {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  background: var(--accent-subtle); color: var(--link-strong);
  font-family: var(--font-display); border-radius: var(--radius);
}
.avatar--lg { width: 56px; height: 56px; font-size: 26px; }
.avatar--md { width: 44px; height: 44px; font-size: var(--text-xl); }

/* ---------------------------------------------- Placeholders / checkbox ---
   A capture is encrypted at rest and viewing one writes an audit row, so the
   detail screen shows a placeholder until someone asks for the real thing. */
.placeholder-box {
  display: inline-block; background: var(--neutral-tint);
  border: 1px dashed var(--border); border-radius: var(--radius-sm);
}
.placeholder-box--photo { width: 44px; height: 44px; }
.placeholder-box--signature { width: 120px; height: 36px; }
.roster-check {
  display: inline-block; width: 22px; height: 22px;
  border: 2px solid var(--border); border-radius: 4px; vertical-align: middle;
}

/* ----------------------------------------------------- Table furniture ----
   Sits inside .fleet-card / .fleet-table-wrap, below the table. */
.table-foot {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--space-3); flex-wrap: wrap;
  padding: 10px var(--space-4); font-size: 13px; color: var(--text-muted);
}
.pager { display: flex; gap: 6px; }
.pager a, .pager span {
  padding: 6px 10px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); color: var(--text-muted); line-height: 1;
}
.pager a:hover { background: var(--neutral-tint); color: var(--text); text-decoration: none; }
.pager .is-current { background: var(--accent-subtle); border-color: var(--accent-subtle); color: var(--link-strong); font-weight: 700; }
.pager .is-disabled { opacity: .45; }

/* Two-line cell: name on top, company or qualifier beneath. */
.cell-title { font-weight: 700; }
.cell-sub { font-size: var(--text-xs); color: var(--text-muted); }
.cell-link { font-size: var(--text-xs); font-weight: 700; color: var(--link); white-space: nowrap; }
.fleet-table .t-mono { font-family: var(--font-mono); font-size: 13px; }

/* Text tones. Use the -label tokens, never the raw hue: the raw hue is too
   light to read as text on a white surface (see the token block). */
.tone-ok { color: var(--success-label); font-weight: 700; }
.tone-warn { color: var(--warning-label); font-weight: 700; }
.tone-bad { color: var(--danger-label); font-weight: 700; }
.tone-info { color: var(--info-label); font-weight: 700; }
.tone-muted { color: var(--text-muted); font-weight: 400; }

/* Legend dots, for the line under a table that explains a colour. The
   existing .legend swatch squares are unchanged; this is the dot variant. */
.legend .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-muted); flex: none; }
.legend .dot.is-ok { background: var(--success); }
.legend .dot.is-warn { background: var(--warning); }
.legend .dot.is-bad { background: var(--danger); }
.legend .dot.is-info { background: var(--info); }

/* --------------------------------------------------------------- Print ----
   The on-site roster is carried to the muster point on paper. Drop the
   chrome, keep the "Accounted for" boxes, and force their border to print --
   browsers strip backgrounds by default and a checkbox drawn as a background
   would come out blank. */
@media print {
  body:has(.admin-shell) > nav.fsi-navbar,
  .app-nav, .side-nav, .fsi-admin-nav, .page-header__actions,
  .fleet-tabs, .filter-row, .pager, .no-print { display: none !important; }
  .admin-layout { grid-template-columns: 1fr; padding: 0; max-width: none; }
  .fleet-card, .fleet-table-wrap, .stat-card, .desk-card { box-shadow: none; break-inside: avoid; }
  .fleet-table { font-size: 12pt; }
  .roster-check { -webkit-print-color-adjust: exact; print-color-adjust: exact; border-color: var(--text); }
}

/* ----------------------------------------------- Page container width ----
   This app is Bootstrap-layered (see the file header: .app-main /
   .app-nav__inner above are for standalone apps, not this one) and had NO
   override of Bootstrap's stock .container max-width (540/720/960/1140/
   1320px per breakpoint) until now -- so its pages sat in the middle
   two-thirds of a wide monitor same as EXPENSES did before its own v1.6.0
   fix. fsi.css loads after bootstrap.min.css in templates/base.html, so this
   bare, unconditional rule wins over every one of Bootstrap's per-breakpoint
   rules without needing extra specificity or !important. No @media needed --
   clamp() already covers the full range. .container-fluid (nav/flash strip)
   is untouched; it's meant to be full-width. */
.container {
  max-width: var(--container-max);
}
