/* ═══════════════════════════════════════════════════════════════════════════
   DK Productions Timelapse Platform — Design System
   ═══════════════════════════════════════════════════════════════════════════

   Single stylesheet for both APP_HTML (the authenticated SPA) and LOGIN_HTML.
   Light mode is the default; [data-theme="dark"] on <html> flips into dark.

   Conventions:
     - All colour/shadow/radius values come from CSS variables. Never hardcode.
     - All interactive elements get a visible :focus-visible ring.
     - Typography is Geist (sans) + Geist Mono — Google Fonts, OFL.
     - No uppercase/widely-spaced labels. Sentence case, calm rhythm.

   Layering order (top → bottom of this file):
     1. Font import
     2. Design tokens (:root = light, [data-theme="dark"] = dark)
     3. Legacy-token aliases (transitional — removed in PR 2 after all views migrate)
     4. Reset + base
     5. Typography utilities
     6. Layout primitives (.app-shell, sidebar, topbar, content)
     7. Responsive rules
     8. Components (buttons, cards, inputs, badges, status-dot, tables, modal,
        empty-state, toast)
     9. Projects list (the one converted view)
    10. Theme toggle

   ═══════════════════════════════════════════════════════════════════════════ */

/* Self-hosted Geist fonts — eliminates the 600ms+ render-blocking
   round-trip to fonts.bunny.net. Latin subset only (covers the
   platform UI); woff2-only (all modern browsers). Files live at
   static/fonts/. Previously loaded via @import from Bunny CDN. */
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/geist-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/static/fonts/geist-latin-500-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/geist-latin-600-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/geist-mono-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/static/fonts/geist-mono-latin-500-normal.woff2') format('woff2');
}

/* ── 2. DESIGN TOKENS ───────────────────────────────────────────────────── */

:root {
  /* Annotation palette — intentionally vivid (pre-2026-05-13 brand hexes),
     NOT the WCAG-darkened UI tokens. Annotations sit on construction-site
     photographs (high visual noise) and need to read against arbitrary
     image backgrounds, not on the chrome surfaces the button tokens cover.
     These values are also persisted into the annotation strokes DB rows
     verbatim — changing them retroactively shifts the appearance of every
     existing saved markup. Treat the values as data-graph constants; the
     token names exist so consumers (templates/app.html, future markup
     tooling) read from one place. Identical in light + dark mode because
     annotations are drawn on the underlying photo, not on the theme. */
  --annotation-clay:   #c46a45;   /* clay — brand primary, vivid */
  --annotation-hivis:  #d4943f;   /* hi-vis — highlighter / safety yellow */
  --annotation-lichen: #87a06b;   /* lichen — measurements / approvals */
  --annotation-data:   #6b8a9c;   /* blueprint — data / informational */
  --annotation-bone:   #fbf6ec;   /* bone — text overlay on dark scenes */

  /* Typography scale.
     Adjacent steps (xs↔sm, sm↔base, base↔lg) sit at 13–17% — below the
     ~25% threshold from Design for Hackers Ch 7 ("Type size changes are
     proportionally significant"). Reach for *non-adjacent* steps when
     using size to establish hierarchy: e.g. xs ↔ base (33%) or sm ↔ xl
     (71%), not sm ↔ base (14%). The token names exist so consumers can
     pick a register, not so consumers can stack adjacent sizes for
     visual rank. If you find yourself reaching for both --text-sm and
     --text-base in the same hierarchy, you want register variation
     (mono caps / weight / color) instead of size variation. */

  /* Mono micro-scale — Site Notes uses mono for every label/data/timestamp/
     section-tag surface, of which there are dozens. Without dedicated
     mono tokens the stylesheet accumulated 12 literal px values between
     9px and 12.5px (theory-audit C1: "type scale is debris field"). These
     three tokens collapse those into a coherent ratio system:
        --text-mono-xs   9.5px  — eyebrow labels (mono-uppercase, faint)
        --text-mono-sm  10.5px  — data lines / metric values
        --text-mono-md   12px   — chip values / card-header tags
     Step ratio 9.5 -> 10.5 -> 12 is ~11% / ~14% — adjacent steps are
     subtle by design (these are co-tenants in info-dense surfaces; you
     want register variation, not size). */
  --text-mono-xs: 9.5px;
  --text-mono-sm: 10.5px;
  --text-mono-md: 12px;
}

/* Bump the mono micro-scale on phones — 9.5/10.5 are below the 11 px legibility
   floor for uppercase mono labels and risk wrap/crop in dense surfaces.
   (Audit 2026-05-27 P2-Y1.) */
@media (max-width: 600px) {
  :root {
    --text-mono-xs: 11px;
    --text-mono-sm: 11.5px;
    --text-mono-md: 12.5px;
  }
}

/* Re-open the original :root so subsequent declarations (font stacks etc.)
   land where they were before. */
:root {

  /* Font stacks — Geist + Geist Mono (Google Fonts, OFL) */
  --font-sans: 'Geist', -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI",
               Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: 'Geist Mono', ui-monospace, "JetBrains Mono", "SF Mono", Menlo,
               Monaco, Consolas, monospace;
}

[data-theme="dark"] {
  --bg:           #1a1714;   /* warm near-black, not pure */
  --surface:      #211d18;   /* card, slightly elevated */
  --surface-2:    #2a251f;   /* hover/rail */
  --border:       #2c2820;
  --border-hover: #3a352d;

  --text:         #fbf6ec;   /* bone */
  --text-dim:     #b8ad97;   /* bumped 2026-04-29 to clear WCAG AA at small mono sizes */
  --text-faint:   #988f7e;   /* bumped 2026-05-13 from #8a8170 — clears AA on --surface */

  /* Primary — UNIFIED with light mode 2026-05-13. The previous
     "clay brightened for dark surround" #d27a55 had 3.13:1 against
     white button-label text (fails AA). Using #a85730 in both themes
     gives 5.05:1 button label contrast in both directions; the loss
     of dark-mode-specific punch is acceptable for the AA gain. */
  --primary:       #a85730;
  --primary-hover: #8f4928;
  --primary-soft:  #3a2419;  /* dark clay tint, sits behind clay text */

  --warn:         #e0a04a;
  --warn-soft:    #3a2c14;
  --success:      #94ae77;
  --success-soft: #2a3a22;
  --danger:       #c06a5d;
  --danger-soft:  #3a1c18;

  /* Annotation palette — same vivid values as light mode. Annotations
     render on top of the underlying photograph, not on theme chrome, so
     they don't need a dark variant. See light-mode block for rationale. */
  --annotation-clay:   #c46a45;
  --annotation-hivis:  #d4943f;
  --annotation-lichen: #87a06b;
  --annotation-data:   #6b8a9c;
  --annotation-bone:   #fbf6ec;

  /* Paired text-on-fill. Same as light because --primary is unified
     (see 2026-05-13 audit comment above). Dark-mode --warn is lighter
     (#e0a04a vs #d4943f) so the same dark-ink warn-fg still clears AA
     at 6.3:1. */
  --primary-fg: #ffffff;
  --success-fg: #ffffff;
  --warn-fg:    #2c1d08;
  --danger-fg:  #ffffff;

  --shadow-sm: 0 1px 2px 0 rgba(0,0,0,0.4);
  --shadow:    0 1px 3px 0 rgba(0,0,0,0.5), 0 1px 2px -1px rgba(0,0,0,0.3);
  --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.5), 0 2px 4px -2px rgba(0,0,0,0.3);
}

/* ── STRATUM B V2 FOUNDATION OVERRIDES ────────────────────────────────────
   The Stratum redesign is landing in batches. This token bridge flips the
   live UI onto the new ink + pewter + citron palette while preserving legacy
   variable names until each surface is fully ported to static/css/stratum-b.css. */
:root {
  --bg:          #f4f3ef;
  --surface:     #ffffff;
  --surface-2:   #f0efe9;
  --surface-3:   #e8e7e0;

  --border:       #e3e2db;
  --border-hover: #c5c4bc;
  --border-h:     #c5c4bc;
  --border-s:     #a0a098;

  --text:       #111110;
  --text-dim:   #4c4c47;
  --text-faint: #6a6a64;   /* 2026-06-17: was #8c8c84 (3.39:1 on white) — the V2 block regressed the 2026-05-13 AA fix; LV-20/39/41 */
  --text-2:     #4c4c47;
  --text-3:     #6a6a64;   /* 2026-06-17: was #8c8c84 — AA on white/--bg/--surface-2; LV-19/29/40 */

  --primary:       #111110;
  --primary-hover: #2a2a28;
  --primary-h:     #2a2a28;
  --primary-soft:  #f0efe9;
  --primary-fg:    #ffffff;

  --accent:      #c4dd1a;
  --accent-h:    #a8be15;
  --accent-soft: #f0f5c6;
  --accent-fg:   #111110;

  --ok:           #3c780a;
  --ok-soft:      #dff0c4;
  --success:      #3c780a;
  --success-soft: #dff0c4;
  --success-fg:   #ffffff;
  --warn:         #98590a;
  --warn-soft:    #faeabc;
  --warn-fg:      #ffffff;
  --bad:          #8b1818;
  --bad-soft:     #f5d4d4;
  --danger:       #8b1818;
  --danger-soft:  #f5d4d4;
  --danger-fg:    #ffffff;
  --info:         #1a5a96;
  --info-soft:    #d4e8f8;

  --sans: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "Geist Mono", "JetBrains Mono", "SF Mono", Menlo, monospace;
  --font-sans: var(--sans);
  --font-mono: var(--mono);

  --t-2xs: 10px;
  --t-xs:  11.5px;
  --t-sm:  12.5px;
  --t-md:  13.5px;
  --t-lg:  15px;
  --t-xl:  18px;
  --t-2xl: 22px;
  --t-3xl: 28px;
  --t-4xl: 36px;

  --r-xs:   3px;
  --r-sm:   5px;
  --r:      8px;
  --r-lg:   12px;
  --r-pill: 999px;

  --nav-h:     52px;
  --projbar-h: 44px;

  --shadow-sm: 0 1px 2px rgba(17,17,16,0.06);
  --shadow:    0 4px 16px -4px rgba(17,17,16,0.11);
  --shadow-md: 0 16px 48px -12px rgba(17,17,16,0.16);
}

[data-theme="dark"] {
  --bg:        #0d0d0b;
  --surface:   #161614;
  --surface-2: #1d1d1a;
  --surface-3: #262622;
  --border:       #2a2a26;
  --border-hover: #3c3c36;
  --border-h:     #3c3c36;
  --border-s:     #555550;
  --text:       #f0f0ea;
  --text-dim:   #aeaea5;
  --text-faint: #8a8a80;   /* 2026-06-17: was #6a6a60 (3.09:1 on --surface-2 #1d1d1a) — now >=4.5:1 on #1d1d1a/#161614/#0d0d0b, stays below --text-2 #aeaea5; LV-22 dark follow-up */
  --text-2:     #aeaea5;
  --text-3:     #6a6a60;
  --primary:       #f0f0ea;
  --primary-hover: #ffffff;
  --primary-h:     #ffffff;
  --primary-soft:  #1d1d1a;
  --primary-fg:    #0d0d0b;
  --accent:      #d2eb3a;
  --accent-h:    #e3f56e;
  --accent-soft: #2c3608;
  --accent-fg:   #0d0d0b;
  --ok:           #84cc16;
  --ok-soft:      #1a2c08;
  --success:      #84cc16;
  --success-soft: #1a2c08;
  --warn:         #d4a017;
  --warn-soft:    #2c2208;
  --bad:          #ef4444;
  --bad-soft:     #280808;
  --danger:       #ef4444;
  --danger-soft:  #280808;
  --info:         #60a5fa;
  --info-soft:    #0a1e38;
}

/* ── STRATUM B V2 SHELL ADAPTER ───────────────────────────────────────────
   Batch 2 introduces the v2 top navigation + project bar while the existing
   route loaders keep serving production-backed views. */
body.stratum-shell {
  background: var(--bg);
}

body.stratum-shell .stratum-nav {
  position: sticky;
  top: 0;
  z-index: 210;
}

body.stratum-shell .stratum-nav .nav-link.active {
  color: var(--text);
  background: var(--surface-2);
  font-weight: 500;
}

body.stratum-shell .stratum-projbar[hidden],
body.stratum-shell .stratum-mobile-shell {
  display: none;
}

body.stratum-shell .app-shell {
  display: block;
  min-height: 100vh;
}

body.stratum-shell .app-topbar {
  display: none;
}

body.stratum-shell .app-main {
  min-height: calc(100vh - var(--nav-h));
  width: 100%;
}

body.stratum-shell .app-content {
  padding: 0;
}

body.stratum-shell #app {
  min-height: calc(100vh - var(--nav-h));
}

body.stratum-shell .projbar-tabs {
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}

body.stratum-shell .projbar-tabs::-webkit-scrollbar {
  display: none;
}

body.stratum-shell .projbar-tab.active {
  border-bottom-color: var(--accent);
}

body.stratum-shell .projbar-actions {
  flex-shrink: 0;
}

body.stratum-shell .stratum-mobile-menu {
  display: none;
}

body.stratum-shell.stratum-canvas-active .stratum-nav,
body.stratum-shell.stratum-canvas-active .stratum-projbar,
body.stratum-shell.stratum-canvas-active .stratum-mobile-shell {
  display: none;
}

body.stratum-shell.stratum-canvas-active .app-main,
body.stratum-shell.stratum-canvas-active #app {
  min-height: 100vh;
}

body.stratum-shell.stratum-canvas-active .app-content {
  padding: 0;
}

body.stratum-shell .dashboard-map-hero .dashboard-map-inner-hero {
  position: absolute;
  inset: 0;
  min-height: 100%;
  z-index: 0;
}

body.stratum-shell .dashboard-map-hero .leaflet-container {
  filter: saturate(0.72) contrast(0.92);
}

body.stratum-shell .dashboard-map-hero .map-kpi-float {
  z-index: 3;
}

body.stratum-shell .dashboard-map-label {
  position: absolute;
  top: 14px;
  left: 22px;
  z-index: 3;
  padding: 5px 8px;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
}

body.stratum-shell .map-kpi-float .kpi {
  min-width: 160px;
  padding: 12px 20px;
  border-right: 1px solid var(--border);
  background: var(--surface);
}

body.stratum-shell .map-kpi-float .kpi:last-child {
  border-right: 0;
}

body.stratum-shell .map-kpi-float .kpi .label {
  font-family: var(--mono);
  font-size: 8.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 5px;
}

body.stratum-shell .map-kpi-float .kpi .val {
  font-family: var(--mono);
  font-size: 1.65rem;
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1;
  color: var(--text);
}

body.stratum-shell .map-kpi-float .kpi.is-warn .val,
body.stratum-shell .map-kpi-float .kpi.is-bad .val {
  color: var(--warn);
}

body.stratum-shell .map-kpi-float .kpi .sub {
  display: none;
}

body.stratum-shell .feat-card .fc-stats,
body.stratum-shell .feat-card .fc-empty-msg,
body.stratum-shell .feat-card .fc-desc {
  font-size: var(--t-xs);
  line-height: 1.5;
  color: var(--text-2);
}

body.stratum-shell .feat-card .fc-stats .accent {
  color: var(--text);
  font-weight: 600;
}

body.stratum-shell .feat-card .fc-stats .dim {
  color: var(--text-3);
}

body.stratum-shell .feat-card .fc-cta {
  margin-top: 12px;
}

body.stratum-shell .station-detail-tabs {
  margin: 0 0 18px;
  padding: 0;
  border-bottom: 1px solid var(--border);
}

body.stratum-shell .station-overview .inst-grid {
  margin-top: 18px;
}

body.stratum-shell .canvas-shell.project-canvas-view {
  padding: 0;
}

body.stratum-shell .canvas-shell.project-canvas-view .canvas-bar {
  margin: 0;
}

@media (max-width: 767px) {
  body.stratum-shell .stratum-nav {
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }

  body.stratum-shell .stratum-nav .nav-links,
  body.stratum-shell .stratum-nav .nav-search,
  body.stratum-shell .stratum-nav .btn-icon:not(.stratum-mobile-menu) {
    display: none;
  }

  body.stratum-shell .stratum-mobile-menu {
    display: grid;
  }

  body.stratum-shell .stratum-mobile-shell {
    display: block;
  }

  body.stratum-shell .m-bottomnav button {
    color: var(--text-3);
    font-size: var(--t-xs);
  }

  body.stratum-shell .m-bottomnav button.active {
    color: var(--text);
    font-weight: 600;
  }

  body.stratum-shell .stratum-projbar {
    top: var(--nav-h);
    padding: 0 12px;
  }

  body.stratum-shell .projbar-back,
  body.stratum-shell .projbar-name,
  body.stratum-shell .projbar-actions {
    display: none;
  }

  body.stratum-shell .projbar-vsep {
    display: none;
  }

  body.stratum-shell .projbar-tabs {
    width: 100%;
  }

  body.stratum-shell .projbar-tab {
    padding: 0 11px;
    white-space: nowrap;
  }

  body.stratum-shell .app-main {
    padding-bottom: calc(64px + env(safe-area-inset-bottom));
  }

  body.stratum-shell.stratum-canvas-active .app-main {
    padding-bottom: 0;
  }
}

/* ── 3. RESET + BASE ────────────────────────────────────────────────────── */

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

html, body {
  min-height: 100vh;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--t-md);
  /* 1.45 sits inside the appendix-recommended 1.2-1.4 band for body copy
     and stays appropriately tight for the instrument-panel mood. Prose
     blocks (.empty-state-body, .page-subtitle, etc.) override locally. */
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Geist stylistic alternates: ss01 = single-storey 'a' (cleaner technical look),
     cv11 = slashed zero in mono fallback contexts. */
  font-feature-settings: "ss01", "cv11";
  transition: background-color 120ms ease, color 120ms ease;
}

/* Tabular numerics anywhere mono is used — locks numbers into columns,
   which is the whole point of mono in an instrument-panel context. */
.mono, code, kbd, pre,
[class*="num"], [class*="numeric"],
.badge { font-variant-numeric: tabular-nums; }

a {
  /* Inline text links use --primary-hover (the darker variant) so they
     hit 5.2:1 on aged paper — --primary at #a85730 only reaches 4.02:1
     and fails WCAG AA for normal text. Underline addresses 1.4.1
     (don't rely on color alone to mark a link); .btn / .btn-* override
     the underline back off since buttons are already visually distinct. */
  color: var(--primary-hover);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  transition: text-decoration-thickness 120ms ease;
}
a:hover { text-decoration-thickness: 2px; }
a.btn, a.btn-primary, a.btn-secondary, a.btn-ghost,
a.btn-warn, a.btn-danger { text-decoration: none; }
/* Sidebar nav, breadcrumb, tab links, etc. use anchor-as-control patterns
   where the surface itself is the affordance — don't underline. */
.app-nav a, .app-nav-item, .tab-item, .sub-tab-item,
.page-breadcrumb a, .page-breadcrumb-back,
.shell-brand-link, .sidebar-footer a,
.empty-state a.btn-primary, .empty-state a.btn-secondary,
.live-pill, .badge, .nvr-chip { text-decoration: none; }

button { font-family: inherit; }

img { max-width: 100%; display: block; }

/* Global focus ring — applied to every interactive element via
   :focus-visible so mouse users aren't bothered by it. */
*:focus { outline: none; }
*:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* Fleet sortable-header buttons: strip UA chrome so they read as plain header
   labels, then RE-ASSERT a visible keyboard focus ring — the all:unset reset
   would otherwise drop the global *:focus-visible outline. LV-42. */
.fleet-sort-btn { all: unset; cursor: pointer; user-select: none; font: inherit; color: inherit; display: inline-flex; align-items: center; gap: 2px; min-height: 24px; }   /* min-height: WCAG 2.5.8 — the sort target must clear 24px in the dense header row */
.fleet-sort-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: var(--r-sm); }

/* WCAG 2.4.1 — skip link. Visually hidden until the keyboard user
   tabs to it (it's the first focusable element on the page). Lets a
   screen-reader user bypass the sidebar nav and topbar instead of
   serializing through every nav button on every page load. */
.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  padding: 0.6rem 1rem;
  background: var(--primary);
  color: var(--primary-fg);
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-decoration: none;
  transform: translateY(-200%);
  transition: transform 120ms ease;
  z-index: 9999;
}
.skip-link:focus,
.skip-link:focus-visible {
  transform: translateY(0);
  outline: 2px solid var(--text);
  outline-offset: 2px;
}

/* ── 5. TYPOGRAPHY UTILITIES ────────────────────────────────────────────── */

.mono { font-family: var(--font-mono); }

.text-xs   { font-size: var(--t-xs); }
.text-sm   { font-size: var(--t-sm); }
.text-base { font-size: var(--t-md); }
.text-lg   { font-size: var(--t-lg); }
.text-xl   { font-size: var(--t-2xl); }
.text-2xl  { font-size: var(--t-3xl); }

.text-dim     { color: var(--text-dim); }
.text-faint   { color: var(--text-faint); }

/* Semantic text utilities — use the deepened "badge text" hues so
   .text-success / .text-warn / .text-danger / .text-primary all clear
   WCAG 2.1 AA (4.5:1) for normal text against --bg and --surface in
   light mode. The raw --success / --warn / --danger brand colors are
   fill colors, not text colors — they fail AA on aged paper (2.06:1
   to 4.10:1, audit Stage 7). The dark-mode overrides below restore
   canonical brand vars (or lighter clay for primary) since those clear
   AA against dark surfaces. */
.text-primary { color: #7a3f1f; }   /* deep clay,  6.53:1 on --bg */
.text-success { color: #3f5a2a; }   /* deep lichen, 6.17:1 on --bg */
.text-warn    { color: #6e3e0f; }   /* deep amber,  7.08:1 on --bg */
.text-danger  { color: #6f2920; }   /* deep brick,  8.29:1 on --bg */
[data-theme="dark"] .text-primary { color: #d27a55; }   /* bright clay, 5.66:1 on dark --bg */
[data-theme="dark"] .text-success { color: var(--success); }  /* 7.29:1 on dark --bg */
[data-theme="dark"] .text-warn    { color: var(--warn); }     /* 7.90:1 on dark --bg */
[data-theme="dark"] .text-danger  { color: #d48275; }         /* bright brick, 6.16:1 on dark --bg */

/* ── 6. LAYOUT PRIMITIVES ───────────────────────────────────────────────── */

.app-shell {
  display: grid;
  /* Phase 2 (2026-05-19): added 56px Tier 1 icon rail to the left of the
     existing 240px sidebar. New grid: rail + sidebar + content. The
     mobile breakpoint in section 7 collapses both to a single column. */
  grid-template-columns: 56px 240px 1fr;
  min-height: 100vh;
}

/* Sidebar — sticky to the top of the viewport so it stays in view as the
   main column scrolls. align-self:start keeps the sticky-context valid in
   the grid (without it, grid stretches the cell and there's no room to
   stick). The sidebar gets its own internal scroll if its content
   overflows 100vh. Mobile (≤767px) overrides this with position:fixed —
   see the @media block in section 7. */
.app-sidebar {
  background: var(--surface);
  border-right: 1px solid var(--border);
  padding: 1.5rem 1rem;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  overflow-y: auto;
}

.app-sidebar-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 2rem;
  padding: 0 0.25rem;
  cursor: pointer;
  color: inherit;
}
.app-sidebar-brand img {
  height: 32px;
  width: auto;
}
.app-sidebar-brand .wordmark {
  font-size: var(--t-md);
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
}

/* Nav */
.app-nav {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  flex: 1;
}
.app-nav-item {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0.75rem;
  border-radius: var(--r);
  color: var(--text-dim);
  font-size: var(--t-sm);
  font-weight: 500;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
  background: none;
  border: 0;
  text-align: left;
  width: 100%;
}
.app-nav-item:hover {
  background: var(--surface-2);
  color: var(--text);
}
.app-nav-item.active {
  background: var(--primary-soft);
  /* var(--primary-hover) text on --primary-soft hits 4.90:1 (AA), vs
     3.79:1 for var(--primary) (fail-text/pass-ui). Dark mode uses an
     even brighter shade via the override at the bottom of the dark
     badge block. (Stage 7 WCAG fix, 2026-05-21). */
  color: var(--primary-hover);
}
.app-nav-item .nav-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  stroke-width: 1.75;
}

.app-sidebar-footer {
  border-top: 1px solid var(--border);
  padding-top: 1rem;
  margin-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

/* Main column */
.app-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Topbar */
.app-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 2rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 10;
  gap: 1rem;
}

.app-topbar-left {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex: 1;
  min-width: 0;
}

.app-topbar-right {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* Breadcrumbs (replaces legacy #breadcrumb id contents) */
.breadcrumbs {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--t-sm);
  flex-wrap: wrap;
}
.breadcrumbs a {
  color: var(--text-dim);
  text-decoration: none;
  transition: color 120ms ease;
}
.breadcrumbs a:hover { color: var(--text); }
.breadcrumbs .sep,
.breadcrumbs-sep {
  color: var(--text-faint);
}
.breadcrumbs-current,
.breadcrumbs > span:last-child {
  color: var(--text);
  font-weight: 500;
}

.user-badge {
  font-size: var(--t-xs);
  color: var(--text-dim);
  font-family: var(--font-mono);
}

/* Content area */
.app-content {
  flex: 1;
  padding: 2rem;
  width: 100%;
  /* Re-introduced 2026-05-13 per the design-for-ai theory audit
     ("density gradient is inverted on the SPA shell — on a 27" monitor
     the grid stretches edge-to-edge with the same density as the
     center, so there is no visual 'focus pool'"). 1440px lets the
     content read as a centered focus instead of a wall of edge-to-
     edge tiles. Inner grids (gallery, instrument-grid, project-grid)
     keep their auto-fill minmax() and reflow inside this width. */
  max-width: none;
}

/* Sidebar toggle: desktop collapses/expands the project shell; mobile opens
   the off-canvas sidebar. */
.sidebar-toggle {
  display: inline-flex;
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--r);
  width: 36px;
  height: 36px;
  color: var(--text);
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  align-items: center;
  justify-content: center;
}
.sidebar-toggle:hover { background: var(--surface-2); }

/* Page header (used inside .app-content by converted views) */
.page-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 2rem;
}
/* .page-title and .page-subtitle live with the Section-11+ overrides at the
   bottom of this file (search "Page header pattern"). Pre-Section-11 versions
   were removed 2026-04-30 to kill the dual-truth confusion flagged in the
   design audit (M3). */

/* ── 7. RESPONSIVE ──────────────────────────────────────────────────────── */

@media (max-width: 767px) {
  .app-shell {
    grid-template-columns: 1fr;
  }
  /* On mobile, hide the rail by default — it can come back via the
     sidebar-toggle button alongside the sidebar (slid in from the left). */
  .app-rail {
    position: fixed;
    left: -56px;
    top: 0;
    bottom: 0;
    width: 56px;
    transition: left 200ms ease;
    z-index: 21;
  }
  .app-sidebar.open ~ .app-rail,
  .app-rail.open { left: 0; }
  .app-sidebar {
    position: fixed;
    left: -240px;
    top: 0;
    bottom: 0;
    width: 240px;
    transition: left 200ms ease;
    z-index: 20;
  }
  .app-sidebar.open { left: 56px; }
  .app-content { padding: 1rem; }
  .app-topbar { padding: 0.75rem 1rem; }
  .sidebar-toggle { display: inline-flex; }
  .app-topbar-right .btn { padding: 0.4rem 0.7rem; font-size: var(--t-xs); }
}

/* Scrim behind open mobile sidebar */
.sidebar-scrim {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.4);
  z-index: 15;
}
.sidebar-scrim.open { display: block; }

/* ── 8. COMPONENTS ─────────────────────────────────────────────────────── */

/* Buttons */

/* Cards */
/* Cards — Site Notes single-edge convention. No box-shadow lift, no
   translateY on hover; hover is a border-color shift, period. The
   override layer further down (line ~6500 "Cards — single edge") used
   to *re-kill* a SaaS-style hover lift that lived here; that lift was
   inlined here directly 2026-05-21 (Site Notes refinement, brand
   character pass) so the file reads as Site Notes top-down instead of
   as "deploy Material, then patch to Site Notes." The override block
   remains as belt-and-suspenders for new card classes that might miss
   this rule. */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
  transition: border-color 120ms ease;
}
.card-interactive {
  cursor: pointer;
}
.card-interactive:hover {
  border-color: var(--primary);
}
.card-header {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.card-header h2, .card-header h3 {
  font-size: var(--t-lg);
  font-weight: 600;
  color: var(--text);
}
.card-body {
  padding: 1.25rem;
}
.card-footer {
  padding: 0.875rem 1.25rem;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

/* Form controls */
.form-field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-bottom: 1rem;
}
.form-field label {
  font-size: var(--t-xs);
  font-weight: 600;
  color: var(--text);
}
.form-hint {
  font-size: var(--t-xs);
  color: var(--text-dim);
}

.input, .select, .textarea {
  width: 100%;
  padding: 0.55rem 0.75rem;
  font-family: var(--font-sans);
  font-size: var(--t-sm);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.input:hover, .select:hover, .textarea:hover {
  border-color: var(--border-hover);
}
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  /* WCAG 2.4.7 — focus indicator stays the box-shadow ring, but
     stepped up from --primary-soft (a faint tint) to a 2-stop ring
     so the indicator clears 3:1 against the surface. */
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary), 0 0 0 3px var(--primary-soft);
}
.input::placeholder, .textarea::placeholder {
  color: var(--text-faint);
}
.textarea {
  min-height: 80px;
  resize: vertical;
}

/* Badges — base + variants consolidated onto stratum-b.css (.badge / .badge-ok/
   -warn/-bad/-accent/-ghost) on 2026-06-09. The platform base was fully shadowed
   by stratum-b except line-height, which was ported into the stratum-b base. */

/* Status dot — base + states consolidated onto stratum-b.css (.status-dot +
   .status-dot.ok/-warn/-bad) on 2026-06-09. Call sites migrated online→ok,
   offline→bad (resolved colors identical: --success≡--ok, --danger≡--bad in
   both themes). flex-shrink:0 ported into the stratum-b base; .status-dot.warning
   was already dead (no emitter used it; dashboard uses 'warn'). The dashboard
   'cold' state intentionally has no rule → neutral base grey ("no recent activity").
   (The 2026-05-21 removal of the online halo-pulse stands — no live-telemetry dot.) */

/* Tables */
.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-sm);
}
.table thead th {
  text-align: left;
  padding: 0.6rem 0.75rem;
  font-size: var(--t-xs);
  font-weight: 600;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.table tbody td {
  padding: 0.7rem 0.75rem;
  border-bottom: 1px solid var(--border);
  color: var(--text);
}
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--surface-2); }

/* Modal — overlay + content. Backward compatible with existing
   .modal-bg + .modal structure so openModal() keeps working.
   z-index 1300 sits above Leaflet's control panes (default ~800-1000)
   and the fullscreen lightbox (1200). Markup discard confirms can be
   opened from inside the lightbox, so the modal has to win that stack. */
.modal-bg {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.5);
  z-index: 1300;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
.modal-bg.open { display: flex; }
.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
  width: 440px;
  max-width: 100%;
  max-height: calc(100vh - 2rem);
  overflow: auto;
}
.modal-header {
  padding: 1.25rem 1.5rem 0.75rem;
}
.modal-title {
  font-size: var(--t-lg);
  font-weight: 600;
  color: var(--text);
}
.modal-body {
  padding: 0.75rem 1.5rem 1rem;
}
.modal-footer {
  padding: 0.75rem 1.5rem 1.25rem;
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

/* Empty state */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 3rem 1.5rem;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--r-lg);
  color: var(--text-dim);
  gap: 0.5rem;
}
.empty-state-icon {
  width: 48px;
  height: 48px;
  color: var(--text-faint);
  margin-bottom: 0.5rem;
}
.empty-state-title {
  font-size: var(--t-lg);
  font-weight: 600;
  color: var(--text);
}
.empty-state-body {
  font-size: var(--t-sm);
  color: var(--text-dim);
  max-width: 400px;
  margin-bottom: 1rem;
}

/* Toast (inherits legacy #toast behaviour — restyled). Slide-in is
   spatial motion — guarded by prefers-reduced-motion below so it
   snaps in instead of sliding for users who opted out (Stage 5 audit
   M2). */
.toast {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
  background: var(--text);
  color: var(--bg);
  font-size: var(--t-sm);
  font-weight: 500;
  padding: 0.7rem 1rem;
  border-radius: var(--r);
  box-shadow: var(--shadow-md);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 180ms ease, transform 180ms ease;
  z-index: 1500;  /* above modals (1100) and lightbox (1200) */
  pointer-events: none;
}
.toast.show {
  opacity: 1;
  transform: translateY(0);
}
/* F-08: severity variants — a colored left edge distinguishes error/success/
   warn from the neutral pill (reinforces the message text, not color-only;
   paired with role=alert/assertive for errors in helpers.ts toast()). */
.toast-error   { border-left: 4px solid var(--danger); }
.toast-success { border-left: 4px solid var(--success); }
.toast-warn    { border-left: 4px solid var(--warn); }
.toast-info    { border-left: 4px solid transparent; }
@media (prefers-reduced-motion: reduce) {
  .toast { transition: opacity 180ms ease; transform: none; }
  .toast.show { transform: none; }
}

/* What's-new banner — sticky-but-dismissible bottom-right notification.
   Distinct from .toast so it doesn't auto-vanish. Site Notes refinement
   (2026-05-21): de-pilled both the outer banner and the inner CTA. Pill
   shape (border-radius: 999px) read as Material/iOS FAB convention; the
   --radius square-corner is on-brand for the drafting-register mood.
   Hover on .wn-cta switched from filter:brightness(1.08) to
   var(--primary-hover) so it darkens (matching .btn-primary) instead of
   brightening — one direction for the brand color across the system. */
.whatsnew-banner {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.5rem 0.4rem 0.5rem 1rem;
  box-shadow: var(--shadow-md);
  display: none;
  align-items: center;
  gap: 0.6rem;
  font-size: var(--t-sm);
  z-index: 90;
  max-width: calc(100vw - 2rem);
}
.whatsnew-banner.open { display: inline-flex; }
.whatsnew-banner .wn-spark { font-size: 1.05em; }
.whatsnew-banner .wn-msg { color: var(--text-dim); }
.whatsnew-banner .wn-cta {
  background: var(--primary);
  color: var(--primary-fg);
  border: 0;
  padding: 0.4rem 0.9rem;
  border-radius: var(--r-sm);
  font-size: var(--t-xs);
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: background-color 120ms ease;
}
.whatsnew-banner .wn-cta:hover { background: var(--primary-hover); }
.whatsnew-banner .wn-x {
  background: transparent;
  border: 0;
  color: var(--text-faint);
  font-size: 1.3rem;
  line-height: 1;
  /* WCAG 2.5.8 Target Size (AA): >=24x24 hit area; visual glyph stays the same
     size, centered inside the expanded button via inline-grid. */
  min-width: 24px;
  min-height: 24px;
  display: inline-grid;
  place-items: center;
  padding: 0;
  cursor: pointer;
}
.whatsnew-banner .wn-x:hover { color: var(--text); }
/* Onboarding "Dismiss setup checklist" ✕ (rendered inline-styled in
   dashboard/index.ts). The inline style sets only color/position/font; these
   layout props are NOT inline, so they apply without !important and give the
   glyph a >=24px hit area (28px here) centred via inline-grid — mirrors the
   .wn-x precedent above. WCAG 2.5.8 Target Size (AA) RISK; LV-22. */
#ob-dismiss-btn {
  min-width: 28px;
  min-height: 28px;
  display: inline-grid;
  place-items: center;
  padding: 0;
}
@media (max-width: 600px) {
  .whatsnew-banner { right: 0.5rem; left: 0.5rem; bottom: 0.5rem; padding-left: 0.7rem; }
  .whatsnew-banner .wn-cta { padding: 0.4rem 0.7rem; }
}
.whatsnew-list { padding-left: 1.2rem; margin: 0.4rem 0; }
.whatsnew-list li { margin-bottom: 0.65rem; line-height: 1.45; }
.whatsnew-list li:last-child { margin-bottom: 0; }

/* ── 9. PROJECTS LIST (the one converted view) ─────────────────────────── */

.projects-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 1.25rem;
}

.project-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  cursor: pointer;
  transition: border-color 120ms ease, box-shadow 180ms ease,
              transform 180ms ease;
  display: flex;
  flex-direction: column;
}
.project-card:hover {
  /* F-20: no-lift convention — hover is a border-color shift only. The lift
     (box-shadow + translateY) was already neutralized by the card-hover kill
     rule (~7104); the dead declarations are removed here. */
  border-color: var(--border-hover);
}
/* 4-state health accent strip (UX-parity cheap-fold): mirrors the dashboard
   card's health-* convention so the /projects and dashboard project surfaces
   read identically. ok=green, warn=amber, bad=red, cold=faint (no stations). */
.project-card::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: transparent;
  z-index: 1;
}
.project-card.health-ok::before { background: var(--success); }
.project-card.health-warn::before { background: var(--warn); }
.project-card.health-bad::before { background: var(--danger); }
.project-card.health-cold::before { background: var(--text-faint); }

.project-card-cover {
  aspect-ratio: 16/9;
  background: var(--surface-2);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
  overflow: hidden;
}
.project-card-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.project-card-cover svg {
  width: 36px;
  height: 36px;
}

.project-card-body {
  padding: 1.1rem 1.25rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  flex: 1;
}
.project-card-title {
  font-size: var(--t-lg);
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
}
.project-card-desc {
  font-size: var(--t-sm);
  color: var(--text-dim);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.4;
  min-height: 2.45em;
}
.project-card-meta {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 0.6rem;
  font-size: var(--t-xs);
  color: var(--text-dim);
}
.project-card-stat {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.project-card-stat svg {
  width: 14px;
  height: 14px;
  stroke-width: 2;
  color: var(--text-faint);
}
.project-card-stat-value {
  color: var(--text);
  font-weight: 600;
}

/* Create-project card (dashed ghost tile matching the grid) */
.project-create-card {
  background: var(--surface);
  border: 2px dashed var(--border);
  border-radius: var(--r-lg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 240px;
  cursor: pointer;
  color: var(--text-dim);
  transition: border-color 120ms ease, background-color 120ms ease,
              color 120ms ease;
  gap: 0.4rem;
}
.project-create-card:hover {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary);
}
.project-create-card svg {
  width: 28px;
  height: 28px;
  stroke-width: 1.75;
}

/* ── 10. THEME TOGGLE (sidebar footer) ─────────────────────────────────── */

.theme-toggle {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0.75rem;
  border-radius: var(--r);
  color: var(--text-dim);
  font-family: var(--font-sans);
  font-size: var(--t-sm);
  font-weight: 500;
  cursor: pointer;
  background: none;
  border: 0;
  text-align: left;
  width: 100%;
  transition: background-color 120ms ease, color 120ms ease;
}
.theme-toggle:hover {
  background: var(--surface-2);
  color: var(--text);
}
.theme-toggle .nav-icon { width: 18px; height: 18px; flex-shrink: 0; }
.theme-toggle .icon-moon { display: none; }
[data-theme="dark"] .theme-toggle .icon-sun  { display: none; }
[data-theme="dark"] .theme-toggle .icon-moon { display: block; }

/* ── 11. LOGIN PAGE ────────────────────────────────────────────────────── */

.login-screen {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: var(--bg);
}
.login-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
  padding: 2.25rem 2rem;
  /* FND-B01: 320px reflow + 400% zoom — let the card shrink to viewport */
  width: 100%;
  max-width: min(400px, 100vw - 2rem);
}
/* FND-B01: reduce padding under ~420px so card content fits at 320 CSS px / 400% zoom */
@media (max-width: 420px) {
  .login-card {
    padding: 1.5rem 1.25rem;
  }
}
.login-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1.5rem;
}
.login-brand img { height: 36px; width: auto; }
.login-brand .wordmark {
  font-size: var(--t-lg);
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
}
.login-title {
  font-size: var(--t-2xl);
  font-weight: 700;
  color: var(--text);
  margin-bottom: 0.4rem;
  letter-spacing: -0.02em;
}
.login-sub {
  font-size: var(--t-sm);
  color: var(--text-dim);
  margin-bottom: 1.75rem;
}
.login-error {
  font-size: var(--t-sm);
  color: var(--danger);
  background: var(--danger-soft);
  border: 1px solid var(--danger-soft);
  padding: 0.55rem 0.75rem;
  border-radius: var(--r-sm);
  margin-bottom: 1rem;
  display: none;
}
.login-error.show { display: block; }
.login-submit {
  width: 100%;
  margin-top: 0.5rem;
}

/* ═══════════════════════════════════════════════════════════════════════════
   PR 1 ITERATION — topbar actions, stats strip, activity panel
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 12. TOPBAR ACTIONS ─────────────────────────────────────────────────────
   Search + notifications bell + help button, on the right side of .app-topbar
   ─────────────────────────────────────────────────────────────────────────── */

.topbar-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.topbar-search {
  position: relative;
  display: flex;
  align-items: center;
  width: 280px;
  max-width: 40vw;
}
.topbar-search svg {
  position: absolute;
  left: 0.7rem;
  width: 16px;
  height: 16px;
  color: var(--text-faint);
  pointer-events: none;
  stroke-width: 2;
}
.topbar-search input {
  width: 100%;
  height: 36px;
  padding: 0 0.75rem 0 2.1rem;
  font-family: var(--font-sans);
  font-size: var(--t-sm);
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid transparent;
  border-radius: var(--r);
  transition: background-color 120ms ease, border-color 120ms ease,
              box-shadow 120ms ease;
}
.topbar-search input::placeholder { color: var(--text-faint); }
.topbar-search input:hover {
  background: var(--surface);
  border-color: var(--border);
}
.topbar-search input:focus {
  outline: none;
  background: var(--surface);
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.topbar-icon-btn {
  position: relative;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r);
  color: var(--text-dim);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease,
              border-color 120ms ease;
}
.topbar-icon-btn:hover {
  background: var(--surface-2);
  color: var(--text);
}
.topbar-icon-btn svg {
  width: 18px;
  height: 18px;
  stroke-width: 1.75;
}

.topbar-badge {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  font-size: var(--text-mono-sm);
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  color: var(--danger-fg);
  background: var(--danger);
  border-radius: 10px;
  border: 2px solid var(--surface);
  box-sizing: content-box;
}
.topbar-badge.hidden { display: none; }

/* ── 13. STATS STRIP (projects page) ───────────────────────────────────────
   Four-card at-a-glance KPI row above the project grid. Cards that have no
   data yet are simply omitted (no "—" placeholders).
   ─────────────────────────────────────────────────────────────────────────── */

.stats-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
  margin-bottom: 2rem;
}
.stats-strip:empty { display: none; }

/* .stat-card base + bare .stat-label/.stat-value/.stat-sub descendants removed
   2026-06-09 (stat-card consolidation). The base was shadowed by the later
   `.status-metric, .stat-card` rule; the bare descendants were the last sans
   holdout (projects-view.ts), now migrated to .stat-card-label/-value/-sub
   (the mono/tabular winners below), matching every other stat strip. */

@media (max-width: 1100px) {
  .stats-strip { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
  .stats-strip { grid-template-columns: 1fr; }
}

/* ── 14. PROJECTS LAYOUT + ACTIVITY PANEL ──────────────────────────────────
   Two-column layout on desktop: the projects grid on the left, a recent
   activity feed on the right. Stacks on tablet and mobile.
   ─────────────────────────────────────────────────────────────────────────── */

.projects-layout {
  display: grid;
  grid-template-columns: 1fr 300px;
  gap: 1.5rem;
  align-items: start;
}
.projects-main { min-width: 0; }

.activity-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  /* Sticky so the feed stays visible when the projects column scrolls past
     on tall viewports. top offset matches the app-topbar height + a little. */
  position: sticky;
  top: 5rem;
  max-height: calc(100vh - 7rem);
  overflow: hidden;
}
.activity-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.9rem 1rem;
  border-bottom: 1px solid var(--border);
}
.activity-header h3 {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
}
.activity-header .btn-ghost.btn-sm {
  padding: 0.25rem 0.4rem;
  font-size: var(--t-sm);
  line-height: 1;
  /* Icon-only ↻ refresh button rendered 23.1px wide; floor the width so the
     tap target clears the AA 24px minimum. WCAG 2.5.8 Target Size RISK; LV-23. */
  min-width: 24px;
}
.activity-list {
  flex: 1;
  overflow-y: auto;
  padding: 0.25rem 0;
}
.activity-item {
  display: flex;
  gap: 0.7rem;
  padding: 0.65rem 1rem;
  border-bottom: 1px solid var(--border);
  font-size: var(--t-sm);
  line-height: 1.4;
}
.activity-item:last-child { border-bottom: 0; }

.activity-dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-top: 0.45rem;
  background: var(--text-faint);
}
.activity-dot.checkin    { background: var(--success); }
.activity-dot.command    { background: var(--primary); }
.activity-dot.enrollment { background: var(--warn); }

.activity-body {
  flex: 1;
  min-width: 0;
}
.activity-message {
  color: var(--text);
  word-wrap: break-word;
}
.activity-message a {
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px dotted var(--border-hover);
}
.activity-message a:hover { color: var(--primary); border-bottom-color: var(--primary); }
.activity-time {
  font-size: var(--t-xs);
  color: var(--text-faint);
  margin-top: 0.15rem;
}

.activity-empty {
  padding: 2rem 1rem;
  text-align: center;
  font-size: var(--t-sm);
  color: var(--text-dim);
}

@media (max-width: 1100px) {
  .projects-layout {
    grid-template-columns: 1fr;
  }
  .activity-panel {
    position: static;
    max-height: none;
  }
  .activity-list {
    max-height: 400px;
  }
}

/* ── 15. TOPBAR — HIDE SEARCH + ACTIONS ON NARROW VIEWPORTS ────────────── */
@media (max-width: 767px) {
  .topbar-search { display: none; }
  .topbar-actions { gap: 0.25rem; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PR 2a — project detail page + all modals
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 16. PROJECT DETAIL HEADER ──────────────────────────────────────────── */

.page-breadcrumb-back {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--t-sm);
  color: var(--text-dim);
  text-decoration: none;
  margin-bottom: 0.6rem;
  transition: color 120ms ease;
}
.page-breadcrumb-back:hover { color: var(--primary); }
.page-breadcrumb-back svg {
  width: 14px;
  height: 14px;
  stroke-width: 2;
}

.page-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

/* Ghost button that reads "danger" on hover — used for "Delete project" in the
   page-actions row. Keeps visual weight low until the user commits. */
.btn-ghost.danger-text {
  color: var(--danger);
}
.btn-ghost.danger-text:hover:not(:disabled) {
  background: var(--danger-soft);
  color: var(--danger);
}

/* ── 17. STATS STRIP (project detail) ───────────────────────────────────── */

.stats-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
  margin-bottom: 2rem;
}
@media (max-width: 900px) {
  .stats-strip { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 500px) {
  .stats-strip { grid-template-columns: 1fr; }
}

/* The global .stat-card (from PR 1) is already defined — we just make sure
   the project-detail variant uses the same rhythm. The card itself carries
   border/shadow/hover from .card; the inner structure is below. */
/* Duplicate .stat-card + the sans .stat-card-label/-value/-sub rules removed
   2026-06-09 (stat-card consolidation) — all shadowed by the later mono winners
   (`.status-metric, .stat-card` + `.stat-card-label, .stat-label` / `-value` /
   `-sub` blocks). Single definition now lives in those later blocks. */

/* ── 18. STATIONS GRID ──────────────────────────────────────────────────── */

.stations-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1rem;
}

.station-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  padding: 1.1rem 1.2rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  cursor: pointer;
  transition: border-color 120ms ease, box-shadow 120ms ease,
              transform 120ms ease;
  min-height: 160px;
}
.station-card:hover {
  /* F-20: border-color shift only (lift was already neutralized at ~7104). */
  border-color: var(--border-hover);
}

.station-card-header {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  min-width: 0;
}
.station-card-name {
  font-size: var(--t-lg);
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1;
}

.station-card-meta {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-top: auto;
}
.station-card-meta-item {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-size: var(--t-xs);
}
.station-card-meta-item .meta-label {
  color: var(--text-dim);
  flex-shrink: 0;
}
.station-card-meta-item .meta-value {
  color: var(--text);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: calc(var(--t-xs) + 0.5px);
}

/* Create-station tile (dashed ghost — matches .project-create-card rhythm) */
.create-station-card {
  background: var(--surface);
  border: 2px dashed var(--border);
  border-radius: var(--r-lg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 160px;
  cursor: pointer;
  color: var(--text-dim);
  transition: border-color 120ms ease, background-color 120ms ease,
              color 120ms ease;
  gap: 0.4rem;
}
.create-station-card:hover {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary);
}
.create-station-card svg {
  width: 24px;
  height: 24px;
  stroke-width: 1.75;
}
.create-station-card-label {
  font-size: var(--t-sm);
  font-weight: 500;
}

/* ── 19. ENROLLMENT MODAL FLOW ──────────────────────────────────────────── */

.enroll-intro {
  font-size: var(--t-sm);
  color: var(--text-dim);
  margin-bottom: 0.9rem;
  line-height: 1.45;
}

.enroll-code {
  display: block;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--t-3xl);
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.9rem 1rem;
  margin: 0.5rem 0 1rem;
  user-select: all;
  cursor: text;
}

.enroll-qr {
  display: flex;
  justify-content: center;
  margin: 0.5rem 0 1rem;
}
.enroll-qr img,
.enroll-qr svg {
  width: 200px;
  height: 200px;
  border-radius: var(--r-sm);
  background: #ffffff;
  padding: 0.5rem;
  border: 1px solid var(--border);
}

.enroll-status {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  font-size: var(--t-sm);
  color: var(--text-dim);
  margin-top: 0.75rem;
}
.enroll-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: enroll-spin 0.8s linear infinite;
  flex-shrink: 0;
}
@media (prefers-reduced-motion: reduce) {
  /* Spinner becomes a static dashed ring — still communicates "in
     progress" via shape, no motion. The enrollment poll JS continues
     to update the phase list text below, which is the load-bearing
     progress signal. */
  .enroll-spinner {
    animation: none;
    border-style: dashed;
  }
}
.enroll-phase-list {
  display: grid;
  gap: 0.35rem;
  margin-top: 0.65rem;
  font-size: var(--t-xs);
  color: var(--text-dim);
}
.enroll-phase-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  min-height: 1rem;
}
.enroll-phase-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--text-faint);
  flex-shrink: 0;
}
.enroll-phase-dot.ok {
  background: var(--success);
}
.enroll-phase-dot.pending {
  background: var(--primary);
}
.enroll-phase-dot.error {
  background: var(--danger);
}
@keyframes enroll-spin {
  to { transform: rotate(360deg); }
}

.enroll-expiry {
  text-align: center;
  font-size: var(--t-xs);
  color: var(--text-faint);
  margin-top: 0.5rem;
}
.enroll-expiry.urgent {
  color: var(--warn);
  font-weight: 600;
}

.enroll-done-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin: 0 auto 1rem;
  border-radius: 50%;
  background: var(--success-soft);
  color: var(--success);
}
.enroll-done-icon svg {
  width: 32px;
  height: 32px;
  stroke-width: 2.5;
}
.enroll-done-title {
  text-align: center;
  font-size: var(--t-lg);
  font-weight: 600;
  color: var(--text);
  margin-bottom: 0.3rem;
}
.enroll-done-sub {
  text-align: center;
  font-size: var(--t-sm);
  color: var(--text-dim);
  line-height: 1.45;
}

/* ── 19b. Boot-bundle additions to the enrollment modal (2026-05-13) ──── */

.enroll-radio-group {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  margin-top: 0.35rem;
}
.enroll-radio,
.enroll-checkbox {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  font-size: var(--t-sm);
  color: var(--text);
  cursor: pointer;
  line-height: 1.4;
}
.enroll-radio input,
.enroll-checkbox input {
  margin-top: 0.18rem;
  flex-shrink: 0;
  accent-color: var(--primary);
}
.enroll-radio span,
.enroll-checkbox span {
  flex: 1;
}
.enroll-radio strong,
.enroll-checkbox strong {
  color: var(--text);
  font-weight: 600;
}

.enroll-profile-note {
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: var(--t-sm);
  line-height: 1.45;
  margin: -0.25rem 0 0.7rem;
  padding: 0.65rem 0.75rem;
}

.enroll-flasher {
  margin-bottom: 1rem;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}
.enroll-flasher-title {
  font-weight: 600;
  color: var(--text);
}
.enroll-flasher-note {
  margin: 0.55rem 0 0.8rem;
  font-size: var(--t-xs);
  line-height: 1.5;
  color: var(--text-faint);
}
.enroll-compact-steps {
  margin-bottom: 0.75rem;
}
.enroll-url-row {
  display: flex;
  align-items: stretch;
  gap: 0.4rem;
  margin-top: 0.5rem;
}
.enroll-url-input {
  flex: 1;
  min-width: 0;
  padding: 0.4rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text);
  font-family: var(--mono);
  font-size: var(--t-xs);
}

.enroll-steps {
  list-style: none;
  counter-reset: enroll-step;
  padding: 0;
  margin: 0 0 1rem;
}
.enroll-steps > li {
  counter-increment: enroll-step;
  position: relative;
  padding: 0 0 0.9rem 2.2rem;
  border-left: 1px dashed var(--border);
  margin-left: 0.85rem;
}
.enroll-steps > li:last-child {
  padding-bottom: 0;
  border-left-color: transparent;
}
.enroll-steps > li::before {
  content: counter(enroll-step);
  position: absolute;
  left: -0.85rem;
  top: 0;
  width: 1.6rem;
  height: 1.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 600;
  color: var(--primary);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 50%;
}
.enroll-step-head {
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text);
  margin-bottom: 0.35rem;
}
.enroll-step-actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 0.25rem;
}

.enroll-fallback {
  margin: 0.4rem 0 0.75rem;
  border-top: 1px dashed var(--border);
  padding-top: 0.75rem;
}
.enroll-fallback > summary {
  font-size: var(--t-xs);
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
}
.enroll-fallback[open] > summary {
  margin-bottom: 0.4rem;
}

.btn-disabled {
  opacity: 0.6;
  pointer-events: none;
  cursor: default;
}

/* ── 20. MEMBERS MODAL ──────────────────────────────────────────────────── */

.member-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

.member-row {
  display: grid;
  grid-template-columns: 1fr 140px auto;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.75rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.member-row-name {
  font-size: var(--t-sm);
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.member-row-name .role-hint {
  display: inline-block;
  margin-left: 0.4rem;
  font-size: var(--t-xs);
  color: var(--text-faint);
  font-weight: 500;
}
.member-role-select {
  padding: 0.35rem 0.5rem;
  font-size: var(--t-xs);
}

.btn-icon-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  background: transparent;
  color: var(--text-faint);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  transition: background-color 120ms ease, color 120ms ease,
              border-color 120ms ease;
}
.btn-icon-danger:hover:not(:disabled) {
  background: var(--danger-soft);
  color: var(--danger);
  border-color: var(--danger-soft);
}

.member-add {
  /* Now hosts two add-rows separated by an "or" divider — the first
   * is "Add existing user by username", the second is "Send email
   * invitation to a non-user". Each row preserves the original
   * 1fr/140px/auto column rhythm. (2026-05-04.) */
  padding-top: 0.85rem;
  border-top: 1px solid var(--border);
  margin-top: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.member-add-row {
  display: grid;
  grid-template-columns: 1fr 140px auto;
  gap: 0.5rem;
  align-items: center;
}
.member-add-divider {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.member-add-divider::before,
.member-add-divider::after {
  content: "";
  flex: 1;
  border-top: 1px dashed var(--border);
}

/* Pending-invitations section: same row visual as member-row but
 * tinted to read as "pending" rather than active. (2026-05-04.) */
.member-pending-section {
  margin-top: 1rem;
}
.member-section-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 0.4rem;
  padding-left: 0.1rem;
}
.member-row.member-row-pending {
  background: var(--bg);
  border-style: dashed;
}

/* Phone width — invitation form rows stack so the email field
 * doesn't crush against the role select. */
@media (max-width: 480px) {
  .member-add-row {
    grid-template-columns: 1fr;
  }
}

/* ── 21. TYPE-TO-CONFIRM DESTRUCTIVE ACTIONS ────────────────────────────── */

.confirm-warning {
  font-size: var(--t-sm);
  color: var(--text);
  line-height: 1.5;
  margin-bottom: 0.9rem;
}
.confirm-warning strong {
  color: var(--danger);
  font-weight: 600;
}
.confirm-error {
  font-size: var(--t-xs);
  color: var(--danger);
  margin-top: 0.35rem;
  min-height: 1.1em;
}

/* ── 22. MEMBERS MODAL — RESPONSIVE ─────────────────────────────────────── */
@media (max-width: 500px) {
  .member-row,
  .member-add {
    grid-template-columns: 1fr;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PR 2b — station detail + admin + profile + lightbox
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 23. TAB NAV ────────────────────────────────────────────────────────────
   Used on the station detail page (Gallery / Status / Settings) and designed
   to be extendable when the Videos tab lands in Phase A. Replaces the legacy
   .st-tabs/.st-tab pair.
   ─────────────────────────────────────────────────────────────────────────── */

.tab-nav {
  display: flex;
  gap: 0.1rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1.5rem;
  overflow-x: auto;
}
.tab-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.65rem 1rem;
  font-family: var(--font-sans);
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text-dim);
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  transition: color 120ms ease, border-color 120ms ease;
  margin-bottom: -1px;
}
.tab-item:hover {
  color: var(--text);
}
.tab-item.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
  font-weight: 600;
}

/* ── 24. DISK BAR (station stats-strip) ────────────────────────────────────
   Thin progress bar used inside .stat-card for disk usage. Color ramps from
   success → warn → danger at 70% / 85%. The data value sets width inline.
   ─────────────────────────────────────────────────────────────────────────── */

.disk-bar {
  width: 100%;
  height: 4px;
  background: var(--surface-2);
  border-radius: var(--r-xs); /* FND-C05: was 2px off-scale → --r-xs (3px) */
  overflow: hidden;
  margin-top: 0.4rem;
}
.disk-bar-fill {
  height: 100%;
  background: var(--success);
  border-radius: var(--r-xs); /* FND-C05: was 2px off-scale → --r-xs (3px) */
  transition: width 200ms ease, background-color 120ms ease;
}
.disk-bar-fill.warn   { background: var(--warn); }
.disk-bar-fill.danger { background: var(--danger); }

/* ── 25. GALLERY ─────────────────────────────────────────────────────────── */

.gallery-layout {
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 1.5rem;
  align-items: start;
}

.gallery-dates {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  position: sticky;
  top: 5rem;
  max-height: calc(100vh - 7rem);
  display: flex;
  flex-direction: column;
}
.gallery-dates-header {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: var(--t-xs);
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.sidebar-close {
  display: none;
  background: none;
  border: 0;
  color: var(--text-dim);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  padding: 0.2rem 0.4rem;
  border-radius: var(--r-sm);
}
.sidebar-close:hover { background: var(--surface-2); color: var(--text); }

.date-list {
  flex: 1;
  overflow-y: auto;
  padding: 0.25rem 0;
}

/* Month grouping in the date sidebar (added 2026-05-04). The newest
 * month renders expanded; older months collapse so the sidebar
 * doesn't become a wall on long-running stations. Click the header
 * to toggle. The active date inside a collapsed group auto-expands. */
.date-month-group {
  border-bottom: 1px dashed var(--border);
}
.date-month-group:last-child { border-bottom: 0; }

.date-month-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.5rem 0.75rem;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  transition: background-color 120ms ease;
}
.date-month-header:hover { background: var(--surface-2); }

.date-month-chevron {
  width: 12px;
  height: 12px;
  flex: 0 0 12px;
  transition: transform 160ms ease;
  transform: rotate(-90deg);   /* collapsed default: chevron points right */
  color: var(--text-faint);
}
.date-month-group.is-expanded .date-month-chevron {
  transform: rotate(0);         /* expanded: chevron points down */
}

.date-month-label {
  flex: 1;
  color: var(--text);
  letter-spacing: 0.06em;
}
.date-month-meta {
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.date-month-items {
  /* Collapsed: hidden via display:none. Showing/hiding rather than
   * height-animating because the items are mono-uppercase rows of
   * unknown count — height animation flickers. */
  display: none;
}
.date-month-group.is-expanded .date-month-items {
  display: block;
}
.date-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  font-size: var(--t-sm);
  color: var(--text);
  cursor: pointer;
  border-left: 2px solid transparent;
  transition: background-color 120ms ease, border-color 120ms ease,
              color 120ms ease;
}
.date-item:hover {
  background: var(--surface-2);
}
.date-item.active {
  background: var(--primary-soft);
  color: var(--primary);
  border-left-color: var(--primary);
  font-weight: 600;
}
.date-item-label {
  font-family: var(--font-mono);
  font-size: calc(var(--t-sm) - 0.5px);
}
.date-item-count {
  font-size: var(--t-xs);
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  font-weight: 600;
  flex-shrink: 0;
}
.date-item.active .date-item-count {
  background: var(--primary);
  color: var(--primary-fg);
}

.gallery-main {
  min-width: 0;
}
.gallery-day-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.gallery-day-header h2 {
  font-size: var(--t-2xl);
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.gallery-day-header h2 .count {
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text-dim);
}
.gallery-day-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.gallery-filters {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex-wrap: wrap;
  margin: 0.5rem 0 0.85rem;
}
.filter-chip {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-size: var(--t-xs);
  font-weight: 500;
  padding: 0.35rem 0.7rem;
  border-radius: 999px;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
.filter-chip:hover:not(:disabled) {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--border-hover);
}
.filter-chip.active {
  background: var(--primary);
  color: var(--primary-fg);
  border-color: var(--primary);
}
.filter-chip:disabled { opacity: 0.45; cursor: default; }
.filter-status {
  font-size: var(--t-xs);
  color: var(--text-faint);
  font-family: var(--font-mono);
  margin-left: 0.25rem;
}

/* AI badge — sparkle next to AI-driven actions. Tiny, never dominant. */
.ai-badge {
  display: inline-block;
  margin-left: 0.35rem;
  font-size: 0.85em;
  opacity: 0.7;
  vertical-align: baseline;
}
.btn:hover .ai-badge { opacity: 1; }


/* Smart-search presets + advanced disclosure */
.ss-preset-row {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex-wrap: wrap;
  margin: 0.25rem 0 0.6rem;
}
.ss-preset {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-dim);
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  font-size: var(--t-xs);
  font-weight: 500;
  cursor: pointer;
}
.ss-preset:hover { background: var(--surface-2); color: var(--text); border-color: var(--border-hover); }
.ss-preset.active { background: var(--primary); color: var(--primary-fg); border-color: var(--primary); }
.ss-range-summary {
  font-size: var(--t-xs);
  color: var(--text-faint);
  font-family: var(--font-mono);
  margin-left: 0.4rem;
}
/* Class picker — chip grid in the Smart Search modal. Renders at modal-open
   time from /api/inference/status; only visible when the inference service
   is reachable AND has loaded models. Re-uses .filter-chip for the chip
   itself; this is just the wrapper grid + active-state colour matching
   the ss-preset pattern. */
.ss-classes-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg);
  max-height: 160px;
  overflow-y: auto;
}
.ss-class-chip {
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-dim);
  padding: 0.25rem 0.55rem;
  border-radius: 3px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
}
.ss-class-chip:hover { color: var(--text); border-color: var(--border); }
.ss-class-chip.active {
  background: var(--primary);
  color: var(--primary-fg);
  border-color: var(--primary);
}
.ss-advanced {
  display: none;
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px dashed var(--border);
}
.ss-advanced.open { display: block; }

/* Smart-search progress bar — shown while the inference stream walks frames.
   Mono caps for the count register, clay fill, single-edge track. */
.ss-progress {
  padding: 0.65rem 0;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}
.ss-progress-label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.ss-progress-classes {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}
.ss-progress-chip {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--primary);
  background: var(--primary-soft);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 2px 7px;
}
.ss-progress-count {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.ss-progress-track {
  height: 6px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 3px;
  overflow: hidden;
}
.ss-progress-fill {
  height: 100%;
  background: var(--primary);
  width: 0%;
  transition: width 180ms ease;
}
.ss-progress-hint {
  font-family: var(--font-sans);
  font-size: var(--text-mono-md);
  color: var(--text-faint);
}
.ss-progress-cancel {
  /* Sits on the right of the progress label row. Mono+caps to match
     the mono-numerics convention of the count it pairs with. */
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 2px 8px;
  margin-left: auto;
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: border-color 120ms ease, color 120ms ease, background 120ms ease;
}
.ss-progress-cancel:hover {
  border-color: var(--danger);
  color: var(--danger);
}
.ss-progress-cancel:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  color: var(--text-faint);
  border-color: var(--border);
}

/* Results header — stats line on the left, Clear button on the right.
   Single dashed top rule so it reads like a section break above the grid. */
.ss-results-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding-top: 0.6rem;
  margin: 0.5rem 0 0.6rem;
  border-top: 1px dashed var(--border);
  flex-wrap: wrap;
}

/* Smart-search results grid (inside the modal) */
.ss-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 0.6rem;
  margin-top: 0.4rem;
}
.ss-card {
  background: var(--surface-2, var(--surface));
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  transition: border-color 120ms ease, transform 120ms ease;
}
.ss-card:hover { border-color: var(--primary); }
/* Hover-lift kill (Site Notes: single-edge rule; cards shift border-color
   not Y-position on hover). Was missed in the section-11 override layer's
   transform-kill list. */
.ss-card img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; }
.ss-card-meta { padding: 0.4rem 0.55rem; font-size: var(--t-xs); }
.ss-card-when { font-family: var(--font-mono); color: var(--text-dim); margin-bottom: 0.15rem; word-break: break-all; }
.ss-card-reason { color: var(--text); line-height: 1.35; }

/* ── Moments tab — sub-nav + saved actions + class filter ─────────────────
   Search and Saved sub-tabs inside the Moments tab. The sub-tab nav uses
   a smaller, lighter visual weight than the top-level station tab nav so
   the hierarchy reads correctly: station tabs (Gallery / Moments / …) →
   sub-tabs (Search / Saved). */
.moments-shell { display: flex; flex-direction: column; gap: 1rem; }
.sub-tab-nav {
  display: flex; gap: 0.05rem;
  border-bottom: 1px dashed var(--border);
  padding: 0;
}
.sub-tab-item {
  font-family: var(--font-sans); font-size: var(--t-xs);
  font-weight: 500; letter-spacing: 0.04em;
  color: var(--text-dim); background: transparent;
  border: 0; border-bottom: 2px solid transparent;
  padding: 0.55rem 0.85rem;
  cursor: pointer;
  margin-bottom: -1px;
  transition: color 120ms ease, border-color 120ms ease;
}
.sub-tab-item:hover { color: var(--text); }
.sub-tab-item.active { color: var(--primary); border-bottom-color: var(--primary); }
.sub-tab-count {
  font-family: var(--font-mono); font-size: var(--text-mono-xs);
  color: var(--text-faint); margin-left: 0.25rem; letter-spacing: 0.04em;
}

.ss-classes-header {
  display: flex; align-items: center; gap: 0.6rem;
  margin-bottom: 0.35rem;
  /* FND-B06: wrap so the filter input doesn't overflow at 768–~900px (was
     clipped 188px past viewport inside #st-content overflow:visible). */
  flex-wrap: wrap;
}
.ss-class-filter-input {
  font-size: var(--t-xs); padding: 0.3rem 0.55rem;
  /* FND-B06: shrink-fit instead of fixed 220px so the input survives any row width */
  flex: 1 1 180px; min-width: 0; width: auto;
}
@media (max-width: 600px) {
  .ss-classes-header { flex-direction: column; align-items: stretch; }
  .ss-class-filter-input { width: 100%; }
  .vision-vlm-status,
  .vision-vlm-form {
    flex-direction: column;
    align-items: stretch;
  }
}

.moments-actions {
  display: flex; align-items: center; gap: 0.5rem;
  margin-top: 1rem; padding-top: 0.85rem;
  border-top: 1px solid var(--border);
}
.moments-saved-actions {
  display: flex; gap: 0.35rem; margin-top: 0.45rem;
}
.moments-saved-actions .btn { flex: 0 0 auto; }
.moments-saved-card .ss-card-meta { padding-bottom: 0.55rem; }
.moments-empty {
  padding: 2rem 1.25rem;
  border: 1px dashed var(--border);
  border-radius: var(--r);
  background: var(--surface);
  text-align: left;
}
.vision-vlm-panel {
  display: grid;
  gap: 0.75rem;
  padding: 1rem;
  margin-bottom: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
}
.vision-vlm-head,
.vision-vlm-form,
.vision-vlm-hints {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.vision-vlm-head {
  justify-content: space-between;
}
.vision-vlm-head h2 {
  margin: 0;
  font-size: 1rem;
}
.vision-vlm-head p {
  margin: 0.15rem 0 0;
  color: var(--text-dim);
  font-size: var(--t-sm);
}
.vision-vlm-form input,
.vision-vlm-form select {
  min-width: 0;
  flex: 1 1 auto;
}
.vision-search-filters {
  flex-wrap: wrap;
}
.vision-search-filters .input {
  flex: 1 1 160px;
}
.vision-vlm-hints {
  flex-wrap: wrap;
}
.vision-vlm-hints button {
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  padding: 0.28rem 0.6rem;
  font-size: var(--t-xs);
  cursor: pointer;
}
.vision-vlm-hints button:hover {
  border-color: var(--primary);
  color: var(--primary);
}
.vision-vlm-badge,
.vision-vlm-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.vision-vlm-results {
  min-height: 28px;
}
.vision-vlm-answer {
  display: grid;
  gap: 0.25rem;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: var(--surface-2);
}
.vision-vlm-answer strong {
  font-size: var(--t-sm);
}
.vision-vlm-answer span,
.vision-vlm-answer em {
  color: var(--text-dim);
  font-size: var(--t-xs);
}
.vision-vlm-answer em {
  font-style: normal;
}
.vision-vlm-status {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  align-items: center;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: var(--surface-2);
}
.vision-vlm-status-main {
  display: grid;
  gap: 0.35rem;
  min-width: 0;
  flex: 1 1 auto;
}
.vision-vlm-status-main strong,
.vision-vlm-status-main span,
.vision-vlm-status-main em,
.vision-vlm-status-copy {
  display: block;
}
.vision-vlm-status-main strong {
  font-size: var(--t-sm);
}
.vision-vlm-status-main span,
.vision-vlm-status-main em,
.vision-vlm-status-copy {
  color: var(--text-dim);
  font-size: var(--t-xs);
}
.vision-vlm-status-main em {
  font-style: normal;
  font-family: var(--font-mono);
}
.vision-vlm-meter {
  height: 6px;
  width: min(360px, 100%);
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}
.vision-vlm-meter span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--primary);
}
.vision-vlm-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 8px;
  margin-top: 0.55rem;
}
.vision-vlm-card {
  display: grid;
  gap: 0;
  padding: 0;
  overflow: hidden;
  text-align: left;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
}
.vision-vlm-card:hover {
  border-color: var(--primary);
}
.vision-vlm-thumb {
  display: block;
  aspect-ratio: 1 / 1;
  background-size: cover;
  background-position: center;
}
.vision-vlm-card-body {
  display: grid;
  gap: 0.18rem;
  padding: 0.5rem;
  font-size: var(--t-xs);
}
.vision-vlm-error,
.vision-vlm-empty {
  padding: 0.75rem;
  border: 1px dashed var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  color: var(--text-dim);
  background: var(--surface-2);
}

/* ── Station-page: compact stats strip + detail-page chooser ──────────────
   The station-page stats strip is a flex row: 4 compact pills on the left,
   a dashed separator, then [Status] [Settings] action buttons. Detail
   pages (Status / Settings) replace the tab content entirely; the tab nav
   hides while a detail page is active. Sizes are calibrated against the
   Site Notes density rule — pills are ~1/3 shorter than the project-grid
   .stat-card, since on the station page the pills are secondary chrome. */
.stats-strip.stats-strip-compact {
  display: flex;
  align-items: stretch;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
  grid-template-columns: none;            /* override the projects-grid rules */
}
.stats-strip-pills {
  display: grid;
  grid-template-columns: repeat(4, minmax(120px, 1fr));
  gap: 0.5rem;
  flex: 1 1 auto;
  min-width: 0;
}
/* Stat pill v2 (2026-05-05 redesign): label + value sit on the same
 * row — label LEFT in mono-uppercase faint, value RIGHT in tabular-
 * nums weight 500. Pills are ~36px tall instead of the old ~64px;
 * the third "sub" line (timestamp / "uploaded" hint) is hidden by
 * default and surfaces in a native tooltip via `title=...` on the
 * pill so the data isn't lost. Disk bar stretches under the pair
 * since it's purely visual. */
.stats-strip.stats-strip-compact .stat-card {
  display: grid;
  grid-template-columns: auto 1fr;
  /* Lock row 1 to a single line-height so label+value baselines align
     across all pills regardless of whether .stat-card-sub is rendered
     below. Without this, grid auto-rows would resize row 1 when row 2
     appears, and adjacent pills baseline-mismatch (theory audit C2). */
  grid-template-rows: 1.5rem auto;
  align-items: baseline;
  gap: 0.55rem;
  padding: 0.55rem 0.75rem;
  min-height: 36px;
  box-shadow: none;
}
.stats-strip.stats-strip-compact .stat-card-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  white-space: nowrap;
}
.stats-strip.stats-strip-compact .stat-card-value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 1.05rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text);
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Sub line still rendered (the existing markup adds it as a sibling
 * of the value), but pulled into the same row visually as a small
 * faint suffix. Falls back to display:none on narrow widths so the
 * value doesn't fight for space. */
.stats-strip.stats-strip-compact .stat-card-sub {
  grid-column: 1 / -1;
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  color: var(--text-faint);
  letter-spacing: 0.04em;
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: -0.15rem;
}
@media (max-width: 880px) {
  .stats-strip.stats-strip-compact .stat-card-sub { display: none; }
}
.stats-strip.stats-strip-compact .disk-bar {
  grid-column: 1 / -1;
  height: 3px;
  margin-top: 0.2rem;
}
/* Vertical stack on the right of the stats strip. The two buttons share
   the strip's vertical rhythm — together they roughly equal one pill's
   height. Each button picks its own brand-palette tint:
     Status   → lichen (success-soft)   — informational read-only surface
     Settings → clay   (primary-soft)   — the place you change things
   They use the soft-tint background by default and fill solid when
   active, so the operator can see at a glance which detail they're in. */
/* Stats-strip actions v2: dropped the dashed left divider that made
 * Status/Settings read as a separate section. They're sibling
 * navigation to the pills now — same row, regular gap, smaller
 * button size so they don't compete with the pills for visual
 * weight. (2026-05-05.) */
.stats-strip-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: stretch;
  gap: 0.3rem;
  padding-left: 0;
  border-left: 0;
  flex: 0 0 auto;
  min-width: 110px;
}
.stats-action-btn {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.32rem 0.7rem;
  white-space: nowrap;
  flex: 1 1 0;
  min-height: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Status — lichen tint */
.stats-action-btn#st-detail-status {
  background: var(--success-soft);
  border-color: var(--success);
  color: var(--success);
}
.stats-action-btn#st-detail-status:hover {
  background: var(--success);
  color: #fff;
  border-color: var(--success);
}
.stats-action-btn#st-detail-status.active {
  background: var(--success);
  color: #fff;
  border-color: var(--success);
}

/* Settings — clay tint */
.stats-action-btn#st-detail-settings {
  background: var(--primary-soft);
  border-color: var(--primary);
  color: var(--primary);
}
.stats-action-btn#st-detail-settings:hover {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
.stats-action-btn#st-detail-settings.active {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}

@media (max-width: 900px) {
  .stats-strip.stats-strip-compact {
    flex-direction: column;
    gap: 0.6rem;
  }
  .stats-strip-pills { grid-template-columns: repeat(2, 1fr); }
  .stats-strip-actions {
    /* Below 900px the strip stacks vertically — Status/Settings revert to
       a horizontal pair so they don't become a tall narrow column. */
    flex-direction: row;
    border-left: 0;
    border-top: 1px dashed var(--border);
    padding-left: 0;
    padding-top: 0.6rem;
    justify-content: stretch;
    min-width: 0;
  }
  .stats-action-btn { flex: 1 1 0; }
}
@media (max-width: 520px) {
  .stats-strip-pills { grid-template-columns: 1fr 1fr; }
}

/* Detail-page shell — used by the Status and Settings surfaces when
   reached via the stats-strip buttons. Header has a back-link, a title,
   and a single right-aligned CTA (Run diagnostic / Rename station). */
.st-detail-page { display: flex; flex-direction: column; gap: 1rem; }
.st-detail-head {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding-bottom: 0.65rem;
  border-bottom: 1px solid var(--border);
}
/* Back-to-gallery button on the Status/Settings detail pages.
   Matches the .page-breadcrumb-back family so the two back-buttons read
   as one consistent control across the app. */
.btn.st-detail-back {
  display: inline-flex; align-items: center; gap: 0.4rem;
  height: 30px;
  padding: 0 0.75rem;
  box-sizing: border-box;
  font-family: var(--font-mono); font-size: var(--text-mono-sm);
  font-weight: 500; letter-spacing: 0.06em; line-height: 1;
  text-transform: uppercase;
  color: var(--text-dim);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}
.btn.st-detail-back:hover {
  color: var(--primary);
  border-color: var(--primary);
  background: var(--primary-soft);
}
.btn.st-detail-back svg { stroke-width: 2; width: 12px; height: 12px; flex: 0 0 auto; }
.st-detail-title {
  font-size: 1.1rem; font-weight: 500; color: var(--text);
  letter-spacing: -0.01em; margin: 0;
}
.st-detail-actions { margin-left: auto; display: flex; gap: 0.5rem; }
@media (max-width: 600px) {
  .st-detail-head { flex-wrap: wrap; }
  .st-detail-actions { width: 100%; justify-content: flex-end; }
}
.mobile-dates-toggle {
  display: none;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: var(--t-xs);
  font-weight: 500;
  padding: 0.4rem 0.75rem;
  border-radius: var(--r);
  cursor: pointer;
}
.mobile-dates-toggle:hover {
  background: var(--surface-2);
  border-color: var(--border-hover);
}

.image-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 0.85rem;
}

.image-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
  cursor: pointer;
  transition: border-color 120ms ease, box-shadow 120ms ease,
              transform 120ms ease;
}
.image-card:hover {
  /* F-20: border-color shift only (lift was already neutralized at ~7104). */
  border-color: var(--border-hover);
}
.image-card.selected {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px var(--primary);
}
.image-card img {
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
  display: block;
  background: var(--surface-2);
}
.image-card-info {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem;
  padding: 0.4rem 0.55rem;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--text-dim);
}
.image-card-size {
  color: var(--text-faint);
}
.image-card-delete {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  display: none;
  width: 26px;
  height: 26px;
  align-items: center;
  justify-content: center;
  background: rgba(0,0,0,0.55);
  color: #ffffff;
  border: 0;
  border-radius: var(--r-sm);
  cursor: pointer;
  font-size: var(--t-xs);
  line-height: 1;
  padding: 0;
  transition: background-color 120ms ease;
}
.image-card-delete:hover {
  background: var(--danger);
}
.image-card.has-actions:hover .image-card-delete {
  display: inline-flex;
}
.image-card-check {
  position: absolute;
  top: 0.4rem;
  left: 0.4rem;
  display: none;
  width: 22px;
  height: 22px;
  border: 2px solid #ffffff;
  border-radius: var(--r-sm);
  background: rgba(0,0,0,0.35);
  box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
.image-card.selected .image-card-check {
  background: var(--primary);
  border-color: var(--primary);
}
.image-card.selected .image-card-check::after {
  content: '\2713';
  display: block;
  text-align: center;
  color: #ffffff;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 18px;
}
body.select-mode .image-card-check    { display: block; }
body.select-mode .image-card-delete   { display: none !important; }

/* ── Gallery compare-pick mode ──
   Activated by the toolbar Compare button. Hides delete (avoid mis-click),
   crosshair cursor, and a numbered "1" badge on the first picked card so
   the user sees which image is locked in. */
body.compare-pick-mode .image-card { cursor: crosshair; }
body.compare-pick-mode .image-card-delete { display: none !important; }
.image-card.compare-a {
  outline: 3px solid var(--primary);
  outline-offset: -3px;
}
.image-card.compare-a::before {
  content: '1';
  position: absolute;
  top: 0.4rem;
  left: 0.4rem;
  z-index: 1;
  background: var(--primary);
  color: #ffffff;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: var(--t-xs);
  box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
/* When active, the toolbar Compare button reads "Cancel compare" — give it a
   distinct fill so the user feels they're in a mode. */
#cmp-pick-btn.active {
  background: var(--primary-soft);
  color: var(--primary);
  border-color: var(--primary);
}

/* Gallery responsive: sidebar becomes off-canvas, toggle button appears */
@media (max-width: 900px) {
  .gallery-layout {
    grid-template-columns: 1fr;
  }
  .gallery-dates {
    position: fixed;
    top: 0;
    left: -280px;
    bottom: 0;
    width: 280px;
    max-height: 100vh;
    z-index: 30;
    transition: left 200ms ease;
    border-radius: 0;
  }
  .gallery-dates.open {
    left: 0;
    box-shadow: var(--shadow-md);
  }
  .sidebar-close { display: inline-flex; align-items: center; justify-content: center; }
  .mobile-dates-toggle { display: inline-flex; align-items: center; gap: 0.35rem; }
}

/* ── 26. LIGHTBOX ────────────────────────────────────────────────────────── */

.lightbox {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(10,10,10,0.96);
  /* z-index 1200 sits above modals (1100) and Leaflet controls (~1000),
     so opening an image takes over the screen even if a map or modal
     was on top. (Audit 2026-04-30 z-index ladder pass.) */
  z-index: 1200;
  align-items: center;
  justify-content: center;
  cursor: zoom-out;
}
.lightbox.open { display: flex; }

.lightbox-stage {
  position: relative;
  width: 92vw;
  height: 88vh;
  overflow: hidden;
  touch-action: none;
  cursor: zoom-in;
}
.lightbox-stage.zoomed { cursor: grab; }
.lightbox-stage.panning { cursor: grabbing; }
.lightbox-stage img {
  position: absolute;
  top: 0;
  left: 0;
  /* The global `img { max-width: 100%; }` reset would otherwise clamp the
     img's box to the stage width BEFORE our transform scales it down to
     fit. That double-shrink rendered captures at roughly 1/3 the stage
     size and made the annotation canvas (which does NOT inherit the
     img reset) misaligned. Force natural dims so transform-scale is the
     only thing that resizes the image. */
  max-width: none;
  max-height: none;
  width: auto;
  height: auto;
  transform-origin: 0 0;
  user-select: none;
  -webkit-user-drag: none;
  cursor: inherit;
  will-change: transform;
}
.lightbox-stage img.lb-anim { transition: transform 140ms ease; }
.lb-canvas {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  pointer-events: none;
}
.lb-canvas.editing {
  pointer-events: auto;
  cursor: crosshair;
}

/* ── Detections overlay (debug "what is the model seeing") ──────────────
   Sits between the image and the markup canvas in the lightbox stage.
   Its width/height are set to image naturalWidth/Height in JS, and the
   container mirrors the same CSS transform as the img — so boxes
   positioned by percentage inside stay aligned through pan + zoom. */
.lb-detections {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  pointer-events: none;
  z-index: 2;       /* above img, below markup canvas */
}
/* Vision AI bottom dock — sibling of .lb-detections so it does NOT
   inherit the image's CSS transform. Pinned to the bottom of the
   lightbox stage in normal coordinates: always full-size, always
   readable + clickable regardless of how the image is zoomed. */
.lb-det-dock {
  position: absolute;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  background: rgba(255,255,255,0.96);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: 0 4px 14px rgba(0,0,0,0.22);
  pointer-events: auto;
  max-width: calc(100% - 32px);
  flex-wrap: wrap;
}
.lb-det-dock-btn {
  font-family: var(--font-sans);
  font-size: var(--text-mono-md);
  font-weight: 500;
  padding: 6px 12px;
  border: 1px solid var(--primary);
  background: var(--primary);
  color: #fff;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background 100ms ease, border-color 100ms ease;
}
.lb-det-dock-btn:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
.lb-det-dock-btn.active {
  background: var(--warn);
  border-color: var(--warn);
  color: #fff;
}
.lb-det-dock-stats {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.lb-det-dock-stats .lb-det-stat-bad { color: var(--danger); }
.lb-det-dock-stats .lb-det-stat-rel { color: var(--warn); }
.lb-det-dock-stats .lb-det-stat-add { color: var(--success); }
.lb-det-dock-toast {
  /* Inline with the dock children. Hidden until populated. */
  font-family: var(--font-sans);
  font-size: var(--text-mono-md);
  color: var(--text);
  background: var(--surface-2);
  border-radius: var(--r-sm);
  padding: 4px 8px;
  display: none;
  align-items: center;
  gap: 6px;
}
.lb-det-dock-toast.open { display: flex; }
.lb-det-dock-toast a {
  color: var(--primary);
  text-decoration: none;
  font-weight: 500;
}
.lb-det-dock-toast a:hover { text-decoration: underline; }
.lb-det-err { color: var(--danger); border-color: var(--danger); }
.lb-det-box {
  position: absolute;
  border: 2px solid var(--detbox, #888);
  background: transparent;
  pointer-events: none;
  box-shadow: 0 0 0 1px rgba(0,0,0,0.3);
}
.lb-det-label {
  position: absolute;
  top: 0; left: 0;
  transform: translateY(-100%);    /* sit above the box */
  font-family: var(--font-mono);
  font-size: 13px;                 /* bumped 2026-05-04 (client feedback) */
  font-weight: 500;
  letter-spacing: 0.02em;
  color: #fff;
  background: var(--detbox, #888);
  padding: 2px 7px;
  white-space: nowrap;
  pointer-events: none;
}
/* Detection-box colours map to the Site Notes risk palette so the
   lightbox overlays stay coherent with the rest of the platform UI.
   Person + Other use a desaturated graphite so they don't compete
   with the warn/success/danger semantic tints — the old #2c7be5
   "SaaS blue" was the only non-palette hue in the system. */
.lb-det-person        { --detbox: var(--text-dim); }
.lb-det-vehicle       { --detbox: var(--warn); }
.lb-det-equipment     { --detbox: var(--warn); }
.lb-det-ppe-compliance{ --detbox: var(--success); }
.lb-det-ppe-violation { --detbox: var(--danger); }
.lb-det-other         { --detbox: var(--text-faint); }

/* Box becomes interactive when feedback is enabled. Hover widens the
   stroke + shows a "click me" cursor; the inner area stays click-through
   so you can still drag the image underneath if you click outside the
   stroke (we set pointer-events on the BORDER region only via padding). */
.lb-det-box {
  cursor: pointer;
  pointer-events: auto;
  transition: box-shadow 100ms ease;
}
.lb-det-box:hover {
  box-shadow: 0 0 0 2px var(--detbox, #888), 0 0 0 4px rgba(0,0,0,0.4);
  z-index: 1;
}
/* Visual states for boxes that already have a verdict */
.lb-det-box.lb-det-fb-confirm { border-style: solid; opacity: 0.55; }
.lb-det-box.lb-det-fb-reject  { border-style: dashed; opacity: 0.4; }
.lb-det-box.lb-det-fb-relabel { border-style: dotted; opacity: 0.55; }
.lb-det-verdict-badge {
  position: absolute;
  top: -10px;
  right: -10px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--detbox, #888);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 3px rgba(0,0,0,0.4);
  pointer-events: none;
}
.lb-det-tally {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin-left: 4px;
}

/* ── Verdict popup (shows on box click) ──────────────────────────────── */
.lb-det-popup {
  position: absolute;
  z-index: 10;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: 0 6px 18px rgba(0,0,0,0.18);
  padding: 0.65rem 0.7rem 0.7rem;
  width: 280px;
  font-family: var(--font-sans);
  font-size: var(--text-mono-md);
  pointer-events: auto;
}
.lb-det-popup-head {
  font-weight: 500;
  font-size: 13px;
  margin-bottom: 0.4rem;
  padding-right: 1.2rem;    /* room for the close × */
}
.lb-det-popup-current {
  font-size: var(--text-mono-sm);
  color: var(--text-dim);
  background: var(--surface-2);
  border-radius: var(--r-sm);
  padding: 4px 6px;
  margin-bottom: 0.5rem;
}
.lb-det-popup-current a {
  color: var(--primary);
  text-decoration: none;
}
.lb-det-popup-current a:hover { text-decoration: underline; }
.lb-det-popup-actions {
  display: grid;
  gap: 0.3rem;
}
.lb-det-act {
  font-family: var(--font-sans);
  font-size: var(--text-mono-md);
  padding: 5px 8px;
  text-align: left;
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: border-color 100ms ease, background 100ms ease;
}
.lb-det-act:hover { background: var(--surface-2); }
.lb-det-act-confirm:hover { border-color: var(--success); background: var(--success-soft); }
.lb-det-act-reject:hover  { border-color: var(--danger);  background: var(--danger-soft); }
.lb-det-act-relabel:hover { border-color: var(--warn);    background: var(--warn-soft); }
.lb-det-popup-close {
  position: absolute;
  top: 4px; right: 6px;
  background: transparent;
  border: none;
  font-size: 18px;
  line-height: 1;
  color: var(--text-faint);
  cursor: pointer;
  padding: 0 4px;
}
.lb-det-popup-close:hover { color: var(--text); }

/* Relabel sub-panel — opens under the action buttons */
.lb-det-popup-relabel {
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px dashed var(--border);
}
.lb-det-popup-relabel input[type="text"] {
  width: 100%;
  font-family: var(--font-sans);
  font-size: var(--text-mono-md);
  padding: 4px 6px;
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: var(--r-sm);
  margin-bottom: 0.3rem;
}
.lb-det-relabel-list {
  max-height: 160px;
  overflow-y: auto;
  display: grid;
  gap: 1px;
}
.lb-det-relabel-opt {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  text-align: left;
  padding: 4px 6px;
  border: none;
  background: var(--surface);
  cursor: pointer;
  border-radius: var(--r-sm);
}
.lb-det-relabel-opt:hover { background: var(--primary-soft); color: var(--primary); }
.lb-det-relabel-loading,
.lb-det-relabel-empty {
  font-size: var(--text-mono-sm);
  color: var(--text-faint);
  padding: 4px 6px;
}

/* Active-state for the Boxes sidebar toggle */
.lb-side-btn.active {
  border-color: var(--primary);
  color: var(--primary);
  background: var(--primary-soft);
}

/* "+ add missing" button in the status bar */
.lb-det-draw-btn {
  margin-left: 8px;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-dim);
  border-radius: var(--r-sm);
  cursor: pointer;
  pointer-events: auto;
  transition: border-color 100ms ease, color 100ms ease, background 100ms ease;
}
.lb-det-draw-btn:hover {
  border-color: var(--primary);
  color: var(--primary);
}
.lb-det-draw-btn.active {
  border-color: var(--warn);
  color: #fff;
  background: var(--warn);
}

/* Draw mode: layer captures pointer events + crosshair cursor */
.lb-detections.lb-det-drawing {
  pointer-events: auto;
  cursor: crosshair;
}
.lb-detections.lb-det-drawing .lb-det-box {
  /* boxes are visible but not clickable while drawing — we want
     the drag-to-create gesture to land on the layer, not on a box */
  pointer-events: none;
}

/* In-progress draw preview rectangle */
.lb-det-draw-preview {
  position: absolute;
  border: 2px dashed var(--warn);
  background: rgba(212, 148, 63, 0.12);
  pointer-events: none;
  z-index: 5;
}

/* User-added "missing" boxes — distinct dashed style + USER tag so
   they're obviously different from model output boxes */
.lb-det-box.lb-det-missing {
  border-style: dashed;
  border-width: 2px;
}
.lb-det-user-tag {
  display: inline-block;
  margin-left: 4px;
  padding: 0 4px;
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  background: rgba(255,255,255,0.85);
  color: var(--text);
  border-radius: var(--r-xs); /* FND-C05: was 2px off-scale → --r-xs (3px) */
}

/* ── 26c. ANNOTATION EDITOR ─────────────────────────────────────────────── */

/* Persistent left sidebar (Compare / Mark up / Analyze) — replaces the old
   ⋯ overflow menu. Pinned to top-left of the lightbox so every lightbox
   action is one click away. Industrial styling matches the markup toolbar. */
.lb-sidebar {
  position: fixed;
  top: 1.5rem;
  left: 1.5rem;
  z-index: 102;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(15, 17, 22, 0.94);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 8px 28px rgba(0,0,0,0.45);
  font-family: var(--font-mono);
}
.lb-side-btn {
  width: 64px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 8px 4px;
  background: transparent;
  /* Border bumped from rgba(255,255,255,0.08) (1.6:1 against the
     lightbox black bg, fails WCAG 1.4.11 ≥3:1 non-text contrast) to
     0.22 (clears 3:1). Weight dropped from 700 to 500 to match the
     mono-uppercase 500 register used by .badge / .live-pill etc. */
  border: 1px solid rgba(255,255,255,0.22);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  color: rgba(255,255,255,0.78);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-mono-sm);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  transition: background-color 80ms, border-color 80ms, color 80ms;
  position: relative;
}
.lb-side-btn:hover {
  background: rgba(255,255,255,0.06);
  border-color: rgba(255,255,255,0.22);
  color: #fff;
}
.lb-side-btn:active { transform: translateY(1px); }
.lb-side-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background: rgba(255,255,255,0.05);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  border: 1px solid rgba(255,255,255,0.06);
}
.lb-side-icon svg { width: 16px; height: 16px; }
.lb-side-label { font-size: var(--text-mono-sm); line-height: 1; }
.lb-side-ai .lb-side-icon {
  background: linear-gradient(135deg, var(--primary), var(--warn));
  border-color: rgba(255,255,255,0.18);
}
.lb-side-ai .ai-badge { opacity: 1; margin-left: 2px; font-size: var(--text-mono-xs); }

@media (max-width: 500px) {
  .lb-sidebar { top: 0.75rem; left: 0.75rem; gap: 2px; padding: 4px; }
  /* Lock min-height to 44px on the narrow-viewport variant to clear
     WCAG 2.5.5 touch-target minimum. The inner icon stays at 22px
     for visual breathing room. */
  .lb-side-btn { width: 52px; min-height: 44px; padding: 6px 3px; font-size: var(--text-mono-xs); }
  .lb-side-icon { width: 22px; height: 22px; }
  .lb-side-icon svg { width: 14px; height: 14px; }
}

.lightbox.editing-annotation .lightbox-prev,
.lightbox.editing-annotation .lightbox-next,
.lightbox.editing-annotation .lb-sidebar,
.lightbox.editing-annotation .lightbox-close,
.lightbox.editing-annotation .lightbox-info { display: none; }

/* AI Analyze panel (Track B) — floats inside the lightbox over the
   bottom-right corner of the stage; doesn't fight pan/zoom. */
.lightbox-analyze-panel {
  display: none;
  position: fixed;
  right: 1.25rem;
  bottom: 4.25rem;
  z-index: 104;
  width: min(360px, calc(100vw - 2rem));
  color: #fff;
}
.ana-card {
  background: rgba(0,0,0,0.78);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 12px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  padding: 0.85rem;
  box-shadow: 0 8px 24px rgba(0,0,0,0.45);
}
.ana-loading, .ana-error {
  background: rgba(0,0,0,0.78);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 12px;
  padding: 0.75rem 1rem;
  font-size: var(--t-sm);
  color: #fff;
}
.ana-error { border-color: var(--danger); color: #ffd6d6; }
.ana-header {
  display: flex; align-items: center; gap: 0.5rem;
  font-size: var(--t-sm); margin-bottom: 0.6rem;
}
.ana-cached {
  font-size: var(--text-mono-sm);
  font-family: var(--font-mono);
  background: rgba(255,255,255,0.12);
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  color: rgba(255,255,255,0.7);
}
.ana-close {
  margin-left: auto;
  background: none; border: 0; color: rgba(255,255,255,0.7);
  cursor: pointer; font-size: 1.3rem; line-height: 1; padding: 0;
}
.ana-stats {
  display: flex; gap: 0.5rem; margin-bottom: 0.6rem;
}
.ana-stat {
  flex: 1;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 8px;
  padding: 0.5rem 0.6rem;
  text-align: center;
  display: flex; flex-direction: column; gap: 0.15rem;
}
.ana-num { font-size: 1.4rem; font-weight: 700; line-height: 1; }
.ana-num.ana-good { color: var(--success); }
.ana-num.ana-warn { color: var(--warn); }
.ana-num.ana-bad  { color: var(--danger); }
.ana-num.ana-dim  { color: rgba(255,255,255,0.55); font-size: var(--t-sm); }
.ana-label {
  font-size: var(--text-mono-sm);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: rgba(255,255,255,0.55);
}
.ana-summary {
  font-size: var(--t-sm);
  line-height: 1.45;
  margin-bottom: 0.6rem;
}
.ana-concerns {
  background: rgba(178,90,77,0.18);   /* translucent --danger; sits on dark .ana-card */
  border-left: 3px solid var(--danger);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  padding: 0.4rem 0.6rem;
  margin-bottom: 0.6rem;
  font-size: var(--t-xs);
}
.ana-concerns strong { display: block; margin-bottom: 0.25rem; }
.ana-concerns ul { margin: 0; padding-left: 1.1rem; }
.ana-actions { display: flex; justify-content: flex-end; }

@media (max-width: 600px) {
  .lightbox-analyze-panel { right: 0.5rem; left: 0.5rem; bottom: 3.5rem; width: auto; }
}

/* Industrial / control-panel toolbar — sharp corners, mono labels, sectioned. */
.ann-toolbar {
  position: fixed;
  top: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 105;
  display: none;
  flex-direction: column;
  background: rgba(15, 17, 22, 0.94);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  max-width: calc(100vw - 2rem);
  font-family: var(--font-mono);
  box-shadow: 0 8px 28px rgba(0,0,0,0.45);
  overflow: hidden;
}
.ann-toolbar.open { display: inline-flex; }

.ann-status-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.4rem 0.75rem;
  font-size: var(--text-mono-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(255,255,255,0.55);
  border-bottom: 1px solid rgba(255,255,255,0.08);
  white-space: nowrap;
  gap: 0.6rem;
  min-width: 0;
}
.ann-status-bar > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.ann-status-bar .ann-status-title {
  color: rgba(255,255,255,0.92);
  font-weight: 700;
  letter-spacing: 0.12em;
}
.ann-status-bar .ann-status-sep { color: rgba(255,255,255,0.3); }
.ann-status-bar .ann-status-dirty {
  display: none;
  color: var(--warn);
  font-weight: 700;
}
.ann-toolbar.dirty .ann-status-bar .ann-status-dirty { display: inline; }

.ann-tools-row {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
}
.ann-tool-group {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.45rem 0.7rem;
  border-right: 1px solid rgba(255,255,255,0.08);
}
.ann-tool-group:last-child { border-right: 0; }
.ann-tool-group-label {
  font-size: var(--text-mono-sm);
  color: rgba(255,255,255,0.4);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-right: 0.15rem;
  font-weight: 600;
}

.ann-tool-btn {
  background: transparent;
  border: 1px solid rgba(255,255,255,0.3);
  color: rgba(255,255,255,0.78);
  padding: 0.35rem 0.65rem;
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  cursor: pointer;
  font-size: var(--text-mono-sm);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-family: inherit;
  white-space: nowrap;
  transition: background-color 80ms, border-color 80ms, color 80ms;
}
.ann-tool-btn:hover:not(:disabled) {
  background: rgba(255,255,255,0.06);
  border-color: rgba(255,255,255,0.22);
  color: #fff;
}
.ann-tool-btn.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
/* Internal-mark toggle: clay when active so "Internal" reads as restricted,
   distinct from the citron/primary active state of the drawing tools. */
.ann-vis-toggle.active {
  background: #c46a45;
  border-color: #c46a45;
  color: #fff;
}
.ann-vis-toggle:disabled { opacity: 0.45; cursor: default; }
.lightbox-ann-status .ann-internal-state { color: #f0b89c; }
/* Write-first note composer: type a comment, then click the image to place it. */
.ann-note-input {
  min-width: 240px;
  padding: 5px 9px;
  font: inherit;
  font-size: 13px;
  color: #fff;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 6px;
}
.ann-note-input::placeholder { color: rgba(255, 255, 255, 0.5); }
.ann-note-input:focus { outline: none; border-color: var(--annotation-hivis, #d4943f); }

.ann-swatches { display: inline-flex; gap: 4px; align-items: center; }
.ann-swatch {
  width: 18px;
  height: 18px;
  border-radius: 3px;
  cursor: pointer;
  border: 1.5px solid rgba(0,0,0,0.55);
  box-shadow: 0 0 0 1px rgba(255,255,255,0.06);
  padding: 0;
}
.ann-swatch.active {
  outline: 2px solid #fff;
  outline-offset: 1px;
}

.ann-sizes { display: inline-flex; gap: 0.25rem; align-items: center; }
.ann-size {
  min-width: 28px;
  height: 26px;
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  background: transparent;
  border: 1px solid rgba(255,255,255,0.12);
  color: rgba(255,255,255,0.7);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-mono-sm);
  font-weight: 700;
  font-family: inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0 0.35rem;
}
.ann-size:hover {
  background: rgba(255,255,255,0.08);
  border-color: rgba(255,255,255,0.24);
  color: #fff;
}
.ann-size.active {
  background: rgba(255,255,255,0.16);
  border-color: rgba(255,255,255,0.32);
  color: #fff;
}

.ann-actions-group {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.45rem 0.7rem;
  margin-left: auto;
  border-left: 1px solid rgba(255,255,255,0.14);
}

.ann-save-btn {
  background: var(--primary) !important;
  border-color: var(--primary) !important;
  color: #fff !important;
  padding: 0.4rem 1rem !important;
  letter-spacing: 0.1em;
}
.ann-save-btn:hover {
  background: var(--primary-hover) !important;
  border-color: var(--primary-hover) !important;
}
/* Dirty-state ring is clay (--primary, rgb(196,106,69)), not the original
   indigo (#6366f1) that survived the Section-11 palette swap. Audit M5
   (2026-04-30). Subdued glow — the saturated indigo halo was the loudest
   element on the page; this matches the rest of the system's dirty-state
   convention. */
.ann-toolbar.dirty .ann-save-btn {
  box-shadow: 0 0 0 2px rgba(196,106,69,0.45), 0 0 14px rgba(196,106,69,0.22);
}

.ann-cancel-btn { color: rgba(255,255,255,0.5) !important; }
.ann-cancel-btn:hover { color: #fff !important; }

.ann-share-btn { opacity: 0.6; }
.ann-share-btn:hover { opacity: 1; }

@media (max-width: 700px) {
  .ann-toolbar { top: 0.75rem; max-width: calc(100vw - 1rem); }
  .ann-tool-group { padding: 0.35rem 0.5rem; }
  .ann-tool-group-label { display: none; }
  .ann-tool-btn { padding: 0.3rem 0.55rem; font-size: var(--text-mono-sm); }
  .ann-status-bar { padding: 0.35rem 0.6rem; font-size: var(--text-mono-sm); }
}

/* ── 26d2. MARKUPS TAB (saved annotated images per station) ─────────────── */

.markups-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 0.85rem;
}
.markup-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-sm);
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.markup-card:hover {
  border-color: var(--border-hover);
  box-shadow: var(--shadow);
}
.markup-thumb {
  position: relative;
  aspect-ratio: 4/3;
  background: var(--surface-2);
  cursor: pointer;
  overflow: hidden;
}
.markup-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.markup-marks {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  background: rgba(15,17,22,0.85);
  color: #fff;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.2rem 0.5rem;
  border-radius: 3px;
  border: 1px solid rgba(255,255,255,0.15);
}
.markup-meta {
  padding: 0.6rem 0.75rem 0.4rem;
  flex: 1 1 auto;
  min-width: 0;
}
.markup-when {
  font-size: var(--t-xs);
  color: var(--text-dim);
  margin-bottom: 0.2rem;
  word-break: break-all;
  line-height: 1.35;
}
.markup-by {
  line-height: 1.35;
}
.markup-actions {
  display: flex;
  gap: 0.4rem;
  padding: 0.4rem 0.75rem 0.75rem;
}
.markup-actions .btn { flex: 1; justify-content: center; }

/* ── 26d. PROGRESS-PHOTO SCHEDULE ROWS ──────────────────────────────────── */

.progress-photo-row {
  display: flex;
  gap: 1rem;
  align-items: center;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface-2, var(--surface));
  margin-bottom: 0.6rem;
}
.progress-photo-row.disabled { opacity: 0.6; }
.progress-photo-row .pp-row-main { flex: 1 1 auto; min-width: 0; }
.progress-photo-row .pp-row-title { font-size: var(--t-sm); margin-bottom: 0.15rem; }
.progress-photo-row .pp-row-meta { line-height: 1.45; word-break: break-word; }
.progress-photo-row .pp-row-actions {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex-wrap: wrap;
  flex-shrink: 0;
}
@media (max-width: 600px) {
  .progress-photo-row { flex-direction: column; align-items: stretch; }
  .progress-photo-row .pp-row-actions { justify-content: flex-start; }
}

.lightbox-close,
.lightbox-prev,
.lightbox-next {
  position: fixed;
  width: 48px;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(0,0,0,0.55);
  color: #ffffff;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 50%;
  cursor: pointer;
  font-size: 1.4rem;
  line-height: 1;
  padding: 0;
  z-index: 102;
  transition: background-color 120ms ease, transform 120ms ease,
              border-color 120ms ease;
  user-select: none;
}
.lightbox-close:hover,
.lightbox-prev:hover,
.lightbox-next:hover {
  background: var(--primary);
  border-color: var(--primary);
  transform: scale(1.05);
}
.lightbox-close { top: 1.5rem; right: 1.5rem; font-size: 1.2rem; }
.lightbox-prev  { left: 1.5rem;  top: 50%; transform: translateY(-50%); }
.lightbox-next  { right: 1.5rem; top: 50%; transform: translateY(-50%); }
.lightbox-prev:hover { transform: translateY(-50%) scale(1.05); }
.lightbox-next:hover { transform: translateY(-50%) scale(1.05); }

.lightbox-ann-status {
  display: none;
  position: fixed;
  bottom: 4rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 101;
  font-size: var(--t-xs);
  color: rgba(255,255,255,0.85);
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  padding: 0.45rem 0.85rem;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.1);
  max-width: calc(100vw - 2rem);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lightbox-ann-status .ann-share-state { color: #ffd; }
.lightbox-ann-status a {
  color: var(--primary);
  text-decoration: underline;
  margin-left: 0.25rem;
}
.lightbox-ann-status a:hover { filter: brightness(1.15); }

.lightbox-info {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 101;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: #ffffff;
  background: rgba(0,0,0,0.5);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  padding: 0.55rem 1rem;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.08);
  max-width: calc(100vw - 2rem);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (max-width: 500px) {
  .lightbox-close { top: 0.75rem; right: 0.75rem; }
  .lightbox-prev  { left: 0.5rem; }
  .lightbox-next  { right: 0.5rem; }
}

/* ── 26b. COMPARE OVERLAY ────────────────────────────────────────────────── */

.compare-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(10,10,10,0.97);
  z-index: 110;
  align-items: center;
  justify-content: center;
}
.compare-overlay.open { display: flex; }

.compare-stage {
  position: relative;
  width: 92vw;
  height: 84vh;
  overflow: hidden;
  user-select: none;
  touch-action: none;
}
.cmp-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
}
.cmp-img-b { z-index: 1; }
.cmp-img-a {
  z-index: 2;
  /* clip from the right edge so left side shows image A */
  clip-path: inset(0 calc(100% - var(--cmp-pos, 50%)) 0 0);
}
.cmp-divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--cmp-pos, 50%);
  width: 2px;
  background: rgba(255,255,255,0.85);
  transform: translateX(-1px);
  z-index: 3;
  pointer-events: none;
}
.cmp-handle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  background: rgba(0,0,0,0.65);
  border: 1px solid rgba(255,255,255,0.4);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  cursor: ew-resize;
  pointer-events: auto;
  transition: transform 120ms ease, background-color 120ms ease;
}
.cmp-handle:hover { background: var(--primary); transform: scale(1.05); }
.cmp-handle svg { width: 22px; height: 22px; }

.cmp-close {
  position: fixed;
  top: 1.5rem;
  right: 1.5rem;
  width: 48px;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(0,0,0,0.55);
  color: #ffffff;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 50%;
  cursor: pointer;
  z-index: 112;
  transition: background-color 120ms ease, transform 120ms ease, border-color 120ms ease;
}
.cmp-close:hover { background: var(--primary); border-color: var(--primary); transform: scale(1.05); }
.cmp-close svg { width: 22px; height: 22px; }

.cmp-info {
  position: fixed;
  top: 1.5rem;
  z-index: 111;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: #ffffff;
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  padding: 0.5rem 0.85rem;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.1);
  max-width: 38vw;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cmp-info-a { left: calc(1.5rem + 56px); }
.cmp-info-b { right: calc(1.5rem + 56px); }
/* No A/B prefix — timestamps speak for themselves; left/right is implicit. */
.cmp-info-a::before { content: ''; }
.cmp-info-b::before { content: ''; }

.cmp-actions {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 111;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  background: rgba(0,0,0,0.55);
  padding: 0.5rem;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.1);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  max-width: calc(100vw - 2rem);
}
.cmp-actions .btn { white-space: nowrap; }
.cmp-mode-toggle {
  display: inline-flex;
  background: rgba(255,255,255,0.08);
  border-radius: 999px;
  padding: 2px;
  margin-left: 0.25rem;
}
.cmp-mode-btn {
  background: transparent;
  border: 0;
  color: rgba(255,255,255,0.7);
  padding: 0.3rem 0.75rem;
  font-size: var(--t-xs);
  font-weight: 600;
  border-radius: 999px;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}
.cmp-mode-btn.active {
  background: var(--primary);
  color: #ffffff;
}
.cmp-mode-btn:not(.active):hover { color: #ffffff; }

/* Diff mode: show only the change-detection canvas. */
.cmp-img-diff { display: none; z-index: 2; background: transparent; }
.compare-overlay.mode-diff .cmp-img-a,
.compare-overlay.mode-diff .cmp-img-b,
.compare-overlay.mode-diff .cmp-divider { display: none; }
.compare-overlay.mode-diff .cmp-img-diff { display: block; }
.cmp-diff-status {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 4;
  display: none;
  padding: 0.4rem 0.85rem;
  background: rgba(0,0,0,0.65);
  color: #fff;
  border-radius: 999px;
  font-size: var(--t-xs);
  font-family: var(--font-mono);
  border: 1px solid rgba(255,255,255,0.1);
  backdrop-filter: blur(8px);
}
.cmp-diff-status.show { display: block; }

@media (max-width: 700px) {
  .cmp-info { max-width: calc(50vw - 4rem); font-size: var(--text-mono-sm); padding: 0.35rem 0.6rem; }
  .cmp-info-a { left: calc(0.75rem + 52px); top: 0.75rem; }
  .cmp-info-b { right: calc(0.75rem + 52px); top: 0.75rem; }
  .cmp-close { top: 0.75rem; right: 0.75rem; }
  .compare-stage { width: 100vw; height: 78vh; }
}

/* Compare picker (date strip + thumbnail grid) */
.cmp-picker-bg {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(10,10,10,0.85);
  z-index: 120;
  align-items: center;
  justify-content: center;
}
.cmp-picker-bg.open { display: flex; }
.cmp-picker {
  background: var(--surface);
  color: var(--text);
  border-radius: var(--r);
  border: 1px solid var(--border);
  width: min(720px, 92vw);
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.cmp-picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
}
.cmp-picker-close {
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--text-dim);
  padding: 0.25rem;
  line-height: 0;
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
}
.cmp-picker-close:hover { background: var(--surface-hover); color: var(--text); }
.cmp-picker-close svg { width: 18px; height: 18px; }
.cmp-picker-dates {
  display: flex;
  gap: 0.4rem;
  padding: 0.6rem 1rem;
  overflow-x: auto;
  border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
}
.cmp-date-pill {
  flex: 0 0 auto;
  padding: 0.35rem 0.7rem;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: var(--t-xs);
  font-family: var(--font-mono);
  cursor: pointer;
  white-space: nowrap;
  color: var(--text-dim);
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
.cmp-date-pill:hover { background: var(--surface-hover); color: var(--text); }
.cmp-date-pill.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #ffffff;
}
.cmp-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 0.4rem;
  padding: 0.75rem 1rem 1rem;
  overflow-y: auto;
}
.cmp-picker-grid .empty {
  grid-column: 1 / -1;
  padding: 1.5rem;
  text-align: center;
  color: var(--text-dim);
  font-size: var(--t-sm);
}
.cmp-thumb {
  position: relative;
  aspect-ratio: 4/3;
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  border: 2px solid transparent;
  background: var(--surface-2);
}
.cmp-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cmp-thumb:hover { border-color: var(--primary); }
.cmp-thumb-time {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(transparent, rgba(0,0,0,0.7));
  color: #ffffff;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  padding: 0.6rem 0.4rem 0.3rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── 27. STATUS TAB (station detail) ────────────────────────────────────── */

.status-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1rem;
}
.status-metrics {
  display: flex;
  flex-direction: column;
}
.status-metric {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0;
  font-size: var(--t-sm);
  border-bottom: 1px solid var(--border);
}
.status-metric:last-child { border-bottom: 0; }
.status-metric-label {
  color: var(--text-dim);
}
.status-metric-value {
  color: var(--text);
  font-weight: 500;
  font-family: var(--font-mono);
  font-size: calc(var(--t-sm) - 0.5px);
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.status-metric-value.success { color: var(--success); }
.status-metric-value.danger  { color: var(--danger);  }
.status-metric-value.warn    { color: var(--warn);    }

/* Command button row inside status cards */
.cmd-btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.5rem;
}

/* Command-history rows (inside a status card) */
.cmd-history-list {
  max-height: 240px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}
.cmd-history-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  border-bottom: 1px solid var(--border);
}
.cmd-history-row:last-child { border-bottom: 0; }
.cmd-history-row .cmd-type {
  color: var(--text);
  font-weight: 500;
}
.cmd-history-row .cmd-status {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--text-dim);
}
.cmd-history-row .cmd-status.completed { color: var(--success); }
.cmd-history-row .cmd-status.failed    { color: var(--danger);  }
.cmd-history-row .cmd-status.delivered { color: var(--warn);    }
.cmd-history-row .cmd-cancel {
  color: var(--danger);
  text-decoration: none;
  margin-left: 0.35rem;
  font-weight: 500;
}
.cmd-history-row .cmd-cancel:hover { text-decoration: underline; }

/* Station token display inside status */
.station-token {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--text-dim);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 0.55rem 0.7rem;
  word-break: break-all;
  user-select: all;
}

/* ── 28. DIAGNOSTIC REPORT MODAL ─────────────────────────────────────────── */

.diag-summary {
  display: flex;
  gap: 1.25rem;
  padding: 0.9rem 1rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
  margin-bottom: 1rem;
}
.diag-summary-item {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.diag-summary-n {
  font-size: var(--t-2xl);
  font-weight: 700;
  color: var(--text);
  line-height: 1.1;
  font-family: var(--font-mono);
}
.diag-summary-n.success { color: var(--success); }
.diag-summary-n.warn    { color: var(--warn);    }
.diag-summary-n.danger  { color: var(--danger);  }
.diag-summary-l {
  font-size: var(--t-xs);
  color: var(--text-dim);
  font-weight: 500;
}
.diag-meta {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--text-faint);
  margin-bottom: 1rem;
}
.diag-section { margin-bottom: 1rem; }
.diag-section h4 {
  font-size: var(--t-xs);
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.5rem;
}
.diag-check {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left-width: 3px;
  border-radius: var(--r-sm);
  padding: 0.6rem 0.8rem;
  margin-bottom: 0.45rem;
}
.diag-check.ok      { border-left-color: var(--success); }
.diag-check.warning { border-left-color: var(--warn);    }
.diag-check.error   { border-left-color: var(--danger);  }
.diag-check.skipped { border-left-color: var(--text-faint); }
.diag-check-hdr {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
}
.diag-check-label {
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text);
}
.diag-check-meta {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--text-faint);
}
.diag-check-detail {
  font-size: var(--t-sm);
  color: var(--text-dim);
  line-height: 1.45;
}
.diag-check details {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--text-dim);
  margin-top: 0.4rem;
}
.diag-check details summary {
  cursor: pointer;
  padding: 0.2rem 0;
  color: var(--text-dim);
}
.diag-check details pre {
  background: var(--bg);
  padding: 0.5rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  overflow: auto;
  max-height: 240px;
  margin-top: 0.3rem;
  white-space: pre-wrap;
  word-break: break-all;
}
.diag-empty {
  color: var(--text-dim);
  font-size: var(--t-sm);
  padding: 1rem;
  text-align: center;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
}

/* ── 29. SETTINGS TAB (station detail) ──────────────────────────────────── */

.settings-sections {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* Form grid — multiple short fields in a row, auto-wrapping. */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.9rem;
}

/* Toggle switch — relabeled primitive. The legacy .toggle.on selector
   migrates to :checked via an <input type="checkbox" class="toggle-input">
   paired with a .toggle-slider element. */
.toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  cursor: pointer;
  user-select: none;
}
.toggle input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}
.toggle-slider {
  position: relative;
  display: inline-block;
  width: 36px;
  height: 20px;
  background: var(--border);
  border-radius: 999px;
  transition: background-color 180ms ease;
  flex-shrink: 0;
}
.toggle-slider::before {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  background: var(--surface);
  border-radius: 50%;
  box-shadow: var(--shadow-sm);
  transition: transform 180ms ease;
}
.toggle input:checked + .toggle-slider {
  background: var(--primary);
}
.toggle input:checked + .toggle-slider::before {
  transform: translateX(16px);
}
.toggle input:focus-visible + .toggle-slider {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.toggle-label {
  font-size: var(--t-sm);
  color: var(--text);
}

/* Danger-variant card — red border + red header color, used for
   "Danger zone" at the bottom of station settings. */
.card.card-danger {
  border-color: var(--danger);
}
.card.card-danger .card-header {
  border-bottom-color: var(--danger-soft);
}
.card.card-danger .card-header h2,
.card.card-danger .card-header h3 {
  color: var(--danger);
}

/* Schedules list (inside Schedules card) */
.schedule-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.schedule-row {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.75rem 0.9rem;
}
.schedule-header {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.6rem;
}
.schedule-header .sched-name-input {
  flex: 1;
  background: transparent;
  border: 0;
  color: var(--text);
  font-size: var(--t-sm);
  font-weight: 600;
  padding: 0.2rem 0;
  outline: 0;
  min-width: 0;
}
.schedule-header .sched-name-input:focus,
.schedule-header .sched-name-input:focus-visible {
  /* WCAG 2.4.7 — was just a 1px border-bottom (too subtle); replace
     with a 2-tone box-shadow ring matching the .input focus pattern. */
  outline: none;
  background: var(--surface);
  box-shadow: 0 0 0 2px var(--primary);
  border-radius: var(--r-sm);
}
.schedule-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 0.7rem;
}

/* Per-schedule camera override (added 2026-05-04). Collapsed by
 * default; opens to a small grid of optional fields. Blank fields
 * inherit the global camera block — savePiConfig only sends filled
 * keys, so the Pi only sees an override when the operator typed
 * something. */
.schedule-camera-override {
  margin-top: 0.7rem;
  border-top: 1px dashed var(--border);
  padding-top: 0.55rem;
}
.schedule-camera-override > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 0.25rem 0;
  user-select: none;
}
.schedule-camera-override > summary::-webkit-details-marker { display: none; }
.schedule-camera-override > summary::before {
  content: "▸";
  display: inline-block;
  width: 10px;
  color: var(--text-faint);
  transition: transform 160ms ease;
}
.schedule-camera-override[open] > summary::before {
  transform: rotate(90deg);
}
.schedule-camera-summary-label { flex: 1; }
.schedule-camera-summary-hint {
  color: var(--text-faint);
  font-weight: 400;
  letter-spacing: 0.1em;
}
.schedule-camera-fields {
  margin-top: 0.55rem;
  padding: 0.6rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}

/* Auto-managed schedule (added 2026-05-05). Renders read-only with a
 * notice. The server expands this into multiple time-of-day windows
 * at update_config push time using lat/lng + sun position. */
.schedule-row-auto {
  border-left: 3px solid var(--success);
}
.schedule-row-auto .sched-name-input {
  font-weight: 600;
  color: var(--text);
}
.schedule-auto-notice {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  padding: 0.65rem 0.8rem;
  margin-top: 0.55rem;
  background: var(--success-soft);
  color: #3f5630;
  border-radius: var(--r-sm);
  font-size: var(--text-mono-md);
  line-height: 1.45;
}
.schedule-auto-notice strong {
  color: #3f5630;
}
[data-theme="dark"] .schedule-auto-notice {
  background: rgba(135, 160, 107, 0.16);
  color: #cce0b4;
}
[data-theme="dark"] .schedule-auto-notice strong {
  color: #e5f0d4;
}

/* Settings shell (2026-05-05 redesign) — left rail nav + main column.
 * Operator complaint: 6 cards stacked all-visible was overwhelming.
 * Rail gives jump-anywhere navigation; IntersectionObserver flips
 * the active item as the operator scrolls. Below 880px the rail
 * collapses above the content (defined later in the section, search
 * "settings-shell mobile"). */
.settings-shell {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 1.5rem;
  align-items: start;
}
.settings-rail {
  position: sticky;
  top: 5rem;
  align-self: start;
  border-right: 1px dashed var(--border);
  padding: 0.5rem 0.5rem 0.5rem 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}
.settings-rail-label-group {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding: 0.55rem 0.85rem 0.45rem;
}
.settings-rail-item {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.85rem;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
  border: 0;
  border-left: 3px solid transparent;
  background: transparent;
  text-decoration: none;
  cursor: pointer;
  text-align: left;
  width: 100%;
  font-weight: 500;
  transition: background-color 120ms ease, color 120ms ease,
              border-color 120ms ease;
}
.settings-rail-item:hover {
  background: var(--surface-2);
  color: var(--text);
}
.settings-rail-item.active {
  color: var(--primary);
  border-left-color: var(--primary);
  background: var(--primary-soft);
}
.settings-rail-item.settings-rail-danger { color: var(--danger); }
.settings-rail-item.settings-rail-danger.active {
  color: var(--danger);
  border-left-color: var(--danger);
  background: var(--danger-soft);
}
.settings-rail-dot {
  width: 6px; height: 6px; flex: none;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
}
.settings-main {
  min-width: 0;
  /* Bottom padding so the sticky save bar doesn't cover the last
   * card's bottom edge when the operator scrolls to it. */
  padding-bottom: 5rem;
}

/* Settings section toggle (2026-05-05): only the section that
 * matches the active rail item is rendered. Default state via JS
 * showSettingsSection('sec-location') on first paint. Using
 * display:none rather than a class-gated visibility/opacity dance
 * because the contents are heavy (map / camera fields) and we want
 * them to truly drop out of the layout. */
.settings-section { display: none; }
.settings-section.is-active { display: block; }

/* Live video feed section layout (2026-05-05 redesign).
 * Operator feedback: the previous form-grid mixed checkbox-inline
 * fields with label-on-top fields, producing uneven heights and
 * misaligned baselines. New layout:
 *   - Hero toggle row at the top (the "is this on?" answer)
 *   - 3-up form grid with consistent label-on-top + helper text
 *   - Two sub-rows (proxy token + tailnet pin) with same shape:
 *     mono-uppercase label ┃ value pill ┃ action button
 */
.ls-hero-toggle {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: 0.85rem;
  padding: 0.85rem 1rem;
  background: var(--surface-2);
  border-left: 3px solid var(--border-hover);
  border-radius: var(--r);
  margin-bottom: 1.25rem;
  transition: border-left-color 160ms ease, background-color 160ms ease;
}
/* Border + tint follow the toggle state. CSS-only because the
 * checkbox is a sibling of the .ls-hero-toggle parent — we use
 * :has() (broad browser support post-2024) so the row turns lichen
 * on enabled, neutral on disabled. */
.ls-hero-toggle:has(input:checked) {
  border-left-color: var(--success);
  background: linear-gradient(90deg, var(--success-soft), var(--surface-2) 60%);
}
.ls-hero-toggle .toggle { padding-top: 0.15rem; }
.ls-hero-toggle-text strong {
  display: block;
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text);
  margin-bottom: 0.25rem;
}
.ls-hero-toggle-text p {
  margin: 0;
  line-height: 1.5;
}

/* Three-column config grid. Forces uniform field heights via
 * align-items:start on the parent and a min-height on each field
 * so the helper text doesn't pull rows out of alignment. */
.ls-config-grid {
  align-items: start;
  margin-bottom: 1.25rem;
}
.ls-config-grid .form-field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.ls-config-grid .form-field label:first-child {
  /* Force a consistent label height so the controls beneath line
   * up across all three columns even when the label is one line vs
   * two. */
  min-height: 1.25rem;
  display: flex;
  align-items: center;
  margin-bottom: 0;
}

/* Suffix-input pattern (e.g. "200 MB"). Lets the unit ride along
 * inside the input's visual frame so it doesn't fight for label
 * real estate. */
.ls-suffix-input {
  position: relative;
  display: flex;
  align-items: stretch;
}
.ls-suffix-input input {
  flex: 1;
  padding-right: 2.5rem;
}
.ls-suffix {
  position: absolute;
  right: 0.7rem;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  pointer-events: none;
}

/* Inline toggle inside a form field — keeps the label-on-top
 * rhythm consistent with the select / number-input siblings. */
.ls-inline-toggle {
  align-self: flex-start;
  padding: 0.35rem 0;
}

/* Per-field helper text. Smaller + faint so it doesn't compete
 * with the actual control. */
.ls-field-hint {
  margin: 0;
  font-size: var(--text-mono-md);
  line-height: 1.45;
  color: var(--text-faint);
}

/* Sub-section blocks for proxy token + tailnet pin. Same shape
 * for both: dashed top rule, label ┃ value ┃ button row, helper
 * text below. */
.ls-sub-section {
  margin-top: 1rem;
  padding-top: 0.85rem;
  border-top: 1px dashed var(--border);
}
.ls-sub-section + .ls-sub-section { margin-top: 0.85rem; }
.ls-sub-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.4rem;
}
.ls-sub-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  white-space: nowrap;
}
.ls-sub-value {
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
  color: var(--text-dim);
  background: var(--surface-2);
  padding: 0.3rem 0.6rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.ls-sub-btn {
  flex: none;
  white-space: nowrap;
}

/* Phone — sub-row stacks: label on row 1, value full width on row
 * 2, button on row 3. Hero toggle keeps its 2-column shape since
 * the toggle is small. Form-grid already collapses via Section 20. */
@media (max-width: 600px) {
  .ls-sub-row {
    grid-template-columns: 1fr;
    gap: 0.4rem;
  }
  .ls-sub-row .ls-sub-btn {
    justify-self: start;
  }
}

/* Phone: collapse the rail above the content as a horizontal
 * scroller of pills so it doesn't eat vertical real estate. */
@media (max-width: 880px) {
  .settings-shell {
    grid-template-columns: 1fr;
    gap: 0.85rem;
  }
  .settings-rail {
    position: static;
    border-right: 0;
    border-bottom: 1px dashed var(--border);
    padding: 0;
    flex-direction: row;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
  }
  .settings-rail-label-group { display: none; }
  .settings-rail-item {
    border-left: 0;
    border-bottom: 3px solid transparent;
    padding: 0.55rem 0.75rem;
    flex: 0 0 auto;
    scroll-snap-align: start;
    white-space: nowrap;
  }
  .settings-rail-item.active {
    border-left-color: transparent;
    border-bottom-color: var(--primary);
  }
}

/* Save bar — sticky bottom of the settings-main column. The single
 * place a save bar belongs is at the bottom of the form; mid-page
 * was a usability bug. (2026-05-05 redesign — was a static row
 * earlier despite the comment claiming sticky.) */
.settings-save-bar {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  padding: 0.85rem 0;
  background: linear-gradient(0deg, var(--bg) 80%, transparent);
  margin-top: 0.5rem;
}

/* ── 30. PROFILE PAGE ─────────────────────────────────────────────────────── */

.profile-layout {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 1.25rem;
  max-width: 900px;
}
.profile-info {
  display: flex;
  flex-direction: column;
}
.profile-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--border);
}
.profile-row:last-child { border-bottom: 0; }
.profile-label {
  font-size: var(--t-sm);
  color: var(--text-dim);
}
.profile-value {
  font-size: var(--t-sm);
  color: var(--text);
  font-weight: 500;
  font-family: var(--font-mono);
  text-align: right;
}
.profile-value.plain { font-family: var(--font-sans); }

/* ═══════════════════════════════════════════════════════════════════════════
   §31 — Admin page helpers
   ─────────────────────────────────────────────────────────────────────────── */

/* Flush body (removes inner padding so a .table reaches the card's edges) */
.card-body-flush { padding: 0; }
.card-body-flush .table { border-radius: 0; }

/* Role badges (reuse the generic .badge shape with role-specific palettes) */
.badge-role-admin   { background: var(--primary-soft); color: var(--primary); }
.badge-role-manager { background: var(--warn-soft);    color: var(--warn);    }
.badge-role-viewer  { background: var(--surface-2);    color: var(--text-dim); }

/* Right-aligned action cell for a row's trailing button(s) */
.table-actions { text-align: right; white-space: nowrap; }

/* Narrow form grid — single column, max ~420px — for modals / settings panes
   where side-by-side fields would feel cramped. */
.form-grid-narrow {
  grid-template-columns: 1fr;
  max-width: 420px;
}

/* Danger-ghost button: red text and border, transparent fill; fills in on hover.
   Used for low-weight destructive actions in dense tables. */
.btn-danger-ghost {
  background: transparent;
  color: var(--danger);
  border: 1px solid var(--danger);
}
.btn-danger-ghost:hover {
  background: var(--danger);
  color: #fff;
}

/* ═══════════════════════════════════════════════════════════════════════════
   §32 — Videos tab (station detail): compile jobs, videos grid, player modal,
   compile wizard
   ─────────────────────────────────────────────────────────────────────────── */

/* Outer wrapper for the entire Videos tab. */
.videos-tab {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* Header row (title + "New video" button). */
.videos-tab-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.videos-tab-title {
  font-size: var(--t-2xl);
  font-weight: 600;
  margin: 0;
}

/* ── Jobs section (in-progress / queued / recently finished) ─────────────── */

.jobs-section {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.jobs-section .section-header {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0;
}
.jobs-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* A single job row. Left border colour-coded by status. */
.job-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.85rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left-width: 3px;
  border-radius: var(--r-sm);
}
.job-row-running { border-left-color: var(--primary); }
.job-row-queued  { border-left-color: var(--text-faint); }
.job-row-done    { border-left-color: var(--success); }
.job-row-failed  { border-left-color: var(--danger); }

.job-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.job-row-title {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.job-row-meta {
  font-size: var(--t-xs);
  color: var(--text-dim);
}
.job-row-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}
.job-row-progress {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-shrink: 0;
}

/* Thin progress bar for running jobs. */
.progress-bar {
  width: 200px;
  height: 6px;
  background: var(--surface-2);
  border-radius: 999px;
  overflow: hidden;
}
.progress-bar-fill {
  height: 100%;
  background: var(--primary);
  border-radius: inherit;
  transition: width 300ms ease;
}

/* ── Videos grid ─────────────────────────────────────────────────────────── */

.videos-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
}
/* Show-all / show-fewer expander under the videos grid (UX-parity cheap-fold). */
.videos-expander {
  display: flex;
  justify-content: center;
  margin-top: 1rem;
}

.video-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  overflow: hidden;
  cursor: pointer;
  transition: border-color 150ms ease, transform 150ms ease, box-shadow 150ms ease;
}
.video-card:hover {
  border-color: var(--border-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow);
}

.video-card-thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--surface-2);
  overflow: hidden;
}
.video-card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.video-card-thumb-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
  font-size: var(--t-sm);
}
.video-card-duration {
  position: absolute;
  right: 0.5rem;
  bottom: 0.5rem;
  padding: 0.15rem 0.45rem;
  background: rgba(0,0,0,0.72);
  color: #fff;
  font-size: var(--t-xs);
  font-weight: 600;
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
}

.video-card-body {
  padding: 0.75rem 0.85rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.video-card-title {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.video-card-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  font-size: var(--t-xs);
  color: var(--text-dim);
}
.video-card-preset {
  padding: 0.08rem 0.4rem;
  background: var(--primary-soft);
  color: var(--primary);
  border-radius: var(--r-sm);
  font-weight: 600;
  text-transform: capitalize;
}
.video-card-date { font-family: var(--font-mono); }

/* Public-visibility toggle in the top-right of the thumbnail. Hidden by
   default and fades in on card hover; stays pinned visible once the video
   is actually public so the state is always discoverable. */
.video-public-toggle {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 150ms ease, background 150ms ease;
  padding: 0;
}
.video-card:hover .video-public-toggle { opacity: 1; }
.video-public-toggle:hover { background: rgba(0, 0, 0, 0.8); }
.video-public-toggle.is-public {
  opacity: 1;
  background: var(--primary);
}
.video-public-toggle.is-public:hover { background: var(--primary-hover); }

/* Inline "Public" badge in the card meta row — mirrors .video-card-preset
   but uses the success tint so it reads as a status, not a classification. */
.video-public-badge {
  display: inline-block;
  padding: 0.08rem 0.4rem;
  border-radius: var(--r-sm);
  background: var(--primary-soft);
  color: var(--primary);
  font-size: var(--t-xs);
  font-weight: 600;
}

/* Brief highlight when scrollToVideo() targets a card. The flash is a
   ring expansion — spatial motion. Guarded by prefers-reduced-motion
   so it falls back to a static ring that fades on its own timeline. */
.video-card-flash {
  animation: videoCardFlash 1.6s ease-out;
}
@keyframes videoCardFlash {
  0%   { box-shadow: 0 0 0 0 var(--primary); }
  30%  { box-shadow: 0 0 0 4px var(--primary-soft); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .video-card-flash {
    animation: none;
    box-shadow: 0 0 0 2px var(--primary);
  }
}

/* ── Wide modal variant (video player + wizard use 800px instead of 440px) */

.modal-wide {
  width: min(800px, calc(100vw - 2rem));
  max-width: none;
}

/* Meta rows under the <video> element in the player modal. */
.video-modal-meta {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-top: 0.75rem;
}
.video-meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  font-size: var(--t-sm);
}
.video-meta-label {
  color: var(--text-dim);
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* ── Wizard steps (2-step compile flow) ──────────────────────────────────── */

.wizard-steps {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-faint);
}
.wizard-step {
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  font-weight: 600;
}
.wizard-step-active {
  background: var(--primary-soft);
  color: var(--primary);
}
.wizard-step-sep {
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* Radio-option groups (mode select + preset select). */
.wizard-mode-options,
.wizard-preset-options {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.wizard-mode-option,
.wizard-preset-option {
  display: flex;
  gap: 0.75rem;
  padding: 0.75rem 0.85rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}
.wizard-mode-option:hover,
.wizard-preset-option:hover {
  border-color: var(--border-hover);
}
.wizard-mode-option:has(input:checked),
.wizard-preset-option:has(input:checked) {
  border-color: var(--primary);
  background: var(--primary-soft);
}
.wizard-mode-option input[type="radio"],
.wizard-preset-option input[type="radio"] {
  margin-top: 0.2rem;
  flex-shrink: 0;
}
.wizard-mode-body,
.wizard-preset-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.wizard-mode-title,
.wizard-preset-title {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--text);
}
.wizard-mode-desc,
.wizard-preset-desc {
  font-size: var(--t-xs);
  color: var(--text-dim);
}
.wizard-mode-field {
  margin-top: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.wizard-mode-field label {
  font-size: var(--t-xs);
  color: var(--text-dim);
}

/* Step-2 summary of the selections from step 1. */
.wizard-summary {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.75rem 0.85rem;
  background: var(--surface-2);
  border-radius: var(--r-sm);
  margin-bottom: 1rem;
}
.wizard-summary-label {
  font-size: var(--t-xs);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.wizard-summary-value {
  font-size: var(--t-sm);
  color: var(--text);
  font-weight: 500;
}

/* ═══════════════════════════════════════════════════════════════════════════
   11. SITE NOTES — STRUCTURAL POLISH (Apr 28 2026)
   ═══════════════════════════════════════════════════════════════════════════
   This block applies the typographic and density discipline from the v1
   redesign mockup on top of the existing component CSS. It targets the
   real class names already in the markup; rules placed here win over the
   earlier definitions via source-order specificity. Revert by deleting
   this section.

   Concepts in play:
     - Cards: one border OR one shadow, never both. Drop the dual-shadow.
     - Numerics, identifiers, timestamps, file sizes: ALL mono.
     - Section headers and tags: mono uppercase, letterspacing 0.08em.
     - Density: tighter padding on cards/tiles, smaller meta text. The
       result feels like an instrument panel instead of a SaaS dashboard.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Cards — single edge ─────────────────────────────────────────────── */
.card { box-shadow: none; }
.card-interactive:hover {
  box-shadow: var(--shadow-sm);
  border-color: var(--primary);
}
.card-header { padding: 0.85rem 1.1rem; }
.card-header h3,
.card-header > h2 {
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.card-body { padding: 1.1rem; }

/* ── Sidebar ─────────────────────────────────────────────────────────── */
.app-sidebar { padding: 1.1rem 0.7rem 1rem; }
.app-sidebar-brand { margin-bottom: 1.4rem; }
.app-sidebar-brand .wordmark {
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: -0.01em;
}
.app-nav { gap: 1px; }
.app-nav-item {
  padding: 0.45rem 0.6rem;
  font-size: var(--t-xs);
  border-radius: var(--r-sm);
}
.app-nav-item .nav-icon { width: 16px; height: 16px; }
.theme-toggle {
  padding: 0.45rem 0.6rem;
  font-size: var(--t-xs);
  letter-spacing: 0.04em;
}

/* User badge in sidebar footer */
.user-badge {
  font-family: var(--font-mono) !important;
  font-size: var(--text-mono-sm) !important;
  letter-spacing: 0.04em;
  color: var(--text-dim);
}

/* ── Topbar ──────────────────────────────────────────────────────────── */
.app-topbar { padding: 0.7rem 1.5rem; }
.breadcrumbs {
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
  letter-spacing: 0.04em;
  color: var(--text-dim);
}
.breadcrumbs-sep { color: var(--text-faint); margin: 0 0.35rem; }
.breadcrumbs-current { color: var(--text); }
.topbar-search {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 0.4rem 0.7rem;
  font-size: var(--text-mono-md);
}
.topbar-icon-btn {
  width: 32px;
  height: 32px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  transition: all 120ms ease;
}
.topbar-icon-btn:hover {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--text);
}

/* ── Page header pattern ─────────────────────────────────────────────── */
.page-header {
  padding-bottom: 0.85rem;
  border-bottom: 1px dashed var(--border);
  margin-bottom: 1.5rem;
}
.page-title {
  font-size: 1.5rem;
  font-weight: 500;
  letter-spacing: -0.02em;
}
/* Subtitle is a register change from the title, not a quieter same-size sans
   line. Mono caps + tracking puts it in the same family as .card-header h3
   ("drafting-block tag" convention) — see docs/design-system.md. The eye
   reads title and subtitle as different *kinds* of information, not as
   "same thing in two colors" (audit M2). */
.page-subtitle {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-top: 0.4rem;
}
/* Breadcrumb back-button — was a low-contrast link, now a proper bordered
   button so the operator's eye picks it up at the top of every detail page.
   Same family as .st-detail-back (the back-button on Status / Settings).
   Site Notes mono uppercase + clay accent on hover, same as the other
   instrument-row controls. */
.page-breadcrumb-back {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  height: 30px;
  padding: 0 0.75rem;
  box-sizing: border-box;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.06em;
  line-height: 1;
  text-transform: uppercase;
  color: var(--text-dim);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  margin-bottom: 0.85rem;
  cursor: pointer;
  text-decoration: none;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}
.page-breadcrumb-back:hover {
  color: var(--primary);
  border-color: var(--primary);
  background: var(--primary-soft);
}
.page-breadcrumb-back svg { stroke-width: 2; width: 12px; height: 12px; flex: 0 0 auto; }

/* ── Buttons — slightly tighter ──────────────────────────────────────── */

/* ── Badges ──────────────────────────────────────────────────────────────
   The mono-uppercase base + the WCAG-tuned badge-primary/-success/-warn/-danger
   variants (and their dark-mode overrides) were consolidated onto the canonical
   Stratum-B badge system (.badge-ok/-warn/-bad/-accent/-ghost in stratum-b.css)
   on 2026-06-09. Call sites were migrated: BIM issue in_progress/in_review →
   badge-ghost (badge-accent fails AA at the 9.5px badge size, 2.85:1), closed →
   badge-ok; diagnostic ok → badge-ok, error → badge-bad. stratum-b's variants
   carry their own AA-checked color pairs (badge-ok light text tuned to #2f6008). */

/* Dark-mode .app-nav-item.active — bg is --primary-soft (#3a2419),
   text was var(--primary) #a85730 at 2.81:1. Bumped to the same bright
   clay used by dark badge-primary so the active nav item reads at AA.
   The light-mode rule keeps var(--primary) since light --primary-soft
   #f0d9c6 + --primary #a85730 sit at 3.79:1 (passes UI 3:1 component
   contrast, borderline for text but the nav item is rendered at
   --text-sm weight 500 which historically reads OK at this ratio). */
[data-theme="dark"] .app-nav-item.active { color: #d27a55; }

/* ── Tabs ────────────────────────────────────────────────────────────── */
.tab-item { font-size: var(--t-xs); padding: 0.55rem 1rem; letter-spacing: 0; }
.tab-item.active { font-weight: 500; border-bottom-width: 2px; }

/* ── Activity feed — mono timestamps, structured row ─────────────────── */
.activity-list { gap: 0; }
.activity-item {
  display: grid;
  grid-template-columns: 56px 8px 1fr;
  gap: 10px;
  padding: 0.58rem 1.1rem;
  border-bottom: 0;
  border-top: 1px solid var(--border);
  align-items: center;
}
.activity-item:first-child { border-top: 0; }
.activity-item:last-child { border-bottom: 0; }
.activity-time {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.02em;
  color: var(--text-faint);
  text-transform: lowercase;
  white-space: nowrap;
}
.activity-dot { align-self: center; width: 6px; height: 6px; margin-top: 0; }
.activity-message { font-size: var(--t-xs); line-height: 1.45; }

/* ── Status / Instrument-panel tiles ─────────────────────────────────── */
.status-grid,
.status-metrics,
.stat-grid { gap: 0.7rem; }
.status-metric,
.stat-card {
  padding: 0.85rem 1rem;
  border-radius: var(--r);
  position: relative;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: none;
}
/* Traffic-light borders — only when explicitly classed */
.status-metric.is-ok::before,
.status-metric.is-warn::before,
.status-metric.is-bad::before,
.stat-card.is-ok::before,
.stat-card.is-warn::before,
.stat-card.is-bad::before {
  content: '';
  position: absolute;
  top: 0; left: 0; bottom: 0;
  width: 3px;
}
.status-metric.is-ok::before,   .stat-card.is-ok::before   { background: var(--success); }
.status-metric.is-warn::before, .stat-card.is-warn::before { background: var(--warn); }
.status-metric.is-bad::before,  .stat-card.is-bad::before  { background: var(--danger); }

.status-metric-label,
.stat-card-label,
.stat-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.status-metric-value,
.stat-card-value,
.stat-value {
  font-family: var(--font-mono);
  font-size: 1.5rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  color: var(--text);
  line-height: 1.1;
  margin-top: 0.2rem;
}
.stat-card-sub, .stat-sub {
  font-size: var(--text-mono-md);
  color: var(--text-dim);
  margin-top: 0.25rem;
}

/* ── Project cards ───────────────────────────────────────────────────── */
.project-card {
  border-radius: var(--r);
  box-shadow: none;
  transition: border-color 120ms ease;
}
.project-card:hover { border-color: var(--primary); }
.project-card-cover { aspect-ratio: 16 / 9; }
.project-card-body { padding: 0.85rem 0.95rem 0.95rem; }
.project-card-title {
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: -0.01em;
}
.project-card-desc { font-size: var(--t-xs); color: var(--text-dim); }
.project-card-meta {
  margin-top: 0.65rem;
  padding-top: 0.55rem;
  border-top: 1px dashed var(--border);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.2rem;
}
.project-card-stat-value {
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.project-card-stat { display: flex; flex-direction: column; }

/* ── Station card (redesigned 2026-05-05) ─────────────────────────────────
 * Latest-capture thumbnail at the top + 4px left-edge color strip that
 * aggregates station health into one signal so the operator can spot a
 * problem station at a glance across the project grid. Single source of
 * truth for the colour: health_state on the API response → is-ok /
 * is-warn / is-bad / is-cold class on the .station-card.
 *
 * Health rules (computed in api_list_stations):
 *   ok    everything healthy → lichen (DK's "smoothly running" green)
 *   warn  disk ≥ 70 OR cpu ≥ 65 OR config drift → hi-vis amber
 *   bad   offline / disk ≥ 85 / failed command / many upload failures
 *         → brick red
 *   cold  never checked in (no signal yet) → faint gray
 */
.station-card {
  /* Override the legacy .card padding/shadow — image is flush. */
  display: grid;
  grid-template-rows: auto 1fr;
  padding: 0;
  overflow: hidden;
  border-left-width: 4px;
  box-shadow: none;
  transition: border-color 120ms ease;
}
.station-card.is-ok    { border-left-color: var(--success); }   /* lichen */
.station-card.is-warn  { border-left-color: var(--warn); }      /* hi-vis */
.station-card.is-bad   { border-left-color: var(--danger); }    /* brick */
.station-card.is-cold  { border-left-color: var(--text-faint); } /* gray */
.station-card:hover { border-color: var(--primary); }
/* Re-apply the health colour on the LEFT edge after hover changes the
 * border colour for the rest of the card — left edge stays the health
 * signal, the other 3 edges become the clay primary on hover. */
.station-card.is-ok:hover    { border-left-color: var(--success); }
.station-card.is-warn:hover  { border-left-color: var(--warn); }
.station-card.is-bad:hover   { border-left-color: var(--danger); }
.station-card.is-cold:hover  { border-left-color: var(--text-faint); }

/* Faint health tint over the body so the colour reads even on dark
 * mode where the 4px strip can disappear into the surrounding card. */
.station-card.is-ok   .station-card-body { background: linear-gradient(0deg, rgba(135,160,107,0.06), transparent 40%); }
.station-card.is-warn .station-card-body { background: linear-gradient(0deg, rgba(212,148,63,0.08), transparent 40%); }
.station-card.is-bad  .station-card-body { background: linear-gradient(0deg, rgba(178,90,77,0.10), transparent 40%); }

.station-card-thumb {
  aspect-ratio: 16 / 9;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  position: relative;
  overflow: hidden;
}
.station-card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.station-card-thumb-empty {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.station-card-body {
  padding: 0.75rem 0.95rem 0.85rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.station-card-header {
  display: flex; align-items: center; gap: 0.5rem;
  min-width: 0;
}
.station-card-name {
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.station-card-loc {
  font-size: var(--t-xs);
  color: var(--text-dim);
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.station-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.85rem;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin-top: 0.15rem;
}
.station-card-meta .meta-item {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.station-card-meta .meta-label {
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: var(--text-mono-xs);
  margin-right: 0.15rem;
}
.station-card-meta .meta-value {
  color: var(--text);
  font-weight: 500;
}
.station-token {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--text-faint);
  letter-spacing: 0.04em;
}

/* ── Gallery ─────────────────────────────────────────────────────────── */
.gallery-day-header {
  padding-bottom: 0.65rem;
  border-bottom: 1px dashed var(--border);
  margin-bottom: 0.85rem;
}
.gallery-day-header > h2,
.gallery-day-header > h3 {
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}
.gallery-day-actions {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
}
.gallery-filters {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
.filter-chip {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  padding: 0.25rem 0.55rem;
  border-radius: 3px;
  color: var(--text-dim);
  background: transparent;
  border: 0;
  cursor: pointer;
}
.filter-chip:hover { color: var(--text); }
.filter-chip.active {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  margin: -1px;
}

/* Date list rail */
.date-list { gap: 0; }
.date-item {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: 2px;
  padding: 0.5rem 0.85rem;
  font-size: var(--t-xs);
  border-bottom: 1px solid var(--border);
  border-radius: 0;
}
.date-item-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.date-item:last-child { border-bottom: 0; }
.date-item.active {
  background: var(--primary-soft);
  color: var(--primary-hover);
  font-weight: 500;
  border-color: var(--primary);
}
.date-item-count {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-variant-numeric: tabular-nums;
  /* Count is load-bearing data, not decoration — promote from --text-faint
     to --text-dim so it reads cleanly on the chip's --surface-2 pill bg. */
  color: var(--text-dim);
}
/* Active row: chip bg is --primary (clay) per section 1 line 1825-1827.
   Section 11 had set this to --primary-hover (darker clay), which collapsed
   to ~1.6:1 contrast — invisible. Restore white for clear contrast on clay. */
.date-item.active .date-item-count { color: #ffffff; }
/* Per-day data line: mono, faint, MB + HH:MM → HH:MM. Drafting-block
   convention — gives the date rail more density than just count + name. */
.date-item-meta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  line-height: 1.3;
}
.date-item.active .date-item-meta { color: var(--primary-hover); opacity: 0.7; }

/* Image (capture) card */
.image-card {
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  transition: all 120ms ease;
}
.image-card:hover { border-color: var(--primary); }
.image-card-info {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}
.image-card-size {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-variant-numeric: tabular-nums;
  color: var(--text-faint);
}

/* ── Markup card ─────────────────────────────────────────────────────── */
.markup-card { box-shadow: none; transition: border-color 120ms ease; }
.markup-card:hover { border-color: var(--primary); }
.markup-marks {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
.markup-when { font-size: var(--t-xs); font-weight: 500; }
.markup-meta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  color: var(--text-dim);
}
.markup-by { font-family: var(--font-mono); font-size: var(--text-mono-sm); color: var(--text-faint); }

/* ── Video card ──────────────────────────────────────────────────────── */
.video-card { box-shadow: none; }
.video-card:hover { border-color: var(--primary); }
.video-card-title {
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}
.video-card-meta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  color: var(--text-dim);
}
.video-card-preset,
.video-card-date,
.video-card-duration {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-mono-sm);
}

/* ── Command history (queue/log) ─────────────────────────────────────── */
.cmd-history-list {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
}
.cmd-history-row {
  display: grid;
  /* id (mono fixed) | type (flex) | status (auto) | time (mono fixed) */
  grid-template-columns: 56px 1fr auto 76px;
  gap: 0.85rem;
  padding: 0.65rem 0.95rem;
  border-bottom: 1px solid var(--border);
  font-size: var(--t-xs);
  align-items: center;
}
.cmd-history-row:last-child { border-bottom: 0; }
.cmd-history-row:hover { background: var(--surface-2); }
.cmd-history-row > *:first-child {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--text-faint);
  letter-spacing: 0.04em;
}
.cmd-type { font-weight: 500; font-family: var(--font-sans); }
.cmd-status {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ── Login screen polish ─────────────────────────────────────────────── */
/* Section 17 — Login split-pane (2026-04-28).
   Left pane: drafting-grid backdrop (engineering paper). Right pane: the
   existing card. Falls back to single-column on narrow viewports — the art
   pane hides entirely so a phone user just sees the form. */
.login-screen {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  justify-content: stretch;
  padding: 0;
  min-height: 100vh;
  background: var(--bg);
}
.login-pane-art {
  flex: 1 1 60%;
  position: relative;
  background-color: var(--surface-2);
  /* Drafting grid: 100px major (stronger), 20px minor (faint).
     color-mix lets us reuse --border so dark/light themes both look right.
     The radial overlay adds the same clay glow the landing hero uses, so
     login + landing read as one design. */
  background-image:
    radial-gradient(900px 500px at 35% 25%,
      color-mix(in srgb, var(--primary-soft) 80%, transparent),
      transparent 65%),
    linear-gradient(to right,
      color-mix(in srgb, var(--border) 80%, transparent) 1px,
      transparent 1px),
    linear-gradient(to bottom,
      color-mix(in srgb, var(--border) 80%, transparent) 1px,
      transparent 1px),
    linear-gradient(to right,
      color-mix(in srgb, var(--border) 32%, transparent) 1px,
      transparent 1px),
    linear-gradient(to bottom,
      color-mix(in srgb, var(--border) 32%, transparent) 1px,
      transparent 1px);
  background-size:
    auto auto,
    100px 100px, 100px 100px,
    20px 20px, 20px 20px;
  background-position:
    0 0,
    -1px -1px, -1px -1px,
    -1px -1px, -1px -1px;
  border-right: 1px solid var(--border);
  overflow: hidden;
}
.login-art-block {
  position: absolute;
  left: clamp(2rem, 5vw, 4rem);
  bottom: clamp(2rem, 5vh, 3.5rem);
  max-width: 32ch;
  padding: 1.4rem 1.5rem 1.5rem;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
}
.login-art-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--primary);
  font-weight: 500;
}
.login-art-title {
  margin-top: 0.35rem;
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
}
.login-art-list {
  margin: 0.85rem 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--t-sm);
  color: var(--text-dim);
  line-height: 1.55;
}
.login-art-list li {
  padding-left: 1.1rem;
  position: relative;
}
.login-art-list li::before {
  content: '—';
  position: absolute;
  left: 0;
  color: var(--text-faint);
}
.login-art-stamp {
  margin-top: 0.85rem;
  padding-top: 0.55rem;
  border-top: 1px dashed var(--border);
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.login-pane-form {
  flex: 0 1 480px;
  /* FND-B01: allow flex item to shrink below its min-content so the form column doesn't push the page wider than the viewport */
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
/* Theme toggle in the login brand row — small ghost button, sits in
   the natural reading-end of the brand line. localStorage 'dk-theme'
   is shared with SPA + landing so flips persist across nav. */
.login-theme-toggle {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-dim);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  transition: border-color 120ms ease, color 120ms ease;
}
.login-theme-toggle:hover {
  border-color: var(--primary);
  color: var(--text);
}
/* Bump tap-target to WCAG 2.5.5 minimum (44×44) on mobile. (Audit 2026-05-27 P2-A2.) */
@media (max-width: 600px) {
  .login-theme-toggle { width: 44px; height: 44px; font-size: 1.15rem; }
}
@media (max-width: 880px) {
  .login-pane-art { display: none; }
  .login-pane-form { flex: 1 1 100%; }
}

.login-card { box-shadow: var(--shadow); border-radius: var(--r-lg); }
.login-title {
  font-size: 1.4rem;
  font-weight: 500;
  letter-spacing: -0.02em;
}
.login-sub { font-size: var(--t-xs); color: var(--text-dim); }

/* ── Wizard summary mono ────────────────────────────────────────────── */
.wizard-summary-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.1em;
}

/* ── Diagnostic panel ────────────────────────────────────────────────── */
.diag-meta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}
.diag-section h4 {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 500;
}

/* ── Forms — tighter ─────────────────────────────────────────────────── */
.form-field label,
.form-grid label,
.form-grid-narrow label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.form-hint { font-size: var(--text-mono-sm); color: var(--text-faint); }

/* ── Modal — tightening ─────────────────────────────────────────────── */
.modal-header { padding: 0.95rem 1.1rem; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.modal-title {
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}
/* S3.13 — Close button: 28×28 icon button, no background until hover */
.modal-close {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  padding: 0; border: none; border-radius: var(--r-sm);
  background: transparent; cursor: pointer;
  font-size: 1.1rem; line-height: 1;
  color: var(--text-dim);
  transition: background 0.12s, color 0.12s;
  flex-shrink: 0;
}
.modal-close:hover { background: var(--surface-2); color: var(--text); }
.modal-body   { padding: 1.1rem; }
.modal-footer { padding: 0.85rem 1.1rem; background: var(--surface-2); }

/* ── Empty state — quieter ───────────────────────────────────────────── */
.empty-state-title {
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: -0.01em;
}
.empty-state-body { font-size: var(--t-xs); color: var(--text-dim); }

/* ── Job rows (compile worker queue) ─────────────────────────────────── */
.job-row { border-radius: var(--r-sm); }
.job-row-meta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}
.job-row-title { font-size: var(--t-xs); font-weight: 500; }

/* ── Smart Search result cards mono ─────────────────────────────────── */
.ss-card-when,
.ss-card-meta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}

/* ── Progress photo rows mono ───────────────────────────────────────── */
.pp-row-meta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-variant-numeric: tabular-nums;
}

/* ── Compare overlay date pills ─────────────────────────────────────── */
.cmp-date-pill {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}

/* ── Enrollment code ─────────────────────────────────────────────────── */
.enroll-code {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
}
.enroll-status,
.enroll-expiry {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ═══════════════════════════════════════════════════════════════════════════
   End of structural polish
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
   12. SITE NOTES — POLISH ROUND 2 (Apr 28 2026)
   Addresses critique findings: kill the SaaS-style hover lifts on cards,
   add the missing chrome elements (sidebar group label, Cmd+K bar look,
   station live pulse pill), bump badge text contrast.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Hover-lift kills ────────────────────────────────────────────────── */
/* Original .card-interactive:hover (line 502) and .project-card:hover
   (line 810) re-add box-shadow + transform: translateY(-1px). That
   contradicts the Site Notes "single edge, no lift" rule. Border-color
   shift on hover is enough — and matches the mockup's mood. */
.card-interactive:hover,
.project-card:hover,
.station-card:hover,
.markup-card:hover,
.video-card:hover,
.image-card:hover {
  transform: none;
  box-shadow: none;
}

/* ── Card-header h2 too — original (line 514) sets font-size: var(--t-lg)
   font-weight: 600 for both h2 and h3. The polish layer (section 11)
   only retargeted h3, leaving h2 with the SaaS treatment. ─────────────── */
.card-header h2 {
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* ── Sidebar nav group label ─────────────────────────────────────────── */
/* Mono uppercase, tracked, dim. Used as a section divider above nav
   items in .app-nav (e.g. "Workspace"). Acts as a drafting-block
   convention rather than a heading. */
.shell-nav-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding: 0.55rem 0.6rem 0.3rem;
  font-weight: 500;
}
.shell-nav-label:not(:first-child) {
  margin-top: 0.4rem;
  border-top: 1px dashed var(--border);
  padding-top: 0.65rem;
}

/* ── Topbar search → Cmd+K bar look ──────────────────────────────────── */
/* The existing .topbar-search markup is <div><svg/><input/></div>.
   We add a <span class="cmd-kbd">⌘ K</span> on the right. CSS-only
   visual; no JS handler attached for v1 (typing in the box still works
   as the live search-as-you-type the input already does). */
.topbar-search {
  position: relative;
}
.topbar-search input {
  font-family: var(--font-sans);
  font-size: var(--text-mono-md);
}
.topbar-search input::placeholder {
  color: var(--text-faint);
}
.cmd-kbd {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-dim);
  padding: 0.05rem 0.35rem;
  border-radius: 3px;
  margin-left: auto;
  flex-shrink: 0;
  pointer-events: none;
  user-select: none;
}

/* Search results dropdown — anchored to .topbar-search via position:absolute.
   Single-edge bone surface; floating control so a small shadow is allowed.
   Hidden by default; opens when results are present (.open). */
.topbar-search-results {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  background: var(--surface);
  border: 1px solid var(--border-hover);
  border-radius: var(--r);
  box-shadow: 0 6px 22px rgba(42,38,32,0.12);
  max-height: 60vh;
  overflow-y: auto;
  z-index: 50;
  padding: 0.3rem 0;
}
[data-theme="dark"] .topbar-search-results {
  box-shadow: 0 6px 22px rgba(0,0,0,0.5);
}
.topbar-search-results.open { display: block; }
.tsr-section {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-weight: 500;
  letter-spacing: 0.1em;
  color: var(--text-faint);
  padding: 0.5rem 0.85rem 0.25rem;
  text-transform: uppercase;
}
.tsr-item {
  display: grid;
  grid-template-columns: 56px 1fr;
  grid-template-areas: "kind label" "kind sub";
  column-gap: 0.5rem;
  align-items: baseline;
  padding: 0.4rem 0.85rem;
  cursor: pointer;
  transition: background-color 100ms ease;
}
.tsr-item:hover,
.tsr-item.is-highlight {
  background: var(--surface-2);
}
.tsr-kind {
  grid-area: kind;
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-weight: 500;
  letter-spacing: 0.1em;
  color: var(--text-faint);
  align-self: center;
}
.tsr-label {
  grid-area: label;
  font-family: var(--font-sans);
  font-size: 0.84rem;
  color: var(--text);
  font-weight: 500;
}
.tsr-sub {
  grid-area: sub;
  font-family: var(--font-sans);
  font-size: var(--text-mono-md);
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tsr-empty {
  padding: 0.85rem;
  font-family: var(--font-sans);
  font-size: var(--t-xs);
  color: var(--text-dim);
  text-align: center;
}

/* ── Live pulse pill (next to station name) ──────────────────────────── */
.live-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 500;
  padding: 0.2rem 0.5rem 0.2rem 0.45rem;
  background: var(--success-soft);
  color: #3f5630;   /* deep lichen on lichen-soft for light-mode AA */
  border: 1px solid var(--success);
  border-radius: var(--r-sm);
  vertical-align: middle;
  margin-left: 0.65rem;
  position: relative;
  top: -2px;
}
/* Dark mode — the hardcoded #3f5630 is calibrated for light --success-soft
   (#d8e2c8). On dark --success-soft (#2a3a22) the same dark green text
   disappears. Restore the canonical brand color, which is calibrated as
   light lichen (#94ae77) in dark mode and pops correctly. Matches the
   sibling .dashboard-head .live-pill / .project-home-head .live-pill
   rules which were authored later and already use var(--success). */
[data-theme="dark"] .live-pill {
  color: var(--success);
}
.live-pill-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--success);
  box-shadow: 0 0 0 2px rgba(135, 160, 107, 0.25);
  animation: live-pulse 2s ease-in-out infinite;
}
@keyframes live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.55; transform: scale(0.85); }
}
@media (prefers-reduced-motion: reduce) {
  .live-pill-dot { animation: none; }
}

/* ── Sidebar system-status panel (admin only) ─────────────────────────
   Mono register at the top of .app-sidebar-footer. Hidden by default;
   loadSidebarHealth() unhides for admin users after the /api/admin/
   health probe lands. Reads as an instrument-panel header. */
.sidebar-system-status {
  padding: 0.55rem 0.5rem 0.65rem;
  margin-bottom: 0.55rem;
  border-bottom: 1px dashed var(--border);
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
}
.sss-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 6px;
}
.sss-label  { color: var(--text-faint); }
.sss-value  {
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.sss-value.is-ok   { color: var(--success); }
.sss-value.is-warn { color: var(--warn); }
.sss-value.is-bad  { color: var(--danger); }

/* ═══════════════════════════════════════════════════════════════════════════
   13. SITE NOTES — STATUS TAB INSTRUMENT PANEL (Apr 28 2026)
   Step 6 of the migration. The Status tab on a station detail page used
   to be three category cards (Connection / System / Activity) of plain
   .status-metric rows. This converts it to a flat instrument grid where
   every metric is a tile with mono-numeric value, mono-uppercase label,
   traffic-light borders on threshold breach, and an optional sub-line.
   The command + diagnostic histories drop their card chrome and become
   tabular logs.
   ═══════════════════════════════════════════════════════════════════════════ */

/* The outer .status-grid wrapper is now a column of sections. The actual
   instrument tiles live inside .instrument-grid. */
.status-grid {
  display: flex;
  flex-direction: column;
  gap: 1.2rem;
}

.instrument-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0.65rem;
}

/* Override the original .status-metric rule (line 3025+) which was a
   horizontal label/value strip inside a card. New tile is vertical:
   tiny mono uppercase label on top, big mono numeric value below,
   optional dim mono-ish sub-line. Border-left state strip via .is-* */
.status-metric {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: 0.15rem;
  padding: 0.85rem 0.95rem 0.95rem 1.05rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  position: relative;
  overflow: hidden;
  font-size: inherit;
}
.status-metric:last-child { border-bottom: 1px solid var(--border); }

.status-metric-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 500;
}
.status-metric-value {
  font-family: var(--font-mono);
  font-size: 1.5rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  color: var(--text);
  line-height: 1.1;
  margin-top: 0.2rem;
}
.status-metric-sub {
  display: block;
  font-size: var(--text-mono-sm);
  color: var(--text-dim);
  margin-top: 0.3rem;
  font-family: var(--font-mono);
  letter-spacing: 0.02em;
}

/* Status-section: a labeled block (Commands / Command history / etc.)
   without the card chrome. Reads as a drafting-block heading on top
   of a flat region. */
.status-section {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.status-section-head {
  display: flex;
  flex-direction: column;        /* stacked: title row above meta line */
  align-items: stretch;
  gap: 0.2rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px dashed var(--border);
}
.status-section-head > span:first-child {
  /* title — mono uppercase tracked, drafting-block convention */
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text);
  font-weight: 500;
}
.status-section-meta {
  /* description — a normal sentence under the heading. NOT uppercase,
     NOT tracked; otherwise long sentences read as one stretched ribbon
     across the screen. */
  font-family: var(--font-sans);
  font-size: var(--text-mono-md);
  color: var(--text-dim);
  letter-spacing: 0;
  text-transform: none;
  font-weight: 400;
  line-height: 1.5;
}
.status-section-meta code {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  background: var(--bg);
  border: 1px solid var(--border);
  padding: 1px 5px;
  border-radius: var(--r-xs); /* FND-C05: was 2px off-scale → --r-xs (3px) */
  color: var(--text);
}

/* Two-column layout for command + diagnostic history */
.status-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
@media (max-width: 980px) { .status-split { grid-template-columns: 1fr; } }

/* Action-row inside the Commands section — mirrors .cmd-btn-row but
   without the surrounding card-body padding the original had. */
.cmd-action-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Empty placeholder for cmd-history-list when nothing yet */
.cmd-history-empty {
  padding: 0.85rem 1rem;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--text-faint);
  letter-spacing: 0.04em;
}

/* The cmd-history-row was 2-cell in the old markup; the new markup
   emits 4 cells (id / type / status / time). Section-12 already
   defined the grid, but the .cmd-status semantic state needs colors
   for completed / pending / failed. */
.cmd-status.is-ok   { color: var(--success); }
.cmd-status.is-warn { color: var(--warn); }
.cmd-status.is-bad  { color: var(--danger); }
.cmd-time {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--text-faint);
  letter-spacing: 0.04em;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Station-token block — promoted from a card to a flat section. */
.station-token {
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
  color: var(--text);
  letter-spacing: 0.04em;
  word-break: break-all;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 0.7rem 0.95rem;
  user-select: all;
  -webkit-user-select: all;
  font-variant-numeric: tabular-nums;
}

/* ═══════════════════════════════════════════════════════════════════════════
   15. STATUS TAB — CAMERA-FIRST LAYOUT (Apr 28 2026)
   Most-recent capture as a small-but-prominent hero, vertical rail of
   status chips alongside, commands + history below. Hero is sized to
   match the surrounding chrome rather than dominating the viewport —
   the photo is one element among many, not the whole page.
   ═══════════════════════════════════════════════════════════════════════════ */
.nvr-layout {
  display: grid;
  /* Hero sized to be visually balanced with the chip rail rather than
     overwhelming it. ~360px hero + flexible rail that grids its chips
     into 2-3 columns depending on available width. */
  grid-template-columns: minmax(0, 360px) 1fr;
  gap: 1rem;
  align-items: start;
}
@media (max-width: 760px) {
  .nvr-layout { grid-template-columns: 1fr; }
}
.nvr-hero {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  overflow: hidden;
}
.nvr-img-link { display: block; line-height: 0; }
.nvr-img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
.nvr-img-meta {
  padding: 0.5rem 0.7rem 0.55rem;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--text-dim);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}
.nvr-img-time { color: var(--text); font-weight: 500; }
.nvr-img-file { color: var(--text-faint); }
.nvr-img-empty {
  padding: 4rem 1rem;
  text-align: center;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
  font-style: italic;
}
.nvr-rail {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.5rem;
  align-self: stretch;
}
.nvr-chip {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 0.55rem 0.7rem 0.6rem 0.8rem;
  position: relative;
  overflow: hidden;
}
.nvr-chip.is-ok::before, .nvr-chip.is-warn::before, .nvr-chip.is-bad::before {
  content: ''; position: absolute; top: 0; left: 0; bottom: 0; width: 3px;
}
.nvr-chip.is-ok::before   { background: var(--success); }
.nvr-chip.is-warn::before { background: var(--warn); }
.nvr-chip.is-bad::before  { background: var(--danger); }
.nvr-chip-label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.nvr-chip-val {
  display: block;
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  margin-top: 0.15rem;
}


/* ═══════════════════════════════════════════════════════════════════════════
   16. POST-NVR POLISH (Apr 28 2026)
   Bumps button presence + spreads the semantic palette across surfaces
   that were previously grayscale-only. DK's note: "we barely use all the
   colors" — addressed by promoting state into cmd/diag history rows,
   bigger high-contrast command buttons, and rail-chip value coloring
   when state is non-ok.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Bigger commands buttons — risk colors (.btn-primary / .btn-warn /
   .btn-danger) now carry the visual weight, and bigger size makes them
   read as primary actions on the page rather than chrome. */
.cmd-action-row { gap: 0.6rem; }
.cmd-action-row .btn {
  font-size: var(--t-sm);
  padding: 0.55rem 1.1rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}

/* Rail chip value coloring when state is breached — currently the strip
   on the left signals state but the value text stays default ink. Color
   the value too so it pops against the surrounding chips. */
.nvr-chip.is-warn .nvr-chip-val { color: #8a5e1e; }
.nvr-chip.is-bad  .nvr-chip-val { color: #8a3a30; }
.nvr-chip.is-ok   .nvr-chip-val { color: #3f5630; }

/* Cmd / diag history rows — left border state strip via :has() so the
   row reads as "this command finished OK / this one failed" at a glance.
   Modern browsers (Chrome 105+, Safari 15.4+, Firefox 121+) support
   :has(); older browsers fall back to plain rows (graceful). */
.cmd-history-row { border-left: 3px solid transparent; }
.cmd-history-row:has(.cmd-status.is-ok)   { border-left-color: var(--success); }
.cmd-history-row:has(.cmd-status.is-warn) { border-left-color: var(--warn); }
.cmd-history-row:has(.cmd-status.is-bad)  { border-left-color: var(--danger); }

/* Date-item active state — bump the left strip from primary-soft fill
   to a clear clay border so the palette is visible at the rail level. */
.date-item.active {
  border-left: 3px solid var(--primary);
  padding-left: calc(0.85rem - 3px);
}


/* ═══════════════════════════════════════════════════════════════════════════
   17. STATUS TAB — NVR FILMSTRIP (Apr 28 2026)
   Horizontal strip of the day's recent captures below the hero. Each
   cell is a clay-bordered thumbnail linking to the full image. The
   most recent capture (rightmost) gets highlighted so the eye
   completes the connection back to the hero card above it.
   ═══════════════════════════════════════════════════════════════════════════ */
.nvr-filmstrip-wrap {
  margin-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}
.nvr-filmstrip-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.6rem;
  padding-bottom: 0.4rem;
  border-bottom: 1px dashed var(--border);
}
.nvr-filmstrip-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text);
  font-weight: 500;
}
.nvr-filmstrip-more {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.06em;
  color: var(--primary);
  cursor: pointer;
  border-bottom: 1px dotted var(--primary);
  text-transform: uppercase;
  text-decoration: none;
}
.nvr-filmstrip-more:hover {
  color: var(--primary-hover);
  border-bottom-style: solid;
}

.nvr-filmstrip {
  display: flex;
  gap: 0.4rem;
  overflow-x: auto;
  padding-bottom: 0.3rem;
  /* Subtle scrollbar styling — no scrollbar in default state on
     macOS/Windows; appears on hover/scroll. */
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
.nvr-filmstrip::-webkit-scrollbar { height: 6px; }
.nvr-filmstrip::-webkit-scrollbar-track { background: transparent; }
.nvr-filmstrip::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 3px;
}

.nvr-filmstrip-cell {
  flex-shrink: 0;
  width: 96px;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--surface);
  text-decoration: none;
  position: relative;
  transition: border-color 120ms ease;
}
.nvr-filmstrip-cell:hover { border-color: var(--primary); }
.nvr-filmstrip-cell img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--bg);
}
.nvr-filmstrip-time {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  padding: 0.2rem 0.4rem 0.25rem;
  text-align: center;
  border-top: 1px solid var(--border);
  background: var(--surface);
}

/* The latest capture gets a clay border + filled label so the eye
   connects it to the hero. Same color language as the live-pill. */
.nvr-filmstrip-cell.is-latest {
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary);
}
.nvr-filmstrip-cell.is-latest .nvr-filmstrip-time {
  background: var(--primary-soft);
  color: var(--primary-hover);
  font-weight: 600;
}

/* ═══════════════════════════════════════════════════════════════════════════
   18. PI CONFIG-DRIFT WARNING PILL (Apr 28 2026)
   Hi-vis warn variant of .live-pill, shown next to a station's name when
   the Pi's reported camera config has diverged from the server's
   expected pi_config (versions match → it's drift, not a pending push).
   Clicking 're-sync' fires resyncStationConfig() which calls the same
   POST /api/stations/<sid>/pi-config endpoint as Save station settings,
   bumping config_version and queuing an update_config command.
   ═══════════════════════════════════════════════════════════════════════════ */
.drift-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 500;
  padding: 0.2rem 0.55rem;
  background: var(--warn-soft);
  color: #6b4818;
  border: 1px solid var(--warn);
  border-radius: var(--r-sm);
  vertical-align: middle;
  margin-left: 0.5rem;
  position: relative;
  top: -2px;
}
.drift-pill-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--warn);
  box-shadow: 0 0 0 2px rgba(212, 148, 63, 0.25);
  animation: live-pulse 2s ease-in-out infinite;
}
.drift-pill-cta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--primary);
  text-decoration: none;
  border-bottom: 1px dotted var(--primary);
  padding-bottom: 1px;
  margin-left: 0.3rem;
  cursor: pointer;
}
.drift-pill-cta:hover {
  color: var(--primary-hover);
  border-bottom-style: solid;
}
@media (prefers-reduced-motion: reduce) {
  .drift-pill-dot { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   19. ADMIN BRANDING SECTION (Apr 28 2026)
   2-column layout: current logo preview on the left, file picker + upload
   button on the right. Lives in the Branding card on /admin/users.
   ═══════════════════════════════════════════════════════════════════════════ */
.branding-row {
  display: grid;
  grid-template-columns: minmax(0, 320px) 1fr;
  gap: 1.5rem;
  align-items: start;
}
@media (max-width: 720px) {
  .branding-row { grid-template-columns: 1fr; }
}
.branding-current {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.form-field-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  font-weight: 500;
}
.branding-preview-frame {
  border: 1px dashed var(--border);
  border-radius: var(--r-sm);
  padding: 1rem;
  background: var(--bg);
  min-height: 90px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.branding-preview-frame img {
  max-height: 96px;
  max-width: 100%;
  height: auto;
  width: auto;
  display: block;
}
.branding-upload {
  display: flex;
  flex-direction: column;
}

/* ═══════════════════════════════════════════════════════════════════════════
   20. LOGO INVERT IN LIGHT MODE (Apr 28 2026)
   When the admin toggles 'Invert logo in light mode' in /admin/users, the
   server writes class="invert-logo-light" onto <body> at render time and
   this rule applies filter: invert(1) to every logo image — but only when
   the active theme is light (data-theme is unset or 'light'). Dark mode is
   intentionally untouched: a logo designed for a dark background already
   reads correctly there.
   ═══════════════════════════════════════════════════════════════════════════ */
body.invert-logo-light img[src^="/branding/logo"] {
  filter: invert(1);
}
[data-theme="dark"] body.invert-logo-light img[src^="/branding/logo"],
html[data-theme="dark"] body.invert-logo-light img[src^="/branding/logo"] {
  filter: none;
}

/* Branding-card preview frames — second frame shows the logo on an ink
   bg so admins can see how it reads in both modes side-by-side without
   actually toggling the theme. */
.branding-preview-frame-dark {
  margin-top: 0.5rem;
  background: var(--text);
}
.branding-preview-frame-dark img {
  /* Mirror the live invert behavior in the dark preview when the toggle
     is OFF: dark-mode page shows the logo as-uploaded. So the dark
     preview is a flat 'as-uploaded' view regardless of the toggle. */
  filter: none !important;
}
/* Top preview tracks the live light-mode rendering — invert applies if
   the toggle is on, since that's what visitors will see. */
body.invert-logo-light .branding-preview-frame:not(.branding-preview-frame-dark) img {
  filter: invert(1);
}

.branding-toggle-label {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-size: var(--t-sm);
  color: var(--text);
  cursor: pointer;
  user-select: none;
}
.branding-toggle-label input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--primary);
  cursor: pointer;
}
.branding-toggle-label code {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  background: var(--bg);
  border: 1px solid var(--border);
  padding: 1px 4px;
  border-radius: var(--r-xs); /* FND-C05: was 2px off-scale → --r-xs (3px) */
}

/* ═══════════════════════════════════════════════════════════════════════════
   Section 18 — Focus indicators (2026-04-29).

   Pre-this-section, only inputs and the toggle slider had visible focus
   rings. Buttons, tabs, nav items, image cards, video cards, markup cards,
   command-history rows, date items — every other interactive element fell
   through to the platform's default focus indication, which is invisible
   against the aged-paper bg on most browsers.

   :focus-visible (not :focus) means mouse clicks don't trigger the ring;
   only keyboard navigation does. Outline + offset is the simplest, most
   robust approach: works under any background, doesn't fight the single-
   edge card convention (no shadow lift), and disappears cleanly on blur.
   WCAG 2.4.7 (Focus Visible) — Level AA.
   ═══════════════════════════════════════════════════════════════════════════ */

.btn:focus-visible,
.tab-item:focus-visible,
.app-nav-item:focus-visible,
.theme-toggle:focus-visible,
.sidebar-toggle:focus-visible,
.topbar-icon-btn:focus-visible,
.image-card:focus-visible,
.markup-card:focus-visible,
.video-card:focus-visible,
.date-item:focus-visible,
.cmd-history-row:focus-visible,
.activity-item:focus-visible,
.project-card:focus-visible,
.station-card:focus-visible,
.filter-chip:focus-visible,
.ss-preset:focus-visible,
.showcase-card:focus-visible,
.ann-tool-btn:focus-visible,
.ann-swatch:focus-visible,
.ann-size:focus-visible,
.video-public-toggle:focus-visible,
.image-card-delete:focus-visible,
.cmd-cancel:focus-visible,
a:focus-visible,
[onclick]:focus-visible,
[role="button"]:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  /* Inner 1px backdrop-coloured halo keeps the ring readable against
     elements whose own border is also clay-on-hover. */
  box-shadow: 0 0 0 1px var(--bg);
}
/* Inside .modal: same ring, slightly stronger so the dimmed backdrop
   doesn't wash it out. */
.modal-bg .btn:focus-visible,
.modal-bg .input:focus-visible,
.modal-bg .select:focus-visible,
.modal-bg .textarea:focus-visible,
.modal-bg [role="button"]:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   MAP VIEW — projects map, project-detail stations map, station-pin picker
   (2026-04-30, "Site Map" feature)

   Three surfaces, one visual language:
     • Projects page   — Grid/Map toggle above .projects-layout. Map shows
                         project centroids; hover → tooltip listing stations.
     • Project page    — Grid/Map toggle above .stations-grid. Map shows the
                         pinned stations of one project, zoomed to bbox.
     • Station Settings — Location card with click-to-pin Leaflet picker.

   Tile chrome is tinted via a subtle CSS filter so CartoDB Voyager warms
   slightly toward the aged-paper palette without losing legibility.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Center-top segmented toggle. Mono uppercase, single edge, clay active. */
.view-toggle-row {
  display: flex;
  justify-content: center;
  margin: .5rem 0 1rem;
}
.view-toggle {
  display: inline-flex;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 3px;
  gap: 2px;
  box-shadow: none;
}
.view-toggle-btn {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: .45rem 1.1rem;
  border-radius: calc(var(--r) - 3px);
  cursor: pointer;
  transition: background-color .12s ease, color .12s ease;
}
.view-toggle-btn:hover { color: var(--text); }
/* Active state is a *selection* indicator, not a CTA. Reuse the same soft-clay
   treatment as .app-nav-item.active so clay-saturated CTAs (Run, Save) keep
   their semantic weight in the same field of view (audit m1). */
.view-toggle-btn.is-active {
  background: var(--primary-soft);
  color: var(--primary);
}
.view-toggle-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Map containers — same single-edge treatment as cards. */
.projects-map-wrap,
.project-map-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 240px;
  gap: 1rem;
}
.projects-map,
.project-map {
  position: relative;
  height: 540px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
}
.loc-map {
  position: relative;
  height: 360px;
  margin: .85rem 0;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
}

/* Subtle tile tint — warm Voyager toward aged paper without breaking
   legibility. Dark theme uses CartoDB DarkMatter tiles (designed for dark
   surrounds), so no filter inversion is needed there. Satellite mode
   (Esri photographic tiles) opts out of the warm tint via the
   data-map-layer="satellite" attribute set on <html> by JS — imagery
   stays true-colour. (Audit M6 + satellite-overlay 2026-04-30.) */
.leaflet-tile {
  filter: saturate(0.88) brightness(0.99);
}
[data-theme="dark"] .leaflet-tile,
[data-map-layer="satellite"] .leaflet-tile {
  filter: none;
}

/* Floating Map / Satellite control — top-right corner of every map.
   Styled like .view-toggle but sits over the tile area, so a small
   shadow is allowed (it's a *floating* control, not a card). */
.map-layer-toggle {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 3px;
  display: inline-flex;
  gap: 2px;
  box-shadow: 0 1px 4px rgba(42,38,32,0.18);
  margin: 8px;
}
[data-theme="dark"] .map-layer-toggle {
  box-shadow: 0 1px 4px rgba(0,0,0,0.5);
}
.map-layer-btn {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: .35rem .75rem;
  border-radius: calc(var(--r) - 3px);
  cursor: pointer;
  transition: background-color .12s ease, color .12s ease;
  line-height: 1;
}
.map-layer-btn:hover { color: var(--text); }
.map-layer-btn.is-active {
  background: var(--primary-soft);
  color: var(--primary);
}
.map-layer-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Leaflet attribution + zoom controls — tone to Site Notes. */
.leaflet-control-attribution {
  background: rgba(246, 239, 220, 0.85) !important;
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs) !important;
  color: var(--text-faint) !important;
  letter-spacing: 0.04em;
}
[data-theme="dark"] .leaflet-control-attribution {
  background: rgba(33, 29, 24, 0.88) !important;
  color: var(--text-faint) !important;
}
.leaflet-control-attribution a { color: var(--text-dim) !important; }
.leaflet-control-zoom a {
  background: var(--surface) !important;
  color: var(--text) !important;
  border-color: var(--border) !important;
}
.leaflet-control-zoom a:hover {
  background: var(--surface-2) !important;
}

/* Pulse pin — DivIcon. Three layered spans:
     .map-pin-pulse — animated halo (scale + fade)
     .map-pin-dot   — fixed shape (state-dependent)
     .map-pin-glyph — center glyph for redundant cue
   ok  = filled disc + ✓ glyph (lichen)
   bad = outlined ring + ! glyph (brick)
   Color + shape + glyph are three independent channels — passes the
   Ch 8 redundant-cue rule for color-blind operators. */
.map-pin {
  position: relative;
  width: 28px;
  height: 28px;
}
.map-pin-dot {
  position: absolute;
  inset: 5px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid var(--surface);
  box-sizing: border-box;
}
.map-pin-glyph {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--surface);
  pointer-events: none;
  line-height: 1;
}
.map-pin-pulse {
  position: absolute;
  inset: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  opacity: 0.55;
  animation: mapPinPulse 2.2s ease-out infinite;
}
/* OK: filled disc, lichen, ✓ glyph. */
.map-pin.is-ok .map-pin-dot   { background: var(--success); }
.map-pin.is-ok .map-pin-pulse { background: var(--success); }
/* BAD: outlined ring (transparent fill), brick stroke, ! glyph. The shape
   change — solid vs ring — is the redundant cue independent of hue. */
.map-pin.is-bad .map-pin-dot {
  background: var(--surface);
  border-color: var(--danger);
  border-width: 4px;
}
.map-pin.is-bad .map-pin-pulse { background: var(--danger); }
.map-pin.is-bad .map-pin-glyph { color: var(--danger); }
@keyframes mapPinPulse {
  0%   { transform: scale(0.7); opacity: 0.55; }
  70%  { transform: scale(2.1); opacity: 0; }
  100% { transform: scale(2.1); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .map-pin-pulse { animation: none; opacity: 0.35; transform: scale(1.3); }
}

/* Tooltip shell — Leaflet wraps our HTML in .leaflet-tooltip; override the
   chrome so it matches Site Notes (single-edge bone surface, mono labels).
   Single edge: 1px border, no shadow. Border bumped to --border-hover so the
   tooltip stays legible against any tile colour. */
.leaflet-tooltip.map-tooltip-shell {
  background: var(--surface);
  border: 1px solid var(--border-hover);
  border-radius: var(--r);
  color: var(--text);
  padding: 0;
  box-shadow: none;
  font-family: var(--font-sans);
}
.leaflet-tooltip.map-tooltip-shell::before { display: none; }  /* kill the default arrow */
.map-tooltip {
  padding: .65rem .8rem;
  min-width: 180px;
  max-width: 260px;
}
.map-tooltip-title {
  font-family: var(--font-sans);
  font-size: .85rem;
  font-weight: 500;
  color: var(--text);
  margin-bottom: .15rem;
}
.map-tooltip-sub {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--text-faint);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.map-tooltip-list {
  list-style: none;
  margin: .55rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .25rem;
}
/* Status row: dot + name + mono caps status word. Three channels — colour,
   shape (solid vs ring) and text — so colour-blind operators don't lose
   meaning. Mirrors the .cmd-history-row pattern (Ch 8 redundant-cue rule,
   audit M4). */
.map-tooltip-row {
  display: grid;
  grid-template-columns: 10px 1fr auto;
  align-items: center;
  gap: .5rem;
  font-family: var(--font-sans);
  font-size: .78rem;
  color: var(--text);
}
.map-tooltip-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-faint);
  border: 1px solid transparent;
  box-sizing: border-box;
}
.map-tooltip-row.is-ok  .map-tooltip-dot { background: var(--success); }
/* BAD = ring shape, not filled — redundant with hue. */
.map-tooltip-row.is-bad .map-tooltip-dot {
  background: transparent;
  border: 2px solid var(--danger);
}
.map-tooltip-tag {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.map-tooltip-row.is-ok  .map-tooltip-tag { color: var(--success); }
.map-tooltip-row.is-bad .map-tooltip-tag { color: var(--danger); }

/* Map empty states — when no project / station has a pin yet. */
.map-empty {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 2rem;
  color: var(--text-dim);
}
.map-empty-title {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: .4rem;
}
.map-empty-body {
  font-size: .85rem;
  max-width: 360px;
  line-height: 1.5;
}

/* Side panel listing unpinned projects/stations. */
.projects-map-aside,
#project-map-aside {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: .85rem;
  display: flex;
  flex-direction: column;
  gap: .55rem;
  align-self: start;
  min-height: 0;
  max-height: 540px;
  overflow-y: auto;
}
.map-aside-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.map-aside-list {
  display: flex;
  flex-direction: column;
  gap: .3rem;
}
.map-aside-item {
  appearance: none;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: .5rem .65rem;
  text-align: left;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: .15rem;
  transition: border-color .12s ease;
}
.map-aside-item:hover { border-color: var(--primary); }
.map-aside-name {
  font-family: var(--font-sans);
  font-size: .82rem;
  color: var(--text);
}
.map-aside-meta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  color: var(--text-faint);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.map-aside-hint {
  font-size: var(--text-mono-sm);
  line-height: 1.5;
  color: var(--text-faint);
  border-top: 1px dashed var(--border);
  padding-top: .55rem;
}

/* Station Settings → Location card: editable coordinate inputs + actions.
 * Replaced the read-only label/value grid with proper text inputs so
 * operators can type coordinates directly (in addition to clicking on the
 * map). The inputs are wired to onLocCoordInput() which parses + validates
 * on change and drops the marker. The map's click and drag handlers also
 * write back into the inputs (focus-aware, so they don't clobber what
 * you're typing). */
.loc-coord-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .8rem;
  margin-bottom: .55rem;
}
.loc-coord-input {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: .9rem;
  letter-spacing: -.005em;
}
.loc-readout-hint {
  font-size: var(--text-mono-sm);
  color: var(--text-faint);
  margin: 0 0 .55rem;
  font-style: italic;
}
.loc-actions {
  display: flex;
  gap: .5rem;
  align-items: center;
  flex-wrap: wrap;
}
@media (max-width: 540px) {
  .loc-coord-grid { grid-template-columns: 1fr; }
}

/* Responsive — collapse the side panel below the map on narrow viewports. */
@media (max-width: 880px) {
  .projects-map-wrap,
  .project-map-wrap {
    grid-template-columns: 1fr;
  }
  .projects-map-aside,
  #project-map-aside {
    max-height: none;
  }
  .projects-map,
  .project-map {
    height: 420px;
  }
}

/* ─────────────────────────────────────────────────────────────────────────
 * 19 — Live video feed (2026-05-04)
 *
 * The live-pill in the title row becomes a clickable button when the
 * station has live_stream.enabled. Two states:
 *   .live-pill-btn (idle)     — lichen pulse + clay play triangle
 *   .live-pill-btn.streaming  — clay pulse + clay stop square
 *
 * The overlay anchors below the stats strip by default (compact pane,
 * keeps the rest of the station page visible) and can toggle to
 * full-screen via the fullscreen button. Mono-uppercase chrome to match
 * the Site Notes drafting-instrument feel.
 * ───────────────────────────────────────────────────────────────────── */

button.live-pill-btn {
  /* Inherits .live-pill base styling. Override to make it interactive. */
  cursor: pointer;
  font: inherit;            /* normalize away <button>'s default font */
  letter-spacing: 0.08em;   /* slightly more spaced when it's a CTA */
  padding: 0.2rem 0.55rem 0.2rem 0.5rem;
  transition: background-color 0.12s ease, border-color 0.12s ease,
              color 0.12s ease;
}
button.live-pill-btn:hover {
  background: var(--success);
  color: #fff;
}
button.live-pill-btn:hover .live-pill-dot {
  background: #fff;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.3);
}

.live-pill-icon {
  width: 8px;
  height: 8px;
  display: inline-block;
  vertical-align: -1px;
  color: var(--primary);     /* clay play triangle on lichen ground */
}
button.live-pill-btn:hover .live-pill-icon {
  color: #fff;
}

/* Active-stream state — operator is currently viewing. Click stops. */
button.live-pill-btn.streaming {
  background: var(--primary-soft);
  color: #6e3a25;
  border-color: var(--primary);
}
button.live-pill-btn.streaming .live-pill-dot {
  background: var(--primary);
  box-shadow: 0 0 0 2px rgba(196, 106, 69, 0.30);
}
button.live-pill-btn.streaming .live-pill-icon {
  color: var(--primary);
}
button.live-pill-btn.streaming:hover {
  background: var(--primary);
  color: #fff;
}

/* ── Stream overlay ──────────────────────────────────────────────────── */

.live-overlay {
  /* Compact mode: fixed-position floating panel in the lower-right.
   * Body-attached so it survives station-header re-renders. Doesn't
   * cover the page so operator can keep working below it. */
  position: fixed;
  right: 1.2rem;
  bottom: 1.2rem;
  width: min(720px, calc(100vw - 2.4rem));
  max-height: min(560px, calc(100vh - 2.4rem));
  background: var(--surface);
  border: 1px solid var(--border-hover);
  border-radius: var(--r);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18),
              0 0 0 1px rgba(0, 0, 0, 0.04);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  z-index: 950;          /* below fullscreen (1000), above page chrome */
}
[data-theme="dark"] .live-overlay {
  box-shadow: 0 14px 40px rgba(0, 0, 0, 0.55);
}

/* Full-screen mode — pinned to viewport, dim backdrop for focus.
 * Override every constraint the base compact rule sets (right/bottom
 * anchor, width cap, max-height cap) — `inset: 0` alone wouldn't
 * release the width/height caps. */
.live-overlay.fullscreen {
  position: fixed;
  inset: 0;
  right: 0;
  bottom: 0;
  width: 100vw;
  max-width: none;
  max-height: none;
  height: 100vh;
  z-index: 1000;
  margin: 0;
  border-radius: 0;
  border: none;
  background: rgba(0, 0, 0, 0.92);
  box-shadow: none;
}
[data-theme="dark"] .live-overlay.fullscreen {
  background: rgba(0, 0, 0, 0.96);
}

.live-overlay-head {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0.8rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  flex-wrap: wrap;
}
.live-overlay.fullscreen .live-overlay-head {
  background: rgba(34, 31, 26, 0.82);
  color: #d8cfb6;
  border-bottom-color: rgba(255, 255, 255, 0.08);
}

.live-overlay-title {
  font-weight: 500;
  color: var(--text);
  letter-spacing: 0.1em;
}
.live-overlay.fullscreen .live-overlay-title { color: #ede5ce; }

.live-overlay-spacer { flex: 1; }

.live-overlay-stat {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-mono-sm);
  color: var(--text-dim);
  letter-spacing: 0.04em;
}
.live-overlay-stat .lo-label {
  color: var(--text-faint);
  text-transform: uppercase;
  margin-right: 0.3em;
}
.live-overlay-stat .lo-value { color: var(--text); }
.live-overlay.fullscreen .live-overlay-stat,
.live-overlay.fullscreen .live-overlay-stat .lo-label {
  color: #b8ad97;
}
.live-overlay.fullscreen .live-overlay-stat .lo-value { color: #ede5ce; }

.live-overlay-btn {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.3rem 0.6rem;
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color 0.12s, color 0.12s, border-color 0.12s;
}
.live-overlay-btn:hover {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
.live-overlay-btn.is-close:hover {
  background: var(--danger);
  border-color: var(--danger);
}

.live-overlay-warn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.8rem;
  background: var(--warn-soft);
  color: #6c4615;
  border-bottom: 1px solid var(--warn);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 500;
}
.live-overlay-warn::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--warn);
  flex: none;
  animation: live-pulse 2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .live-overlay-warn::before { animation: none; }
}

.live-overlay-stage {
  position: relative;
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 240px;
  flex: 1;
}
.live-overlay-img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}
.live-overlay.fullscreen .live-overlay-stage {
  flex: 1 1 auto;
}
.live-overlay.fullscreen .live-overlay-img {
  max-height: calc(100vh - 100px);  /* leave room for head + footer */
}

.live-overlay-empty,
.live-overlay-error {
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #b8ad97;
  text-align: center;
  padding: 2rem 1rem;
}
.live-overlay-error { color: #d8a896; }

.live-overlay-foot {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.5rem 0.8rem;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  flex-wrap: wrap;
}
.live-overlay.fullscreen .live-overlay-foot {
  background: rgba(34, 31, 26, 0.82);
  border-top-color: rgba(255, 255, 255, 0.08);
}

/* Profile picker — mono-uppercase pills, low/med/high. Disabled
 * options (above max_profile, or "high" without mains_powered) render
 * dimmed and non-clickable. */
.live-profile-row {
  display: flex;
  gap: 0.35rem;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.live-profile-row .lp-label {
  color: var(--text-faint);
  margin-right: 0.3rem;
}
.live-profile-pill {
  font: inherit;
  padding: 0.25rem 0.55rem;
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color 0.12s, color 0.12s, border-color 0.12s;
}
.live-profile-pill:hover:not([disabled]) {
  border-color: var(--primary);
  color: var(--text);
}
.live-profile-pill.active {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
.live-profile-pill[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}
.live-overlay.fullscreen .live-profile-row .lp-label,
.live-overlay.fullscreen .live-profile-pill {
  color: #b8ad97;
  border-color: rgba(255, 255, 255, 0.18);
}
.live-overlay.fullscreen .live-profile-pill.active {
  color: #fff;
}

/* Compact viewport: head + foot stack neatly on narrow screens. */
@media (max-width: 600px) {
  .live-overlay-head,
  .live-overlay-foot {
    gap: 0.4rem;
    padding: 0.45rem 0.6rem;
  }
  .live-overlay-stat { font-size: var(--text-mono-xs); }
}

/* ─────────────────────────────────────────────────────────────────────────
 * 20 — Mobile (≤480 / ≤380) — added 2026-05-04
 *
 * Mobile-responsive overlay. The original CSS targeted 500/520/600/767 and
 * up; nothing collapsed below 480 except a handful of single-purpose rules.
 * This section is the "Site Notes on a phone" layer: tap-target floor,
 * form collapses, sticky save bar, lightbox bottom rail, live-overlay
 * auto-fullscreen, gallery toolbar wrap, admin tables-as-cards.
 *
 * RULE FOR EDITING: nothing in this section may affect the desktop
 * (≥768) rendering. Anything cross-cutting (utility classes, etc.) gets
 * wrapped in `(pointer: coarse)` so devtools-narrow-on-desktop keeps
 * the slim desktop sizes.
 *
 * STRUCTURE:
 *   20.1  Touch-device baseline (pointer: coarse + ≤767)
 *   20.2  Utility classes (.table-scroll, .sticky-save-bar)
 *   20.3  Full-viewport surface dvh swaps
 *   20.4  ≤480 — phone layout collapses (forms, status, gallery, lightbox, ...)
 *   20.5  ≤380 — small-phone tightening
 *   20.6  Reduced-motion + landscape-orientation tweaks
 * ───────────────────────────────────────────────────────────────────── */

/* 20.1 — Touch-device baseline ──────────────────────────────────────────
 * Bumps every interactive element to a 44pt tap floor on real touch
 * devices. The (pointer: coarse) qualifier means desktop browsers
 * narrow-resized via devtools or split-screen retain their slim
 * desktop sizes — this only fires on phones/tablets.
 */
@media (max-width: 767px) and (pointer: coarse) {
  .btn,
  .btn-sm,
  .live-pill-btn,
  .stats-action-btn,
  .filter-chip,
  .ss-preset,
  .cmp-date-pill,
  .lb-side-btn,
  .ann-tool-btn,
  .tab-item,
  .sub-tab-item,
  .live-profile-pill,
  .live-overlay-btn,
  .cmd-cancel,
  .mobile-dates-toggle,
  .live-pill,
  .input,
  .select,
  textarea {
    min-height: 44px;
  }
  .input,
  .select,
  textarea {
    /* iOS auto-zooms text fields below 16px. Keep body input at 16
     * to defeat the zoom; visual size unchanged via line-height. */
    font-size: max(16px, 0.95rem);
  }
  /* Kill the legacy 300ms tap delay on iOS Safari. */
  button,
  a,
  [role="button"],
  .btn,
  input[type="checkbox"],
  input[type="radio"] {
    touch-action: manipulation;
  }
  /* Pad the tappable inner so the increased min-height doesn't
   * change the visual padding asymmetrically. */
  .btn-sm,
  .stats-action-btn,
  .live-overlay-btn {
    padding-block: max(0.55rem, 0.4rem);
  }
}

/* 20.2 — Utility classes ───────────────────────────────────────────────
 * .table-scroll wraps a wide table in a horizontal scroller so it
 * doesn't blow the viewport. .sticky-save-bar pins a save action to
 * the bottom of a card with safe-area inset padding. */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* Keep border-radius edges clean even with overflow. */
  border-radius: var(--r);
}
.table-scroll > table {
  min-width: 100%;
}

.sticky-save-bar {
  position: sticky;
  bottom: 0;
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding: 0.85rem 1rem
           calc(0.85rem + env(safe-area-inset-bottom, 0px))
           1rem;
  z-index: 5;
  display: flex;
  gap: 0.6rem;
  align-items: center;
  flex-wrap: wrap;
}
.sticky-save-bar > .btn {
  flex: 1 1 auto;
  min-width: 140px;
}

/* 20.3 — Full-viewport surface dvh swaps ───────────────────────────────
 * Mobile Safari shrinks `vh` units when the URL bar collapses, then
 * redraws on tap — visible layout twitch. `dvh` is dynamic-viewport-
 * height and tracks the actual visible rect. Only applies to surfaces
 * that genuinely take over the screen. */
@media (max-width: 767px) {
  .live-overlay.fullscreen {
    height: 100dvh;
    max-height: 100dvh;
  }
  .lightbox-stage,
  .lightbox {
    min-height: 100dvh;
  }
  .login-bg {
    min-height: 100dvh;
  }
}

/* 20.4 — ≤480 phone layout collapses ───────────────────────────────────
 * Per-view rules. Each block calls out the view it targets so this
 * section stays maintainable as the design system evolves. */
@media (max-width: 480px) {

  /* — Shell padding tightens — */
  .app-content { padding: 0.85rem 0.75rem; }
  .app-topbar  { padding: 0.6rem 0.75rem; }
  .page-header { margin-bottom: 1.25rem; }
  .page-title  { font-size: 1.25rem; }

  /* — Login: tighter card on small phones — */
  .login-card,
  .login-pane-form,
  .login-pane-art {
    padding: 1.25rem 1rem;
  }

  /* — Stats strip: stack info + actions vertically so neither
   *   gets squeezed. Keeps mono numerics readable. — */
  .stats-strip-compact {
    grid-template-columns: 1fr;
    gap: 0.85rem;
  }
  .stats-strip-actions {
    border-left: none !important;
    border-top: 1px dashed var(--border);
    padding-left: 0 !important;
    padding-top: 0.85rem;
    flex-direction: row;
  }
  .stats-strip-actions .stats-action-btn {
    flex: 1 1 0;
  }

  /* — Form grid: single-column on phone — */
  .form-grid,
  .form-grid-narrow {
    grid-template-columns: 1fr !important;
  }
  .form-field { margin-bottom: 0.85rem; }

  /* — Schedule fields: 2x2 (start+end on row 1, interval spans
   *   full width on row 2). The .schedule-fields auto-fit grid
   *   would already drop to 2-col on phone, but pinning makes the
   *   layout deterministic and gives interval enough room. — */
  .schedule-fields {
    grid-template-columns: 1fr 1fr !important;
    gap: 0.5rem 0.6rem !important;
  }
  .schedule-fields > .form-field:nth-child(3) {
    grid-column: 1 / -1;
  }

  /* — Settings save bar pins to the bottom of the viewport on
   *   phone so the Save button is always reachable. — */
  .settings-save-bar {
    position: sticky;
    bottom: 0;
    background: var(--surface);
    border-top: 1px solid var(--border);
    margin: 0.85rem -0.75rem -0.85rem;
    padding: 0.85rem 0.75rem
             calc(0.85rem + env(safe-area-inset-bottom, 0px));
    z-index: 6;
  }
  .settings-save-bar .btn {
    width: 100%;
  }

  /* — Status: instrument tiles single column — */
  .instrument-grid,
  .status-metrics {
    grid-template-columns: 1fr !important;
  }

  /* — NVR rail: single column under hero (already collapses
   *   at 760, just gentler gap on phone) — */
  .nvr-rail {
    grid-template-columns: 1fr 1fr !important;
    gap: 0.5rem;
  }

  /* — Commands history: collapse 4-col grid to 2-line card.
   *   Line 1: id + type. Line 2: status + time. — */
  .cmd-history-row {
    grid-template-columns: 56px 1fr !important;
    grid-template-areas:
      "id     type"
      "status time" !important;
    row-gap: 0.25rem;
    padding-block: 0.6rem;
  }
  .cmd-history-row > :nth-child(1) { grid-area: id; }
  .cmd-history-row > :nth-child(2) { grid-area: type; }
  .cmd-history-row > :nth-child(3) { grid-area: status; }
  .cmd-history-row > :nth-child(4) { grid-area: time; justify-self: end; }

  /* — Commands action row: stack vertically, full-width buttons — */
  .cmd-action-row {
    flex-direction: column !important;
    gap: 0.5rem !important;
  }
  .cmd-action-row .btn {
    width: 100%;
    justify-content: center;
  }

  /* — Gallery day toolbar: wrap instead of overflow horizontally — */
  .gallery-day-actions {
    flex-wrap: wrap;
    gap: 0.4rem;
  }
  .gallery-day-actions .btn {
    flex: 0 1 auto;
  }

  /* — Image grid: 2 cols at 360 (was 1 col due to 180 minmax) — */
  .image-grid {
    grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
    gap: 0.45rem;
  }

  /* — Lightbox side rail → bottom horizontal pill bar — */
  .lb-sidebar {
    position: fixed !important;
    top: auto !important;
    left: 0 !important;
    right: 0 !important;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 0.5rem) !important;
    flex-direction: row !important;
    justify-content: center;
    padding: 0.4rem 0.6rem !important;
    background: rgba(34, 31, 26, 0.82);
    border-radius: var(--r);
    margin: 0 0.5rem;
    gap: 0.4rem !important;
    z-index: 30;
  }
  .lb-side-btn {
    flex: 1 1 0;
    min-width: 56px;
    width: auto !important;
  }

  /* — Live overlay: auto-fullscreen on phone (compact mode awkward).
   *   Profile pills wrap if they overflow; head + foot rows stack. — */
  .live-overlay {
    right: 0;
    bottom: 0;
    width: 100vw;
    max-width: none;
    height: 100dvh;
    max-height: 100dvh;
    border-radius: 0;
    border: none;
    box-shadow: none;
  }
  .live-overlay-head,
  .live-overlay-foot {
    flex-wrap: wrap;
    row-gap: 0.5rem;
  }
  .live-profile-row { flex-wrap: wrap; }

  /* — Compare: stack images top-bottom instead of side-by-side — */
  .cmp-stage {
    flex-direction: column !important;
    grid-template-columns: 1fr !important;
  }
  .cmp-half {
    width: 100% !important;
  }
  .cmp-info {
    max-width: 100% !important;
    position: static !important;
    transform: none !important;
    margin-top: 0.4rem;
  }

  /* — Annotation toolbar: two-row layout — */
  .ann-toolbar {
    flex-wrap: wrap;
    row-gap: 0.4rem;
    padding: 0.5rem 0.6rem;
  }
  .ann-tool-group { flex: 0 0 auto; }

  /* — Admin Users: card-per-row — */
  .users-table-wrap .users-table thead {
    /* Hide table head on phone; each cell becomes its own row
     * with a data-label prefix. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }
  .users-table-wrap .users-table,
  .users-table-wrap .users-table tbody,
  .users-table-wrap .users-table tr,
  .users-table-wrap .users-table td {
    display: block;
    width: 100%;
  }
  .users-table-wrap .users-table tr {
    border: 1px solid var(--border);
    border-radius: var(--r);
    margin-bottom: 0.6rem;
    padding: 0.6rem 0.75rem;
    background: var(--surface);
  }
  .users-table-wrap .users-table td {
    padding: 0.2rem 0;
    text-align: left;
    border: none;
  }
  .users-table-wrap .users-table td::before {
    content: attr(data-label);
    display: inline-block;
    min-width: 88px;
    color: var(--text-faint);
    font-family: var(--font-mono);
    font-size: var(--text-mono-sm);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-right: 0.5rem;
  }

  /* — Modals: full-viewport on phone with sticky footer — */
  .modal-bg .modal,
  .modal-bg-wide .modal {
    width: 100vw !important;
    max-width: 100vw !important;
    max-height: 100dvh !important;
    border-radius: 0;
    margin: 0;
  }
  .modal-bg .modal-footer,
  .modal-bg-wide .modal-footer {
    position: sticky;
    bottom: 0;
    padding-bottom: calc(0.85rem + env(safe-area-inset-bottom, 0px));
    background: var(--surface);
  }

  /* — Configurator: dimensions to 2 cols on phone — */
  .cfg-dims {
    grid-template-columns: repeat(2, 1fr) !important;
  }
  .cfg-options {
    grid-template-columns: 1fr !important;
  }

  /* — Marketing landing: clamp hero text + collapse feature grid — */
  .landing-hero-title { font-size: clamp(2rem, 8vw, 2.6rem); }
  .landing-features-grid,
  .landing-howitworks-steps {
    grid-template-columns: 1fr !important;
  }

  /* — Live pill button: a touch more breathing room — */
  .live-pill,
  .live-pill-btn {
    padding: 0.35rem 0.65rem 0.35rem 0.55rem;
  }
}

/* 20.5 — ≤380 small-phone tightening ───────────────────────────────────
 * iPhone SE / Mini territory. Just shaves padding and drops gallery
 * dim-grid + cfg-dims to single column. */
@media (max-width: 380px) {
  .app-content { padding: 0.7rem 0.6rem; }
  .login-card,
  .login-pane-form,
  .login-pane-art {
    padding: 1rem 0.85rem;
  }
  .image-grid {
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
    gap: 0.35rem;
  }
  .cfg-dims {
    grid-template-columns: 1fr !important;
  }
  .nvr-rail {
    grid-template-columns: 1fr !important;
  }
  /* Mono numerics down a notch so 6-digit timestamps don't wrap. */
  .status-metric-value { font-size: 1.25rem; }
}

/* 20.6 — Reduced-motion + landscape ────────────────────────────────────
 * Global prefers-reduced-motion guard below collapses every animation
 * and transition to ~0ms; per-selector blocks elsewhere additionally
 * communicate static fallback state (e.g. dashed border, low opacity).
 * Also trims top padding in phone landscape so the shrinking viewport
 * doesn't eat the page header. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
@media (max-width: 900px) and (orientation: landscape) and (max-height: 500px) {
  .app-topbar     { padding: 0.4rem 0.75rem; }
  .page-header    { margin-bottom: 0.85rem; }
  .stats-strip-compact { padding-block: 0.5rem; }
}

/* ═════════════════════════════════════════════════════════════════════════
 * Section 19 — Station front-page instrument register (2026-05-05)
 * ═════════════════════════════════════════════════════════════════════════
 *
 * The Status detail page was dissolved on 2026-05-05. Its 7-chip rail
 * was promoted to the station front page as a 4×2 grid of pills
 * directly above the gallery. The right-column action stack collapsed
 * to a single full-height "Settings" button (Status was the other half;
 * it's gone). Commands and command/diagnostic history moved into
 * Settings → Maintenance.
 *
 * Three additions over the old strip:
 *   1. Live-pulse dot on the Status pill   (.stat-pulse-dot)
 *   2. Click-Disk-pill popover             (.disk-popover)
 *   3. Threshold sub-lines on banded chips (warn 70 / crit 90, etc.)
 *
 * The .stats-strip-pills already grids 4-wide with auto-flow; rendering
 * 8 children naturally fills 2 rows. No grid override needed beyond the
 * v2 modifier opting into the slightly taller per-pill min-height.
 */

/* Allow traffic-light borders + threshold sub-lines on the front-page
 * pills. The compact strip already strips the standard .stat-card box-
 * shadow; here we add the 3px left strip in the four state classes. */
.stats-strip.stats-strip-compact .stat-card.is-ok   { border-left: 3px solid var(--success); }
.stats-strip.stats-strip-compact .stat-card.is-warn { border-left: 3px solid var(--warn); }
.stats-strip.stats-strip-compact .stat-card.is-bad  { border-left: 3px solid var(--danger); }
/* And tint the value text to match — color redundancy for a11y. */
.stats-strip.stats-strip-compact .stat-card.is-ok   .stat-card-value { color: var(--success); }
.stats-strip.stats-strip-compact .stat-card.is-warn .stat-card-value { color: var(--warn); }
.stats-strip.stats-strip-compact .stat-card.is-bad  .stat-card-value { color: var(--danger); }

/* v2 grid — slightly taller min-height to accommodate the threshold
 * sub-lines without making row 2 (no subs) look short. The existing
 * v1 .stat-card style is reused inside; v2 just opts up the row height. */
.stats-strip-pills-v2 {
  grid-template-columns: repeat(4, minmax(120px, 1fr));
  /* Two rows is implicit via 8 children + 4 columns. */
}
.stats-strip-pills-v2 .stat-card {
  min-height: 48px;
  padding: 0.5rem 0.75rem 0.55rem;
  align-items: center;
}
.stats-strip-pills-v2 .stat-card-sub {
  text-align: right;
  font-size: var(--text-mono-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-top: -0.05rem;
}
@media (max-width: 880px) {
  /* Threshold sub-lines hidden on narrow widths to keep 2-col layouts
   * legible — the color border still communicates the state. */
  .stats-strip-pills-v2 .stat-card-sub { display: none; }
}

/* Live-pulse dot inside the Status pill value. Keyed to staleness:
 *   pulse-ok  → online, gentle 2s lichen pulse
 *   pulse-warn → never checked in, static hi-vis
 *   pulse-bad  → went offline, static brick
 * Pulse animation is identical to .live-pill-dot (Section 12) so the
 * page reads coherently. Honors prefers-reduced-motion. */
.stat-pulse-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  margin-right: 0.4rem;
  vertical-align: middle;
  background: var(--text-faint);
  flex: 0 0 auto;
}
.stat-pulse-dot.pulse-ok {
  background: var(--success);
  animation: stat-pulse 2s ease-in-out infinite;
}
.stat-pulse-dot.pulse-warn { background: var(--warn); }
.stat-pulse-dot.pulse-bad  { background: var(--danger); }
@keyframes stat-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(135, 160, 107, 0.55); }
  50%      { box-shadow: 0 0 0 5px rgba(135, 160, 107, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .stat-pulse-dot.pulse-ok { animation: none; }
}

/* Inline mini disk-bar — replaces the larger ~3px below-value bar with
 * a thinner one nested inside the value cell. The pill's main numeric
 * stays the focus; the bar is a quiet accent. */
.stat-card-bar {
  display: inline-block;
  width: 36px;
  height: 4px;
  border-radius: var(--r-xs); /* FND-C05: was 2px off-scale → --r-xs (3px) */
  background: var(--surface-2);
  margin-left: 0.45rem;
  vertical-align: middle;
  overflow: hidden;
}
.stat-card-bar-fill {
  display: block;
  height: 100%;
  background: var(--success);
  transition: width 200ms ease;
}
.stat-card-bar-fill.warn { background: var(--warn); }
.stat-card-bar-fill.bad  { background: var(--danger); }

/* Disk popover — fixed-position card anchored under the Disk pill on
 * click. Auto-closes on the next document click. */
.disk-popover {
  position: absolute;
  z-index: 60;
  min-width: 220px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: var(--r);
  padding: 0.65rem 0.85rem 0.7rem;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}
.disk-popover-head {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 0.5rem;
}
.disk-popover-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.18rem 0;
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
}
.disk-popover-row .dp-label { color: var(--text-dim); }

/* F-16: admin platform-health popover (re-homed off the Stratum admin gear).
   position:fixed so it stays anchored under the nav button on scroll. */
.health-popover {
  position: fixed;
  z-index: 1400;
  min-width: 230px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: var(--r);
  padding: 0.65rem 0.85rem 0.7rem;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16);
}
.health-popover-head {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 0.5rem;
}
.health-popover .sss-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.2rem 0;
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
}
.disk-popover-row .dp-val   {
  color: var(--text);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}
.disk-popover-foot {
  margin-top: 0.45rem;
  padding-top: 0.4rem;
  border-top: 1px dashed var(--border);
  font-size: var(--text-mono-xs);
  color: var(--text-faint);
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  font-style: italic;
}

/* Solo right-column — when the strip has only one button (Settings),
 * the column expands to align the button to the strip's full height. */
.stats-strip-actions-solo .stats-action-btn {
  flex: 1 1 auto;
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  padding: 0.7rem 0.9rem;
  height: 100%;
}
.stats-strip-actions-solo {
  min-width: 130px;
}

/* Recent-commands collapsible (under the pills, above the tab nav) ───
 * Default-collapsed <details> with a thin drafting-block summary row.
 * On open, the body shows the last 5 commands using the existing
 * .cmd-history-row layout so it's visually consistent with the
 * Maintenance section's history. */
.st-recent-cmds {
  margin: -0.6rem 0 0.85rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  overflow: hidden;
}
.st-recent-cmds[open] { border-color: var(--border-hover); }
.st-recent-cmds-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.55rem 0.85rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.st-recent-cmds-head::-webkit-details-marker { display: none; }
.st-recent-cmds-head::before {
  content: "▸";
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--text-faint);
  margin-right: 0.5rem;
  transition: transform 150ms ease;
}
.st-recent-cmds[open] .st-recent-cmds-head::before { transform: rotate(90deg); }
.st-recent-cmds-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
  flex: 1;
}
.st-recent-cmds-hint {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.st-recent-cmds[open] .st-recent-cmds-hint { display: none; }
.st-recent-cmds-body {
  padding: 0.25rem 0.65rem 0.6rem;
  border-top: 1px dashed var(--border);
}

/* ── Title-row inline Settings button (2026-05-06) ──────────────────────────
 * Sits inline with the station name + LIVE pill in .page-title. Matches the
 * .live-pill visual scale (mono uppercase 10.5px, ~32px tall, vertical-
 * centered to the title baseline via top:-2px) so the eye reads the row as
 * a single coherent cluster rather than a heading + a stranded button.
 *
 * Clay tint per the design system convention "clay = the place you change
 * things" (Section "When to use which" in docs/design-system.md). Soft-tint
 * at rest, fills solid on hover, locks solid when the Settings detail page
 * is active.
 *
 * The .page-title was previously a plain inline-element flow; we now turn
 * it into an inline-flex row with consistent gap so name / LIVE / drift /
 * settings all align on the same baseline at any width without margin
 * tweaking each child.
 */
.page-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1.1rem;   /* widened 2026-05-06: name / LIVE / Settings now read as
                    three distinct items with breathing room, not a packed pill cluster */
}
/* Reset the live-pill's hand-tuned margin-left now that gap handles spacing */
.page-title .live-pill,
.page-title .live-pill-btn,
.page-title .drift-pill {
  margin-left: 0;
}
/* LIVE + Settings: pixel-locked to the same height (30px) and font (12px)
 * so they're visually identical regardless of inherited line-height from
 * the parent .page-title. Padding is horizontal-only — vertical centering
 * comes from the fixed height + flex align. */
.page-title .live-pill,
.page-title .live-pill-btn,
.title-settings-btn {
  height: 30px;
  padding: 0 0.75rem;
  font-size: var(--text-mono-md);
  line-height: 1;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  top: -1px;
  position: relative;
}
.page-title .live-pill-dot {
  width: 7px;
  height: 7px;
}
.page-title .live-pill-icon {
  width: 11px;
  height: 11px;
}

.title-settings-btn {
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 500;
  background: var(--primary-soft);
  color: var(--primary);
  border: 1px solid var(--primary);
  border-radius: var(--r-sm);
  cursor: pointer;
  vertical-align: middle;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
.title-settings-btn svg {
  width: 13px;
  height: 13px;
  flex: 0 0 auto;
}
.title-settings-btn:hover {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
.title-settings-btn.active {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
.title-settings-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Mobile: keep the cluster compact. The title can wrap, but the button
 * should never split below the title on narrow screens — it stays on the
 * right of the name (or wraps as a unit). */
@media (max-width: 540px) {
  .page-title { gap: 0.75rem; }
  .page-title .live-pill,
  .page-title .live-pill-btn,
  .title-settings-btn {
    height: 26px;
    font-size: var(--text-mono-sm);
    padding: 0 0.6rem;
  }
  .title-settings-btn svg { width: 11px; height: 11px; }
}

/* ─────────────────────────────────────────────────────────────────────────
   Section 19 — BIM Compare MVP (2026-05-11).

   The BIM tab on station detail (5th tab next to Gallery / Moments /
   Markups / Videos) plus the project-level BIM management modal.
   Both surfaces share the design-system tokens; recipes lean on the
   instrument-tile / chip-rail conventions documented in
   docs/design-system.md so the BIM surface visually matches the
   rest of the station page. Viewer chrome (P2.3+) extends these
   primitives — every name prefixed `bim-`.
   ───────────────────────────────────────────────────────────────────────── */

.bim-tab {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  margin-top: 1rem;
}
.bim-tab-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.bim-tab-title {
  margin: 0;
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text);
}
.bim-tab-meta {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  align-items: center;
}
.bim-meta-pill {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.25rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text);
}
.bim-meta-pill.is-ok    { color: var(--success); border-color: var(--success); background: var(--success-soft); }
.bim-meta-pill.is-warn  { color: var(--warn);    border-color: var(--warn);    background: var(--warn-soft); }
.bim-meta-pill.is-bad   { color: var(--danger);  border-color: var(--danger);  background: var(--danger-soft); }
.bim-meta-pill-faint    { color: var(--text-faint); }
.bim-meta-pill-warn     { color: var(--warn); border-color: var(--warn); background: var(--warn-soft); }

.bim-viewer-host {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  min-height: 480px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  position: relative;
}

.bim-empty {
  padding: 1.5rem;
  text-align: center;
  max-width: 540px;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  align-items: center;
}
.bim-empty-title {
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--text);
}
.bim-empty-body {
  font-size: var(--t-xs);
  color: var(--text-dim);
  line-height: 1.5;
}

/* Modal: BIM model management (project page actions row) */
.bim-current {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-bottom: 0.75rem;
  padding: 0.75rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
.bim-current-row {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  font-size: var(--t-xs);
}
.bim-current-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  align-self: center;
}
.bim-current-value { color: var(--text); }
.bim-current-value.mono { font-family: var(--font-mono); font-size: var(--t-xs); }

.bim-upload-progress {
  margin: 0.6rem 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.bim-upload-progress-bar {
  height: 6px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  overflow: hidden;
}
.bim-upload-progress-bar-fill {
  height: 100%;
  width: 0%;
  background: var(--primary);
  transition: width 120ms linear;
}
.bim-upload-progress-meta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  color: var(--text-dim);
}
.bim-modal-error {
  margin-top: 0.5rem;
  padding: 0.55rem 0.75rem;
  border-radius: var(--r-sm);
  background: var(--danger-soft);
  color: var(--danger);
  font-size: var(--t-xs);
}

/* Viewer chrome — overlaid on the three.js canvas */
.bim-viewer-toolbar {
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.55rem;
  background: rgba(246, 239, 220, 0.92);  /* surface @ 92% */
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  backdrop-filter: blur(6px);
  z-index: 4;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.06em;
}
.bim-viewer-btn {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.3rem 0.55rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
.bim-viewer-btn:hover { background: var(--primary-soft); border-color: var(--primary); color: var(--primary); }
.bim-viewer-toolbar-sep {
  width: 1px;
  height: 14px;
  background: var(--border);
}
.bim-viewer-toolbar-label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.1em;
  color: var(--text-faint);
  text-transform: uppercase;
}
.bim-viewer-select {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  padding: 0.25rem 0.4rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text);
}
.bim-viewer-toolbar-stats {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

/* Loader (shown until the viewer is mounted) */
.bim-loader {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  align-items: stretch;
  width: 360px;
  max-width: 80%;
  padding: 1.5rem;
}
.bim-loader-bar {
  height: 6px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  overflow: hidden;
}
.bim-loader-bar-fill {
  height: 100%;
  width: 0%;
  background: var(--primary);
  transition: width 200ms linear;
}
.bim-loader-meta {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.04em;
  color: var(--text-dim);
  text-align: center;
}

/* ─── Tab head actions row (Re-calibrate button) ──────────────────────── */
.bim-tab-actions {
  display: flex;
  gap: 0.4rem;
  align-items: center;
}

/* ── Section 19: skeleton loader ────────────────────────────────────────
   Site Notes loading state. Plain "Loading…" text leaves operators on
   flaky 4G guessing whether the page is broken or just slow. A pulsing
   skeleton on the same surface confirms work is in-flight and gives
   the eye somewhere stable to rest while waiting.

   Usage: drop in <div class="skeleton" style="height:1rem;width:60%"></div>
   anywhere a request result will land. Honours prefers-reduced-motion
   per the rest of the system. */
.skeleton {
  background: var(--surface-2);
  background-image: linear-gradient(
    90deg,
    var(--surface-2) 0%,
    color-mix(in oklab, var(--surface-2) 80%, var(--border) 20%) 50%,
    var(--surface-2) 100%
  );
  background-size: 200% 100%;
  border-radius: var(--r-sm);
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; opacity: 0.6; }
}
.skeleton-row { height: 0.9rem; margin: 0.5rem 0; }
.skeleton-card {
  height: 6.5rem;
  margin: 0.6rem 0;
  border: 1px solid var(--border);
  background: var(--surface);
  /* No animated stripe on the outer card; the inner stripes do the
     work. Keeping the border so the surface still feels like a card. */
  animation: none;
}
.skeleton-stack { padding: 0.85rem 1.1rem; }
.skeleton-stack .skeleton-row + .skeleton-row { margin-top: 0.5rem; }

/* ────────────────────────────────────────────────────────────────────────
   19. SUPER DASHBOARD (Phase 1 of IA redesign — 2026-05-19)
   ──────────────────────────────────────────────────────────────────────── */
/* New workspace-home surface above projects. Layout: page head + 4-tile
   KPI strip + two-col (activity left, fleet map right) + footer CTA.
   Reuses existing tokens, .activity-item, .card. New classes scoped
   .dashboard-* so the Vite hot-reload + selector specificity stays clean. */
.dashboard-view { display: block; padding-bottom: 60px; }

.dashboard-head {
  display: flex; align-items: baseline; gap: 14px;
  margin: 4px 0 18px;
}
.dashboard-head .page-title { font-size: 1.5rem; font-weight: 500; letter-spacing: -0.02em; margin: 0; }
.dashboard-asof {
  margin-left: auto;
  font-family: var(--font-mono); font-size: 11px;
  color: var(--text-faint); letter-spacing: 0.04em;
}

/* KPI strip — four instrument tiles, single row, single-edge composite */
.dashboard-kpi-strip {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
  margin-bottom: 22px;
}
.dashboard-kpi-strip > .kpi {
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 14px 18px;
  position: relative;
}
.dashboard-kpi-strip > .kpi:not(:last-child) { border-right: 0; }
.dashboard-kpi-strip > .kpi:first-child { border-radius: var(--r) 0 0 var(--r); }
.dashboard-kpi-strip > .kpi:last-child  { border-radius: 0 var(--r) var(--r) 0; }
.dashboard-kpi-strip > .kpi.is-ok::before,
.dashboard-kpi-strip > .kpi.is-warn::before,
.dashboard-kpi-strip > .kpi.is-bad::before {
  content: ""; position: absolute; left: 0; top: 8px; bottom: 8px;
  width: 3px; border-radius: 0 2px 2px 0;
}
.dashboard-kpi-strip > .kpi.is-ok::before   { background: var(--success); }
.dashboard-kpi-strip > .kpi.is-warn::before { background: var(--warn); }
.dashboard-kpi-strip > .kpi.is-bad::before  { background: var(--danger); }
.dashboard-kpi-strip .kpi .label {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-faint);
}
.dashboard-kpi-strip .kpi .val {
  font-family: var(--font-mono); font-weight: 500; font-size: 1.55rem;
  letter-spacing: -0.01em; line-height: 1.1; margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
.dashboard-kpi-strip > .kpi.is-warn .val { color: var(--warn); }
.dashboard-kpi-strip > .kpi.is-bad  .val { color: var(--danger); }
.dashboard-kpi-strip .kpi .sub {
  font-family: var(--font-mono); font-size: 11px; color: var(--text-faint);
  letter-spacing: 0.03em; margin-top: 4px;
}

/* Two-col activity + map */
.dashboard-twocol {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 18px;
  margin-bottom: 22px;
}
.dashboard-activity-card,
.dashboard-map-card { display: flex; flex-direction: column; min-height: 380px; }
.dashboard-activity-card .activity-list {
  max-height: 300px;
  overflow-y: auto;
}
.dashboard-activity-card .card-header {
  padding: 0.85rem 1.1rem;
  border-bottom: 0;
}
.dashboard-map-card { padding: 0; overflow: hidden; }
.dashboard-map-card .card-header {
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--border);
}
.dashboard-card-meta {
  font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-faint); letter-spacing: 0.04em;
}
.dashboard-map-inner { flex: 1; min-height: 320px; background: var(--surface-2); }
.dashboard-map-inner.leaflet-container { background: var(--surface-2); }
.dashboard-empty {
  padding: 18px 22px; color: var(--text-faint);
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.02em;
  /* FND-B04/FND-PERF02: empty/loading state must reserve the eventual map height
     (~320px) so the late hydration swap doesn't collapse + push the page (was
     contributing to dashboard CLS 0.282). */
  min-height: 320px;
}

/* Footer CTA — keeps the dashboard from dead-ending */
.dashboard-foot { display: flex; justify-content: flex-end; }
.dashboard-cta {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  border: 1px solid var(--border); border-radius: var(--r);
  background: var(--surface);
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim);
  transition: all 120ms;
}
.dashboard-cta:hover {
  border-color: var(--primary); color: var(--primary);
  text-decoration: none;
}

/* Live pill (same as station header — replicating so we don't break the
   existing rule by widening its scope). */
.dashboard-head .live-pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--success);
  padding: 2px 8px;
  border: 1px solid var(--success);
  border-radius: 999px;
  background: var(--success-soft);
}
.dashboard-head .live-pill-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--success);
  animation: dash-live-pulse 2s ease-in-out infinite;
}
@keyframes dash-live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .dashboard-head .live-pill-dot { animation: none; } }

/* Responsive: collapse to single col below 880px */
@media (max-width: 880px) {
  .dashboard-kpi-strip { grid-template-columns: repeat(2, 1fr); }
  .dashboard-kpi-strip > .kpi:nth-child(2) { border-right: 1px solid var(--border); border-radius: 0 var(--r) 0 0; }
  .dashboard-kpi-strip > .kpi:nth-child(3) { border-top: 0; border-radius: 0 0 0 var(--r); }
  .dashboard-kpi-strip > .kpi:nth-child(4) { border-top: 0; border-radius: 0 0 var(--r) 0; }
  .dashboard-twocol { grid-template-columns: 1fr; }
}

/* PROJECTS grid — Bug 2 (2026-05-20): the dashboard projects band sits
   between the activity/map two-col and the footer CTA. Each card is a
   single-edge .project-card shell with a 3px health-strip on the left,
   a 16:9 thumbnail, a project-name + meta line, and a feature-badges
   row. Click anywhere → nav('/project/<id>'). Mockup reference:
   mockups/redesign-2026-05/01-super-dashboard.html lines 342–423. */
.dashboard-projects-section { margin-bottom: 22px; }
.dashboard-projects-head {
  display: flex; align-items: baseline; gap: 14px;
  margin: 0 0 12px;
}
.dashboard-projects-title {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin: 0;
  color: var(--text-dim);
}
.dashboard-projects-head .dashboard-card-meta { margin-left: auto; }

.dashboard-projects-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
}

.dashboard-projects-grid .dash-project-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
  transition: border-color 120ms;
  padding: 0;
}
.dashboard-projects-grid .dash-project-card:hover {
  border-color: var(--primary);
}

/* 3px health strip flush against the left edge — paired with text so
   colour is never the only signal (per ISA-101 / a11y). */
.health-strip {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  z-index: 1;
}
.health-strip.health-ok   { background: var(--success); }
.health-strip.health-warn { background: var(--warn); }
.health-strip.health-bad  { background: var(--danger); }
.health-strip.health-cold { background: var(--text-faint); }

.dashboard-projects-grid .dash-project-card .pc-body {
  display: flex; flex-direction: column;
  padding-left: 3px;  /* leave room for the health strip */
}

.dashboard-projects-grid .dash-project-card .thumb {
  aspect-ratio: 16 / 9;
  background-color: var(--surface-2);
  background-size: cover;
  background-position: center;
  border-bottom: 1px solid var(--border);
}

.dashboard-projects-grid .dash-project-card .pc-info {
  padding: 10px 12px 12px;
  display: flex; flex-direction: column; gap: 4px;
}
.dashboard-projects-grid .dash-project-card .pc-name {
  font-size: 0.95rem; font-weight: 500; color: var(--text);
  letter-spacing: -0.01em;
}
.dashboard-projects-grid .dash-project-card .pc-meta {
  font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-faint); letter-spacing: 0.03em;
  font-variant-numeric: tabular-nums;
}
.dashboard-projects-grid .dash-project-card .pc-feats {
  display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px;
}
.dashboard-projects-grid .dash-project-card .feat-badge {
  display: inline-flex; align-items: center;
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.08em;
  padding: 2px 6px;
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text-dim);
  background: var(--surface-2);
}
.dashboard-projects-grid .dash-project-card .feat-badge.ai {
  color: var(--success); border-color: var(--success);
  background: var(--success-soft);
}
.dashboard-projects-grid .dash-project-card .feat-badge.gs {
  color: var(--primary); border-color: var(--primary);
  background: var(--primary-soft);
}
.dashboard-projects-grid .dash-project-card .feat-badge.alert {
  color: var(--warn); border-color: var(--warn);
  background: var(--warn-soft);
}
.dashboard-projects-grid .dash-project-card.health-bad .feat-badge.alert {
  color: var(--danger); border-color: var(--danger);
  background: var(--danger-soft);
}
.dashboard-projects-grid .dash-project-card.health-cold .feat-badge.alert {
  color: var(--text-faint); border-color: var(--border);
  background: var(--surface-2);
}

/* Project-level Gallery (Gap 1 of the 2026-05-20 IA recovery plan).
   Day section + station strip + thumbnail row. Same drafting-block
   palette as the rest of section 19. */
.pg-day { margin: 24px 0; }
.pg-day-label { font-family: var(--font-mono); font-size: 10.5px;
                letter-spacing: 0.08em; text-transform: uppercase;
                color: var(--text-faint); margin: 0 0 10px; }
.pg-station-strip { display: flex; gap: 12px; align-items: flex-start;
                    margin-bottom: 14px; }
.pg-station-name { flex: 0 0 160px; font-family: var(--font-mono);
                   font-size: 12px; color: var(--text-dim);
                   padding-top: 6px; }
.pg-thumbs { display: flex; gap: 8px; overflow-x: auto;
             flex: 1; min-width: 0; }
.pg-thumb { flex: 0 0 96px; height: 72px; background: var(--surface-2);
            background-size: cover; background-position: center;
            border: 1px solid var(--border); border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
            cursor: pointer; transition: border-color 0.15s; padding: 0; }
.pg-thumb:hover { border-color: var(--primary); }
.pg-more { flex: 0 0 auto; align-self: center; font-family: var(--font-mono);
           font-size: 11px; color: var(--text-dim);
           text-decoration: none; padding: 0 12px; }
.pg-more:hover { color: var(--primary); }
.pg-empty { padding: 48px; text-align: center; color: var(--text-dim);
            background: var(--surface); border: 1px solid var(--border);
            border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */ }

.reports-grid {
  display: grid;
  grid-template-columns: minmax(280px, 0.9fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 16px;
}
.report-panel { min-height: 260px; }
.report-form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 12px;
  padding: 14px;
}
.report-form label {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.report-form .input { width: 100%; }
.report-wide { grid-column: 1 / -1; }
.report-check {
  flex-direction: row !important;
  align-items: center;
  text-transform: none !important;
  letter-spacing: 0 !important;
  font-family: var(--font-sans) !important;
  font-size: 12px !important;
  color: var(--text-dim) !important;
}
.report-list { display: flex; flex-direction: column; }
.report-row {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 12px 14px;
  border-top: 1px solid var(--border);
  transition: background 120ms ease;
}
.report-row:first-child { border-top: 0; }
/* Visible hover state when the row is interactive (rendered as <button> or with onclick).
   (Audit 2026-05-27 P2-T3: station rows had no visible hover affordance.) */
button.report-row:hover,
a.report-row:hover,
.report-row[onclick]:hover { background: var(--surface-2); cursor: pointer; }
.report-row-title { font-size: 13.5px; font-weight: 500; color: var(--text); }
.report-row-meta,
.report-narrative {
  font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-faint); letter-spacing: 0.03em;
  margin-top: 3px;
}
.report-narrative {
  font-family: var(--font-sans);
  letter-spacing: 0;
  line-height: 1.45;
  max-width: 62ch;
}
.project-action-queue {
  display: grid;
  gap: 0;
  padding: 0;
  overflow: hidden;
  /* FND-B04: reserve height so the queue doesn't shove when items hydrate */
  min-height: 180px;
}
/* FND-B04: ph-roster / ph-deviation / ph-features placeholders need height so
   the loaded card swap doesn't collapse + reflow the page (projhome CLS 0.756). */
#ph-roster,
#ph-deviation,
#ph-deviation-body,
#ph-features {
  min-height: 220px;
}
.project-action-queue .report-row,
.site-automation-action-row {
  width: 100%;
  border: 0;
  border-top: 1px solid var(--border);
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.project-action-queue .report-row:first-child,
.site-automation-action-row:first-of-type {
  border-top: 0;
}
.project-action-queue .report-row:hover,
.site-automation-action-row:hover {
  background: color-mix(in oklch, var(--primary-soft) 30%, transparent);
}
.report-chip {
  align-self: flex-start;
  font-family: var(--font-mono); font-size: 9.5px;
  text-transform: uppercase; letter-spacing: 0.08em;
  border: 1px solid var(--border); border-radius: 3px;
  color: var(--text-dim); padding: 2px 6px;
  white-space: nowrap;
}
@media (max-width: 900px) {
  .reports-grid { grid-template-columns: 1fr; }
}

/* ────────────────────────────────────────────────────────────────────────
   20. THREE-TIER RAIL + CONTEXTUAL SIDEBAR (Phase 2 — 2026-05-19)
   ──────────────────────────────────────────────────────────────────────── */
/* Tier 1 is a 56px icon column sitting flush against the left edge of the
   viewport. It holds the workspace icon, the all-projects icon, an
   ordered list of per-project icons (clay/lichen/brick rotation), the +
   add-project button, and (admin only) the gear icon. Active state is
   a 3px clay strip on the left edge of the active icon. */
.app-rail {
  background: var(--surface-2);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 14px 0 12px;
  gap: 6px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  overflow-x: hidden;
}
.app-rail::-webkit-scrollbar { width: 0; height: 0; }
.app-rail .rail-brand {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  color: var(--primary);
  font-family: var(--font-mono);
  font-weight: 600; font-size: 18px;
  text-decoration: none;
  cursor: pointer;
}
.app-rail .rail-brand:hover { color: var(--primary-hover); }
.app-rail .rail-divider {
  width: 24px; height: 1px;
  background: var(--border);
  margin: 4px 0;
  flex-shrink: 0;
}
.app-rail .rail-spacer { flex: 1; min-height: 8px; }

.app-rail .rail-icon {
  width: 40px; height: 40px;
  border-radius: 7px;
  display: grid; place-items: center;
  position: relative;
  color: var(--text-dim);
  cursor: pointer;
  transition: background 120ms, color 120ms;
  user-select: none;
  text-decoration: none;
  flex-shrink: 0;
}
.app-rail .rail-icon:hover {
  background: var(--surface);
  color: var(--text);
}
.app-rail .rail-icon.active {
  color: var(--text);
  background: var(--surface);
}
.app-rail .rail-icon.active::before {
  content: "";
  position: absolute;
  left: -4px; top: 8px; bottom: 8px;
  width: 3px;
  border-radius: 0 2px 2px 0;
  background: var(--primary);
}
.app-rail .rail-icon.project-icon {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.02em;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-dim);
}
.app-rail .rail-icon.project-icon[data-color="clay"]   { color: var(--primary); }
.app-rail .rail-icon.project-icon[data-color="lichen"] { color: var(--success); }
.app-rail .rail-icon.project-icon[data-color="brick"]  { color: var(--danger); }
.app-rail .rail-icon.project-icon.active {
  border-color: var(--primary);
}
.app-rail .rail-icon svg {
  width: 18px; height: 18px;
  stroke-width: 1.75;
}

/* Tooltip — appears on hover, anchored to the right of the icon, never
   intercepts pointer events. */
.app-rail .rail-tooltip {
  position: absolute;
  left: calc(100% + 8px);
  top: 50%;
  transform: translateY(-50%);
  background: var(--text);
  color: var(--bg);
  padding: 4px 9px;
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 100ms;
  z-index: 50;
}
.app-rail .rail-icon:hover .rail-tooltip { opacity: 1; }

/* Tier 2 sidebar — contextual swap. */
/* When the sidebar is in project context, the header block (replacing the
   workspace brand area) carries the project name + back link. The flag-
   driven items get the same .app-nav-item base; .dot for enabled, .lock
   svg for upsells / unbuilt features. */
.app-sidebar.in-project-context .app-sidebar-brand {
  display: none;  /* project-header replaces the workspace brand */
}
.app-sidebar .project-header {
  padding: 4px 6px 14px;
  border-bottom: 1px dashed var(--border);
  margin: 2px 0 10px;
}
.app-sidebar .project-header .ph-eyebrow {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.app-sidebar .project-header .ph-name {
  font-size: 14px;
  font-weight: 500;
  margin-top: 4px;
  color: var(--text);
  line-height: 1.25;
}
.app-sidebar .project-header .ph-back {
  margin-top: 6px;
}
.app-sidebar .project-header .ph-back a {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  text-decoration: none;
}
.app-sidebar .project-header .ph-back a:hover {
  color: var(--primary);
}

/* Locked nav items — Linear-style faint state + small lock icon at the
   right edge. No hover background (signals click-disabled). */
.app-nav-item.locked {
  color: var(--text-faint);
  cursor: not-allowed;
}
.app-nav-item.locked:hover {
  background: transparent;
  color: var(--text-faint);
}
.app-nav-item.locked .lock {
  margin-left: auto;
  opacity: 0.7;
  stroke-width: 1.8;
}

/* Clay dot indicator at right edge for enabled features. */
.app-nav-item .dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--success);
  margin-left: auto;
  flex-shrink: 0;
}

/* "new" pill (Canvas) — mono caps clay, small. */
.app-nav-item .nav-pill-new {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--primary);
}

/* Nav group divider — same as the workspace shell-nav-label but the
   project sidebar may render multiple groups (Features / Upgrades /
   Owner). The dashed top border separates groups visually. */
.app-sidebar .nav-group-divider {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding: 14px 6px 6px;
  border-top: 1px dashed var(--border);
  margin-top: 6px;
}
.app-sidebar .nav-group-divider:first-of-type {
  border-top: 0;
  margin-top: 12px;
}

/* ────────────────────────────────────────────────────────────────────────
   21. PROJECT HOME + SETTINGS (Phase 3 — 2026-05-19)
   ──────────────────────────────────────────────────────────────────────── */
.project-home,
.project-settings { display: block; padding-bottom: 60px; }

.project-home-head {
  display: flex; align-items: baseline; gap: 14px;
  flex-wrap: wrap;
  margin: 4px 0 18px;
}
.project-home-head .page-breadcrumb-back {
  font-family: var(--font-mono); font-size: 10.5px;
  text-transform: uppercase; letter-spacing: 0.06em;
  padding: 5px 10px; border: 1px solid var(--border); border-radius: 5px;
  background: var(--surface); color: var(--text-dim);
  text-decoration: none; transition: all 120ms; cursor: pointer;
}
.project-home-head .page-breadcrumb-back:hover {
  border-color: var(--primary); color: var(--primary); text-decoration: none;
}
.project-home-head .page-title { font-size: 1.5rem; font-weight: 500; letter-spacing: -0.02em; margin: 0; }
.project-home-head .ph-meta {
  margin-left: auto;
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: 0.04em; color: var(--text-faint);
}
.project-home-head .live-pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--success);
  padding: 2px 8px;
  border: 1px solid var(--success); border-radius: 999px;
  background: var(--success-soft);
}
.project-home-head .live-pill-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--success);
  animation: dash-live-pulse 2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .project-home-head .live-pill-dot { animation: none; }
}

/* 5-pill stats strip (project Home) */
.ph-stats-strip {
  display: grid;
  /* FND-B05: auto-fit minmax wraps to 2-3 rows on mobile so trailing tile isn't clipped */
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 0;
  background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r);
  overflow: hidden;
  margin-bottom: 24px;
  /* FND-B04/FND-PERF02: reserve layout space so async hydration of stat pills
     doesn't reflow the page (was the dominant 0.554 CLS shift @808ms). */
  min-height: 64px;
}
/* FND-B05: collapse to 2 cols on tight phones */
@media (max-width: 600px) {
  .ph-stats-strip { grid-template-columns: repeat(2, 1fr); }
}
.ph-stats-strip .stat-pill {
  padding: 14px 18px;
  display: flex; flex-direction: column; gap: 4px;
  position: relative;
  border-right: 1px solid var(--border);
}
.ph-stats-strip .stat-pill:last-child { border-right: 0; }
.ph-stats-strip .stat-pill .l {
  font-family: var(--font-mono); font-size: 9.5px;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint);
}
.ph-stats-strip .stat-pill .v {
  font-family: var(--font-mono); font-weight: 500;
  font-size: 1.4rem; letter-spacing: -0.01em; line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.ph-stats-strip .stat-pill .s {
  font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-faint); letter-spacing: 0.03em;
}
.ph-stats-strip .stat-pill.warn::before {
  content: ""; position: absolute; left: 0; top: 10px; bottom: 10px;
  width: 3px; background: var(--warn);
}
.ph-stats-strip .stat-pill.warn .v { color: var(--warn); }

/* Features header */
.features-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: 0 0 12px;
}
.features-head h2 {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-dim); margin: 0;
}
.features-head .help {
  font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-faint); letter-spacing: 0.04em;
}
.features-head .help a {
  color: var(--text-dim); border-bottom: 1px dashed var(--border-hover);
}
.features-head .help a:hover { color: var(--primary); border-bottom-color: var(--primary); text-decoration: none; }

/* 6-card features grid (3 columns; collapses to 2 then 1 on narrow widths) */
.features-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
  margin-bottom: 28px;
}
@media (max-width: 1100px) { .features-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 680px) { .features-grid { grid-template-columns: 1fr; } }

.feature-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 16px 18px;
  display: flex; flex-direction: column; gap: 8px;
  min-height: 168px;
  transition: border-color 140ms;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.feature-card:hover { border-color: var(--primary); }
.feature-card .fc-head { display: flex; align-items: center; gap: 8px; }
.feature-card .fc-icon {
  width: 24px; height: 24px; border-radius: 5px;
  background: var(--primary-soft); color: var(--primary-hover);
  display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 12px; font-weight: 600;
}
.feature-card .fc-name {
  font-family: var(--font-mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim);
}
.feature-card .fc-stats {
  font-family: var(--font-mono); font-size: 13px; line-height: 1.6;
  color: var(--text); margin-top: 6px;
}
.feature-card .fc-stats .accent { color: var(--primary-hover); font-weight: 500; }
.feature-card .fc-stats .dim { color: var(--text-faint); }
.feature-card .fc-desc {
  color: var(--text-dim); font-size: 12.5px; line-height: 1.5; margin-top: 6px;
}
.feature-card .fc-empty-msg { font-size: 12.5px; color: var(--text-dim); margin-top: 6px; }
.feature-card .fc-cta { margin-top: auto; padding-top: 10px; }
.feature-card .btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: 5px;
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: 0.04em; text-transform: uppercase;
  border: 1px solid var(--border); background: transparent;
  color: var(--text-dim);
  transition: all 120ms;
  cursor: pointer;
}
.feature-card .btn.primary { border-color: var(--primary); color: var(--primary); }
.feature-card .btn.primary:hover { background: var(--primary); color: #fff; }
.feature-card .btn:hover { border-color: var(--primary); color: var(--primary); }

/* Locked / upsell state */
.feature-card.locked {
  background: linear-gradient(180deg, var(--surface) 0%,
    color-mix(in srgb, var(--surface-2) 50%, var(--surface)) 100%);
}
.feature-card.locked .fc-icon { background: var(--surface-2); color: var(--text-faint); }
.feature-card.locked .fc-name { color: var(--text-faint); }
.feature-card.locked .lock-tag {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 3px;
  background: var(--warn-soft); color: #8b5a18;
  border: 1px solid color-mix(in srgb, var(--warn) 40%, transparent);
}
.feature-card .lock-icon {
  width: 14px; height: 14px; color: var(--text-faint); margin-right: 4px;
}

/* Upsell tooltip on hover */
.feature-tooltip {
  position: absolute; top: 8px; right: 8px;
  background: var(--text); color: var(--bg);
  padding: 6px 10px; border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.04em;
  opacity: 0; transform: translateY(-4px);
  transition: all 140ms;
  pointer-events: none;
  z-index: 10;
  white-space: nowrap;
}
.feature-card.locked:hover .feature-tooltip { opacity: 1; transform: translateY(0); }

/* Section heads (used by stations roster + activity) */
.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: 8px 0 12px;
}
.section-head h2 {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-dim); margin: 0;
}
.section-head .help {
  font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-faint); letter-spacing: 0.04em;
}

/* Stations roster (5-column row: id / name / status / meta / thumb) */
.roster {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r); overflow: hidden;
  margin-bottom: 28px;
}
.roster-row {
  display: grid; grid-template-columns: 86px 1fr 200px 110px 140px;
  gap: 14px; align-items: center;
  padding: 11px 16px;
  border-top: 1px solid var(--border);
  cursor: pointer;
  transition: background 120ms;
}
.roster-row:first-child { border-top: 0; }
.roster-row:hover { background: var(--surface-2); }
.roster-id {
  font-family: var(--font-mono); font-weight: 500; font-size: 12.5px;
  letter-spacing: 0.02em;
}
.roster-name { font-size: 13.5px; }
.roster-name .dim { color: var(--text-dim); }
.roster-status {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em;
}
.roster-status .sd { width: 7px; height: 7px; border-radius: 50%; }
.roster-status .sd.ok { background: var(--success); }
.roster-status .sd.bad { background: var(--danger); }
.roster-status .sd.warn { background: var(--warn); }
.roster-meta {
  font-family: var(--font-mono); font-size: 11px;
  color: var(--text-faint); letter-spacing: 0.03em;
}
.roster-thumb {
  width: 120px; height: 68px;
  background-size: cover; background-position: center;
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  background-color: var(--surface-2);
}

/* Project Settings — feature toggles (Phase 3 — 2026-05-19).
   QA 2026-05-20: original class was .settings-section which collided
   with an older rule at line ~4715 (.settings-section { display: none })
   used by the legacy station-settings drawer. Same specificity, older
   rule won → entire Project Settings page rendered with display:none.
   Renamed to .ps-section* to scope cleanly. */
.ps-section { display: block; margin-bottom: 32px; }
.ps-section-h {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-dim); margin: 0 0 6px;
}
.ps-section-desc {
  color: var(--text-dim); font-size: 13px; line-height: 1.5;
  margin: 0 0 18px;
  max-width: 720px;
}

.feature-toggles {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
}
.ps-panel-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 16px 18px;
}
.ps-panel-focus {
  outline: 2px solid color-mix(in srgb, var(--primary) 38%, transparent);
  outline-offset: 3px;
}
.ps-panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 14px;
}
.ps-panel-head h3 {
  margin: 0 0 4px;
  font-size: 16px;
  font-weight: 500;
}
.ps-panel-head p {
  margin: 0;
  color: var(--text-dim);
  font-size: 12.5px;
  line-height: 1.45;
  max-width: 68ch;
}
.ps-status {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 3px 7px;
  white-space: nowrap;
}
.ps-status.on { color: var(--success); border-color: var(--success); background: var(--success-soft); }
.ps-status.off { color: #8b5a18; border-color: color-mix(in srgb, var(--warn) 40%, transparent); background: var(--warn-soft); }
.ps-form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.ps-form-grid label,
.ps-token-row span {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.ps-form-grid .input,
.ps-token-row .input { width: 100%; }
.ps-inline-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
  align-items: center;
}
/* Inline save-status indicator (UX-parity cheap-fold). */
.ps-save-status {
  font-size: var(--t-sm);
  font-weight: 500;
  margin-left: 4px;
  transition: opacity 120ms ease;
}
.ps-save-status.is-saving { color: var(--text-dim); }
.ps-save-status.is-saved { color: var(--success); }
.ps-save-status.is-error { color: var(--danger); }
.ps-token-row {
  display: grid;
  grid-template-columns: 90px 1fr;
  gap: 10px;
  align-items: center;
  margin-top: 12px;
}
.ps-members-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}
.ps-mini-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 8px;
}
.ps-member-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid var(--border);
}
.ps-member-row:first-of-type { border-top: 0; }
.ps-member-row strong { display: block; font-size: 13px; font-weight: 500; }
.ps-member-row span { display: block; margin-top: 2px; font-size: 11px; color: var(--text-faint); }
@media (max-width: 820px) {
  .ps-form-grid,
  .ps-members-grid,
  .ps-token-row { grid-template-columns: 1fr; }
}
.feature-toggle-row {
  display: grid; grid-template-columns: 1fr 60px; gap: 16px;
  align-items: center;
  padding: 14px 18px;
  border-top: 1px solid var(--border);
}
.feature-toggle-row:first-child { border-top: 0; }
/* G-5 (Anna's-week full-pass audit): when the caller can't manage,
 * the row visually de-emphasises and the switch shows it's locked. */
.feature-toggle-row.ftr-readonly { opacity: 0.7; cursor: not-allowed; }
.feature-toggle-row.ftr-readonly .ftr-switch { cursor: not-allowed; }
.feature-toggle-row.ftr-readonly .ftr-switch input { cursor: not-allowed; }
.feature-toggle-row .ftr-label {
  font-weight: 500; font-size: 14px;
  display: flex; align-items: center; gap: 10px;
  cursor: pointer;
}
.feature-toggle-row .ftr-soon {
  font-family: var(--font-mono); font-size: 9.5px;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 3px;
  background: var(--warn-soft); color: #8b5a18;
  border: 1px solid color-mix(in srgb, var(--warn) 40%, transparent);
}
.feature-toggle-row .ftr-desc {
  color: var(--text-dim); font-size: 12.5px; line-height: 1.5;
  margin-top: 4px; max-width: 560px;
}
.feature-toggle-row .ftr-pricing {
  font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-faint); letter-spacing: 0.03em;
  margin-top: 4px;
}

/* Toggle switch — drafting-log clay accent */
.ftr-switch {
  position: relative; display: inline-block;
  width: 42px; height: 22px;
  cursor: pointer;
}
.ftr-switch input { opacity: 0; width: 0; height: 0; }
.ftr-knob {
  position: absolute; inset: 0;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  transition: background 120ms, border-color 120ms;
}
.ftr-knob::before {
  content: "";
  position: absolute; left: 2px; top: 2px;
  width: 16px; height: 16px;
  background: var(--text-faint);
  border-radius: 50%;
  transition: transform 140ms, background 140ms;
}
.ftr-switch input:checked + .ftr-knob { background: var(--primary-soft); border-color: var(--primary); }
.ftr-switch input:checked + .ftr-knob::before { transform: translateX(20px); background: var(--primary); }
.ftr-switch input:disabled + .ftr-knob { opacity: 0.5; cursor: wait; }

/* ────────────────────────────────────────────────────────────────────────
   22. PROJECT CANVAS (Phase 4 — 2026-05-19)
   ──────────────────────────────────────────────────────────────────────── */
/* Three-pane layout: 220px layer/time sidebar on the left of the content,
   1fr canvas surface on the right. Below 880px collapses to single col. */
.project-canvas-view { display: block; padding-bottom: 28px; }
.canvas-grid {
  display: block;
  min-height: 70vh;
}

.canvas-side {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 14px 14px 16px;
  display: flex; flex-direction: column; gap: 16px;
  position: sticky;
  top: 16px;
  align-self: start;
  max-height: calc(100vh - 32px);
  overflow-y: auto;
}
.canvas-inline-tools {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 10px 12px;
  display: grid;
  grid-template-columns: minmax(150px, 0.8fr) minmax(280px, 1.6fr) minmax(220px, 1fr);
  gap: 14px;
  margin-bottom: 12px;
  align-items: start;
}
.canvas-inline-tools .canvas-side-section {
  min-width: 0;
}
.canvas-inline-tools .canvas-layer-panel {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px;
}
.canvas-inline-tools .layer-row {
  grid-template-columns: 14px minmax(0, 1fr) 34px;
}
@media (max-width: 980px) {
  .canvas-inline-tools { grid-template-columns: 1fr; }
  .canvas-inline-tools .canvas-layer-panel { grid-template-columns: 1fr; }
}
.canvas-side-section { display: flex; flex-direction: column; gap: 8px; }
.canvas-side-h {
  font-family: var(--font-mono); font-size: 9.5px;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-faint);
  padding-bottom: 6px;
  border-bottom: 1px dashed var(--border);
}

.canvas-station-pick {
  padding: 6px 0;
  display: flex; flex-direction: column; gap: 2px;
}
.cv-station-id {
  font-family: var(--font-mono); font-size: 12px; font-weight: 500;
  color: var(--primary); letter-spacing: 0.02em;
}
.cv-station-name { font-size: 13.5px; }
.cv-station-link {
  font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--text-dim);
  display: inline-flex; align-items: center; gap: 4px;
  text-decoration: none;
  margin-top: 4px;
}
.cv-station-link:hover { color: var(--primary); }

/* Layer panel — checkbox rows with active highlighting */
.canvas-layer-panel { display: flex; flex-direction: column; gap: 4px; }
.canvas-layer-panel .layer-row {
  display: grid; grid-template-columns: 14px minmax(0, 1fr) 38px;
  gap: 8px; align-items: center;
  border: 1px solid var(--border);
  padding: 6px 8px; border-radius: 5px;
  background: var(--surface-2);
  color: var(--text-dim);
  cursor: pointer;
  transition: background 100ms;
}
.canvas-layer-panel .layer-row:hover {
  border-color: color-mix(in oklch, var(--primary) 34%, var(--border));
  background: color-mix(in oklch, var(--primary-soft) 22%, var(--surface-2));
}
.canvas-layer-panel .layer-row.locked {
  opacity: 0.55; cursor: not-allowed;
}
.canvas-layer-panel .layer-row.locked:hover { background: transparent; }
.canvas-layer-panel .layer-row.disabled {
  opacity: 0.68;
  cursor: default;
}
.canvas-layer-panel .layer-row.disabled:hover {
  border-color: var(--border);
  background: var(--surface-2);
}
.canvas-layer-panel .layer-check {
  width: 13px; height: 13px; border-radius: 3px;
  border: 1.5px solid var(--border-hover);
  display: grid; place-items: center;
}
.canvas-layer-panel .layer-row.active .layer-check {
  background: var(--primary);
  border-color: var(--primary);
}
.canvas-layer-panel .layer-row.active {
  border-color: color-mix(in oklch, var(--primary) 42%, var(--border));
  background: color-mix(in oklch, var(--primary-soft) 42%, var(--surface));
}
.canvas-layer-panel .layer-check svg { width: 9px; height: 9px; }
.canvas-layer-panel .layer-copy {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.canvas-layer-panel .layer-name {
  font-size: 12.5px; color: var(--text-dim);
  text-align: left;
}
.canvas-layer-panel .layer-detail {
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 9.5px;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.canvas-layer-panel .layer-row.active .layer-name {
  color: var(--text); font-weight: 500;
}
.canvas-layer-panel .layer-opacity {
  font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-faint); text-align: right;
}
.canvas-layer-panel .layer-row.active .layer-opacity { color: var(--primary); }
.canvas-layer-panel .layer-lock { color: var(--text-faint); }

/* Time controls (stub for Phase 4 — full scrubber in Phase 4.5) */
.canvas-time-current {
  font-family: var(--font-mono); font-size: 13px; font-weight: 500;
  color: var(--text);
}
.canvas-time-controls {
  display: flex; gap: 4px;
}
.canvas-time-controls .time-btn {
  flex: 1; padding: 5px;
  border: 1px solid var(--border); background: var(--surface-2);
  border-radius: 5px; color: var(--text-dim);
  font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: 0.04em; text-transform: uppercase;
  transition: all 100ms;
}
.canvas-time-controls .time-btn:not(:disabled):hover {
  border-color: var(--primary); color: var(--primary);
}
.canvas-time-controls .time-btn.active {
  background: var(--primary); color: #fff; border-color: var(--primary);
}
.canvas-time-controls .time-btn:disabled {
  opacity: 0.45; cursor: not-allowed;
}
.canvas-time-note {
  font-family: var(--font-mono); font-size: 10px;
  color: var(--text-faint); letter-spacing: 0.03em;
  line-height: 1.4;
  border-top: 1px dashed var(--border);
  padding-top: 8px;
}
.canvas-time-scrubber {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
  width: 100%;
}
.canvas-time-dock.canvas-scrubber {
  display: grid;
  align-items: stretch;
  height: auto;
  gap: 8px;
}
.canvas-scrubber-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}
.canvas-player-bar {
  align-items: center;
}
.canvas-time-controls {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.time-speed-select {
  min-height: 32px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: var(--surface-2);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 10px;
  padding: 0 8px;
}
.canvas-date-density {
  display: flex;
  align-items: end;
  gap: 2px;
  min-height: 48px;
  padding: 0 2px;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
}
.density-bar {
  /* WCAG 2.5.8 Target Size (AA): >=24px wide hit area via transparent padding;
     visible 10px bar painted into the content box via background-clip so the
     density viz looks identical. Height stays inline-driven by JS so the data
     shape is preserved. */
  flex: 0 0 24px;
  min-width: 24px;
  padding: 0 7px;
  box-sizing: border-box;
  background-clip: content-box;
  border: 0;
  border-radius: 2px 2px 0 0;
  background-color: var(--primary-soft);
  cursor: pointer;
}
.density-bar:hover,
.density-bar.active {
  background-color: var(--primary);
}
.canvas-capture-strip {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  padding-bottom: 2px;
}
.canvas-day-scrub {
  position: relative;
  display: grid;
  gap: 8px;
  padding: 12px 0 4px;
}
.canvas-capture-range {
  width: 100%;
  height: 26px;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  cursor: ew-resize;
}
.canvas-capture-range::-webkit-slider-runnable-track {
  height: 8px;
  border: 1px solid rgba(255,255,255,0.2);
  border-radius: 999px;
  background:
    linear-gradient(90deg, oklch(0.8 0.16 110) 0 var(--capture-progress, 0%), rgba(255,255,255,0.18) var(--capture-progress, 0%) 100%),
    rgba(0,0,0,0.35);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.22), 0 0 24px rgba(190,255,80,0.08);
}
.canvas-capture-range::-moz-range-track {
  height: 8px;
  border: 1px solid rgba(255,255,255,0.2);
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}
.canvas-capture-range::-moz-range-progress {
  height: 8px;
  border-radius: 999px;
  background: oklch(0.8 0.16 110);
}
.canvas-capture-range::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 24px;
  height: 24px;
  margin-top: -9px;
  border: 2px solid rgba(8,8,8,0.82);
  border-radius: 999px;
  background: oklch(0.8 0.16 110);
  box-shadow: 0 0 0 2px rgba(255,255,255,0.72), 0 10px 24px rgba(0,0,0,0.38);
}
.canvas-capture-range::-moz-range-thumb {
  width: 22px;
  height: 22px;
  border: 2px solid rgba(8,8,8,0.82);
  border-radius: 999px;
  background: oklch(0.8 0.16 110);
  box-shadow: 0 0 0 2px rgba(255,255,255,0.72), 0 10px 24px rgba(0,0,0,0.38);
}
.canvas-capture-range:focus-visible {
  outline: none;
}
.canvas-capture-range:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 4px rgba(190,255,80,0.28), 0 10px 24px rgba(0,0,0,0.38);
}
.canvas-timeline-tools {
  display: inline-flex;
  gap: 5px;
  justify-content: flex-end;
}
.canvas-timeline-tools button {
  min-height: 26px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0 9px;
}
.canvas-timeline-tools button.active,
.canvas-timeline-tools button:hover {
  border-color: color-mix(in oklch, var(--primary) 60%, var(--border));
  color: var(--primary);
}
.canvas-scrub-preview {
  position: absolute;
  left: var(--scrub-x, 0%);
  bottom: calc(100% + 8px);
  z-index: 8;
  width: min(172px, 42vw);
  transform: translateX(-50%);
  border: 1px solid color-mix(in oklch, var(--primary) 54%, var(--border));
  border-radius: 7px;
  background: color-mix(in oklch, var(--surface) 92%, oklch(0.08 0.01 70));
  box-shadow: 0 14px 34px rgba(22, 18, 13, 0.32);
  padding: 6px;
  pointer-events: none;
}
.canvas-scrub-preview[hidden] {
  display: none;
}
.canvas-scrub-preview::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -6px;
  width: 10px;
  height: 10px;
  transform: translateX(-50%) rotate(45deg);
  border-right: 1px solid color-mix(in oklch, var(--primary) 54%, var(--border));
  border-bottom: 1px solid color-mix(in oklch, var(--primary) 54%, var(--border));
  background: inherit;
}
.canvas-scrub-preview span {
  display: block;
  aspect-ratio: 16 / 9;
  border-radius: 5px;
  background: var(--surface-2) center / cover no-repeat;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.08);
}
.canvas-scrub-preview b,
.canvas-scrub-preview small {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.canvas-scrub-preview b {
  margin-top: 5px;
  color: var(--text);
  font-size: 11px;
  font-weight: 700;
}
.canvas-scrub-preview small {
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 9.5px;
}
.canvas-scrub-meta {
  display: flex;
  justify-content: space-between;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.canvas-scrub-stage-chip {
  position: absolute;
  left: 50%;
  top: 14px;
  z-index: 9;
  transform: translateX(-50%) translateY(-6px);
  opacity: 0;
  pointer-events: none;
  border: 1px solid color-mix(in oklch, var(--primary) 46%, rgba(255,255,255,0.18));
  border-radius: 999px;
  background: rgba(0,0,0,0.68);
  color: oklch(0.93 0.018 74);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 7px 11px;
  backdrop-filter: blur(6px);
  transition: opacity 120ms ease, transform 120ms ease;
}
.project-canvas-view.scrub-preview-active .canvas-scrub-stage-chip {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.project-canvas-view.scrub-preview-active .canvas-compare-stage,
.project-canvas-view.scrub-preview-active .canvas-layer:not(.canvas-layer-photo),
.project-canvas-view.scrub-preview-active .canvas-markup-editor,
.project-canvas-view.scrub-preview-active .canvas-splat-toolbar,
.project-canvas-view.scrub-preview-active .canvas-splat-info-toggle {
  visibility: hidden;
}
.capture-tick {
  position: relative;
  min-width: 42px;
  width: 42px;
  height: 30px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  background: var(--surface-2);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10px;
  overflow: hidden;
  padding: 0;
}
.capture-tick.marked {
  border-color: var(--warn);
  box-shadow: inset 0 -3px 0 var(--warn);
}
.capture-tick.marked.active {
  border-color: var(--primary);
  box-shadow: inset 0 -3px 0 var(--warn), 0 0 0 1px var(--primary);
}
.capture-tick.preview {
  border-color: color-mix(in oklch, var(--primary) 72%, var(--border));
  box-shadow: 0 0 0 2px color-mix(in oklch, var(--primary) 20%, transparent), inset 0 -3px 0 var(--primary);
}
.capture-tick.preview span {
  filter: saturate(1.1) contrast(1.05);
}
.capture-chapter-marker {
  position: absolute;
  top: 3px;
  right: 3px;
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--warn);
  box-shadow: 0 0 0 2px rgba(26, 24, 20, 0.82);
  z-index: 2;
}
.capture-tick span {
  display: block;
  width: 100%;
  height: 100%;
  background-size: cover;
  background-position: center;
  opacity: 0.82;
}
.capture-tick:hover,
.capture-tick.active {
  border-color: var(--primary);
  color: var(--primary);
  background: var(--primary-soft);
}

/* Main canvas pane */
.canvas-main {
  position: relative;
  display: flex; flex-direction: column;
  min-height: 70vh;
  min-width: 0;
  width: 100%;
}
.canvas-surface {
  flex: 1;
  background: oklch(0.1 0.01 65);
  border: 1px solid var(--border);
  border-radius: var(--r);
  position: relative;
  overflow: hidden;
  min-height: 540px;
}
.canvas-surface.has-media-ratio {
  flex: 0 1 auto;
  align-self: center;
  width: 100%;
  max-width: max(320px, calc((100vh - 260px) * var(--canvas-media-aspect, 1.777)));
  aspect-ratio: var(--canvas-media-ratio, 16 / 9);
  min-height: min(540px, calc(100vh - 330px));
  max-height: calc(100vh - 260px);
}
.canvas-grid-standalone {
  display: block;
}
.canvas-grid-standalone .canvas-main {
  min-height: calc(100vh - 170px);
  background: oklch(0.09 0.01 65);
  border: 1px solid color-mix(in oklch, var(--border) 55%, oklch(0.14 0.016 65));
  border-radius: 8px;
  overflow: hidden;
  position: relative;
}
.canvas-grid-standalone .canvas-inline-tools {
  position: absolute;
  left: 14px;
  top: 14px;
  z-index: 6;
  width: auto;
  max-width: min(360px, calc(100% - 28px));
  background: color-mix(in oklch, oklch(0.08 0.01 65) 82%, transparent);
  border: 1px solid color-mix(in oklch, oklch(0.72 0.05 62) 28%, transparent);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  padding: 10px;
  backdrop-filter: blur(10px);
}
.canvas-grid-standalone .canvas-side-section {
  background: transparent;
  border: 0;
  padding: 0;
}
.canvas-grid-standalone .canvas-side-h {
  color: color-mix(in oklch, oklch(0.86 0.018 75) 72%, transparent);
}
.canvas-grid-standalone .canvas-layer-panel {
  display: flex;
  gap: 8px;
}
.canvas-grid-standalone .layer-row {
  background: color-mix(in oklch, oklch(0.16 0.015 65) 82%, transparent);
  border-color: color-mix(in oklch, oklch(0.72 0.05 62) 35%, transparent);
  color: oklch(0.9 0.012 75);
}
.canvas-grid-standalone .canvas-surface {
  min-height: calc(100vh - 170px);
  border: 0;
  border-radius: 0;
  background: oklch(0.05 0.006 68);
}
.canvas-grid-standalone .canvas-surface.has-media-ratio {
  width: 100%;
  max-width: max(320px, calc((100vh - 170px) * var(--canvas-media-aspect, 1.777)));
  min-height: min(calc(100vh - 170px), 760px);
  max-height: calc(100vh - 170px);
}
.canvas-grid-standalone .canvas-splat-toolbar {
  top: auto;
  right: 14px;
  bottom: 14px;
  z-index: 7;
  max-width: min(520px, calc(100% - 28px));
  background: color-mix(in oklch, oklch(0.07 0.006 68) 78%, transparent);
  border-color: color-mix(in oklch, oklch(0.76 0.055 62) 28%, transparent);
  backdrop-filter: blur(10px);
}
.canvas-grid-standalone .canvas-hud {
  right: auto;
  max-width: min(520px, calc(100% - 28px));
}
.canvas-layer {
  position: absolute; inset: 0;
  pointer-events: none;
  transition: opacity 200ms;
}
.canvas-layer-photo {
  width: 100%; height: 100%;
  object-fit: contain;
  background: #1a1814;
}
.canvas-photo-label {
  position: absolute; bottom: 10px; left: 14px;
  font-family: var(--font-mono); font-size: 10.5px;
  color: rgba(255,255,255,0.85);
  background: rgba(0,0,0,0.55);
  padding: 4px 9px; border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  letter-spacing: 0.04em;
  pointer-events: auto;
  backdrop-filter: blur(4px);
}
.canvas-layer-placeholder {
  display: grid; place-items: center;
  background: rgba(196, 106, 69, 0.06);
}
/* S3.3 — No-capture placeholder on the photo layer */
.canvas-photo-placeholder {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 8px;
  background: #1a1814;
  color: rgba(255,255,255,0.4);
  pointer-events: none;
}
.canvas-photo-placeholder-title {
  font-size: 0.85rem; font-weight: 500;
  color: rgba(255,255,255,0.55);
  letter-spacing: -0.01em;
}
.canvas-photo-placeholder-sub {
  font-family: var(--font-mono); font-size: 11px;
  color: rgba(255,255,255,0.3);
  letter-spacing: 0.04em;
}
.canvas-layer-splat-viewer {
  background: #0f0d09;
  pointer-events: auto;
}
.canvas-splat-frame {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  background: #0f0d09;
}
.canvas-splat-toolbar {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  max-width: calc(100% - 24px);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.82);
  background: rgba(0,0,0,0.62);
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  padding: 7px 10px;
}
.canvas-splat-info-toggle {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 3;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  background: rgba(0,0,0,0.62);
  color: rgba(255,255,255,0.86);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 6px 8px;
  cursor: pointer;
}
.canvas-layer-splat-viewer.splat-info-hidden .canvas-splat-toolbar,
.project-canvas-view.splat-info-hidden .canvas-splat-toolbar {
  display: none;
}
.canvas-layer-splat-viewer:not(.splat-info-hidden) .canvas-splat-info-toggle,
.project-canvas-view:not(.splat-info-hidden) .canvas-splat-info-toggle {
  right: calc(12px + min(360px, 48vw));
}
.canvas-splat-toolbar a {
  color: #f1b28d;
  text-decoration: none;
}
.canvas-splat-toolbar button,
.canvas-splat-select {
  font: inherit;
  color: rgba(255,255,255,0.86);
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  padding: 4px 7px;
}
.canvas-splat-toolbar button {
  cursor: pointer;
}
.canvas-splat-select {
  max-width: min(220px, 32vw);
}
.canvas-ph-msg {
  font-family: var(--font-mono); font-size: 11.5px;
  color: rgba(255, 255, 255, 0.8);
  background: rgba(0, 0, 0, 0.65);
  padding: 8px 14px; border-radius: 5px;
  letter-spacing: 0.04em; line-height: 1.5;
  max-width: 460px; text-align: center;
}
.canvas-ph-sub {
  color: rgba(255, 255, 255, 0.62);
}
.canvas-layer-detections .det-box {
  position: absolute;
  border: 1.5px solid var(--success);
  border-radius: var(--r-xs); /* FND-C05: was 2px off-scale → --r-xs (3px) */
  pointer-events: auto;
}
.canvas-layer-detections .det-box .det-lbl {
  position: absolute; top: -18px; left: -1px;
  background: var(--success); color: #0f0d09;
  font-family: var(--font-mono); font-size: 10px; font-weight: 500;
  padding: 1px 6px; letter-spacing: 0.06em; text-transform: uppercase;
}
.canvas-empty {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: var(--text-faint);
  font-family: var(--font-mono); font-size: 12px;
  letter-spacing: 0.04em;
  background: #1a1814;
  padding: 24px;
  text-align: center;
}

/* HUD chips along the bottom of the canvas */
.canvas-hud {
  position: absolute; bottom: 14px; left: 14px; right: 14px;
  display: flex; gap: 8px; pointer-events: none;
  flex-wrap: wrap;
  z-index: 5;
}
.canvas-hud .hud-chip {
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-family: var(--font-mono); font-size: 10.5px;
  padding: 4px 10px; border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  letter-spacing: 0.06em; text-transform: uppercase;
  backdrop-filter: blur(4px);
}
.canvas-hud button.hud-chip {
  border: 1px solid rgba(255,255,255,0.28);
  cursor: pointer;
  pointer-events: auto;
}
.canvas-hud button.hud-chip:hover {
  background: rgba(168, 87, 48, 0.82);
}
.canvas-viewer-toggles {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 6;
  display: inline-flex;
  gap: 6px;
  pointer-events: auto;
}
.canvas-viewer-toggles button {
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  background: rgba(0,0,0,0.58);
  color: rgba(255,255,255,0.86);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 6px 8px;
  cursor: pointer;
  backdrop-filter: blur(5px);
}
.project-canvas-view.metadata-hidden .canvas-hud,
.project-canvas-view.metadata-hidden .canvas-photo-label {
  display: none;
}

/* Canvas Inspection Workbench */
.canvas-context-top {
  display: grid;
  grid-template-columns: minmax(280px, 0.8fr) minmax(360px, 1.1fr) auto;
  gap: 12px;
  align-items: stretch;
  margin-bottom: 12px;
}
.canvas-context-station .station-context-bar { height: 100%; margin: 0; }
.canvas-context-report { align-self: stretch; white-space: nowrap; }
.canvas-context-actions {
  display: grid;
  grid-template-rows: 1fr 1fr;
  gap: 6px;
  min-width: 164px;
}
.canvas-context-actions .btn {
  width: 100%;
  justify-content: center;
}
.canvas-mode-nav {
  display: grid;
  /* 3 fluid columns for Inspect/Compare/Immersive + 1 auto for the
   * Reset View button on the right. Previously had 3 equal columns
   * which pushed Reset to a second row. */
  grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
  gap: 6px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  padding: 6px;
  align-items: stretch;
}
.canvas-mode-btn {
  min-width: 0;
  border: 1px solid transparent;
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: transparent;
  color: var(--text-dim);
  padding: 8px 10px;
  text-align: left;
  cursor: pointer;
}
.canvas-mode-btn span,
.canvas-mode-btn small { display: block; }
.canvas-mode-btn span { color: var(--text); font-size: 13px; font-weight: 650; }
.canvas-mode-btn small {
  margin-top: 2px;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.canvas-mode-btn:hover,
.canvas-mode-btn.active {
  border-color: color-mix(in oklch, var(--primary) 36%, var(--border));
  background: color-mix(in oklch, var(--primary-soft) 42%, var(--surface));
}
.canvas-mode-btn.active span { color: var(--primary); }
.canvas-mode-btn.locked,
.canvas-mode-btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  background: var(--surface-2);
}
.canvas-mode-btn.locked:hover {
  border-color: var(--border);
  background: var(--surface-2);
}
.canvas-mode-lock {
  display: inline-block;
  vertical-align: -1px;
  margin-left: 6px;
  color: var(--text-faint);
}
.canvas-mode-reset {
  align-self: stretch;
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
}
.canvas-mode-reset:hover { border-color: var(--primary); color: var(--primary); }
.canvas-mode-reset:disabled { opacity: 0.5; cursor: default; }
.canvas-mode-reset.active { border-color: var(--warn); color: var(--warn); }
.canvas-workbench-grid {
  display: grid;
  grid-template-columns: minmax(164px, 180px) minmax(0, 1fr) minmax(280px, 320px);
  gap: 12px;
  align-items: stretch;
}
.project-canvas-view {
  container-type: inline-size;
}
.project-canvas-view.left-collapsed .canvas-workbench-grid {
  grid-template-columns: 44px minmax(0, 1fr) minmax(280px, 320px);
}
.project-canvas-view.inspector-collapsed .canvas-workbench-grid {
  grid-template-columns: minmax(164px, 180px) minmax(0, 1fr) 44px;
}
.project-canvas-view.left-collapsed.inspector-collapsed .canvas-workbench-grid {
  grid-template-columns: 44px minmax(0, 1fr) 44px;
}
.project-canvas-view.markup-open:not(.left-collapsed) .canvas-workbench-grid {
  grid-template-columns: minmax(230px, 260px) minmax(0, 1fr) minmax(280px, 320px);
}
.canvas-left-panel,
.canvas-inspector,
.canvas-time-dock {
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.canvas-left-panel {
  position: sticky;
  top: 14px;
  align-self: start;
  display: grid;
  gap: 14px;
  padding: 12px;
  max-height: calc(100vh - 120px);
  overflow: auto;
  transition: width 160ms ease, padding 160ms ease, opacity 160ms ease;
}
.canvas-panel-rail {
  display: none;
}
.canvas-panel-rail .panel-toggle-btn {
  width: 100%;
  min-height: 34px;
}
.project-canvas-view.left-collapsed .canvas-left-panel {
  padding: 8px;
  overflow: hidden;
}
.project-canvas-view.left-collapsed .canvas-left-panel .canvas-left-rail {
  display: grid;
  gap: 8px;
}
.project-canvas-view.left-collapsed .canvas-left-panel .canvas-side-section:not(:first-child),
.project-canvas-view.left-collapsed .canvas-left-panel .canvas-left-workbench,
.project-canvas-view.left-collapsed .canvas-left-panel .canvas-layer-panel,
.project-canvas-view.left-collapsed .canvas-left-panel .canvas-side-h span {
  display: none;
}
.canvas-stage-column {
  min-width: 0;
  display: grid;
  grid-template-rows: minmax(520px, 1fr) auto;
  gap: 12px;
}
.canvas-stage-column .canvas-main {
  min-height: 560px;
  overflow: hidden;
}
.canvas-stage-column .canvas-surface {
  min-height: 560px;
  max-width: 100%;
  border-radius: 8px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.04), 0 18px 48px -32px rgba(42,37,32,0.68);
}
.canvas-stage-column .canvas-surface.has-media-ratio {
  min-height: min(560px, calc(100vh - 330px));
}
.canvas-time-dock { padding: 10px 12px 12px; }
.canvas-inspector {
  display: flex;
  flex-direction: column;
  min-height: 520px;
  overflow: hidden;
  transition: width 160ms ease, padding 160ms ease, opacity 160ms ease;
}
.project-canvas-view.inspector-collapsed .canvas-inspector {
  min-width: 44px;
}
.project-canvas-view.inspector-collapsed .canvas-inspector-rail {
  display: grid;
  gap: 8px;
  padding: 8px;
}
.project-canvas-view.inspector-collapsed .canvas-inspector-body,
.project-canvas-view.inspector-collapsed .canvas-inspector-head {
  display: none;
}
.canvas-panel-heading,
.canvas-inspector-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.canvas-panel-heading { margin-bottom: 8px; }
.panel-toggle-btn {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 5px 6px;
  cursor: pointer;
}
.panel-toggle-btn:hover { border-color: var(--primary); color: var(--primary); }
.canvas-inspector-head {
  padding: 11px 12px;
  border-bottom: 1px solid var(--border);
}
.canvas-settings-tile {
  gap: 0;
}
.canvas-settings-top,
.canvas-settings-section {
  display: grid;
  gap: 10px;
  padding: 12px;
  border-bottom: 1px solid var(--border);
}
.canvas-settings-top .canvas-mode-nav {
  grid-template-columns: 1fr;
}
.canvas-settings-top .station-context-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 7px;
  min-width: 0;
}
.canvas-settings-top .station-context-main {
  min-width: 0;
}
.canvas-settings-top .station-context-select {
  min-width: 0;
  width: 100%;
}
.canvas-settings-top .station-context-meta {
  justify-self: start;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.canvas-settings-top .canvas-context-actions {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: none;
  min-width: 0;
}
.canvas-settings-top .canvas-context-actions .btn {
  min-height: 36px;
  padding-inline: 8px;
  white-space: normal;
}
.canvas-inspector-head-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.canvas-inspector-head span,
.canvas-inspector-label,
.canvas-inspector-kicker {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.canvas-inspector-body {
  flex: 1;
  overflow: auto;
  display: grid;
  align-content: start;
  gap: 12px;
  padding: 12px;
}
.canvas-inspector-card {
  display: grid;
  gap: 4px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: color-mix(in oklch, var(--surface-2) 66%, var(--surface));
  padding: 10px;
}
.canvas-inspector-card strong {
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--text);
  font-size: 13px;
}
.canvas-inspector-card small,
.canvas-inspector-empty,
.canvas-report-basket,
.canvas-report-result { color: var(--text-dim); font-size: 12px; line-height: 1.4; }
.canvas-inspector-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
}
.canvas-inspector-actions .btn { min-width: 0; justify-content: center; }
.canvas-inspector-section {
  display: grid;
  gap: 8px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: color-mix(in oklch, var(--surface-2) 42%, transparent);
  overflow: hidden;
}
.canvas-inspector-section summary {
  list-style: none;
  cursor: pointer;
  padding: 9px 10px;
  /* WCAG 2.5.8 Target Size (AA): ensure disclosure toggle is >=24px tall. */
  min-height: 24px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.canvas-inspector-section summary::-webkit-details-marker { display: none; }
.canvas-inspector-section summary::after {
  content: "+";
  color: var(--text-faint);
}
.canvas-inspector-section[open] summary::after { content: "-"; }
.canvas-inspector-section-body {
  display: grid;
  gap: 9px;
  padding: 0 10px 10px;
}
.canvas-evidence-list { display: flex; flex-wrap: wrap; gap: 6px; }
.canvas-evidence-list span,
.canvas-evidence-list button {
  display: inline-flex;
  gap: 5px;
  align-items: center;
  border: 1px solid color-mix(in oklch, var(--success) 28%, var(--border));
  border-radius: 999px;
  background: color-mix(in oklch, var(--success-soft) 45%, var(--surface));
  color: var(--text-dim);
  padding: 4px 7px;
  font-family: var(--font-mono);
  font-size: 10px;
  cursor: pointer;
}
.canvas-evidence-list b { color: var(--success); font-weight: 650; }
.canvas-report-result a { color: var(--primary); text-decoration: none; }
.canvas-meta-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  margin: 0;
}
.canvas-meta-grid div {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  padding: 7px;
  background: var(--surface);
}
.canvas-meta-grid dt {
  margin: 0 0 4px;
  font-family: var(--font-mono);
  font-size: 9px;
  text-transform: uppercase;
  color: var(--text-faint);
}
.canvas-meta-grid dd {
  margin: 0;
  font-size: 12px;
  color: var(--text);
  overflow-wrap: anywhere;
}
.canvas-minimap { display: grid; gap: 8px; }
.canvas-minimap-field {
  position: relative;
  height: 180px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background:
    linear-gradient(color-mix(in oklch, var(--border) 45%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in oklch, var(--border) 45%, transparent) 1px, transparent 1px),
    color-mix(in oklch, var(--surface-2) 76%, var(--surface));
  background-size: 28px 28px;
  overflow: hidden;
}
.canvas-map-path {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.canvas-map-path polyline {
  fill: none;
  stroke: color-mix(in oklch, var(--primary) 52%, transparent);
  stroke-width: 1.6;
  stroke-dasharray: 3 2;
  vector-effect: non-scaling-stroke;
}
.canvas-map-pin {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 26px;
  height: 26px;
  border: 1px solid var(--border-hover);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10px;
  cursor: pointer;
}
.canvas-map-pin.active { border-color: var(--primary); background: var(--primary); color: var(--bg); }
.canvas-capture-marker {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 42px;
  height: 42px;
  border: 1px solid color-mix(in oklch, var(--primary) 68%, white);
  border-radius: 999px;
  pointer-events: none;
  box-shadow: 0 0 0 10px color-mix(in oklch, var(--primary-soft) 36%, transparent);
  animation: canvas-marker-pulse 1.8s ease-in-out infinite;
}
@keyframes canvas-marker-pulse {
  0%, 100% { opacity: 0.55; transform: translate(-50%, -50%) scale(0.92); }
  50% { opacity: 1; transform: translate(-50%, -50%) scale(1.05); }
}
@media (prefers-reduced-motion: reduce) {
  .canvas-capture-marker { animation: none; }
}
.canvas-minimap-caption,
.canvas-minimap-empty {
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.canvas-minimap-list { display: grid; gap: 4px; }
.canvas-minimap-list button {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text-dim);
  padding: 6px 8px;
  text-align: left;
  font-size: 12px;
}
.canvas-minimap-list button.active,
.canvas-minimap-list button:hover { color: var(--primary); border-color: var(--primary); }
.canvas-compare-stage,
.canvas-markup-editor {
  position: absolute;
  inset: 0;
  z-index: 4;
  background: oklch(0.1 0.01 65);
}
.canvas-compare-stage {
  cursor: grab;
  touch-action: none;
}
.canvas-compare-stage:active { cursor: grabbing; }
.canvas-compare-side {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  height: 100%;
}
.canvas-compare-side figure {
  min-width: 0;
  margin: 0;
  position: relative;
  display: grid;
  place-items: center;
  border-right: 1px solid rgba(255,255,255,0.12);
}
.canvas-compare-side img,
.canvas-compare-wipe img,
.canvas-compare-ghost img { max-width: 100%; max-height: 100%; object-fit: contain; }
.compare-pan-node {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  transform-origin: center center;
  will-change: transform;
}
.canvas-compare-wipe .compare-pan-node,
.canvas-compare-ghost .compare-pan-node {
  position: absolute;
  inset: 0;
}
.canvas-compare-side figcaption {
  position: absolute;
  left: 12px;
  bottom: 12px;
  max-width: calc(100% - 24px);
  background: rgba(0,0,0,0.58);
  color: oklch(0.92 0.012 75);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  padding: 5px 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  overflow-wrap: anywhere;
}
.canvas-compare-side figcaption b {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  margin-right: 5px;
  border-radius: 999px;
  background: oklch(0.74 0.13 54);
  color: oklch(0.12 0.014 65);
}
.compare-frame-panel-b figcaption b {
  background: oklch(0.72 0.13 215);
}
.canvas-compare-wipe,
.canvas-compare-ghost { position: relative; height: 100%; display: grid; place-items: center; }
.canvas-compare-wipe > .wipe-base,
.canvas-compare-wipe > .wipe-top,
.canvas-compare-ghost img { position: absolute; inset: 0; width: 100%; height: 100%; }
.canvas-compare-wipe > .wipe-top { overflow: hidden; clip-path: inset(0 calc(100% - var(--wipe, 50%)) 0 0); }
.canvas-compare-wipe input {
  position: absolute;
  left: 18px;
  right: 18px;
  bottom: 18px;
  width: calc(100% - 36px);
  accent-color: var(--primary);
  z-index: 2;
}
.canvas-compare-wipe .canvas-wipe-range {
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  z-index: 7;
  cursor: ew-resize;
  accent-color: oklch(0.72 0.13 215);
}
.canvas-wipe-divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--wipe, 50%);
  width: 0;
  z-index: 6;
  pointer-events: none;
}
.canvas-wipe-divider::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -1px;
  width: 2px;
  background: oklch(0.72 0.13 215);
  box-shadow: 0 0 0 1px rgba(0,0,0,0.42), 0 0 18px rgba(56,189,248,0.45);
}
.canvas-wipe-handle {
  position: absolute;
  top: 50%;
  left: 0;
  transform: translate(-50%, -50%);
  min-width: 58px;
  min-height: 38px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(255,255,255,0.72);
  border-radius: 999px;
  background: oklch(0.72 0.13 215);
  color: oklch(0.1 0.01 65);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  box-shadow: 0 10px 24px rgba(0,0,0,0.34);
}
.canvas-wipe-handle::after {
  content: attr(data-value);
  position: absolute;
  top: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  background: rgba(0,0,0,0.68);
  color: rgba(255,255,255,0.88);
  padding: 3px 6px;
  font-size: 9px;
  opacity: 0;
}
.canvas-compare-wipe:hover .canvas-wipe-handle::after,
.canvas-compare-wipe:focus-within .canvas-wipe-handle::after {
  opacity: 1;
}
.compare-frame-label,
.compare-frame-badge {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 8;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border-radius: 999px;
  background: rgba(0,0,0,0.68);
  color: rgba(255,255,255,0.92);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 5px 9px 5px 5px;
  border: 1px solid rgba(255,255,255,0.22);
  box-shadow: 0 8px 18px rgba(0,0,0,0.26);
}
.compare-frame-badge b {
  display: inline-grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: oklch(0.74 0.13 54);
  color: oklch(0.12 0.014 65);
  font-size: 14px;
  letter-spacing: 0;
}
.compare-frame-badge small {
  font-size: 9px;
  color: currentColor;
}
.compare-frame-label.after,
.compare-frame-badge.right {
  left: auto;
  right: 14px;
}
.canvas-compare-stage .compare-frame-badge.right {
  top: 64px;
}
.compare-frame-badge.b b {
  background: color-mix(in oklch, oklch(0.72 0.13 215) 72%, rgba(0,0,0,0.62));
  color: oklch(0.1 0.01 65);
}
.canvas-compare-ghost img:last-child {
  opacity: var(--ghost, 0.52);
  mix-blend-mode: normal;
}
.canvas-compare-session {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 5px;
}
.canvas-compare-session small {
  color: var(--text-faint);
  font-size: 11px;
}
.canvas-compare-select {
  display: grid;
  gap: 4px;
  color: var(--text-dim);
  font-size: 12px;
}
.canvas-compare-select select {
  min-width: 0;
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface);
  color: var(--text);
  padding: 6px 7px;
  font: inherit;
}
.canvas-compare-mode-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 5px; }
.canvas-compare-pin-row,
.canvas-compare-tools {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 5px;
}
.canvas-compare-tools { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.canvas-compare-mode-row button {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text-dim);
  min-height: 34px;
  padding: 7px 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
}
.canvas-compare-pin-row button,
.canvas-compare-tools button {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text-dim);
  min-height: 34px;
  padding: 7px 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
}
.canvas-compare-pin-row button:hover,
.canvas-compare-tools button:hover { border-color: var(--primary); color: var(--primary); }
.canvas-compare-mode-row button.active,
.canvas-compare-mode-row button:hover { border-color: var(--primary); color: var(--primary); }
.canvas-compare-slider {
  display: grid;
  gap: 6px;
  color: var(--text-dim);
  font-size: 12px;
}
.canvas-compare-slider.is-hidden {
  display: none;
}
.canvas-compare-slider span {
  display: flex;
  justify-content: space-between;
  gap: 10px;
}
.canvas-compare-slider input {
  width: 100%;
  accent-color: oklch(0.72 0.13 215);
}
.canvas-compare-queue {
  display: grid;
  gap: 6px;
  border-top: 1px dashed var(--border);
  padding-top: 8px;
}
.canvas-compare-queue > span {
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.canvas-compare-queue-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 4px 8px;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: var(--surface);
  padding: 7px;
}
.canvas-compare-queue-row small,
.canvas-compare-queue-row b {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.canvas-compare-queue-row small {
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 9.5px;
  text-transform: uppercase;
}
.canvas-compare-queue-row b {
  color: var(--text-dim);
  font-size: 11px;
  font-weight: 500;
}
.canvas-compare-queue-row button {
  grid-row: 1 / span 2;
  grid-column: 2;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  padding: 6px 8px;
  cursor: pointer;
}
.canvas-compare-queue-row button:hover {
  border-color: var(--danger, #ef4444);
  color: var(--danger, #ef4444);
}
.canvas-markup-editor { pointer-events: auto; background: transparent; }
.canvas-markup-svg { position: absolute; inset: 0; width: 100%; height: 100%; cursor: crosshair; }
/* S3.4 — chip moved into panel; keep rule but suppress display (no longer inserted into DOM) */
.canvas-markup-mode-chip { display: none; }

/* S3.4 — one-line hint at the top of the Markup Studio panel */
.markup-studio-hint {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding: 6px 12px 2px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 2px;
}
.canvas-markup-toolbar {
  position: absolute;
  z-index: 6;
  left: 14px;
  top: 14px;
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
  max-width: calc(100% - 28px);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 7px;
  background: rgba(0,0,0,0.66);
  padding: 7px;
  backdrop-filter: blur(8px);
}
.canvas-markup-toolbar button {
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 5px;
  background: rgba(255,255,255,0.08);
  color: oklch(0.92 0.012 75);
  padding: 5px 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
}
.canvas-markup-toolbar button.active,
.canvas-markup-toolbar button:hover { border-color: var(--primary); color: oklch(0.9 0.075 56); }
.canvas-markup-toolbar button.primary {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--bg);
}
.markup-divider {
  width: 1px;
  min-height: 24px;
  background: rgba(255,255,255,0.16);
}
.markup-swatch {
  width: 24px;
  min-width: 24px;
  padding: 0 !important;
}
.markup-swatch::before {
  content: "";
  display: block;
  width: 12px;
  height: 12px;
  margin: auto;
  border-radius: 999px;
  background: var(--swatch);
}
.markup-stroke {
  /* Was oklch(0.84 0.012 75) — virtually invisible on our paper bg.
   * Use the design-system text-dim so the "STROKE" label is legible. */
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.markup-stroke input { flex: 1 1 auto; min-width: 0; accent-color: var(--primary); }
.markup-stroke span { color: var(--text); font-family: var(--font-mono); }
.canvas-markup-studio {
  display: grid;
  gap: 12px;
  border: 1px solid color-mix(in oklch, var(--primary) 36%, var(--border));
  border-radius: 8px;
  background: color-mix(in oklch, var(--surface-2) 74%, var(--surface));
  padding: 12px;
}
.markup-studio-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}
.markup-studio-head strong,
.markup-selected-meta strong {
  color: var(--text);
}
.markup-studio-title {
  display: flex;
  align-items: baseline;
  gap: 7px;
  min-width: 0;
}
.markup-studio-title strong {
  font-size: 13px;
  white-space: nowrap;
}
.markup-studio-title small {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-faint);
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.markup-studio-head small,
.markup-selected-meta,
.markup-property-label {
  color: var(--text-dim);
  font-size: 12px;
}
.markup-studio-head button,
.markup-studio-actions button,
.markup-tool-grid button,
.canvas-report-frame-row button {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 6px 8px;
  cursor: pointer;
}
.markup-tool-grid {
  display: grid;
  /* 3 columns was making RECTANGLE/CALLOUT/HIGHLIGHT truncate in the
   * narrow studio panel. 2 columns keeps every label readable. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
}
.markup-tool-grid button {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.markup-tool-grid button.active,
.markup-tool-grid button:hover,
.markup-studio-actions button:hover,
.markup-studio-head button:hover,
.canvas-report-frame-row button:hover {
  border-color: var(--primary);
  color: var(--primary);
}
.markup-property-group {
  display: grid;
  gap: 7px;
  min-width: 0;
}
.markup-size-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 6px;
}
.markup-size-row button,
.markup-fill-row button {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 6px 8px;
  cursor: pointer;
}
.markup-size-row button.active,
.markup-size-row button:hover,
.markup-fill-row button.active,
.markup-fill-row button:hover {
  border-color: var(--primary);
  color: var(--primary);
  background: color-mix(in oklch, var(--primary-soft) 40%, var(--surface));
}
.markup-swatch-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.canvas-markup-studio .markup-swatch {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface);
  height: 28px;
  cursor: pointer;
}
.canvas-markup-studio .markup-swatch.active {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px color-mix(in oklch, var(--primary) 20%, transparent);
}
.canvas-markup-studio .markup-stroke {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 7px;
  text-transform: none;
}
.canvas-markup-studio .markup-stroke input {
  grid-column: 1 / -1;
  width: 100%;
}
.markup-text-prop textarea {
  width: 100%;
  min-width: 0;
  resize: vertical;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: var(--surface);
  color: var(--text);
  padding: 8px;
  font: inherit;
}
.markup-text-prop.disabled {
  opacity: 0.55;
}
.markup-selected-meta {
  display: grid;
  gap: 3px;
  border-top: 1px dashed var(--border);
  padding-top: 8px;
}
.markup-studio-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
}
.markup-studio-actions .primary {
  grid-column: 1 / -1;
  background: var(--primary);
  border-color: var(--primary);
  color: var(--bg);
}
.markup-draft-mark {
  pointer-events: auto;
  cursor: pointer;
}
.markup-draft-mark.selected > * {
  filter: drop-shadow(0 0 7px rgba(255,255,255,0.78));
}
.markup-selection-overlay {
  pointer-events: none;
}
.markup-selection-outline {
  fill: none;
  stroke: #ffffff;
  stroke-width: 2;
  stroke-dasharray: 10 6;
  vector-effect: non-scaling-stroke;
  pointer-events: none;
}
.markup-handle {
  fill: #ffffff;
  stroke: #1a1814;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  pointer-events: auto;
}
.markup-handle-endpoint,
.markup-handle-vertex { fill: var(--primary); stroke: #ffffff; }
.markup-handle-corner { fill: #ffffff; opacity: 0.85; }
.markup-handle[data-handle-mode="resize-nw"],
.markup-handle[data-handle-mode="resize-se"] { cursor: nwse-resize; }
.markup-handle[data-handle-mode="resize-ne"],
.markup-handle[data-handle-mode="resize-sw"] { cursor: nesw-resize; }
.markup-handle[data-handle-mode="resize-n"],
.markup-handle[data-handle-mode="resize-s"] { cursor: ns-resize; }
.markup-handle[data-handle-mode="resize-e"],
.markup-handle[data-handle-mode="resize-w"] { cursor: ew-resize; }
.markup-handle[data-handle-mode^="arrow-end"],
.markup-handle[data-handle-mode="poly-vertex"] { cursor: grab; }
.markup-handle[data-handle-mode^="arrow-end"]:active,
.markup-handle[data-handle-mode="poly-vertex"]:active { cursor: grabbing; }
.markup-handle[data-handle-mode="pen-corner"] { cursor: move; }
.canvas-timeline-zoom {
  display: inline-flex;
  gap: 4px;
  margin: 8px 0 6px;
}
.canvas-timeline-zoom button,
.time-speed {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  padding: 5px 7px;
}
.canvas-timeline-zoom button.active,
.time-speed:focus { border-color: var(--primary); color: var(--primary); }
.capture-tick { position: relative; }
.capture-tick.ai::after,
.capture-tick.report::before {
  content: "";
  position: absolute;
  right: 4px;
  top: 4px;
  width: 7px;
  height: 7px;
  border-radius: 999px;
}
.capture-tick.ai::after { background: #38bdf8; }
.capture-tick.report::before { background: #22c55e; }
.capture-pin {
  position: absolute;
  left: 4px;
  top: 4px;
  width: 16px;
  height: 16px;
  display: grid;
  place-items: center;
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  background: rgba(0,0,0,0.72);
  color: white;
  font-family: var(--font-mono);
  font-size: 9px;
}
.capture-pin.pin-a { border: 1px solid #f59e0b; }
.capture-pin.pin-b { border: 1px solid #38bdf8; }
.canvas-capture-strip-detail .capture-tick { min-width: 74px; height: 54px; }
.canvas-capture-strip-dense .capture-tick { min-width: 36px; height: 38px; }
.canvas-issue-new {
  display: grid;
  gap: 5px;
  color: var(--text-dim);
  font-size: 12px;
}
.canvas-issue-new textarea,
.canvas-report-composer input {
  width: 100%;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: var(--surface);
  color: var(--text);
  padding: 8px;
  font: inherit;
}
.canvas-issue-list,
.canvas-viewpoint-list,
.canvas-report-composer {
  display: grid;
  gap: 7px;
}
.canvas-issue-row,
.canvas-viewpoint-list button,
.canvas-report-preview {
  display: grid;
  gap: 4px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: var(--surface);
  padding: 8px;
  color: var(--text-dim);
}
.canvas-issue-row {
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
}
.canvas-issue-row button,
.canvas-viewpoint-list button {
  cursor: pointer;
  text-align: left;
}
.canvas-immersive-actions,
.canvas-report-composer-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
}
.canvas-report-preview strong { color: var(--text); }
.canvas-report-preview small { color: var(--text-faint); }
.canvas-report-preview-list {
  display: grid;
  gap: 8px;
}
.canvas-report-frame-row {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr) auto;
  gap: 9px;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--surface);
  padding: 8px;
}
.canvas-report-frame-row img,
.canvas-report-compare-pair {
  width: 54px;
  height: 42px;
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  object-fit: cover;
  background: var(--surface-2);
}
.canvas-report-compare-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px;
  overflow: hidden;
}
.canvas-report-compare-pair img {
  width: 100%;
  height: 100%;
  border-radius: 0;
}
.canvas-report-frame-row strong,
.canvas-report-frame-row small {
  display: block;
  min-width: 0;
  overflow-wrap: anywhere;
}
.canvas-report-frame-row strong {
  color: var(--text);
  font-size: 12px;
}
.canvas-report-frame-row small,
.canvas-report-check,
.canvas-report-data-summary {
  color: var(--text-dim);
  font-size: 11px;
}
.canvas-report-check {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 4px;
}
.canvas-report-data-summary {
  border: 1px dashed var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  padding: 8px;
}
.canvas-report-frame-row.has-marks {
  border-color: var(--primary);
  box-shadow: inset 3px 0 0 var(--primary);
}
.canvas-report-pills {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 4px;
}
.canvas-report-pill {
  display: inline-flex;
  align-items: center;
  height: 16px;
  padding: 0 6px;
  border-radius: 999px;
  border: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
  background: var(--surface-2);
}
.canvas-report-pill-marked {
  border-color: var(--primary);
  color: var(--primary-fg, #ffffff);
  background: var(--primary);
}
.canvas-report-pill-clean {
  opacity: 0.6;
}
.canvas-report-pill-issue {
  border-color: var(--warn);
  color: var(--warn);
  background: var(--warn-soft);
}
.canvas-report-pill-ai {
  border-color: var(--success);
  color: var(--success);
  background: var(--success-soft);
}
.canvas-report-pill-mode-wipe { border-color: var(--primary); color: var(--primary); }
.canvas-report-pill-mode-ghost { border-color: var(--success); color: var(--success); }
.canvas-report-pill-mode-side { border-color: var(--text-dim); }
.canvas-report-pill-compare { background: var(--surface-2); }
.canvas-report-pill-layer {
  font-family: var(--font-sans);
  text-transform: none;
  letter-spacing: 0;
  font-size: 10px;
  color: var(--text-dim);
}
.canvas-report-frame-notes {
  list-style: none;
  margin: 6px 0 0;
  padding-left: 0;
  display: grid;
  gap: 3px;
}
.canvas-report-frame-notes li {
  position: relative;
  padding-left: 12px;
  font-size: 11px;
  color: var(--text-dim);
}
.canvas-report-frame-notes li::before {
  content: "•";
  position: absolute;
  left: 0;
  color: var(--warn);
}
.canvas-report-frame-ai {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
  font-size: 11px;
  color: var(--text-dim);
}
.canvas-report-frame-ai span {
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 7px;
  background: var(--surface-2);
  font-family: var(--font-mono);
  font-size: 10px;
}
.canvas-report-frame-ai b {
  color: var(--success);
  font-weight: 500;
  margin-left: 3px;
}
.canvas-report-compare-arrow {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-faint);
  padding: 0 2px;
}
.canvas-report-compare-pair {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 4px;
  overflow: hidden;
}
@media (max-width: 1240px) {
  .canvas-context-top { grid-template-columns: 1fr; }
  .canvas-context-report { justify-self: start; min-height: 38px; }
  .canvas-workbench-grid { grid-template-columns: minmax(190px, 230px) minmax(0, 1fr); }
  .canvas-inspector { grid-column: 1 / -1; min-height: 0; }
}
@media (max-width: 820px) {
  .canvas-workbench-grid { grid-template-columns: 1fr; }
  .canvas-left-panel { position: static; max-height: none; }
  .canvas-stage-column { grid-template-rows: minmax(380px, 60vh) auto; }
  .canvas-stage-column .canvas-main,
  .canvas-stage-column .canvas-surface { min-height: 380px; }
  .canvas-mode-nav { grid-template-columns: 1fr; }
  .canvas-compare-side { grid-template-columns: 1fr; }
}

@media (max-width: 520px) {
  .canvas-scrubber-head {
    display: grid;
    grid-template-columns: 1fr;
  }
  .canvas-time-controls {
    flex-wrap: wrap;
  }
  .canvas-time-controls .time-btn,
  .time-speed {
    flex: 1 1 68px;
    min-width: 0;
  }
  .canvas-meta-grid,
  .canvas-immersive-actions,
  .canvas-report-composer-actions {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 1180px) and (min-width: 1101px) {
  .canvas-workbench-grid {
    grid-template-columns: minmax(0, 1fr) minmax(280px, 340px);
  }
  .canvas-left-panel {
    grid-column: 1 / -1;
    position: static;
    max-height: none;
    grid-template-columns: minmax(0, 1fr) minmax(220px, 320px);
    align-items: start;
  }
  .canvas-stage-column {
    grid-column: 1;
  }
  .canvas-inspector {
    grid-column: 2;
  }
}

@media (max-width: 1100px) {
  .canvas-workbench-grid {
    grid-template-columns: 1fr;
  }
  .canvas-left-panel,
  .canvas-inspector,
  .canvas-stage-column {
    grid-column: 1;
  }
  .canvas-left-panel {
    position: static;
    max-height: none;
  }
}

/* ────────────────────────────────────────────────────────────────────────
   23. CMD+K PALETTE (Phase 7 — 2026-05-19)
   ──────────────────────────────────────────────────────────────────────── */
/* Modal overlay matching mockup 04. Triggered globally by Cmd/Ctrl+K.
   Lives on document.body so it sits above any view-specific overlay. */
.cmdk-overlay {
  position: fixed; inset: 0;
  background: rgba(42, 37, 32, 0.42);
  backdrop-filter: blur(8px);
  display: grid; place-items: start center;
  padding-top: 12vh;
  z-index: 9999;
  animation: cmdk-fade 160ms ease-out;
}
@keyframes cmdk-fade { from { opacity: 0; } to { opacity: 1; } }

.cmdk-modal {
  width: min(680px, 92vw);
  background: var(--surface);
  border: 1px solid var(--border-hover);
  border-radius: 12px;
  box-shadow: 0 24px 60px -10px rgba(42, 37, 32, 0.35),
              0 0 0 1px rgba(196, 106, 69, 0.05);
  overflow: hidden;
  display: flex; flex-direction: column;
  max-height: 78vh;
  animation: cmdk-scale 200ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes cmdk-scale {
  from { transform: scale(0.96) translateY(-8px); opacity: 0; }
  to   { transform: scale(1) translateY(0); opacity: 1; }
}

.cmdk-input-row {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  color: var(--text-faint);
}
.cmdk-input-row svg { color: var(--text-faint); flex-shrink: 0; }
.cmdk-scope {
  font-family: var(--font-mono); font-size: 10.5px;
  padding: 3px 8px; border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  color: var(--text-dim);
  letter-spacing: 0.06em; text-transform: uppercase;
  background: var(--surface-2);
  flex-shrink: 0;
}
.cmdk-input {
  flex: 1;
  background: transparent;
  border: 0; outline: 0;
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 16px;
}
.cmdk-input::placeholder { color: var(--text-faint); }
.cmdk-esc {
  font-family: var(--font-mono); font-size: 10.5px;
  padding: 3px 7px; border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  color: var(--text-faint);
  letter-spacing: 0.04em;
  flex-shrink: 0;
}

.cmdk-body {
  overflow-y: auto;
  padding: 6px 0 4px;
  flex: 1;
}
.cmdk-hint {
  padding: 24px 18px;
  text-align: center;
  font-family: var(--font-mono); font-size: 12.5px;
  color: var(--text-faint);
  letter-spacing: 0.03em;
}

.cmdk-group-label {
  font-family: var(--font-mono); font-size: 9.5px;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-faint);
  padding: 10px 18px 4px;
}

.cmdk-row {
  display: grid;
  grid-template-columns: 22px 1fr auto auto auto;
  gap: 12px;
  align-items: center;
  padding: 8px 18px;
  cursor: pointer;
  transition: background 80ms;
  position: relative;
}
.cmdk-row:hover { background: var(--surface-2); }
.cmdk-row.selected {
  background: linear-gradient(90deg, var(--primary-soft) 0%,
    color-mix(in srgb, var(--primary-soft) 60%, var(--surface)) 100%);
}
.cmdk-row.selected::before {
  content: ""; position: absolute; left: 0; top: 4px; bottom: 4px;
  width: 3px; background: var(--primary);
}
.cmdk-row.locked { opacity: 0.7; cursor: not-allowed; }
.cmdk-row.locked:hover { background: transparent; }

.cmdk-icon {
  color: var(--text-faint);
  display: grid; place-items: center;
}
.cmdk-row.selected .cmdk-icon { color: var(--primary); }
.cmdk-thumb {
  width: 22px;
  height: 22px;
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  background: var(--surface-2);
  background-size: cover;
  background-position: center;
  border: 1px solid var(--border);
}
.cmdk-name { font-size: 14px; color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmdk-row.selected .cmdk-name { font-weight: 500; }
.cmdk-match {
  background: var(--primary-soft);
  color: var(--primary-hover);
  padding: 1px 3px; border-radius: var(--r-xs); /* FND-C05: was 2px off-scale → --r-xs (3px) */
  font-weight: 500;
}

.cmdk-meta {
  font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-faint);
  letter-spacing: 0.04em;
}
.cmdk-tag {
  font-family: var(--font-mono); font-size: 9.5px;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 3px;
  background: var(--surface-2); color: var(--text-dim);
  border: 1px solid var(--border);
}
.cmdk-tag.ai { background: var(--success-soft); color: #4f6b3a; border-color: color-mix(in srgb, var(--success) 35%, transparent); }
.cmdk-tag.bim { background: var(--primary-soft); color: var(--primary-hover); border-color: color-mix(in srgb, var(--primary) 30%, transparent); }
.cmdk-tag.gs { background: #e3d8ee; color: #5b3f7d; border-color: #b8a5cf; }
.cmdk-tag.locked {
  background: var(--warn-soft); color: #8b5a18;
  border-color: color-mix(in srgb, var(--warn) 40%, transparent);
  display: inline-flex; align-items: center; gap: 4px;
}

.cmdk-enter {
  font-family: var(--font-mono); font-size: 13px;
  color: var(--text-faint);
}

.cmdk-footer {
  display: flex; align-items: center; gap: 16px;
  padding: 10px 18px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: 0.04em; color: var(--text-faint);
}
.cmdk-footer kbd {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 3px; padding: 1px 5px;
  font-family: inherit; color: var(--text-dim);
  margin-right: 4px;
}
.cmdk-footer-spacer { flex: 1; }
.cmdk-powered { color: var(--text-faint); }

@media (prefers-reduced-motion: reduce) {
  .cmdk-overlay, .cmdk-modal { animation: none; }
}

/* ─────────────────────────────────────────────────────────────────────
   24. IA LOGIC CLEANUP (2026-05-20)
   One navigation surface at a time: expanded = full sidebar, collapsed =
   icon rail. The rail is no longer a permanent second nav column.
   ───────────────────────────────────────────────────────────────────── */
@media (min-width: 768px) {
  .app-shell {
    grid-template-columns: 240px 1fr;
  }
  .app-rail {
    display: none;
  }
  body.shell-nav-collapsed .app-shell {
    grid-template-columns: 56px 1fr;
  }
  body.shell-nav-collapsed .app-rail {
    display: flex;
  }
  body.shell-nav-collapsed .app-sidebar {
    display: none;
  }
}

@media (max-width: 767px) {
  .app-shell {
    display: block;
    min-height: 100vh;
  }
  .app-rail {
    position: fixed;
    left: -56px;
    top: 0;
    bottom: 0;
    height: auto;
    z-index: 21;
    transition: left 200ms ease;
  }
  .app-rail.open { left: 0; }
  .app-main {
    min-height: 100vh;
  }
}

.app-sidebar .app-nav-item.active {
  background: var(--surface-2);
  color: var(--text);
  position: relative;
}
.app-sidebar .app-nav-item.active::before {
  content: "";
  position: absolute;
  left: -1rem;
  top: 6px;
  bottom: 6px;
  width: 3px;
  border-radius: 0 2px 2px 0;
  background: var(--primary);
}
.project-stations-group {
  margin: 0.35rem 0 0.55rem;
  border-top: 1px dashed var(--border);
  border-bottom: 1px dashed var(--border);
  padding: 0.45rem 0;
}
.project-stations-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  padding: 0.35rem 0.55rem;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.project-stations-filter-wrap {
  padding: 0.15rem 0.45rem 0.4rem;
}
.project-stations-filter,
.station-context-select {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
}
.project-stations-filter {
  padding: 0.38rem 0.5rem;
  font-size: 12px;
}
.project-stations-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 280px;
  overflow: auto;
  padding: 0 0.25rem;
}
.project-station-nav.app-nav-item {
  gap: 0.5rem;
  padding: 0.42rem 0.45rem;
}
.project-station-thumb {
  width: 26px;
  height: 26px;
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  background: var(--surface-2);
  background-size: cover;
  background-position: center;
  border: 1px solid var(--border);
  flex: 0 0 auto;
}
.project-station-initial {
  display: inline-grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-dim);
}
.project-station-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.project-station-empty {
  padding: 0.6rem 0.75rem;
  color: var(--text-faint);
  font-size: 12px;
}
.station-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--text-faint);
  margin-left: auto;
  flex: 0 0 auto;
}
.station-dot.ok { background: var(--success); }
.station-dot.warn { background: var(--warn); }
.station-dot.bad { background: var(--danger); }
.station-dot.cold { background: var(--text-faint); }

.station-context-bar {
  display: flex;
  align-items: center;
  gap: 1rem;
  justify-content: space-between;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.7rem 0.85rem;
  margin-bottom: 1rem;
}
.station-context-main {
  display: grid;
  grid-template-columns: auto minmax(220px, 320px);
  align-items: center;
  gap: 0.7rem;
}
.station-context-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.station-context-select {
  padding: 0.42rem 0.55rem;
  min-height: 34px;
}
.station-context-meta {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: var(--text-faint);
}

.project-station-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 14px;
  margin-bottom: 28px;
}
.project-station-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
}
.project-station-card:hover,
.project-station-card:focus-visible {
  border-color: var(--primary);
  outline: none;
}
.project-station-card-thumb {
  aspect-ratio: 1 / 1;
  width: 100%;
  background-size: cover;
  background-position: center;
  display: grid;
  place-items: center;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 2rem;
  border-bottom: 1px solid var(--border);
}
.project-station-card-body {
  padding: 0.8rem 0.9rem 0.9rem;
}
.project-station-card-top,
.project-station-card-status,
.project-station-card-meta {
  display: flex;
  align-items: center;
  gap: 0.45rem;
}
.project-station-card-top {
  justify-content: space-between;
  margin-bottom: 0.45rem;
}
.project-station-card-id,
.project-station-card-status,
.project-station-card-meta {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: var(--text-faint);
}
.project-station-card-status .sd {
  width: 7px;
  height: 7px;
  border-radius: 999px;
}
.project-station-card-status .sd.ok { background: var(--success); }
.project-station-card-status .sd.bad { background: var(--danger); }
.project-station-card h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
}
.project-station-card p {
  margin: 0.25rem 0 0;
  color: var(--text-dim);
  font-size: 12.5px;
}
.project-station-card-meta {
  flex-wrap: wrap;
  margin-top: 0.75rem;
}
.project-station-card.is-bad { border-color: color-mix(in srgb, var(--danger) 42%, var(--border)); }
.project-station-card.is-warn { border-color: color-mix(in srgb, var(--warn) 48%, var(--border)); }

.station-under-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1rem;
}
.station-under-header h1 {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 600;
}
.station-under-label,
.station-under-status,
.station-overview-card-head {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.station-under-status {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}
.station-overview-grid {
  display: grid;
  grid-template-columns: minmax(260px, 380px) 1fr;
  gap: 18px;
  align-items: stretch;
  margin-bottom: 18px;
}
.station-hero-capture {
  aspect-ratio: 1 / 1;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background-size: cover;
  background-position: center;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: 2.5rem;
  color: var(--text-faint);
}
.station-overview-panel,
.station-overview-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 1rem;
}
.station-overview-kpis {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.station-overview-kpis div {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  padding: 0.75rem;
}
.station-overview-kpis span {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.station-overview-kpis strong {
  display: block;
  margin-top: 0.25rem;
  font-size: 1.1rem;
  font-weight: 600;
}
.station-overview-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1rem;
}
.station-settings-shortcuts {
  margin-top: 1rem;
}
.station-settings-shortcut-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
}
.station-settings-shortcut-grid button {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: var(--surface-2);
  color: var(--text);
  padding: 0.6rem 0.7rem;
  text-align: left;
  font-size: var(--t-sm);
  cursor: pointer;
}
.station-settings-shortcut-grid button:hover {
  border-color: var(--primary);
  color: var(--primary);
}
.station-overview-two {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
}
.station-overview-card-head {
  margin-bottom: 0.75rem;
}
.station-overview-empty {
  color: var(--text-dim);
  font-size: 13px;
}
.station-issue-row,
.station-command-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.55rem 0;
  border-top: 1px solid var(--border);
  color: var(--text-dim);
}
.station-issue-row:first-of-type,
.station-command-row:first-of-type {
  border-top: 0;
}
.station-command-row {
  display: grid;
  grid-template-columns: 54px 1fr auto auto;
  font-family: var(--font-mono);
  font-size: 11px;
}
.station-command-row em {
  font-style: normal;
  color: var(--text-faint);
}

.gallery-mode-nav {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  margin: 0 0 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.gallery-mode-btn {
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: var(--text-dim);
  padding: 0.45rem 0.8rem;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.gallery-mode-btn:hover,
.gallery-mode-btn.active {
  background: var(--primary);
  color: var(--bg);
}
.gallery-date-rail {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 10px;
  margin-bottom: 1rem;
}
.gallery-date-pill {
  min-width: 132px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  background: var(--surface);
  color: var(--text-dim);
  padding: 0.55rem 0.65rem;
  text-align: left;
}
.gallery-date-pill strong,
.gallery-date-pill span {
  display: block;
  font-family: var(--font-mono);
  font-size: 10.5px;
}
.gallery-date-pill.active,
.gallery-date-pill:hover {
  border-color: var(--primary);
  color: var(--primary);
}
.pg-photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 8px;
}
.pg-photo-thumb {
  aspect-ratio: 1 / 1;
  background-size: cover;
  background-position: center;
  border: 1px solid var(--border);
  border-radius: 5px;
  position: relative;
}
/* removed: legacy always-on warm .pg-photo-thumb span — Stratum
   .gallery-thumb-meta (static/css/stratum-b.css:586, hover-reveal, neutral)
   is the canonical implementation for the same <span class="gallery-thumb-meta">
   inside .pg-photo-thumb. FND-C10 audit V2. */

/* §3 quick-compare picks: compact bottom-left A/B overlay on every capture
   card. Hover-reveal on desktop (pointer:fine), always-visible-compact on
   touch. stopPropagation lives in JS so the card still opens the lightbox. */
.cmp-pick {
  position: absolute;
  left: 5px;
  bottom: 5px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 5px;
  border-radius: var(--r-pill, 999px);
  background: rgba(13, 13, 11, 0.72);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity 120ms ease;
}
.pg-photo-thumb:hover .cmp-pick,
.pg-photo-thumb:focus-within .cmp-pick,
.cmp-pick:focus-within { opacity: 1; }
/* touch / coarse pointer: always show (no hover) */
@media (hover: none), (pointer: coarse) { .cmp-pick { opacity: 1; } }
.cmp-pick-tag {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #f0f0ea;
}
.cmp-pick-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: var(--r-pill, 999px);
  font-size: 11px;
  font-weight: 700;
  color: #f0f0ea;
  background: rgba(255, 255, 255, 0.14);
  cursor: pointer;
  user-select: none;
  transition: background 120ms ease, color 120ms ease;
}
/* ≥44px hit target via an invisible padded overlay (keeps the chip compact) */
.cmp-pick-btn::after {
  content: "";
  position: absolute;
  inset: -12px;
}
.cmp-pick-btn:hover { background: rgba(255, 255, 255, 0.26); }
.cmp-pick-btn.on {
  /* citron accent on near-black text = AA-large+ contrast */
  background: #d2eb3a;
  color: #0d0d0b;
}
.cmp-pick-btn:focus-visible { outline: 2px solid #d2eb3a; outline-offset: 2px; }
.pg-photo-thumb.cmp-picked { border-color: #d2eb3a; }

/* floating "Open compare" action bar (both A + B set) */
.cmp-pick-bar {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 9000;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-radius: var(--r-lg, 12px);
  background: var(--surface, #161614);
  border: 1px solid var(--border, #2a2a26);
  box-shadow: 0 16px 48px -12px rgba(0, 0, 0, 0.6);
}
.cmp-pick-bar-label { font-size: 12.5px; color: var(--text, #f0f0ea); }
.cmp-pick-bar-label strong { color: #d2eb3a; }
.cmp-pick-bar-label .sep { color: var(--text-dim, #aeaea5); margin: 0 4px; }

.splat-create-panel,
.splat-upload-panel,
.splat-secondary-panel,
.vision-feedback-panel {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  padding: 1rem;
  margin-bottom: 1rem;
}
.project-splat {
  max-width: 100%;
  min-width: 0;
  overflow-x: clip;
}
.splat-home-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.5rem;
}
.splat-ready-hero {
  display: grid;
  grid-template-columns: minmax(220px, 0.48fr) minmax(0, 1fr);
  gap: 1rem;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: color-mix(in oklch, var(--surface) 84%, var(--bg));
  padding: 1rem;
  margin: 1rem 0;
  min-width: 0;
}
.splat-ready-hero.empty {
  background: color-mix(in oklch, var(--primary-soft) 18%, var(--surface));
}
.splat-ready-preview,
.splat-gallery-preview {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--surface-2);
  background-size: cover;
  background-position: center;
  display: grid;
  place-items: center;
  color: var(--text-faint);
  font-family: var(--font-mono);
  letter-spacing: 0.08em;
}
.splat-ready-preview {
  aspect-ratio: 1 / 1;
  min-height: 220px;
  font-size: 22px;
}
.splat-gallery-preview {
  aspect-ratio: 16 / 10;
  min-height: 150px;
  font-size: 16px;
}
.splat-ready-main {
  display: grid;
  align-content: center;
  gap: 0.85rem;
  min-width: 0;
}
.splat-ready-main h2 {
  margin: 0;
  color: var(--text);
  font-size: clamp(24px, 3vw, 38px);
  letter-spacing: 0;
  overflow-wrap: anywhere;
}
.splat-ready-main p {
  margin: 0;
  max-width: 72ch;
  color: var(--text-dim);
}
.splat-ready-metrics {
  display: grid;
  grid-template-columns: repeat(4, minmax(120px, 1fr));
  gap: 8px;
}
.splat-ready-metrics div {
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--surface-2);
  padding: 10px 12px;
  min-width: 0;
}
.splat-ready-metrics b,
.splat-ready-metrics span,
.splat-gallery-copy strong,
.splat-gallery-copy span,
.splat-gallery-copy small {
  display: block;
}
.splat-ready-metrics b {
  color: var(--text);
  font-size: 13px;
  overflow-wrap: anywhere;
}
.splat-ready-metrics span {
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.splat-active-jobs,
.splat-model-gallery,
.splat-wizard-shell,
.splat-roadmap-note {
  min-width: 0;
}
.splat-gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 0.85rem;
}
.splat-gallery-card {
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  padding: 0.85rem;
  min-width: 0;
}
.splat-gallery-copy {
  display: grid;
  gap: 3px;
  min-width: 0;
}
.splat-gallery-copy strong {
  color: var(--text);
  font-size: 15px;
  overflow-wrap: anywhere;
}
.splat-gallery-copy span {
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10.5px;
}
.splat-gallery-copy small {
  color: var(--text-muted);
  font-size: 11px;
  line-height: 1.35;
}
.splat-roadmap-note {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  border: 1px solid color-mix(in oklch, var(--warning) 30%, var(--border));
  border-radius: 8px;
  background: color-mix(in oklch, var(--warning) 8%, var(--surface));
  padding: 0.9rem 1rem;
  margin: 1rem 0;
}
.splat-roadmap-note strong,
.splat-roadmap-note p {
  display: block;
}
.splat-roadmap-note strong {
  color: var(--text);
  font-size: 14px;
}
.splat-roadmap-note p {
  margin: 0.25rem 0 0;
  color: var(--text-dim);
  font-size: 12px;
}
.splat-wizard-shell {
  border: 1px solid color-mix(in oklch, var(--primary) 35%, var(--border));
  border-radius: 8px;
  background: color-mix(in oklch, var(--primary-soft) 10%, var(--bg));
  padding: 1rem;
  margin-top: 1rem;
}
.splat-wizard-shell.is-hidden {
  display: none;
}
.splat-wizard-head {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 1rem;
  min-width: 0;
}
.splat-wizard-head h2 {
  margin: 0.2rem 0 0;
  color: var(--text);
  font-size: 22px;
}
.splat-wizard-head p {
  margin: 0.35rem 0 0;
  color: var(--text-dim);
  max-width: 78ch;
}
.splat-flow-stepper {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin: 1rem 0 1.1rem;
}
.splat-flow-step {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text-dim);
  padding: 10px 12px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.splat-flow-step b,
.splat-stage-index {
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid var(--border);
  color: var(--text-faint);
  background: var(--surface-2);
  flex: 0 0 auto;
}
.splat-flow-step.done b {
  border-color: color-mix(in oklch, var(--success) 45%, var(--border));
  color: var(--success);
}
.splat-flow-step.active {
  border-color: color-mix(in oklch, var(--primary) 55%, var(--border));
  color: var(--text);
  background: color-mix(in oklch, var(--primary-soft) 62%, var(--surface));
}
.splat-flow-step.active b {
  border-color: var(--primary);
  color: var(--primary);
}
.splat-stage {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: color-mix(in oklch, var(--surface) 82%, var(--bg));
  padding: 1rem;
  margin-bottom: 1rem;
}
.splat-stage-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: start;
  margin-bottom: 0.85rem;
}
.splat-stage-head h2 {
  margin: 0;
  color: var(--text);
  font-size: 18px;
  font-weight: 650;
}
.splat-stage-head p {
  margin: 0.2rem 0 0;
  color: var(--text-dim);
  max-width: 78ch;
}
.splat-stage .splat-create-panel {
  margin-bottom: 0;
  border-color: color-mix(in oklch, var(--primary) 26%, var(--border));
  background: color-mix(in oklch, var(--primary-soft) 34%, var(--surface));
}
.splat-create-panel,
.splat-job-form {
  display: grid;
  gap: 14px;
}
.drone-import-create {
  gap: 18px;
}
.drone-import-copy {
  display: grid;
  gap: 5px;
  max-width: 820px;
}
.splat-kicker {
  display: block;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.drone-import-copy strong {
  color: var(--text);
  font-size: clamp(18px, 2vw, 26px);
  letter-spacing: 0;
}
.drone-import-copy p {
  margin: 0;
  color: var(--text-dim);
  max-width: 72ch;
}
.splat-workflow-steps {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: 6px;
}
.splat-workflow-steps span {
  display: inline-flex;
  gap: 7px;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-dim);
  padding: 5px 9px 5px 6px;
  font-family: var(--font-mono);
  font-size: 10.5px;
}
.splat-workflow-steps b {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--primary);
  color: var(--bg);
  font-size: 10px;
}
.drone-import-form {
  display: grid;
  gap: 12px;
}
.drone-import-grid {
  grid-template-columns: minmax(220px, 0.9fr) minmax(300px, 1.4fr) auto;
}
.drone-source-picker {
  min-width: 0;
}
.drone-source-inputs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.drone-source-inputs input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.drone-source-summary {
  display: block;
  margin-top: 6px;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 10.5px;
  line-height: 1.35;
}
.drone-source-summary.warn {
  color: var(--warning);
}
.splat-dropzone {
  display: grid;
  grid-template-columns: minmax(220px, 0.7fr) 1fr;
  gap: 16px;
  align-items: center;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  padding: 14px;
  border: 1px dashed var(--border-hover);
  border-radius: 8px;
  background: var(--surface-2);
}
.splat-dropzone strong,
.splat-dropzone span,
.splat-row strong,
.splat-row span,
.splat-job-card strong,
.splat-job-card span {
  display: block;
}
.splat-dropzone span,
.splat-job-card span {
  color: var(--text-dim);
  font-size: 12px;
}
.splat-form-grid {
  display: grid;
  grid-template-columns: minmax(180px, 1fr) minmax(140px, 0.5fr) minmax(160px, 0.65fr) auto;
  gap: 0.75rem;
  align-items: end;
  max-width: 100%;
  min-width: 0;
}
.splat-submit {
  min-height: 39px;
}
.splat-guidance {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.splat-guidance span {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-dim);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  padding: 5px 8px;
}
.splat-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin: 1.25rem 0 0.65rem;
}
.splat-section-head h2 {
  margin: 0;
  font-size: 16px;
  color: var(--text);
}
.splat-section-head span {
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.splat-upload-form {
  display: grid;
  grid-template-columns: minmax(150px, 0.7fr) minmax(180px, 1.3fr) auto;
  gap: 0.75rem;
  align-items: end;
  max-width: 100%;
  min-width: 0;
}
.splat-main-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  gap: 1rem;
  align-items: start;
  max-width: 100%;
  min-width: 0;
}
.splat-main-grid-linear {
  grid-template-columns: minmax(0, 1fr);
}
.splat-side-stack {
  display: grid;
  gap: 1rem;
  min-width: 0;
}
.splat-advanced-row {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.splat-secondary-panel {
  margin-bottom: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  padding: 0.85rem 1rem;
}
.splat-secondary-panel summary {
  cursor: pointer;
  font-weight: 650;
  color: var(--text);
  overflow-wrap: anywhere;
  font-size: 14px;
  line-height: 1.3;
}
.splat-secondary-body,
.splat-advanced .splat-upload-form {
  margin-top: 0.85rem;
}
.splat-secondary-panel:not([open]) .splat-secondary-body,
.splat-secondary-panel:not([open]) .splat-upload-form {
  display: none;
}
.splat-job-list {
  display: grid;
  gap: 0.65rem;
}
.drone-import-list {
  display: grid;
  gap: 0.85rem;
}
.drone-import-card {
  display: grid;
  gap: 0.85rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  padding: 1rem;
}
.drone-import-card-head {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: start;
}
.drone-import-card-head strong,
.drone-import-card-head span {
  display: block;
}
.drone-import-card-head strong {
  color: var(--text);
  font-size: 16px;
}
.drone-import-card-head span:not(.splat-kicker) {
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10.5px;
}
.drone-contact-sheet {
  width: auto;
  max-width: min(100%, 560px);
  max-height: 520px;
  object-fit: contain;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--surface-2);
}
.drone-import-metrics {
  display: grid;
  grid-template-columns: repeat(4, minmax(120px, 1fr));
  gap: 8px;
}
.drone-import-metrics div {
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--surface-2);
  padding: 10px 12px;
}
.drone-import-metrics b,
.drone-import-metrics span {
  display: block;
}
.drone-import-metrics b {
  color: var(--text);
  font-size: 18px;
}
.drone-import-metrics span {
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.drone-report-block {
  display: grid;
  gap: 6px;
}
.drone-report-block h3 {
  margin: 0 0 2px;
  color: var(--text);
  font-size: 13px;
}
.drone-report-row,
.drone-video-candidate {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.8rem;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--surface-2);
  padding: 9px 10px;
}
.drone-video-main {
  display: grid;
  gap: 8px;
  min-width: 0;
}
.drone-report-row b,
.drone-report-row span,
.drone-video-candidate b,
.drone-video-candidate span {
  display: block;
}
.drone-report-row b,
.drone-video-candidate b {
  color: var(--text);
  font-size: 12px;
}
.drone-report-row span,
.drone-video-candidate span {
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10px;
}
.drone-video-candidate small {
  display: block;
  color: var(--text-muted);
  font-size: 11px;
  line-height: 1.35;
  margin-top: 2px;
}
.drone-video-upload {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
  align-items: center;
  min-width: min(100%, 280px);
}
.drone-video-upload input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
/* M4 scorecard: per-pass weighted score breakdown + dominant risk. */
.drone-scorecard {
  display: grid;
  gap: 5px;
  margin-top: 7px;
  padding: 7px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: color-mix(in oklch, var(--surface) 80%, var(--bg));
}
.drone-scorecard.rejected {
  border-color: color-mix(in oklch, var(--danger) 45%, var(--border));
  background: color-mix(in oklch, var(--danger) 8%, var(--surface));
}
.drone-scorecard-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}
.drone-scorecard-head b {
  font-size: 12px;
  color: var(--text);
}
.drone-score-label {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-dim);
}
.drone-score-reject {
  font-size: 10px;
  font-weight: 600;
  color: var(--danger);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.drone-score-bars {
  display: grid;
  gap: 3px;
}
.drone-score-bar {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) 28px;
  gap: 6px;
  align-items: center;
}
.drone-score-bar-label {
  font-size: 10px;
  color: var(--text-dim);
}
.drone-score-bar-track {
  height: 6px;
  border-radius: 3px;
  background: color-mix(in oklch, var(--border) 70%, transparent);
  overflow: hidden;
}
.drone-score-bar-fill {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: var(--primary);
}
.drone-score-bar-val {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-muted);
  text-align: right;
}
.drone-score-risk {
  font-size: 10.5px;
  color: var(--text-muted);
  line-height: 1.35;
}
.drone-candidate-rejected {
  opacity: 0.85;
}
/* M4 fusion control. */
.drone-fusion-block {
  border: 1px dashed color-mix(in oklch, var(--primary) 35%, var(--border));
  border-radius: 7px;
  padding: 9px 10px;
  background: color-mix(in oklch, var(--primary-soft) 14%, var(--surface));
}
.drone-fusion-hint {
  margin: 0 0 4px;
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.4;
}
.drone-fusion-pair {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 6px 8px;
  align-items: center;
  padding: 4px 0;
}
.drone-fusion-pair small {
  grid-column: 2;
  font-size: 10px;
  color: var(--text-dim);
}
.splat-quality-panel {
  display: grid;
  gap: 8px;
  max-width: 760px;
  border: 1px solid color-mix(in oklch, var(--primary) 22%, var(--border));
  border-radius: 7px;
  background: color-mix(in oklch, var(--primary-soft) 22%, var(--surface));
  padding: 10px;
}
.splat-quality-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(145px, auto);
  gap: 10px;
  align-items: end;
}
.splat-quality-head b,
.splat-quality-head span,
.splat-quality-head label,
.splat-expert-controls label {
  display: block;
}
.splat-quality-head b {
  color: var(--text);
  font-size: 12px;
}
.splat-quality-head span,
.splat-quality-panel p {
  color: var(--text-dim);
  font-size: 11px;
  margin: 0;
}
.splat-quality-head label,
.splat-expert-controls label {
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.splat-quality-panel .input-sm {
  min-height: 32px;
  padding: 6px 8px;
  margin-top: 4px;
  font-size: 12px;
}
.splat-expert-controls {
  border-top: 1px solid var(--border);
  padding-top: 8px;
}
.splat-expert-controls summary {
  cursor: pointer;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.splat-expert-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(120px, 1fr));
  gap: 8px;
  margin-top: 8px;
}
.splat-quality-result {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 8px;
  color: var(--text-dim);
  font-size: 11px;
}
.splat-quality-result b {
  color: var(--success);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.drone-import-actions {
  justify-content: flex-end;
}
.splat-job-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  padding: 0.9rem 1rem;
}
.splat-job-card.failed {
  border-color: color-mix(in srgb, var(--danger) 38%, var(--border));
}
.splat-job-title-row,
.splat-job-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-width: 0;
  flex-wrap: wrap;
}
.splat-status {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  padding: 4px 7px;
  white-space: nowrap;
}
.splat-status.ready { color: var(--success); }
.splat-status.failed { color: var(--danger); }
.splat-status.running { color: var(--primary); }
.splat-progress {
  height: 8px;
  margin: 10px 0 8px;
  overflow: hidden;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.splat-progress span {
  display: block;
  height: 100%;
  background: var(--primary);
  transition: width 220ms ease-out;
}
.splat-job-meta,
.splat-job-event,
.splat-job-error {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
}
.splat-job-event {
  color: var(--text-dim);
  margin-top: 8px;
}
.splat-job-error {
  color: var(--danger);
  margin-top: 8px;
}
.splat-list {
  display: grid;
  gap: 0.65rem;
}
.splat-row {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr);
  gap: 1rem;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  padding: 0.85rem 1rem;
}
.splat-preview {
  width: 58px;
  height: 58px;
  flex: 0 0 58px;
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  border: 1px solid var(--border);
  background: var(--surface-2);
  background-size: cover;
  background-position: center;
  display: grid;
  place-items: center;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 11px;
}
.splat-row-main {
  flex: 1;
  min-width: 0;
}
.splat-row-main strong,
.splat-job-title-row strong {
  overflow-wrap: anywhere;
}
.splat-row strong,
.splat-row span,
.splat-row small,
.vision-feedback-panel strong,
.vision-feedback-panel span {
  display: block;
}
.splat-row span,
.vision-feedback-panel span {
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 10.5px;
}
.splat-row small {
  color: var(--text-muted);
  font-size: 11px;
  margin-top: 3px;
}
.splat-actions,
.report-run-actions,
.vision-feedback-chips {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
}
.splat-row .splat-actions {
  grid-column: 1 / -1;
  justify-content: flex-end;
}
.vision-feedback-panel {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: center;
}
.vision-feedback-panel code {
  color: var(--text-dim);
  font-size: 11px;
}

.site-intelligence-tabs {
  position: sticky;
  top: 74px;
  z-index: 8;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.5rem;
  margin: 0.25rem 0 1rem;
  padding: 0.45rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(10px);
}
.site-intelligence-tab {
  min-width: 0;
  display: grid;
  gap: 0.15rem;
  padding: 0.65rem 0.75rem;
  border: 1px solid transparent;
  border-radius: calc(var(--r) - 2px);
  background: transparent;
  color: var(--text-dim);
  text-align: left;
  cursor: pointer;
}
.site-intelligence-tab span {
  color: var(--text-main);
  font-weight: 800;
}
.site-intelligence-tab small {
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  white-space: nowrap;
}
.site-intelligence-tab.active {
  border-color: var(--primary);
  background: var(--primary-soft);
}
.site-intelligence-tab-panel[hidden] {
  display: none !important;
}
.site-intelligence-layout-shell {
  display: grid;
  gap: 1rem;
}
.site-mode-head {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
}
.site-mode-head h2,
.site-mode-head p {
  margin: 0;
}
.site-mode-head h2 {
  font-size: 1.05rem;
}
.site-mode-head p {
  margin-top: 0.2rem;
  color: var(--text-dim);
  font-size: var(--t-sm);
}

.site-watch-panel {
  gap: 1rem;
}
.site-watch-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(280px, 0.9fr);
  gap: 1rem;
  align-items: start;
}
.site-watch-live,
.site-watch-recordings,
.site-watch-playback {
  min-width: 0;
  display: grid;
  gap: 0.65rem;
}
.site-watch-player {
  width: 100%;
  aspect-ratio: 16 / 9;
  min-height: 220px;
  object-fit: contain;
  background: #050505;
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.site-recording-timeline {
  display: grid;
  gap: 0.45rem;
  max-height: 420px;
  overflow: auto;
  padding-right: 0.2rem;
}
.site-recording-row {
  width: 100%;
  text-align: left;
  color: inherit;
  cursor: pointer;
}
.site-recording-row.active {
  border-color: var(--primary);
  background: var(--primary-soft);
}
.site-watch-playback {
  border-top: 1px solid var(--border);
  padding-top: 1rem;
}
.site-watch-saved-clips {
  border-top: 1px solid var(--border);
  padding-top: 1rem;
  display: grid;
  gap: 0.55rem;
}
.site-saved-clips {
  display: grid;
  gap: 0.45rem;
}
.site-saved-clip-row {
  background: var(--surface);
}
.site-clip-export {
  display: flex;
  align-items: end;
  gap: 0.65rem;
  flex-wrap: wrap;
}
.site-clip-export label {
  display: grid;
  gap: 0.25rem;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.site-clip-export input {
  width: 7rem;
}
.site-events-root {
  display: grid;
  gap: 0.75rem;
}
.site-find-command {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.75rem;
  align-items: end;
}
.site-find-command textarea {
  min-height: 4.5rem;
  resize: vertical;
}
.site-find-shortcuts {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
}
.site-search-workspace {
  display: grid;
  gap: 0.75rem;
}
.site-search-query-label {
  display: grid;
  gap: 0.3rem;
  color: var(--text-main);
  font-weight: 800;
}
.site-search-query-label input {
  width: min(46rem, 100%);
}
.site-events-tools {
  display: flex;
  align-items: end;
  gap: 0.65rem;
  flex-wrap: wrap;
}
.site-events-tools-heading {
  flex-basis: 100%;
  font-weight: 800;
  color: var(--text-main);
}
.site-events-tools label {
  display: grid;
  gap: 0.25rem;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.site-events-tools input {
  width: min(20rem, 72vw);
}
.site-events-tools input[type="datetime-local"] {
  width: 13rem;
}
.site-events-tools select {
  width: 12rem;
}
.site-search-interpretation {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.75rem;
  background: var(--surface);
}
.site-search-groups {
  display: grid;
  gap: 0.85rem;
}
.site-search-group {
  display: grid;
  gap: 0.55rem;
}
.site-search-group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.site-safety-panel {
  gap: 0.9rem;
}
.site-gate-panel {
  gap: 0.9rem;
}
.site-automation-panel {
  gap: 0.9rem;
}
.site-ask-panel {
  gap: 0.9rem;
}
.site-safety-summary-root {
  display: grid;
  gap: 0.75rem;
}
.site-gate-summary-root {
  display: grid;
  gap: 0.75rem;
}
.site-automation-summary-root {
  display: grid;
  gap: 0.75rem;
}
.site-safety-detail {
  display: grid;
  grid-template-columns: minmax(160px, 0.7fr) minmax(0, 1.4fr) minmax(150px, 0.8fr);
  gap: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.75rem;
  background: var(--surface);
}
.site-ppe-compliance {
  display: grid;
  gap: 0.55rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.75rem;
  background: var(--surface);
}
.site-safety-review-queue {
  display: grid;
  gap: 0.65rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.75rem;
  background: var(--surface);
}
.site-safety-review-queue.is-loading {
  opacity: 0.72;
}
.site-safety-review-head {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.site-safety-review-counts {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.site-safety-review-list {
  display: grid;
  gap: 0.55rem;
}
.site-safety-review-row {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr) auto;
  gap: 0.75rem;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.65rem;
  background: var(--surface-muted);
}
.site-safety-review-main {
  min-width: 0;
}
.site-safety-review-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.site-ppe-latest {
  gap: 0.5rem;
}
.site-gate-detail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(150px, 0.7fr) minmax(220px, 1fr);
  gap: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.75rem;
  background: var(--surface);
}
.site-gate-timeline {
  display: grid;
  gap: 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.75rem;
  background: var(--surface);
}
.site-gate-timeline-row {
  min-height: 3.25rem;
}
.site-gate-activity-events {
  display: grid;
  gap: 0.65rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.75rem;
  background: var(--surface);
}
.site-gate-feed-head {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.site-gate-event-list {
  display: grid;
  gap: 0.55rem;
}
.site-gate-event-row {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr) auto;
  gap: 0.75rem;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.65rem;
  background: var(--surface-muted);
}
.site-automation-grid {
  display: grid;
  gap: 0.75rem;
}
.site-automation-opportunities {
  display: grid;
  gap: 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.75rem;
  background: var(--surface);
}
.site-automation-section-head {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.site-automation-opportunity-row {
  text-align: left;
  background: var(--surface-muted);
}
.site-automation-priority-high {
  border-color: color-mix(in srgb, var(--danger, #b42318) 38%, var(--border));
}
.site-automation-actions {
  display: grid;
  gap: 0.5rem;
}
.site-automation-action-row {
  text-align: left;
}
.site-ask-box {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.65rem;
  align-items: end;
}
.site-ask-box textarea {
  min-height: 4.25rem;
  resize: vertical;
}
.site-ask-result,
.site-ask-answer {
  display: grid;
  gap: 0.65rem;
}
.site-ask-answer {
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.75rem;
  background: var(--surface);
}
.site-ask-answer p {
  margin: 0;
  color: var(--text);
  line-height: 1.5;
}
.site-ask-evidence {
  display: flex;
  gap: 0.45rem;
  flex-wrap: wrap;
}
.review-level {
  font-weight: 700;
}
.site-events-summary {
  display: grid;
  gap: 0.25rem;
  color: var(--text-dim);
  font-size: var(--t-sm);
}
.site-events-summary span:first-child {
  color: var(--text);
  font-weight: 700;
}
.site-event-list {
  display: grid;
  gap: 0.55rem;
}
.site-event-row {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr) auto;
  gap: 0.75rem;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.65rem;
  background: var(--surface);
}
.site-event-thumb {
  width: 96px;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: calc(var(--r) - 2px);
  background: var(--surface-muted);
}
.site-event-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.site-event-thumb-empty {
  width: 100%;
  height: 100%;
  background: repeating-linear-gradient(135deg, var(--surface-muted), var(--surface-muted) 8px, var(--surface) 8px, var(--surface) 16px);
}
.site-event-main {
  min-width: 0;
}
.site-event-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  justify-content: flex-end;
}

@media (max-width: 920px) {
  .site-intelligence-tabs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    top: 58px;
  }
  .site-watch-grid {
    grid-template-columns: 1fr;
  }
  .site-watch-player {
    min-height: 180px;
  }
  .site-event-row {
    grid-template-columns: 84px minmax(0, 1fr);
  }
  .site-event-actions {
    grid-column: 1 / -1;
    justify-content: flex-start;
  }
  .site-safety-detail {
    grid-template-columns: 1fr;
  }
  .site-gate-detail {
    grid-template-columns: 1fr;
  }
  .site-find-command,
  .site-ask-box {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .site-intelligence-tab-panel,
  .site-intelligence-layout-shell,
  .site-intelligence-layout-shell .vision-vlm-panel {
    min-width: 0;
    max-width: 100%;
  }
  .site-intelligence-layout-shell .vision-vlm-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
  }
  .site-intelligence-layout-shell .vision-vlm-head > div {
    min-width: 0;
  }
  .site-intelligence-layout-shell .vision-vlm-head p {
    overflow-wrap: anywhere;
  }
  .site-watch-panel,
  .site-watch-panel .vision-vlm-head {
    min-width: 0;
    max-width: 100%;
  }
  .site-watch-panel {
    grid-template-columns: minmax(0, 1fr);
  }
  .site-watch-panel .vision-vlm-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
  }
  .site-watch-panel .vision-vlm-head > div {
    min-width: 0;
  }
  .site-watch-panel .vision-vlm-head p {
    overflow-wrap: anywhere;
  }
  .site-watch-panel .vision-feedback-panel {
    align-items: stretch;
    grid-template-columns: minmax(0, 1fr);
    overflow: hidden;
  }
  .site-watch-panel .vision-feedback-panel > div {
    min-width: 0;
  }
  .site-watch-panel .vision-feedback-panel span {
    overflow-wrap: anywhere;
    white-space: normal;
  }
  .site-watch-panel .vision-feedback-panel .btn {
    min-width: 0;
    width: 100%;
    white-space: normal;
  }
  .site-watch-health.ph-stats-strip {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .site-watch-health.ph-stats-strip .stat-pill {
    min-width: 0;
    border-bottom: 1px solid var(--border);
  }
  .site-watch-health.ph-stats-strip .stat-pill:nth-child(2n) {
    border-right: 0;
  }
  .site-watch-health.ph-stats-strip .stat-pill:nth-last-child(-n + 2) {
    border-bottom: 0;
  }
  .site-watch-health.ph-stats-strip .stat-pill .s {
    overflow-wrap: anywhere;
  }
  .site-find-command .report-run-actions {
    justify-content: flex-start;
  }
  .site-event-row,
  .site-event-list,
  .site-search-groups,
  .site-events-root {
    min-width: 0;
  }
  .site-event-main .report-row-meta {
    overflow-wrap: anywhere;
  }
  .site-saved-clip-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    min-width: 0;
  }
  .site-saved-clip-row .report-chip {
    justify-self: start;
  }
  .site-saved-clip-row .report-row-title,
  .site-saved-clip-row .report-row-meta {
    min-width: 0;
    overflow-wrap: anywhere;
  }
}

@media (max-width: 900px) {
  .canvas-grid-standalone .canvas-main,
  .canvas-grid-standalone .canvas-surface {
    min-height: calc(100vh - 220px);
  }
  .canvas-grid-standalone .canvas-inline-tools {
    position: relative;
    left: auto;
    top: auto;
    max-width: 100%;
    margin: 10px;
  }
  .canvas-grid-standalone .canvas-layer-panel,
  .canvas-grid-standalone .canvas-splat-toolbar {
    align-items: stretch;
    flex-direction: column;
  }
  .canvas-grid-standalone .canvas-splat-toolbar {
    left: 10px;
    right: 10px;
    bottom: 10px;
    max-width: none;
  }
  .splat-flow-stepper {
    grid-template-columns: 1fr;
  }
  .splat-form-grid,
  .drone-import-grid,
  .drone-server-row,
  .splat-ready-hero,
  .splat-ready-metrics,
  .splat-dropzone,
  .splat-upload-form,
  .splat-main-grid,
  .drone-import-card-head,
  .drone-import-metrics,
  .drone-report-row,
  .drone-video-candidate,
  .splat-job-card,
  .splat-row,
  .vision-feedback-panel {
    display: grid;
    grid-template-columns: 1fr;
  }
  .splat-row,
  .splat-job-card {
    align-items: stretch;
  }
  .splat-row .splat-actions {
    justify-content: stretch;
  }
  .splat-row .splat-actions .btn {
    justify-content: center;
  }
  .splat-home-actions,
  .splat-roadmap-note,
  .splat-wizard-head {
    align-items: stretch;
    flex-direction: column;
  }
  .splat-home-actions .btn,
  .splat-roadmap-note .btn,
  .splat-wizard-head .btn {
    justify-content: center;
  }
  .splat-ready-preview {
    min-height: 180px;
  }
  .splat-quality-head,
  .splat-expert-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 1280px) {
  .splat-main-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 900px) {
  .station-overview-grid,
  .station-overview-two,
  .station-settings-shortcut-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 760px) {
  .station-context-bar,
  .station-context-main {
    display: flex;
    flex-direction: column;
    align-items: stretch;
  }
}

/* === Section 24: Canvas pattern-context strip === */
.canvas-pattern-context {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 14px;
  margin: 0 0 6px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: 5px;
  font-family: var(--font-mono);
  font-size: 11px;
}
.canvas-pattern-context-id {
  color: var(--text-faint);
  font-weight: 500;
}
.canvas-pattern-context-headline {
  font-family: var(--font-sans);
  font-weight: 500;
  color: var(--text);
  flex: 1 1 auto;
}
.canvas-pattern-context-severity {
  padding: 2px 8px;
  border-radius: var(--r-sm);
  font-weight: 500;
}
.canvas-pattern-context-severity-low  { background: var(--surface-2); color: var(--text-dim); }
.canvas-pattern-context-severity-med  { background: var(--warn-soft); color: var(--warn); }
.canvas-pattern-context-severity-high { background: var(--danger-soft); color: var(--danger); }
.canvas-pattern-context-back {
  color: var(--text-dim);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.canvas-pattern-context-back:hover { color: var(--primary); }

/* ── W4.3: Markup Studio — Markups List panel ───────────────────────── */
.markup-list-panel {
  margin-top: 10px;
  padding: 10px;
  background: var(--surface-2);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
  border: 1px solid var(--border);
}
.markup-list-head {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 7px;
}
.markup-list-empty {
  font-size: 11px;
  color: var(--text-faint);
}
.markup-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 4px;
  max-height: 200px;
  overflow-y: auto;
}
.markup-list-row {
  /* Compact mode for the narrow studio panel: only # / type / status fit
   * comfortably. Author + created collapse to tooltips. The wide grid
   * (6 columns) overflowed the 180–220px left rail and ate the
   * description into 0px width. */
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr) auto;
  gap: 6px;
  align-items: center;
  padding: 4px 6px;
  border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  cursor: pointer;
  font-size: 11px;
  min-width: 0;
}
.markup-list-row:hover { background: var(--surface); }
.markup-list-row.selected { background: var(--surface); border-left: 2px solid var(--primary); padding-left: 4px; }
.markup-list-num { font-family: var(--font-mono); color: var(--text-faint); }
.markup-list-type {
  /* Type chip — replaces the desc column in compact mode. The full
   * description is still readable via title attribute / hover. */
  font-family: var(--font-mono);
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.markup-list-desc { display: none; }
.markup-list-author, .markup-list-created { display: none; }
.markup-list-status {
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 1px 7px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  background: var(--surface);
  cursor: pointer;
}
.markup-list-status-open        { color: var(--text-dim); }
.markup-list-status-in_progress { background: var(--warn-soft); color: var(--warn); border-color: var(--warn); }
.markup-list-status-resolved    { background: var(--success-soft); color: var(--success); border-color: var(--success); }

/* ── Section 24: Patterns landing page (W2, 2026-05-23) ─────────────────── */
.project-patterns-view { padding: 0 18px 24px; }
.patterns-toolbar {
  display: flex; gap: 10px; align-items: center;
  margin: 8px 0 16px;
  font-family: var(--font-mono); font-size: 11px;
}
.patterns-toolbar select {
  padding: 5px 9px; border: 1px solid var(--border); border-radius: 5px;
  background: var(--surface-2); color: var(--text); font-family: inherit; font-size: inherit;
}
.patterns-toolbar-toggle { display: inline-flex; align-items: center; gap: 5px; }
.patterns-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 12px;
}
.patterns-empty {
  padding: 36px;
  text-align: center;
  color: var(--text-faint);
  border: 1px dashed var(--border);
  border-radius: var(--r-sm); /* FND-C05: was 6px off-scale → --r-sm (5px) */
}

/* S3.1 — Proper empty state for Patterns landing (zero patterns) */
.patterns-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 48px 24px 36px;
  text-align: center;
}
.patterns-empty-icon {
  color: var(--text-faint);
  opacity: 0.7;
  margin-bottom: 4px;
}
.patterns-empty-headline {
  font-size: 1.1rem;
  font-weight: 500;
  color: var(--text);
  margin: 0;
  letter-spacing: -0.01em;
}
.patterns-empty-sub {
  font-size: 0.83rem;
  color: var(--text-dim);
  max-width: 380px;
  line-height: 1.5;
  margin: 0;
}
.patterns-empty-state .btn-primary { margin-top: 4px; }

/* Dimmed skeleton cards — show what populated state looks like */
.patterns-skeleton-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  width: 100%;
  max-width: 640px;
  margin-top: 20px;
  opacity: 0.22;
  pointer-events: none;
}
.patterns-skeleton-card {
  height: 90px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.pattern-card {
  display: grid; grid-template-rows: auto 1fr; gap: 8px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
  overflow: hidden;
  transition: border-color 120ms ease;
}
.pattern-card:hover { border-color: var(--primary); }
.pattern-card-strip { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 2px; height: 90px; background: var(--surface-2); }
.pattern-card-strip img { width: 100%; height: 100%; object-fit: cover; }
.pattern-card-strip.empty { background: var(--surface-2); }
.pattern-card-body { padding: 10px 12px; display: grid; gap: 6px; }
.pattern-card-head { display: flex; justify-content: space-between; align-items: center; }
.pattern-card-id { font-family: var(--font-mono); font-size: 10px; color: var(--text-faint); }
.pattern-card-severity {
  font-family: var(--font-mono); font-size: 10px;
  padding: 1px 8px; border-radius: 999px;
}
.pattern-card-severity-low  { background: var(--surface-2); color: var(--text-dim); }
.pattern-card-severity-med  { background: var(--warn-soft); color: var(--warn); }
.pattern-card-severity-high { background: var(--danger-soft); color: var(--danger); }
.pattern-card-headline { font-size: 14px; line-height: 1.3; color: var(--text); }
.pattern-card-facts { font-family: var(--font-mono); font-size: 11px; color: var(--text-dim); }
.pattern-card-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.pattern-card-action {
  font-family: var(--font-sans); font-size: 11px;
  padding: 4px 10px; border: 1px solid var(--border); border-radius: 5px;
  background: var(--surface); color: var(--text-dim); cursor: pointer; text-decoration: none;
}
.pattern-card-action.primary { background: var(--primary); color: var(--primary-fg, #fff); border-color: var(--primary); }
.pattern-card-action:hover { border-color: var(--primary); color: var(--primary); }
.pattern-card-action.primary:hover { background: var(--primary-hover); }
.pattern-card-feedback {
  display: flex; gap: 6px; align-items: center;
  padding-top: 6px; border-top: 1px dashed var(--border);
  font-family: var(--font-mono); font-size: 10px; color: var(--text-faint);
}
.pattern-card-feedback button {
  background: transparent; border: 1px solid var(--border); border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  padding: 2px 7px; font-family: inherit; font-size: inherit; color: var(--text-dim); cursor: pointer;
}
.pattern-card-feedback button:hover { border-color: var(--primary); color: var(--primary); }
.pattern-card-feedback button:disabled { opacity: 0.55; cursor: default; }

/* ============================================================
   Section 24 — Pattern Rules widget (F7 / 2026-05-23)
   Rules list on the project home dashboard.
   ============================================================ */

/* Container card */
.pattern-rules-list {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r); overflow: hidden;
  margin-bottom: 28px;
}
.pattern-rules-empty {
  padding: 20px 18px; font-family: var(--font-mono); font-size: 12px;
  color: var(--text-faint); letter-spacing: 0.04em;
}
/* S3.2 — empty-state layout with inline CTA */
.pattern-rules-empty-state {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px;
  flex-wrap: wrap;
}
.pattern-rules-empty-msg {
  font-family: var(--font-mono); font-size: 12px;
  color: var(--text-faint); letter-spacing: 0.04em;
}

/* Each rule row */
.pr-row {
  display: grid; grid-template-columns: 1fr auto auto auto auto;
  align-items: center; gap: 8px;
  padding: 10px 14px; border-bottom: 1px solid var(--border);
  font-size: 13px; transition: background 0.1s;
}
.pr-row:last-child { border-bottom: 0; }
.pr-row:hover { background: var(--surface-2); }

/* Disabled state — dim everything */
.pr-row.pr-disabled { opacity: 0.55; }

/* Rule name */
.pr-name {
  font-family: var(--font-sans); font-size: 13px;
  color: var(--text); line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pr-name .pr-class {
  font-family: var(--font-mono); font-size: 11px;
  color: var(--text-dim); letter-spacing: 0.04em; margin-left: 6px;
}

/* Severity badge */
.pr-badge {
  font-family: var(--font-mono); font-size: 10px; font-weight: 500;
  letter-spacing: 0.07em; text-transform: uppercase;
  padding: 2px 7px; border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */ white-space: nowrap;
}
.pr-badge-low  { background: var(--surface-2); color: var(--text-faint); border: 1px solid var(--border); }
.pr-badge-med  { background: var(--warn-soft);    color: var(--warn);         border: 1px solid var(--warn); }
.pr-badge-high { background: var(--danger-soft);  color: var(--danger);       border: 1px solid var(--danger); }

/* Detector type chip */
.pr-detector {
  font-family: var(--font-mono); font-size: 10.5px;
  color: var(--text-faint); letter-spacing: 0.03em; white-space: nowrap;
}

/* Toggle button (enable/disable) */
.pr-toggle {
  background: transparent; border: 1px solid var(--border); border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  padding: 2px 8px; font-family: var(--font-mono); font-size: 10px;
  color: var(--text-dim); cursor: pointer; white-space: nowrap;
  transition: border-color 0.1s, color 0.1s;
}
.pr-toggle:hover { border-color: var(--primary); color: var(--primary); }
.pr-toggle.enabled { border-color: var(--success); color: var(--success); }
.pr-toggle.enabled:hover { border-color: var(--danger); color: var(--danger); }

/* Edit / delete mini-buttons */
.pr-actions { display: flex; gap: 4px; }
.pr-action {
  background: transparent; border: 1px solid var(--border); border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  padding: 2px 7px; font-family: var(--font-mono); font-size: 10px;
  color: var(--text-dim); cursor: pointer;
}
.pr-action:hover { border-color: var(--primary); color: var(--primary); }
.pr-action.del:hover { border-color: var(--danger); color: var(--danger); }

/* Rules form modal — re-uses existing .modal infrastructure */
.pr-form { display: flex; flex-direction: column; gap: 12px; }
.pr-form label {
  display: flex; flex-direction: column; gap: 4px;
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim);
}
.pr-form input[type="text"],
.pr-form input[type="number"],
.pr-form select {
  font-family: var(--font-sans); font-size: 13px;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--r-sm); /* FND-C05: collapse 4px legacy → 5px Stratum --r-sm */
  padding: 6px 8px; outline: none; width: 100%; box-sizing: border-box;
}
.pr-form input[type="text"]:focus,
.pr-form input[type="number"]:focus,
.pr-form select:focus { border-color: var(--primary); }
.pr-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
/* S3.14 — Detector hint icon */
.pr-field-hint { font-size: 11px; color: var(--text-faint); cursor: help; margin-left: 4px; vertical-align: middle; }
.pr-field-hint:hover { color: var(--text-dim); }
/* S3.15 — Plain-language rule preview */
.pr-preview {
  font-family: var(--font-mono); font-size: 11px; line-height: 1.5;
  color: var(--text-dim); letter-spacing: 0.03em;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: 8px 10px;
  margin-top: 6px;
}
.pr-form-err {
  font-family: var(--font-mono); font-size: 11px;
  color: var(--danger); min-height: 14px;
}
/* Window kind sub-fields */
.pr-window-extra { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }

/* E6 (Anna's-week): inline validation error treatment for form inputs.
 * Used by the add-station modal; available for any input that needs to
 * flag itself invalid without a full form-library treatment. */
.input.input-error,
.input-error.input {
  border-color: var(--danger);
  box-shadow: 0 0 0 1px var(--danger);
}
.input.input-error:focus,
.input-error.input:focus {
  outline-color: var(--danger);
}
.form-error {
  color: var(--danger);
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.4;
  margin-top: 6px;
}
/* Batch A (2026-05-28): inline form helper text — sits below an input
 * to clarify what the field is for. Sibling of .form-error. */
.form-help {
  color: var(--text-dim);
  font-size: var(--t-sm);
  line-height: 1.4;
  margin-top: 6px;
}

/* ────────────────────────────────────────────────────────────────────
 * Batch C (2026-05-28): loading skeletons. CSS-only shimmer used by
 * gallery / detections / recordings / patterns / project home while
 * async data arrives, replacing "Loading…" text nodes.
 * prefers-reduced-motion guard turns the shimmer off (static block stays).
 * ──────────────────────────────────────────────────────────────────── */
.sk-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 8px;
}
.sk-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}
.sk-tile {
  background: var(--surface-2);
  border-radius: var(--r-sm);
  min-height: 96px;
  position: relative;
  overflow: hidden;
}
.sk-tile.sk-tile--row {
  min-height: 56px;
}
.sk-tile.sk-tile--line {
  min-height: 14px;
}
.sk-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    color-mix(in srgb, var(--surface) 55%, transparent) 50%,
    transparent 100%
  );
  transform: translateX(-100%);
  animation: sk-shimmer 1.4s ease-in-out infinite;
}
@keyframes sk-shimmer {
  100% { transform: translateX(100%); }
}
@media (prefers-reduced-motion: reduce) {
  .sk-tile::after { animation: none; opacity: 0; }
}

/* Batch L (2026-05-28): lightbox detection-layer loading overlay.
 * A subtle pulsing border on the layer signals AI work in flight
 * without covering the underlying image. */
.lb-det-loading-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  border: 2px dashed var(--primary);
  border-radius: 4px;
  opacity: 0.65;
  animation: lb-det-loading-pulse 1.2s ease-in-out infinite;
}
@keyframes lb-det-loading-pulse {
  0%, 100% { opacity: 0.30; }
  50%      { opacity: 0.75; }
}
@media (prefers-reduced-motion: reduce) {
  .lb-det-loading-overlay { animation: none; opacity: 0.55; }
}

/* ────────────────────────────────────────────────────────────────────
 * Section 20 — Token foundation extension (UX overhaul Phase 1, 2026-05-27)
 *
 * Adds the user-spec systematic token scales (space, transition, shadow-lg,
 * radius-lg/full, font weights, text-3xl/4xl, semantic colour aliases)
 * ALONGSIDE the existing Site Notes tokens. The short names (--text, --bg,
 * --primary, --surface, …) remain the canonical references; the long names
 * below are aliases new components can adopt without a global rename PR.
 *
 * Rationale: 15.5k lines of CSS already use the short names; rename = big
 * regression risk for marginal gain. Migration happens organically.
 * ──────────────────────────────────────────────────────────────────── */

:root {
  /* Type scale extension — adds 3xl/4xl to the existing xs..2xl scale. */
  --text-3xl: 2.25rem;   /* 36px — hero headlines */
  --text-4xl: 3rem;      /* 48px — landing splash */

  /* Font weights — explicit names so callers don't sprinkle literals. */
  --font-normal:   400;
  --font-medium:   500;
  --font-semibold: 600;
  --font-bold:     700;

  /* Spacing scale — 4px base grid; mirrors Tailwind defaults so muscle
     memory transfers. Use these for margin/padding/gap; never literal px. */
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  20px;
  --space-6:  24px;
  --space-7:  28px;
  --space-8:  32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-14: 56px;
  --space-16: 64px;
  --space-20: 80px;

  /* Radius — extends existing sm/(default)/md with lg + full. */
  --radius-lg:   16px;
  --radius-full: 9999px;

  /* Shadow scale — extends existing sm/(default)/md with a deeper lg
     for floating elements (popovers, modals, drag overlays). Warm
     graphite to match the existing scale. */
  --shadow-lg: 0 12px 32px -8px rgba(42,38,32,0.18),
               0 6px 12px -4px rgba(42,38,32,0.12);

  /* Transitions — single source of truth for animation durations. All
     ease-out; honors prefers-reduced-motion via consumer @media rules. */
  --transition-fast: 100ms ease-out;
  --transition-base: 200ms ease-out;
  --transition-slow: 300ms ease-out;

  /* Semantic colour aliases — let new code use long expressive names
     while old code keeps the short names. Both resolve to the same hex
     so theme switching stays consistent. */
  --color-text-primary:   var(--text);
  --color-text-muted:     var(--text-dim);
  --color-text-faint:     var(--text-faint);
  --color-surface:        var(--surface);
  --color-surface-raised: var(--surface-2);
  --color-border:         var(--border);
  --color-border-subtle:  var(--border);
  --color-border-strong:  var(--border-hover);
  --color-focus-ring:     var(--primary);
  --color-error:          var(--danger);
  --color-success:        var(--success);
  --color-warning:        var(--warn);

  /* Inverse text — for use on dark photographic surfaces (replaces #fff
     hardcodes flagged in the Phase 0 token audit). In light theme this
     is white; in dark theme it flips to the warm bone. */
  --text-inverse: #ffffff;
}

[data-theme="dark"] {
  /* Shadows lifted for darker bg — same envelope, deeper alpha. */
  --shadow-lg: 0 12px 32px -8px rgba(0,0,0,0.55),
               0 6px 12px -4px rgba(0,0,0,0.40);

  /* On dark theme, inverse text flips toward warm ink. */
  --text-inverse: var(--bg);
}

@media (prefers-color-scheme: dark) {
  /* OS dark-mode preference — applies when no explicit data-theme is set
     on <html>. Defensive: the theme toggle (toggle.ts) writes
     data-theme="light" or "dark" explicitly, so this only kicks in for
     unauthed/public surfaces that haven't run the toggle bootstrap. */
  :root:not([data-theme="light"]):not([data-theme="dark"]) {
    --shadow-lg: 0 12px 32px -8px rgba(0,0,0,0.55),
                 0 6px 12px -4px rgba(0,0,0,0.40);
    --text-inverse: var(--bg);
  }
}

/* ────────────────────────────────────────────────────────────────────
 * Section 19 — Dashboard facelift (2026-05-27)
 * Adds: pulsing fleet-marker (DivIcon), leaner KPI float, slightly
 * larger sidebar nav rail. Site Notes token graph only — no hex.
 * Honors prefers-reduced-motion.
 * ──────────────────────────────────────────────────────────────────── */

/* Fleet markers — replaces Leaflet circleMarker. */
.fleet-marker {
  position: relative;
  display: block;
  width: 22px;
  height: 22px;
}
.fleet-marker__core {
  position: absolute;
  inset: 7px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-faint);
  box-shadow: 0 0 0 1.5px var(--surface);
  z-index: 2;
}
.fleet-marker__ripple {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: transparent;
  border: 2px solid var(--text-faint);
  opacity: 0;
  z-index: 1;
  animation: fleet-marker-pulse 2s ease-out infinite;
}
.fleet-marker--ok       .fleet-marker__core   { background: var(--success); }
.fleet-marker--ok       .fleet-marker__ripple { border-color: var(--success); }
.fleet-marker--warn     .fleet-marker__core   { background: var(--warn); }
.fleet-marker--warn     .fleet-marker__ripple { border-color: var(--warn); }
.fleet-marker--bad      .fleet-marker__core   { background: var(--danger); }
.fleet-marker--bad      .fleet-marker__ripple { border-color: var(--danger); }
.fleet-marker--cold     .fleet-marker__core   { background: var(--text-faint); }
.fleet-marker--cold     .fleet-marker__ripple { animation: none; opacity: 0; } /* no pulse on never-seen */
@keyframes fleet-marker-pulse {
  0%   { transform: scale(0.55); opacity: 0.85; }
  70%  { transform: scale(1.6);  opacity: 0; }
  100% { transform: scale(1.6);  opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .fleet-marker__ripple { animation: none; opacity: 0; }
}

/* Dashboard KPI float — lean it down so it stops competing with the map.
 * Removes the heavy per-tile right-border + extra padding inherited from
 * the legacy `.mkf-tile` block; keeps the data legible. */
body.stratum-shell .map-kpi-float {
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 8px 14px;
  box-shadow: none;
}
body.stratum-shell .map-kpi-float .mkf-tile {
  padding: 4px 14px 4px 0;
  border-right: 1px solid var(--border);
  background: transparent;
}
body.stratum-shell .map-kpi-float .mkf-tile:last-child { border-right: 0; padding-right: 0; }
body.stratum-shell .map-kpi-float .mkf-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint);
  line-height: 1;
  margin-bottom: 4px;
}
body.stratum-shell .map-kpi-float .mkf-val {
  font-family: var(--font-mono);
  font-size: 1.05rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  line-height: 1.1;
}
body.stratum-shell .map-kpi-float .mkf-tile.warn .mkf-val { color: var(--warn); }
@media (max-width: 880px) {
  body.stratum-shell .map-kpi-float {
    flex-wrap: wrap;
    gap: 0;
    max-width: calc(100% - 24px);
  }
  body.stratum-shell .map-kpi-float .mkf-tile {
    padding: 4px 10px;
    border-right: 0;
    border-bottom: 1px dashed var(--border);
    flex: 1 1 45%;
  }
}

/* Project list row — compact rail variant (kills the heavy thumb tile
 * look; keeps a small thumb chip + single-line meta). */
body.stratum-shell .proj-row.dash-project-card {
  padding: 10px 14px;
  gap: 12px;
  min-height: 0;
}
body.stratum-shell .proj-row.dash-project-card .proj-thumb {
  width: 40px;
  height: 40px;
  border-radius: 6px;
  flex: 0 0 40px;
}
body.stratum-shell .proj-row.dash-project-card .proj-meta {
  font-size: 0.78rem;
  color: var(--text-dim);
}

/* Sidebar nav polish — a touch wider rail + slightly taller items so
 * the labels breathe; hover/active reuse the established clay accent. */
body.stratum-shell .app-sidebar { width: 244px; }
@media (max-width: 880px) { body.stratum-shell .app-sidebar { width: 100%; } }
body.stratum-shell .app-nav-item {
  min-height: 36px;
  padding: 8px 14px;
  font-size: 14px;
  letter-spacing: 0;
  display: flex;
  align-items: center;
  gap: 10px;
}
body.stratum-shell .app-nav-item:hover {
  background: var(--surface-2);
  border-color: var(--border);
  transform: none;
  box-shadow: none;
}
body.stratum-shell .app-nav-item.active {
  background: var(--surface-2);
  font-weight: 500;
}
body.stratum-shell .shell-nav-label {
  font-size: 10px;
  letter-spacing: 0.12em;
  padding: 14px 14px 6px;
}

/* Recordings IA split (Slice 3, 2026-05-27): sub-tabs + hour grid. */
.rec-subtab-nav { margin-bottom: 14px; }
.rec-hour-grid {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 16px;
}
.rec-hour-row {
  display: grid;
  grid-template-columns: 90px 1fr;
  gap: 12px;
  align-items: center;
}
.rec-hour-row-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.rec-hour-chips {
  display: grid;
  grid-template-columns: repeat(24, minmax(0, 1fr));
  gap: 4px;
}
.rec-hour-chip {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  padding: 6px 0;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 4px;
  cursor: pointer;
  min-height: 32px;
}
.rec-hour-chip:hover:not(.is-empty) { border-color: var(--primary); }
.rec-hour-chip.active {
  background: var(--primary);
  color: var(--primary-fg, #fff);
  border-color: var(--primary);
}
.rec-hour-chip.is-empty {
  color: var(--text-faint);
  background: transparent;
  cursor: not-allowed;
  opacity: 0.45;
}
@media (max-width: 880px) {
  .rec-hour-row { grid-template-columns: 1fr; gap: 4px; }
  .rec-hour-chips { grid-template-columns: repeat(12, minmax(0, 1fr)); }
}

/* Detections tab (Slice 6, 2026-05-27). */
.det-class-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 10px;
}
.det-class-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  cursor: pointer;
  text-align: left;
}
.det-class-card:hover { border-color: var(--primary); }
.det-class-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}
.det-class-label {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.det-class-count {
  font-family: var(--font-mono);
  font-size: 1.25rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.det-class-thumbs {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
  min-height: 56px;
}
.det-class-thumb {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 3px;
}
.det-class-empty {
  font-size: 11px;
  color: var(--text-faint);
}
.det-class-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.det-class-chips .rec-hour-chip {
  padding: 4px 10px;
  min-height: 28px;
  font-size: 11px;
  text-transform: none;
  letter-spacing: 0;
}
.det-chip-count {
  font-family: var(--font-mono);
  font-size: 10px;
  margin-left: 4px;
  opacity: 0.75;
}
.det-feed-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.det-feed-row {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 12px;
  align-items: center;
  padding: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  cursor: pointer;
  text-align: left;
}
.det-feed-row:hover { border-color: var(--primary); }
.det-feed-thumb {
  width: 96px;
  height: 56px;
  object-fit: cover;
  border-radius: 3px;
}

/* Gallery Browse + Scrubber sub-tabs (Slice 5, 2026-05-27). */
.gallery-subtab-nav { margin-bottom: 10px; }
.gallery-bulk-bar {
  display: flex;
  gap: 8px;
  margin-bottom: 10px;
  align-items: center;
}
body.select-mode .gallery-bulk-bar {
  position: sticky;
  bottom: 0;
  padding: 10px 14px;
  background: color-mix(in srgb, var(--surface) 96%, transparent);
  border-top: 1px solid var(--border);
  z-index: 20;
}
.image-card.selected,
.pg-photo-thumb.selected {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}

/* ── Vision AI tab (2026-05-29) — Site Notes tokens (stratum-b.css) ── */
.vai-layout { display: grid; grid-template-columns: 268px 1fr; gap: 20px; align-items: start; }
.vai-rail-card { padding: 14px 15px; margin-bottom: 12px; }
.vai-rail-h { font-family: var(--mono); font-size: var(--t-2xs); font-weight: 500; letter-spacing: .12em; text-transform: uppercase; color: var(--text-2); margin: 0 0 11px; display: flex; align-items: center; justify-content: space-between; }
.vai-clr { color: var(--text-3); text-transform: none; letter-spacing: 0; font-size: 10px; cursor: pointer; }
.vai-seg { display: flex; border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden; }
.vai-seg button { flex: 1; border: 0; background: var(--surface); font-family: var(--mono); font-size: var(--t-xs); padding: 6px 0; color: var(--text-2); border-right: 1px solid var(--border); cursor: pointer; }
.vai-seg button:last-child { border-right: 0; }
.vai-seg button.active { background: var(--primary); color: var(--primary-fg); }
.vai-daterange { margin-top: 9px; font-family: var(--mono); font-size: var(--t-xs); color: var(--text-3); }
.vai-subh { font-family: var(--mono); font-size: 9px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-3); margin: 12px 4px 6px; }
.vai-opt { display: flex; align-items: center; gap: 9px; padding: 6px 4px; border-radius: var(--r-sm); cursor: pointer; width: 100%; border: 0; background: transparent; text-align: left; }
.vai-opt:hover { background: var(--surface-2); }
.vai-cbx { width: 15px; height: 15px; border-radius: 4px; border: 1.5px solid var(--border-s); flex-shrink: 0; display: grid; place-items: center; }
.vai-cbx.on { background: var(--primary); border-color: var(--primary); color: var(--accent); }
.vai-cbx.on::after { content: "✓"; font-size: 10px; font-weight: 700; line-height: 1; }
.vai-lab { flex: 1; font-size: var(--t-md); color: var(--text); }
.vai-cnt { font-family: var(--mono); font-size: var(--t-xs); color: var(--text-3); font-variant-numeric: tabular-nums; }
.vai-opt.vai-zero { opacity: .42; cursor: not-allowed; }
.vai-opt.vai-zero:hover { background: transparent; }
.vai-pip { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; background: var(--text-3); }
.vai-pip-ok { background: var(--ok); }
.vai-pip-warn { background: var(--warn); }
.vai-more { display: flex; align-items: center; gap: 7px; padding: 8px 4px 2px; font-size: var(--t-sm); color: var(--text-2); cursor: pointer; border: 0; border-top: 1px dashed var(--border); background: transparent; margin-top: 8px; width: 100%; }
.vai-more-n { margin-left: auto; font-family: var(--mono); font-size: 10px; color: var(--text-3); }
.vai-searchwithin { margin: 9px 0 4px; }
.vai-searchwithin input { width: 100%; height: 30px; padding: 0 9px; border: 1px solid var(--border); border-radius: var(--r-sm); font-size: var(--t-sm); background: var(--surface); color: var(--text); }
.vai-empty-sm { font-size: var(--t-xs); color: var(--text-3); padding: 6px 4px; }
.vai-results-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; min-height: 32px; }
.vai-fchip { display: inline-flex; align-items: center; gap: 7px; height: 28px; padding: 0 6px 0 11px; border-radius: var(--r-pill); background: var(--accent-soft); border: 1px solid var(--accent); color: var(--accent-fg); font-size: var(--t-sm); font-weight: 500; }
.vai-fchip .vai-x { width: 16px; height: 16px; border-radius: 50%; display: grid; place-items: center; background: rgba(17,17,16,.12); font-size: 10px; cursor: pointer; }
.vai-res-count { font-family: var(--mono); font-size: var(--t-sm); color: var(--text-2); }
.vai-res-count b { color: var(--text); }
.vai-res-actions { margin-left: auto; display: flex; gap: 8px; }
.btn-deep { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
.vai-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.vai-daygroup { margin-bottom: 22px; }
.vai-day-h { display: flex; align-items: center; gap: 10px; margin-bottom: 9px; }
.vai-day-label { font-family: var(--mono); font-size: var(--t-xs); font-weight: 500; letter-spacing: .04em; color: var(--text-2); }
.vai-day-rule { flex: 1; height: 1px; background: var(--border); }
.vai-day-n { font-family: var(--mono); font-size: var(--t-2xs); color: var(--text-3); }
.vai-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.vai-thumb { position: relative; aspect-ratio: 16/10; border-radius: var(--r-sm); border: 1px solid var(--border); overflow: hidden; cursor: pointer; background-size: cover; background-position: center; padding: 0; }
.vai-thumb:hover { border-color: var(--border-h); }
.vai-tmeta { position: absolute; bottom: 0; left: 0; right: 0; padding: 10px 7px 5px; background: linear-gradient(0deg, rgba(0,0,0,.62), transparent); display: flex; gap: 4px; align-items: center; }
.vai-tbadge { font-family: var(--mono); font-size: 8.5px; font-weight: 600; color: #fff; background: rgba(0,0,0,.45); border: 1px solid rgba(255,255,255,.35); border-radius: 3px; padding: 1px 5px; }
.vai-tbadge.acc { background: var(--accent); color: #111110; border-color: var(--accent); }
.vai-ttime { margin-left: auto; font-family: var(--mono); font-size: 8.5px; color: rgba(255,255,255,.85); }
.vai-hint { padding: 28px; text-align: center; color: var(--text-2); font-size: var(--t-sm); }
.vai-empty { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px; padding: 40px 20px; }
.vai-empty-ico { width: 40px; height: 40px; border-radius: 50%; background: var(--surface-2); display: grid; place-items: center; color: var(--text-3); border: 1px solid var(--border); }
.vai-empty-t { font-weight: 600; }
.vai-empty-s { color: var(--text-2); font-size: var(--t-sm); max-width: 360px; }
.vai-empty-a { display: flex; gap: 8px; margin-top: 6px; }
.vai-scan-bar, .vai-scan-note { font-family: var(--mono); font-size: var(--t-xs); color: var(--accent-fg); background: var(--accent-soft); border: 1px solid var(--accent); border-radius: var(--r-sm); padding: 8px 12px; margin-bottom: 12px; }
/* Backlog index status + 'Index now' button (top-right of the Vision AI head). */
.page-meta-col { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.vai-index { display: flex; align-items: center; gap: 8px; font-family: var(--mono); font-size: var(--t-2xs); color: var(--text-3); }
.vai-idx-label { letter-spacing: .04em; }
.vai-idx-run { color: var(--accent-fg); background: var(--accent-soft); border: 1px solid var(--accent); border-radius: var(--r-sm); padding: 2px 8px; letter-spacing: .04em; }
.vai-idx-err { color: var(--danger); }
.vai-idx-off { color: var(--warn); }
.vai-idx-btn { font-family: var(--mono); font-size: var(--t-2xs); letter-spacing: .04em; text-transform: uppercase; color: var(--ink, var(--text)); background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 3px 9px; cursor: pointer; }
.vai-idx-btn:hover { border-color: var(--border-h); background: var(--surface-3, var(--surface-2)); }
/* Top-detection-confidence badge (top-right of each result thumb). */
.vai-tconf { position: absolute; top: 6px; right: 6px; font-family: var(--mono); font-size: 9px; font-weight: 600; color: #fff; background: rgba(0,0,0,.55); border: 1px solid rgba(255,255,255,.3); border-radius: 3px; padding: 1px 5px; letter-spacing: .02em; }
/* Min-confidence slider in the rail. */
.vai-conf-range { -webkit-appearance: none; appearance: none; height: 4px; border-radius: 4px; background: var(--border); outline: none; }
.vai-conf-range::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 14px; height: 14px; border-radius: 50%; background: var(--accent); border: 1px solid var(--accent); cursor: pointer; }
.vai-conf-range::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%; background: var(--accent); border: 1px solid var(--accent); cursor: pointer; }
/* Class-distribution bar above the result grid. */
.vai-dist { display: flex; flex-direction: column; gap: 5px; margin-bottom: 16px; padding: 12px 14px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm); }
.vai-dist-row { display: grid; grid-template-columns: 120px 1fr 32px; align-items: center; gap: 10px; }
.vai-dist-label { font-size: var(--t-xs); color: var(--text-2); text-transform: capitalize; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vai-dist-track { height: 7px; border-radius: 4px; background: var(--surface-3, var(--border)); overflow: hidden; }
.vai-dist-fill { display: block; height: 100%; background: var(--accent); border-radius: 4px; }
.vai-dist-n { font-family: var(--mono); font-size: var(--t-2xs); color: var(--text-3); text-align: right; }
@media (max-width: 880px) {
  .vai-layout { grid-template-columns: 1fr; }
  .vai-grid { grid-template-columns: repeat(2, 1fr); }
}
/* ── TypeScript lightbox (Ship 1) ───────────────────────────────────────── */

html.ts-lightbox-modal-open,
body.ts-lightbox-modal-open {
  width: 100%;
  max-width: 100vw;
  overflow: hidden !important;
  overscroll-behavior: none;
}

body.ts-lightbox-modal-open > :not(#ts-lightbox):not(script):not(style) {
  display: none !important;
}

/* ============================================================
   Stratum lightbox (reskin) — Stratum image-review viewer
   Scoped, always-dark token block + all surface styles.
   Tokens live ONLY under #ts-lightbox so the viewer is immune to
   the host app's light/dark cascade. Values lifted verbatim from
   docs/superpowers/specs/lightbox-design-package/stratum-lightbox/lb.css.
   The root positioning is fixed/inset/z-index (full-screen modal)
   instead of lb.css's relative/100% — the live viewer is appended to
   <body> as an overlay, not nested in a host container.
   ============================================================ */
#ts-lightbox {
  --bg:#0d0d0b; --surface:#161614; --surface-2:#1d1d1a; --surface-3:#262622;
  --border:#2a2a26; --border-hover:#3c3c36;
  --text:#f0f0ea; --text-dim:#aeaea5; --text-faint:#6a6a60;
  --accent:#d2eb3a; --accent-h:#e3f56e; --accent-soft:#2c3608; --accent-fg:#0d0d0b;
  --success:#84cc16; --success-soft:#1a2c08;
  --warn:#d4a017;    --warn-soft:#2c2208;
  --danger:#ef4444;  --danger-soft:#280808;
  --info:#60a5fa;    --info-soft:#0a1e38;
  --primary-fg:#0d0d0b;
  --sans:"Geist", system-ui, sans-serif;
  --mono:"Geist Mono", ui-monospace, monospace;
  --t-2xs:10px; --t-xs:11.5px; --t-sm:12.5px; --t-md:13.5px; --t-lg:15px; --t-xl:18px; --t-2xl:22px;
  --m-xs:11px; --m-sm:11.5px; --m-md:12.5px;
  --r-xs:3px; --r-sm:5px; --r:8px; --r-lg:12px; --r-pill:999px;
  --shadow-md:0 16px 48px -12px rgba(0,0,0,.6);
  --panel-w:340px; --rail-w:60px;
  --ease:cubic-bezier(0.16,1,0.3,1);
}

/* live viewer is a full-screen overlay appended to <body> */
#ts-lightbox.ts-lightbox {
  position:fixed; inset:0; z-index:10020;
  width:100%; height:100%; min-height:540px;
  background:var(--bg); color:var(--text);
  font-family:var(--sans); font-size:var(--t-md);
  -webkit-font-smoothing:antialiased; overflow:hidden;
  display:grid;
  grid-template-columns:var(--rail-w) 1fr var(--panel-w);
  grid-template-rows:1fr auto;
  grid-template-areas:"rail stage panel" "bottom bottom bottom";
}
#ts-lightbox.panel-collapsed { --panel-w:0px; }
#ts-lightbox *, #ts-lightbox *::before, #ts-lightbox *::after { box-sizing:border-box; }
#ts-lightbox .mono { font-family:var(--mono); font-variant-numeric:tabular-nums; }
#ts-lightbox .eyebrow { font-family:var(--mono); font-size:var(--m-xs); text-transform:uppercase; letter-spacing:.08em; color:var(--text-faint); }
#ts-lightbox button { font-family:var(--sans); cursor:pointer; border:0; background:none; color:inherit; }
#ts-lightbox :focus-visible { outline:none; box-shadow:0 0 0 2px var(--bg), 0 0 0 4px var(--accent); border-radius:var(--r-xs); }

/* ---------------- LEFT RAIL ---------------- */
#ts-lightbox .ts-lb-rail { grid-area:rail; background:var(--surface); border-right:1px solid var(--border);
  display:flex; flex-direction:column; align-items:center; gap:var(--s2,8px); padding:14px 0; z-index:6; }
#ts-lightbox .rail-mark { width:26px; height:26px; margin-bottom:10px; opacity:.95; }
#ts-lightbox .rail-btn { position:relative; width:46px; height:48px; border-radius:var(--r-sm);
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3px;
  color:var(--text-dim); transition:background var(--ease) 140ms, color var(--ease) 140ms; }
#ts-lightbox .rail-btn .ico { width:22px; height:22px; display:block; }
#ts-lightbox .rail-btn .lbl { font-family:var(--mono); font-size:9px; text-transform:uppercase; letter-spacing:.05em; }
#ts-lightbox .rail-btn:hover { background:var(--surface-2); color:var(--text); }
#ts-lightbox .rail-btn[aria-pressed="true"] { background:var(--surface-3); color:var(--text); }
#ts-lightbox .rail-btn[aria-pressed="true"] .ico { color:var(--accent); }
#ts-lightbox .rail-btn[aria-pressed="true"]::before { content:""; position:absolute; left:-0px; top:8px; bottom:8px; width:2px; border-radius:var(--r-pill); background:var(--accent); }
#ts-lightbox .rail-btn[disabled] { opacity:.4; pointer-events:none; }
#ts-lightbox .rail-sep { width:26px; height:1px; background:var(--border); margin:4px 0; }
#ts-lightbox .rail-spacer { flex:1; }

/* ---------------- STAGE ---------------- */
#ts-lightbox .ts-lb-stage { grid-area:stage; position:relative; overflow:hidden;
  display:flex; align-items:center; justify-content:center; background:var(--bg); }
/* §2 stage centering: the pad fills the real available stage area (viewport
   minus rail / panel / caption / bottom strip via the CSS grid), and the image
   is centered on BOTH axes inside it. No fixed aspect-ratio box (the old
   16/10 forced letterboxed dead space for off-ratio frames). */
#ts-lightbox .stage-pad { position:absolute; inset:24px; display:flex; align-items:center; justify-content:center; min-width:0; min-height:0; }
#ts-lightbox .stage-img-wrap { position:relative; display:flex; align-items:center; justify-content:center;
  max-width:100%; max-height:100%; width:100%; height:100%; }
#ts-lightbox .stage-img-wrap image-slot, #ts-lightbox .stage-img { display:block; max-width:100%; max-height:100%; width:auto; height:auto; border-radius:var(--r-sm); box-shadow:0 8px 40px -8px rgba(0,0,0,.7); }
#ts-lightbox img.stage-img { object-fit:contain; background:#000; transform-origin:center center; }
#ts-lightbox img.stage-img.scrub-preview { width:100%; height:100%; image-rendering:auto; }
#ts-lightbox .stage-vignette { position:absolute; inset:0; pointer-events:none; border-radius:var(--r-sm);
  background:radial-gradient(ellipse at center, transparent 55%, rgba(0,0,0,.35) 100%); }

/* caption (overlaid, auto-hide) */
#ts-lightbox .ts-caption { position:absolute; left:0; right:0; top:0; z-index:5; padding:16px 20px;
  display:flex; align-items:flex-start; gap:16px;
  background:linear-gradient(to bottom, rgba(0,0,0,.62), rgba(0,0,0,0));
  transition:opacity var(--ease) 240ms; }
#ts-lightbox.chrome-hidden .ts-caption { opacity:0; pointer-events:none; }
#ts-lightbox .cap-info { min-width:0; }
#ts-lightbox .cap-title { font-size:var(--t-lg); font-weight:600; color:var(--text); letter-spacing:-.01em; }
#ts-lightbox .cap-meta { font-family:var(--mono); font-size:var(--m-sm); color:var(--text-dim); margin-top:2px; display:flex; gap:10px; }
#ts-lightbox .cap-spacer { flex:1; }
#ts-lightbox .cap-counter { font-family:var(--mono); font-size:var(--m-md); color:var(--text-dim); padding-top:2px; }
#ts-lightbox .cap-close { width:34px; height:34px; border-radius:var(--r-sm); display:flex; align-items:center; justify-content:center; color:var(--text-dim); transition:background var(--ease) 140ms, color var(--ease) 140ms; }
#ts-lightbox .cap-close:hover { background:rgba(255,255,255,.1); color:var(--text); }
#ts-lightbox .panel-caret { width:30px; height:30px; border-radius:var(--r-sm); display:flex; align-items:center; justify-content:center; color:var(--text-dim); transition:background var(--ease) 140ms, color var(--ease) 140ms; }
#ts-lightbox .panel-caret:hover { background:rgba(255,255,255,.1); color:var(--text); }

/* stage states */
#ts-lightbox .stage-loading { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; }
#ts-lightbox .stage-loading .pulse { width:54px; height:54px; border-radius:var(--r-pill); background:var(--surface-2);
  animation:lbpulse 1.4s var(--ease) infinite; }
@keyframes lbpulse { 0%,100%{ opacity:.4; transform:scale(.9);} 50%{ opacity:1; transform:scale(1);} }
#ts-lightbox .stage-msg { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; }
#ts-lightbox .msg-card { background:var(--surface); border:1px solid var(--border); border-radius:var(--r);
  padding:22px 24px; text-align:center; max-width:320px; }
#ts-lightbox .msg-card h4 { margin:0 0 6px; font-size:var(--t-lg); font-weight:600; }
#ts-lightbox .msg-card p { margin:0 0 14px; font-size:var(--t-sm); color:var(--text-dim); }
#ts-lightbox .msg-card .retry { color:var(--danger); font-weight:600; font-size:var(--t-sm); display:inline-flex; gap:6px; align-items:center; }

/* ---------------- AI on-image boxes ---------------- */
#ts-lightbox .ts-lb-image-overlay { position:absolute; inset:0; pointer-events:none; }
#ts-lightbox.chrome-hidden .ts-lb-image-overlay { opacity:.5; }
#ts-lightbox .ts-lb-ai-box { position:absolute; border:1.5px solid var(--accent); border-radius:2px;
  pointer-events:auto; cursor:pointer; opacity:0; animation:boxin .28s var(--ease) forwards; }
@keyframes boxin { to { opacity:1; } }
#ts-lightbox .ts-lb-ai-box.conf-hi { border-color:var(--success); }
#ts-lightbox .ts-lb-ai-box.conf-md { border-color:var(--warn); }
#ts-lightbox .ts-lb-ai-box.conf-lo { border-color:var(--danger); }
#ts-lightbox .ts-lb-ai-box.fp { border-style:dashed; opacity:.5; }
#ts-lightbox .ts-lb-ai-box.sel { border-width:2px; box-shadow:0 0 0 1px rgba(0,0,0,.5), 0 0 14px -2px var(--accent); }
#ts-lightbox .box-tab { position:absolute; left:-1.5px; top:-19px; display:flex; gap:5px; align-items:center;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-xs); padding:1px 6px;
  font-family:var(--mono); font-size:9.5px; white-space:nowrap; color:var(--text); }
#ts-lightbox .box-tab .cf { color:var(--text-dim); }
#ts-lightbox .ai-banner { position:absolute; left:50%; top:18px; transform:translateX(-50%); z-index:6;
  background:var(--accent-soft); border:1px solid var(--accent); color:var(--accent); border-radius:var(--r-pill);
  padding:7px 16px; font-family:var(--mono); font-size:var(--m-sm); display:flex; gap:10px; align-items:center; }
#ts-lightbox .ts-lb-stage.create-box { cursor:crosshair; }

/* ---------------- RIGHT PANEL ---------------- */
#ts-lightbox .ts-lb-panel { grid-area:panel; background:var(--surface); border-left:1px solid var(--border);
  display:flex; flex-direction:column; overflow:hidden; transition:width var(--ease) 200ms; }
#ts-lightbox.panel-collapsed .ts-lb-panel { border-left:0; }
#ts-lightbox .panel-head { display:flex; align-items:center; gap:10px; padding:14px 16px 12px; border-bottom:1px solid var(--border); }
#ts-lightbox .panel-head .ph-title { flex:1; }
#ts-lightbox .panel-head .ph-sum { font-family:var(--mono); font-size:var(--m-sm); color:var(--text-dim); margin-top:3px; }
#ts-lightbox .panel-body { flex:1; overflow-y:auto; }
#ts-lightbox .panel-body::-webkit-scrollbar { width:10px; }
#ts-lightbox .panel-body::-webkit-scrollbar-thumb { background:var(--surface-3); border-radius:var(--r-pill); border:3px solid var(--surface); }
#ts-lightbox .panel-foot { border-top:1px solid var(--border); padding:12px 16px; }
#ts-lightbox .icon-toggle { width:30px; height:30px; border-radius:var(--r-sm); display:flex; align-items:center; justify-content:center; color:var(--text-dim); border:1px solid var(--border); }
#ts-lightbox .icon-toggle:hover { background:var(--surface-2); color:var(--text); }
#ts-lightbox .icon-toggle.on { color:var(--accent); border-color:var(--accent); background:var(--accent-soft); }

/* detection rows */
#ts-lightbox .det-row { display:flex; gap:10px; align-items:flex-start; padding:12px 16px; border-bottom:1px solid var(--border); position:relative; }
#ts-lightbox .det-row:hover { background:var(--surface-2); }
#ts-lightbox .det-row.sel { background:var(--surface-2); box-shadow:inset 2px 0 0 var(--accent); }
#ts-lightbox .det-row.verdict-fp { background:var(--danger-soft); }
#ts-lightbox .det-row.verdict-fp .det-class { text-decoration:line-through; color:var(--text-dim); }
#ts-lightbox .conf-pill { flex:none; font-family:var(--mono); font-size:var(--m-xs); font-weight:600; padding:3px 7px; border-radius:var(--r-xs); }
#ts-lightbox .conf-pill.hi { background:var(--success-soft); color:var(--success); }
#ts-lightbox .conf-pill.md { background:var(--warn-soft); color:var(--warn); }
#ts-lightbox .conf-pill.lo { background:var(--danger-soft); color:var(--danger); }
#ts-lightbox .det-main { flex:1; min-width:0; }
#ts-lightbox .det-class { font-size:var(--t-md); color:var(--text); font-weight:500; }
#ts-lightbox .det-class .corr { color:var(--accent); font-weight:600; }
#ts-lightbox .det-model { font-family:var(--mono); font-size:9.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.04em; margin-top:2px; }
#ts-lightbox .det-verdicts { display:flex; gap:4px; margin-top:8px; opacity:0; max-height:0; overflow:hidden; transition:opacity 140ms var(--ease); }
#ts-lightbox .det-row:hover .det-verdicts, #ts-lightbox .det-row.touch .det-verdicts, #ts-lightbox .det-row.has-verdict .det-verdicts { opacity:1; max-height:40px; }
#ts-lightbox .vbtn { width:28px; height:26px; border-radius:var(--r-xs); border:1px solid var(--border); color:var(--text-dim); display:flex; align-items:center; justify-content:center; font-size:13px; }
#ts-lightbox .vbtn:hover { background:var(--surface-3); color:var(--text); border-color:var(--border-hover); }
#ts-lightbox .vbtn.ok.on { color:var(--success); border-color:var(--success); background:var(--success-soft); }
#ts-lightbox .vbtn.no.on { color:var(--danger); border-color:var(--danger); background:var(--danger-soft); }
#ts-lightbox .vbtn.wrong.on { color:var(--warn); border-color:var(--warn); background:var(--warn-soft); }
#ts-lightbox .det-empty { padding:40px 20px; text-align:center; color:var(--text-dim); font-size:var(--t-sm); }

/* compare panel */
#ts-lightbox .ab-pick { display:flex; flex-direction:column; gap:8px; padding:14px 16px; }
#ts-lightbox .ab-chip { display:flex; align-items:center; gap:10px; padding:10px 12px; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--surface-2); }
#ts-lightbox .ab-chip .tag { font-family:var(--mono); font-size:var(--m-md); font-weight:600; width:14px; color:var(--accent); }
#ts-lightbox .ab-chip .val { font-family:var(--mono); font-size:var(--m-sm); color:var(--text); flex:1; }
#ts-lightbox .ab-chip.empty .val { color:var(--text-faint); }
#ts-lightbox .ab-chip .edit { font-size:var(--t-xs); font-weight:600; color:var(--accent); border:1px solid var(--border); border-radius:var(--r-pill); padding:4px 12px; background:var(--surface); cursor:pointer; white-space:nowrap; transition:background-color 120ms ease, border-color 120ms ease; }
#ts-lightbox .ab-chip .edit:hover { background:var(--surface-2); border-color:var(--accent); }
#ts-lightbox .ab-chip .edit:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
#ts-lightbox .seg { display:flex; gap:3px; padding:3px; background:var(--surface-2); border:1px solid var(--border); border-radius:var(--r-sm); margin:6px 16px 14px; }
#ts-lightbox .seg button { flex:1; height:30px; border-radius:var(--r-xs); font-family:var(--mono); font-size:var(--m-xs); text-transform:uppercase; letter-spacing:.05em; color:var(--text-dim); position:relative; }
#ts-lightbox .seg button:hover { color:var(--text); }
#ts-lightbox .seg button.on { background:var(--accent); color:var(--accent-fg); font-weight:700; }
#ts-lightbox .seg button .soon { position:absolute; top:-6px; right:2px; font-size:7px; background:var(--surface-3); color:var(--text-faint); padding:1px 3px; border-radius:2px; letter-spacing:.04em; }

/* compare stage modes */
#ts-lightbox .cmp-stage { position:absolute; inset:24px; border-radius:var(--r-sm); overflow:hidden; }
#ts-lightbox .cmp-layer { position:absolute; inset:0; background-size:cover; background-position:center; }
#ts-lightbox .cmp-time { position:absolute; bottom:10px; font-family:var(--mono); font-size:var(--m-sm); color:#fff; background:rgba(0,0,0,.55); padding:3px 9px; border-radius:var(--r-xs); }
#ts-lightbox .cmp-handle { position:absolute; top:0; bottom:0; height:auto; margin:0; border:0; border-radius:0; width:2px; background:var(--accent); cursor:ew-resize; z-index:3; }
#ts-lightbox .cmp-handle .grip { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); width:34px; height:34px; border-radius:var(--r-pill); background:var(--accent); color:var(--accent-fg); display:flex; align-items:center; justify-content:center; font-size:13px; box-shadow:var(--shadow-md); }
#ts-lightbox .cmp-divider { position:absolute; top:0; bottom:0; left:50%; width:1px; background:rgba(255,255,255,.4); z-index:2; }

/* download panel */
#ts-lightbox .dl-file { padding:16px; }
#ts-lightbox .dl-name { font-family:var(--mono); font-size:var(--m-md); color:var(--text); word-break:break-all; }
#ts-lightbox .dl-size { font-family:var(--mono); font-size:var(--m-xs); color:var(--text-faint); margin-top:3px; }
#ts-lightbox .dl-actions { display:flex; flex-direction:column; gap:8px; padding:0 16px 16px; }

/* markup tool dock */
#ts-lightbox .mk-dock { position:absolute; left:50%; bottom:20px; transform:translateX(-50%); z-index:6;
  display:flex; align-items:center; gap:4px; padding:6px; background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-pill); box-shadow:var(--shadow-md); }
#ts-lightbox .mk-tool { width:34px; height:34px; border-radius:var(--r-pill); display:flex; align-items:center; justify-content:center; color:var(--text-dim); }
#ts-lightbox .mk-tool:hover { background:var(--surface-2); color:var(--text); }
#ts-lightbox .mk-tool.on { background:var(--accent); color:var(--accent-fg); }
#ts-lightbox .mk-dock-sep { width:1px; height:22px; background:var(--border); margin:0 3px; }
#ts-lightbox .mk-swatch { width:18px; height:18px; border-radius:var(--r-pill); border:2px solid transparent; }
#ts-lightbox .mk-swatch.on { border-color:#fff; }
#ts-lightbox .mk-row { display:flex; align-items:center; gap:10px; padding:10px 16px; border-bottom:1px solid var(--border); }
#ts-lightbox .mk-row:hover { background:var(--surface-2); }
#ts-lightbox .mk-row.sel { background:var(--surface-2); box-shadow:inset 2px 0 0 var(--accent); }
#ts-lightbox .mk-ico { width:24px; height:24px; border-radius:var(--r-xs); display:flex; align-items:center; justify-content:center; font-size:13px; flex:none; }
#ts-lightbox .mk-label { flex:1; font-size:var(--t-sm); color:var(--text); }
#ts-lightbox .mk-status { font-family:var(--mono); font-size:9px; text-transform:uppercase; letter-spacing:.05em; padding:2px 6px; border-radius:var(--r-pill); }
#ts-lightbox .mk-status.open { background:var(--danger-soft); color:var(--danger); }
#ts-lightbox .mk-status.review { background:var(--warn-soft); color:var(--warn); }
#ts-lightbox .mk-status.resolved { background:var(--success-soft); color:var(--success); }
#ts-lightbox .future-tag { font-family:var(--mono); font-size:8px; text-transform:uppercase; letter-spacing:.06em; color:var(--text-faint); border:1px dashed var(--border-hover); border-radius:2px; padding:1px 4px; }

/* buttons (scoped) */
#ts-lightbox .lb-btn { display:inline-flex; align-items:center; justify-content:center; gap:7px; height:36px; padding:0 14px;
  border-radius:var(--r-sm); font-size:var(--t-sm); font-weight:500; border:1px solid transparent; transition:background 140ms var(--ease), border-color 140ms var(--ease); }
#ts-lightbox .lb-btn.full { width:100%; }
#ts-lightbox .lb-btn.primary { background:var(--accent); color:var(--accent-fg); font-weight:600; }
#ts-lightbox .lb-btn.primary:hover { background:var(--accent-h); }
#ts-lightbox .lb-btn.secondary { background:var(--surface-2); color:var(--text); border-color:var(--border); }
#ts-lightbox .lb-btn.secondary:hover { border-color:var(--border-hover); }
#ts-lightbox .lb-btn.ghost { color:var(--text-dim); }
#ts-lightbox .lb-btn.ghost:hover { background:var(--surface-2); color:var(--text); }
#ts-lightbox .lb-btn[disabled] { opacity:.4; pointer-events:none; }
#ts-lightbox .lb-btn .spin { width:14px; height:14px; border-radius:var(--r-pill); border:2px solid currentColor; border-top-color:transparent; animation:lbspin .7s linear infinite; }
@keyframes lbspin { to { transform:rotate(360deg); } }

/* ---------------- BOTTOM FILMSTRIP ---------------- */
#ts-lightbox .ts-lb-bottom { grid-area:bottom; background:var(--surface); border-top:1px solid var(--border);
  display:flex; align-items:center; gap:14px; padding:10px 16px; z-index:6; }
#ts-lightbox .strip-main { flex:1 1 0; width:0; display:flex; flex-direction:column; gap:8px; overflow:hidden; }
#ts-lightbox .date-chip { flex:none; display:flex; align-items:center; gap:7px; height:34px; padding:0 12px;
  border:1px solid var(--border); border-radius:var(--r-sm); background:var(--surface-2); font-family:var(--mono); font-size:var(--m-sm); color:var(--text); }
#ts-lightbox .date-chip:hover { border-color:var(--border-hover); }
#ts-lightbox .strip-count { flex:none; font-family:var(--mono); font-size:var(--m-sm); color:var(--text-dim); }
#ts-lightbox .strip-scroll { position:relative; height:86px; overflow:hidden; flex-shrink:0; }
#ts-lightbox .strip-track { display:flex; gap:6px; height:100%; align-items:center; position:relative; transition:transform var(--ease) 200ms; }
#ts-lightbox .thumb { position:relative; flex:none; width:140px; height:84px; border-radius:var(--r-sm); border:1px solid var(--border);
  background-size:cover; background-position:center; cursor:pointer; overflow:hidden; }
#ts-lightbox .thumb:hover { border-color:var(--border-hover); }
#ts-lightbox .thumb.cur { border:2px solid var(--accent); }
#ts-lightbox .thumb.cur::before { content:""; position:absolute; top:-7px; left:50%; transform:translateX(-50%); width:0; height:0;
  border-left:5px solid transparent; border-right:5px solid transparent; border-top:6px solid var(--accent); }
#ts-lightbox .thumb .tt { position:absolute; left:0; right:0; bottom:0; padding:2px 5px; font-family:var(--mono); font-size:10px; color:#fff; background:linear-gradient(to top, rgba(0,0,0,.6), transparent); text-align:right; }
#ts-lightbox .strip-end { flex:none; font-family:var(--mono); font-size:9px; color:var(--text-faint); align-self:center; }

/* range segmented control (Day · Week · Month · All) */
#ts-lightbox .scrub-range-seg { display:flex; gap:3px; align-self:center; padding:2px; background:var(--surface-2); border:1px solid var(--border); border-radius:var(--r-sm); flex-shrink:0; }
#ts-lightbox .scrub-range-seg button { height:22px; padding:0 10px; border-radius:var(--r-xs); font-family:var(--mono); font-size:9.5px; text-transform:uppercase; letter-spacing:.05em; color:var(--text-dim); transition:background var(--ease) 120ms, color var(--ease) 120ms; }
#ts-lightbox .scrub-range-seg button:hover { color:var(--text); }
#ts-lightbox .scrub-range-seg button.on { background:var(--accent); color:var(--accent-fg); font-weight:700; }

/* scrubber slider (tickless, continuous handle, half-length centered rail) */
#ts-lightbox .scrubber { position:relative; height:34px; cursor:pointer; touch-action:none; flex-shrink:0;
  width:50%; max-width:520px; margin:0 auto; }
#ts-lightbox .scrub-rail { position:absolute; left:0; right:0; top:50%; transform:translateY(-50%); height:4px; border-radius:var(--r-pill); background:var(--surface-3); }
#ts-lightbox .scrub-fill { position:absolute; left:0; top:50%; transform:translateY(-50%); height:4px; border-radius:var(--r-pill); background:var(--accent); opacity:.55; }
/* rail edge labels: left = range start, right = newest capture */
#ts-lightbox .scrub-edge { position:absolute; top:calc(50% + 9px); font-family:var(--mono); font-size:8.5px; color:var(--text-faint); white-space:nowrap; pointer-events:none; }
#ts-lightbox .scrub-edge-start { left:0; }
#ts-lightbox .scrub-edge-end { right:0; }
#ts-lightbox .scrub-handle { position:absolute; top:50%; left:0; transform:translate(-50%,-50%); width:16px; height:16px; border-radius:var(--r-pill); background:var(--accent); border:2px solid var(--surface); box-shadow:0 2px 8px -2px rgba(0,0,0,.7); pointer-events:none; transition:left var(--ease) 90ms; }
#ts-lightbox .scrubber:focus-visible .scrub-handle { box-shadow:0 0 0 3px var(--bg), 0 0 0 5px var(--accent); }
#ts-lightbox .scrub-time { position:absolute; bottom:20px; left:50%; transform:translateX(-50%); font-family:var(--mono); font-size:9.5px; color:var(--accent-fg); background:var(--accent); padding:2px 6px; border-radius:var(--r-xs); white-space:nowrap; }
/* reduced motion: no handle easing (§1) */
@media (prefers-reduced-motion: reduce) { #ts-lightbox .scrub-handle { transition:none; } }
/* wide ranges (week/month/all) hide the per-frame filmstrip — 240 sampled
   points isn't a thumbnail rail; the rail + handle + edge labels carry it. */
#ts-lightbox [data-scrub-mode="week"] .strip-scroll,
#ts-lightbox [data-scrub-mode="month"] .strip-scroll,
#ts-lightbox [data-scrub-mode="all"] .strip-scroll { display:none; }
#ts-lightbox .strip-disabled { flex:1; display:flex; align-items:center; justify-content:center; color:var(--text-faint); font-family:var(--mono); font-size:var(--m-sm); height:72px; border:1px dashed var(--border); border-radius:var(--r-sm); }
#ts-lightbox .strip-arrows { display:flex; gap:4px; }
#ts-lightbox .strip-arrow { width:30px; height:30px; border-radius:var(--r-sm); border:1px solid var(--border); color:var(--text-dim); display:flex; align-items:center; justify-content:center; }
#ts-lightbox .strip-arrow:hover { background:var(--surface-2); color:var(--text); }

/* day popover */
#ts-lightbox .day-pop { position:absolute; left:16px; bottom:100%; z-index:20; width:230px; max-height:300px; overflow-y:auto;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r); box-shadow:var(--shadow-md); padding:6px; }
#ts-lightbox .day-item { display:flex; justify-content:space-between; align-items:center; padding:8px 10px; border-radius:var(--r-sm); font-family:var(--mono); font-size:var(--m-sm); }
#ts-lightbox .day-item:hover { background:var(--surface-2); }
#ts-lightbox .day-item.on { background:var(--surface-3); color:var(--text); }
#ts-lightbox .day-item .dc { color:var(--text-faint); font-size:var(--m-xs); }

/* nested modal (compare picker) */
#ts-lightbox .lb-modal-scrim { position:absolute; inset:0; z-index:40; background:rgba(0,0,0,.55); display:flex; align-items:center; justify-content:center; }
#ts-lightbox .lb-modal { width:420px; max-width:90%; background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); box-shadow:var(--shadow-md); overflow:hidden; }
#ts-lightbox .lb-modal-head { padding:14px 18px; border-bottom:1px solid var(--border); display:flex; align-items:center; gap:10px; }
#ts-lightbox .lb-modal-body { padding:16px 18px; max-height:340px; overflow-y:auto; }
#ts-lightbox .lb-modal-foot { padding:12px 18px; border-top:1px solid var(--border); display:flex; justify-content:flex-end; gap:8px; }

/* toast */
#ts-lightbox .lb-toast { position:absolute; left:50%; bottom:120px; transform:translateX(-50%); z-index:50;
  background:var(--surface-3); border:1px solid var(--border); color:var(--text); border-radius:var(--r-pill);
  padding:8px 16px; font-size:var(--t-sm); box-shadow:var(--shadow-md); display:flex; gap:8px; align-items:center;
  animation:toastin .24s var(--ease); }
@keyframes toastin { from { opacity:0; transform:translate(-50%,8px);} }

/* ---------------- NARROW (≤720) ---------------- */
#ts-lightbox.is-narrow { grid-template-columns:1fr; grid-template-rows:auto 1fr auto auto;
  grid-template-areas:"rail" "stage" "panel" "bottom"; }
#ts-lightbox.is-narrow .ts-lb-rail { flex-direction:row; width:auto; height:54px; border-right:0; border-bottom:1px solid var(--border); padding:0 12px; justify-content:flex-start; }
#ts-lightbox.is-narrow .rail-mark { margin:0 8px 0 0; }
#ts-lightbox.is-narrow .rail-btn { width:54px; height:42px; }
#ts-lightbox.is-narrow .rail-btn[aria-pressed="true"]::before { left:8px; right:8px; top:auto; bottom:0; width:auto; height:2px; }
#ts-lightbox.is-narrow .rail-sep, #ts-lightbox.is-narrow .rail-spacer { display:none; }
#ts-lightbox.is-narrow .ts-lb-panel { --panel-w:auto; border-left:0; border-top:1px solid var(--border); max-height:42%; }
#ts-lightbox.is-narrow .ts-lb-stage { min-height:240px; }
/* Touch targets: bump the compact caption controls to >=40px on narrow/mobile
   (desktop keeps the 34/30px chrome). WCAG 2.5.5 / mobile pointer-target rule. */
#ts-lightbox.is-narrow .cap-close { width:40px; height:40px; }
#ts-lightbox.is-narrow .panel-caret { width:40px; height:40px; }

@media (prefers-reduced-motion: reduce) {
  #ts-lightbox * { animation:none !important; transition:none !important; }
}

/* F-21: skeleton sizing for the dashboard KPI number tiles (reuses the
   .sk-tile shimmer; shown until refreshKpis() replaces the strip). */
.mkf-sk { display: inline-block; width: 3rem; height: 1.4rem; border-radius: 5px; }
