/* ============================================================
   PRISMWEB Design System — "Cartographic Field Station"
   ============================================================ */

/* Self-hosted fonts (no external CDN dependency) */
@font-face { font-family: 'Inter'; font-weight: 400; font-style: normal; font-display: swap; src: url('../fonts/inter-400.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-weight: 500; font-style: normal; font-display: swap; src: url('../fonts/inter-500.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-weight: 600; font-style: normal; font-display: swap; src: url('../fonts/inter-600.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-weight: 700; font-style: normal; font-display: swap; src: url('../fonts/inter-700.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-weight: 400; font-style: normal; font-display: swap; src: url('../fonts/jetbrains-mono-400.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-weight: 500; font-style: normal; font-display: swap; src: url('../fonts/jetbrains-mono-500.woff2') format('woff2'); }

:root {
  /* Field Greens */
  --color-deep-forest: #1A3A2A;
  --color-canopy: #2D5F3F;
  --color-canopy-dark: #1E4D33;
  --color-sage-wash: #D4E8DC;

  /* Earth Tones */
  --color-terracotta: #8B5E3C;
  --color-clay: #A47149;
  --color-terracotta-dark: #7A4F31;

  /* Text */
  --color-charcoal: #374151;
  --color-slate: #5A6B7F;
  --color-muted: #637082;

  /* Status */
  --color-success: #059669;
  --color-warning: #D97706;
  --color-error: #B91C1C;
  /* V2-22a — alias for pre-existing .thread-dot--dead, .progress-age--stale,
     and .thread-indicator--dead .thread-label which reference --color-danger.
     Without this alias those rules resolve to `initial` (transparent). */
  --color-danger: var(--color-error);

  /* Amber warning palette (Gate B LOW — tokens replace hard-coded hex).
     Dark amber text reads WCAG AA on both Parchment (6.0:1) and Warm
     White. Tint / border are the soft amber wash used by warning
     banners + concurrent-run + toast. */
  --color-warning-ink: #78350F;
  --color-warning-tint: #FEF3C7;
  --color-warning-border: #FDE68A;

  /* Semantic status triads: ink=text, tint=bg, border. Join the warning triad above. */
  --color-success-ink: var(--color-canopy-dark);
  --color-success-tint: var(--color-sage-green-100);
  --color-success-border: #BFD9C8;
  --color-error-ink: var(--color-error);
  --color-error-tint: #F7E7E2;
  --color-error-border: #E8C3B9;
  --color-info-ink: #1E40AF;
  --color-info-tint: #DBEAFE;
  --color-info-border: #BFDBFE;
  --color-info: #3B82F6;
  --color-cancelled-ink: #9A3412;
  --color-cancelled-tint: #FED7AA;
  /* Semantic rgba bases for translucent fills (match the solid tokens). */
  --color-success-rgb: 5,150,105;
  --color-danger-rgb: 185,28,28;

  /* Project effective-state badge palette (the My-Projects list).
     Mockup-exact fg/bg per state; each badge rule also carries a literal
     fallback so an undefined token never renders invisible. Ready and
     Ready-to-rebuild share the lighter sage-wash (#E7F0EA) — it MUST stay
     distinct from Running's #D4E8DC or the two collapse; Ready-to-rebuild
     is set apart from Ready-to-run by its border + refresh glyph, not fill. */
  --color-badge-draft-fg: #6B7280;      --color-badge-draft-bg: #EFEEEB;
  --color-badge-preparing-fg: #8B5E3C;  --color-badge-preparing-bg: #F4EBE1;
  --color-badge-ready-fg: #1E4D33;      --color-badge-ready-bg: #E7F0EA;
  --color-badge-running-fg: #1E4D33;    --color-badge-running-bg: #D4E8DC;
  --color-badge-results-fg: #0B8A5A;    --color-badge-results-bg: #E3F5EC;
  --color-badge-partial-fg: #B5730D;    --color-badge-partial-bg: #FBF1E0;
  --color-badge-failed-fg: var(--color-error-ink);     --color-badge-failed-bg: #FBECEA;
  --color-badge-rebuild-fg: #1E4D33;    --color-badge-rebuild-bg: #E7F0EA;
  --color-badge-rebuild-border: #C4DBCB;
  --color-badge-caveat-fg: #8A6D3B;     --color-badge-caveat-bg: #FBF4E6;
  --color-badge-caveat-border: #ECD9B5;

  /* N-cycle computed-verdict palette (the A+C display). Dedicated verdict
     tokens — the lifecycle-badge palette above carries unrelated meanings — so a
     verdict hero never borrows a "preparing"/"failed" colour. fg accent + a soft
     tint background per verdict; loss/mining warm, build/clean sage, neutral a
     calm slate, partial steady-blue. Sparklines + tints read these, never a hex. */
  --color-verdict-loss-fg: #8B5E3C;     --color-verdict-loss-bg: #F4EBE1;
  --color-verdict-mining-fg: var(--color-error-ink);   --color-verdict-mining-bg: #FBECEA;
  --color-verdict-build-fg: #0B8A5A;    --color-verdict-build-bg: #E3F5EC;
  --color-verdict-neutral-fg: #5A6B7F;  --color-verdict-neutral-bg: #EEF0F2;
  --color-verdict-partial-fg: #3E6E8C;  --color-verdict-partial-bg: #E9F0F4;
  --color-verdict-loss-border: #E4D3BE; --color-verdict-mining-border: #EBC9C4;
  --color-verdict-build-border: #BFE0CF; --color-verdict-neutral-border: #D5DBE1;
  --color-verdict-partial-border: #CBDCE6;

  /* Sprint E.3 cycle-4 Phase 4.5 fixup +15 F-BU — canonical
     map-cell WARN/WARN+ palette per durable §24. The cockpit grid
     map + results-page portrait legend both read these vars so the
     two surfaces stay in sync; structural pin asserts no duplicate
     hex literals across grid-map.js / cockpit.css / style.css.

     `--color-warn-1-fill` (yellow-200) = light yellow for single-
     warning informational cells (e.g., INTERPOLATABLE Bucket 4).
     `--color-warn-2-plus-fill` (amber-500) = saturated orange for
     blocking warnings (Bucket 3 TRUE_EXCLUDE re-routed to amber
     per Q2; Bucket 5 OVERRIDE).

     The saturation jump (yellow-200 → amber-500) gives the persona
     a hue-family + saturation distinction that the prior amber-100
     vs amber-200 gradient lacked (F-BU user-empirical at Rice-
     Kédougou: "no difference between warn and warn+ cells").
     Matches the F18 results-page absorption that originally chose
     these values. */
  --color-warn-1-fill: #fef08a;
  --color-warn-2-plus-fill: #f59e0b;

  /* Sprint E.3 cycle-4 Phase 4.5 fixup +15 F-CD — decision-
     aware palette tokens. Mirror the cockpit-redesign grid-
     map.js STATUS_PALETTE entries so /cockpit/ + /results/
     legend swatches + map cell fills consume the SAME values
     per durable §24 canonical-source-or-pin. Family-coherence
     per V6 Stage 2 §2.1: sage-green for "user-acknowledged
     (in-output)", sage-blue for "user-modified (in-output)".
     ACKNOWLEDGED — Cat D documentary OR explicit acknowledge.
     OVERRIDDEN — Cat A/B/C value replacement.
     INTERPOLATED — IDW or neighbor-fill (synthetic value). */
  --color-decision-acknowledged-fill: #ECF6EF;
  --color-decision-acknowledged-border: #2D5F3F;
  --color-decision-overridden-fill: #5A8A8E;
  --color-decision-overridden-border: #22383B;
  --color-decision-interpolated-fill: #5A8A8E;
  --color-decision-interpolated-border: #3F6D72;

  /* Map status palette — single cross-language source of map + legend paint color; every client resolves fill/ink by palette_state, the server emits state not color. */
  --color-map-status-pass-fill: #bbf7d0;
  --color-map-status-pass-ink: #166534;
  --color-map-status-info-fill: #bfdbfe;
  --color-map-status-info-ink: #1e40af;
  --color-map-status-fail-fill: #fecaca;
  --color-map-status-fail-ink: #991b1b;
  --color-map-status-defect-fill: #fecaca;
  --color-map-status-defect-ink: #7f1d1d;
  --color-map-status-skipped-fill: #D1D5DB;
  --color-map-status-skipped-ink: #6B7280;
  --color-map-status-partially-decided-fill: #fef08a;
  --color-map-status-partially-decided-ink: #78350F;
  --color-map-status-interpolated-fill: #9CC0C2;
  --color-map-status-interpolated-ink: #22383B;
  --color-map-status-unavailable-fill: #F5EFE2;
  --color-map-status-unavailable-ink: #6B7280;
  --color-map-status-warn-1-fill: var(--color-warn-1-fill);
  --color-map-status-warn-1-ink: var(--color-warning-ink);
  --color-map-status-warn-2-plus-fill: var(--color-warn-2-plus-fill);
  --color-map-status-warn-2-plus-ink: var(--color-warning-ink);
  --color-map-status-acknowledged-fill: var(--color-decision-acknowledged-fill);
  --color-map-status-acknowledged-ink: var(--color-decision-acknowledged-border);
  --color-map-status-overridden-value-fill: var(--color-decision-overridden-fill);
  --color-map-status-overridden-value-ink: var(--color-decision-overridden-border);

  /* Surfaces */
  --color-white: #FFFFFF;
  --color-warm-white: #FAFAF7;
  --color-parchment: #F5EDE4;
  --color-sandstone: #D6CEC4;

  /* Sprint E.2 cockpit redesign palette aliases.
     The redesign uses a granite / sandstone / sage-green / bone
     vocabulary documented in
     ``prismweb/.local/sprint-e-2-ux-component-specs/01-component-specs.md``
     §0.1. The aliases below map onto the existing Field-Greens +
     Earth-Tones palette so the new cockpit reads as the same
     product (durable §7 token-resolution discipline +
     ``feedback_verify_css_tokens.md``). The 4 mid-tone shades
     that don't have a legacy equivalent are derived warm-neutral
     tints anchored on the existing Sandstone hex. */

  /* Granite scale — primary text spectrum.
     ``--color-granite-900`` is the same hex as
     ``--color-charcoal`` — the redesign's "primary text" + the
     legacy "primary text" resolve to the same value, so a
     viewer scanning a page that mixes both stays consistent. */
  --color-granite-900: #374151;
  --color-granite-700: #4E5865;
  --color-granite-500: #9CA3AF;

  /* Sandstone scale — chrome borders + warm tints.
     ``--color-sandstone-400`` matches the legacy
     ``--color-sandstone`` exactly; the lighter tints derive from
     it with progressive lightness. */
  --color-sandstone-500: #B8AC9E;
  --color-sandstone-400: #D6CEC4;
  --color-sandstone-300: #E0D9CF;
  --color-sandstone-200: #E8E2D9;
  --color-sandstone-100: #F0EBE4;
  --color-sandstone-50: #F8F5EF;

  /* Amber scale — alert / warning chrome.
     Sprint E.3 AC-E3-FIXUP-2 — promote the hex fallbacks already
     used in cockpit-redesign/cockpit.css (var(--color-amber-*, ...))
     up to canonical :root definitions per durable §24 single-
     canonical-source. Without these defs, every consumer's
     var(--color-amber-*, hex) renders the hex fallback silently
     (per feedback_token_vocabulary_fallback_chain_discipline.md);
     the chain still renders, but a token-vocabulary migration on
     the design side wouldn't propagate. */
  --color-amber-600: var(--color-warning);
  --color-amber-300: #FCD34D;
  --color-amber-50: #FFFBEB;
  --color-danger-600: var(--color-error);
  --color-sage-200: #A8C4B4;
  --color-sage-400: #5E8B7E;
  /* Text-role aliases → canonical tokens; these refs were
     undefined (no fallback) and silently inherited the parent. */
  --color-text: var(--color-charcoal);
  --color-text-primary: var(--color-charcoal);
  --color-text-muted: var(--color-muted);

  /* Sage-green scale — primary action + active halos.
     ``--color-sage-green-500`` matches the legacy
     ``--color-canopy``; ``--color-sage-green-50`` matches the
     legacy ``--color-sage-wash``. The aliases preserve the
     redesign vocabulary without forking the visual palette. */
  --color-sage-green-500: #2D5F3F;
  --color-sage-green-100: #E0EBE2;
  --color-sage-green-50: #D4E8DC;

  /* Bone — warm card / surface alternative to white. */
  --color-bone: #FCF8F0;

  /* Sprint E.3 cycle-4 Phase 2 trailing-polish token additions
     per ux-expert iter-3 spec §0. The drawer-family elevation +
     dim-overlay tokens land here at the platform :root so the
     fallback chain (spec-name → platform-legacy → hex) per
     ``feedback_token_vocabulary_fallback_chain_discipline.md``
     stays single-canonical-source per durable §24. */
  --shadow-modal: 0 20px 48px rgba(34, 41, 51, 0.18);
  --shadow-dropdown: 0 4px 16px rgba(0, 0, 0, 0.12);
  --backdrop-modal: rgba(34, 41, 51, 0.45);

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

  /* F26+F27 — chrome-respect drawer geometry. The right-anchored
     drawers (Effective Resolution + per-cell inspection) anchor
     to var(--nav-height) at top so the navbar stays accessible
     while the drawer is open, and to var(--sticky-cta-height)
     at bottom so any per-page bottom-sticky CTA stays accessible
     too. Default ``--sticky-cta-height: 0px`` → drawer reaches
     the viewport bottom on pages with no bottom CTA. Per-page
     opt-in: a page with a bottom CTA declares its own
     ``--sticky-cta-height`` value (no JS measurement; manual
     opt-in pattern per ux-expert F27 OQ-F27.a).

     ``--nav-height: 56px`` matches the .nav element's rendered
     height — 40px nav-brand-logo + 8px+8px vertical padding
     (var(--space-2) ×2) flex-align-center. Evaluator's
     pre-commit Gate B criterion: independent Chrome DevTools
     measurement; divergence >4px → reject. */
  --nav-height: 56px;
  --sticky-cta-height: 0px;

  /* Sprint E.1 — cockpit cell drawer width is a deviation
     from the canonical 360 px drawer-family width because the
     cockpit's three-column shell needs to leave readable width
     for the FLAGGED CELLS + cell map + REFINEMENT QUEUE columns
     when the drawer is open. 280 px was empirically chosen as
     the compromise that fits cell body content (footer buttons,
     methods preview) without wrapping mid-word AND leaves the
     queue column at least 220 px at the 1200 px viewport floor.
     The token is referenced by the drawer width property and
     by the cockpit shell drawer-open push padding-right so the
     two values always match. Codifying as a token also lets
     future sibling drawers (methodology preview, lineage
     inspection) share the same geometry. */
  --drawer-width: 280px;

  /* Typography */
  --font-primary: 'Inter', system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', monospace;
  --font-size-display-xl: 3rem;
  --font-size-display-l: 1.75rem;

  /* Border-radius family rule (container-hierarchy axis):
       --radius-sm    (4px):  small UI element — chip, button, tooltip.
       --radius-md    (8px):  figure card / panel within a section.
       --radius-lg   (12px):  primary workspace surface — operator's
                              active work area, top-level section
                              container, modal-as-primary.
       --radius-full (9999px): pill / badge — browser clamps to half-
                              height on short elements; preserves
                              "this IS a pill" semantic regardless
                              of size.
     Severity-tier axis sits orthogonal: ``.fetch-banner--prominent``
     uses ``--radius-lg`` as a deliberate elevation of info-tier
     (--radius-md) → prominent-tier (--radius-lg) when a banner is
     surfacing a critical signal. */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-full: 9999px;
}

/* ---- Accessibility utilities ---- */

/* Visually hidden but screen-reader-available (clip-rect); for aria-live / role=status announcements that must not render on screen. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---- Reset & Base ---- */

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

body {
  font-family: var(--font-primary);
  font-size: 16px;
  line-height: 1.6;
  color: var(--color-charcoal);
  background-color: var(--color-warm-white);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* ---- Typography ---- */

h1 {
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--color-deep-forest);
}

h2 {
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-deep-forest);
}

h3 {
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--color-charcoal);
}

p {
  margin-bottom: var(--space-3);
}

.text-muted {
  color: var(--color-muted);
}

.text-slate {
  color: var(--color-slate);
}

code, pre {
  font-family: var(--font-mono);
  font-size: 0.875rem;
}

/* ---- Navigation ---- */

.nav {
  background-color: var(--color-deep-forest);
  padding: var(--space-2) var(--space-5);
  position: sticky;
  top: 0;
  z-index: 100;
}

.nav-inner {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

.nav-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--color-white);
  text-decoration: none;
  letter-spacing: 0.12em;
}

.nav-brand-logo {
  height: 40px;
  width: auto;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

/* #209: the personal cluster — bell + account (or Login/Register), right-anchored OUTSIDE
   .nav-links so it never collapses into the mobile hamburger. One gap token, a touch tighter than
   the primary-links gap, so the members read as one group; the open left edge is where #201's
   activity view slots in before the bell. */
.nav-personal {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-left: auto;
}

.nav-link {
  color: var(--color-sage-wash);
  text-decoration: none;
  font-size: 0.9375rem;
  font-weight: 500;
  transition: color 0.15s ease;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.nav-link:hover {
  color: var(--color-white);
}

/* Canonical numeric counter badge (SSOT §4.2). Light amber-tint fill + dark
   amber-ink text — keeps the running-pipeline signal vocabulary and stays
   prominent on the dark nav (a light badge pops), while the ink-on-tint clears
   WCAG 1.4.3 (the badge is a number = text) at 4.5:1. Server-rendered. */
.count-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 var(--space-1);
  background-color: var(--color-warning-tint);
  color: var(--color-warning-ink);
  border-radius: var(--radius-full);
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1;
}

/* Hamburger toggle (hidden on desktop) */
.nav-hamburger {
  display: none;
  background: none;
  border: none;
  color: var(--color-sage-wash);
  cursor: pointer;
  padding: var(--space-1);
  line-height: 0;
}

/* Logout button styled as dropdown link */
.nav-logout-btn {
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--font-primary);
}

@media (max-width: 768px) {
  .nav-hamburger {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
  }

  .nav-brand-logo {
    height: 32px;
  }

  .nav-links {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background-color: var(--color-deep-forest);
    padding: var(--space-2) var(--space-4) var(--space-4);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
    z-index: 150;
  }

  .nav-links--open {
    display: flex;
  }

  .nav-link {
    padding: var(--space-3) var(--space-2);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    min-height: 44px;
    display: flex;
    align-items: center;
  }

  .btn-nav-register {
    margin-top: var(--space-2);
    text-align: center;
    justify-content: center;
    min-height: 44px;
  }

  .nav-dropdown {
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  }

  .nav-dropdown-btn {
    padding: var(--space-3) var(--space-2);
    width: 100%;
    justify-content: space-between;
    min-height: 44px;
  }

  .nav-dropdown-menu {
    position: static;
    box-shadow: none;
    background-color: rgba(0, 0, 0, 0.15);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-2);
  }

  /* #209: the account now lives in the always-visible .nav-personal cluster (not the collapsing
     nav-links), so on mobile it stays a compact chevron control — override the full-width menu-item
     styling back to a normal dropdown, hide the username label (chevron only), and give the bell a
     44px touch target. */
  .nav-personal .nav-dropdown { border-bottom: none; }
  .nav-personal .nav-dropdown-btn {
    width: auto;
    padding: var(--space-1);
    min-width: 44px;
    min-height: 44px;
    justify-content: center;
  }
  .nav-personal .nav-dropdown-menu {
    position: absolute;
    background-color: var(--color-white);
    margin-bottom: 0;
  }
  .nav-personal .nav-dropdown-username { display: none; }
  .notification-bell { min-width: 44px; min-height: 44px; }

  .nav-dropdown-item {
    color: var(--color-sage-wash);
    min-height: 44px;
    display: flex;
    align-items: center;
  }

  .nav-dropdown-item:hover {
    background-color: rgba(255, 255, 255, 0.08);
  }

  .nav-logout-btn {
    color: var(--color-sage-wash);
  }

  .nav {
    position: relative;
  }
}

/* ---- Main Content ---- */

.main {
  flex: 1;
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--space-6) var(--space-5);
  width: 100%;
}

/* ---- Hero Split (Home Page Above-the-Fold) ---- */

.hero-split {
  display: flex;
  min-height: calc(100vh - 57px);
  background-color: var(--color-warm-white);
}

.hero-text {
  flex: 0 0 55%;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: var(--space-7) var(--space-7) var(--space-7) calc((100vw - 1200px) / 2 + var(--space-5));
  max-width: 55%;
}

.hero-logo {
  height: 140px;
  width: auto;
  margin-bottom: var(--space-3);
  align-self: center;
}

.hero-headline {
  font-size: var(--font-size-display-xl);
  font-weight: 700;
  line-height: 1.2;
  color: var(--color-deep-forest);
  margin-bottom: var(--space-4);
  letter-spacing: -0.02em;
}

.hero-sub {
  font-size: 1.125rem;
  line-height: 1.7;
  color: var(--color-slate);
  margin-bottom: var(--space-5);
  max-width: 520px;
}

.btn-cta {
  padding: 12px var(--space-5);
  font-size: 1rem;
  height: 48px;
  width: fit-content;
}

.hero-note {
  font-size: 0.875rem;
  color: var(--color-muted);
  margin-top: var(--space-3);
  margin-bottom: 0;
}

.hero-credit {
  font-size: 0.875rem;
  color: var(--color-muted);
  margin-top: var(--space-4);
  margin-bottom: 0;
}

.hero-map-wrap {
  flex: 0 0 45%;
  max-width: 45%;
  position: relative;
  z-index: 1;
}

#hero-map {
  width: 100%;
  height: 100%;
  min-height: 500px;
  background-color: var(--color-warm-white);
  /* Navbar-overlay containment — anchor Leaflet's internal
     stacking context, clip overflow, stay below navbar
     (z-index: 100+). Mirrors .portrait-map pattern. */
  position: relative;
  overflow: hidden;
  z-index: 1;
}

.map-tooltip {
  font-family: var(--font-primary);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-deep-forest);
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-sm);
  padding: 4px 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

/* ---- Sections (Below the Fold) ---- */

.section {
  padding: var(--space-7) var(--space-5);
}

.section--alt {
  background-color: var(--color-white);
}

.section--cta {
  background-color: var(--color-deep-forest);
}

.section-inner {
  max-width: 1200px;
  margin: 0 auto;
}

.section-title {
  text-align: center;
  margin-bottom: var(--space-6);
}

/* ---- Pain-Solution Grid ---- */

.pain-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
}

/* Pain-solution card — canon .card shell + a warm-white tone delta; no
   margin (it lives in .pain-grid, which owns the gap). Compose as ``card pain-card``. */
.card.pain-card {
  background-color: var(--color-warm-white);
  margin-bottom: 0;
}

.pain-icon {
  color: var(--color-canopy);
  margin-bottom: var(--space-3);
}

.pain-icon i {
  width: 24px;
  height: 24px;
}

.pain-heading {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--color-deep-forest);
  margin-bottom: var(--space-2);
}

.pain-solution {
  font-size: 0.9375rem;
  color: var(--color-slate);
  margin-bottom: 0;
}

/* ---- Platform Strip ---- */

.platform-strip {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-4);
}

/* Platform card — canon .card shell + centered flex-column layout delta; no
   margin (lives in .platform-strip). Compose as ``card platform-card``. */
.card.platform-card {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  margin-bottom: 0;
}

.platform-name {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--color-deep-forest);
}

.platform-parent {
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.platform-badge {
  display: inline-block;
  margin-top: var(--space-2);
  padding: 2px 10px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-canopy);
  background-color: var(--color-sage-wash);
  border-radius: var(--radius-full);
}

.platform-badge--soon {
  color: var(--color-muted);
  background-color: var(--color-sandstone-100);
}

.platform-paper {
  margin-top: var(--space-2);
  font-size: 0.75rem;
  color: var(--color-muted);
  text-decoration: none;
}

.platform-paper:hover {
  color: var(--color-canopy);
  text-decoration: underline;
}

/* ---- How It Works Timeline ---- */

.steps-timeline {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 0;
}

.step-node {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  flex: 0 0 180px;
}

.step-circle {
  width: 48px;
  height: 48px;
  border-radius: var(--radius-full);
  background-color: var(--color-canopy);
  color: var(--color-white);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--space-3);
}

.step-number {
  font-size: 1.125rem;
  font-weight: 700;
}

.step-icon {
  color: var(--color-canopy);
  margin-bottom: var(--space-2);
}

.step-icon i {
  width: 20px;
  height: 20px;
}

.step-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-deep-forest);
  margin-bottom: var(--space-1);
}

.step-desc {
  font-size: 0.8125rem;
  color: var(--color-slate);
  margin-bottom: 0;
  max-width: 150px;
}

.step-connector {
  flex: 0 0 60px;
  height: 2px;
  background-color: var(--color-sandstone);
  margin-top: 24px;
}

/* ---- Trust Signals ---- */

.trust-section {
  max-width: 800px;
}

.trust-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.trust-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: 0.9375rem;
  color: var(--color-charcoal);
  line-height: 1.5;
}

.trust-icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  color: var(--color-canopy);
}

.trust-link {
  color: var(--color-canopy);
  text-decoration: none;
  font-weight: 500;
}

.trust-link:hover {
  text-decoration: underline;
}

/* ---- Recent Projects ---- */

.recent-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-4);
  justify-content: center;
}

/* Recent-project link card — canon .card shell + link/flex deltas; no margin
   (lives in .recent-grid). Compose as ``card recent-card``. */
.card.recent-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  text-decoration: none;
  transition: box-shadow 0.15s ease;
  margin-bottom: 0;
}

.recent-card:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.recent-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.recent-card-name {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-deep-forest);
}

.recent-card-date {
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  flex-shrink: 0;
  font-size: 0.75rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--radius-full);
  text-transform: capitalize;
}

.status-badge--complete {
  background-color: var(--color-success-tint);
  color: var(--color-success-ink);
}

/* Success / good / recommended (SSOT §4.2) — a semantic axis distinct from
   --complete's run-lifecycle "finished"; shares the success triad colours. */
.status-badge--success {
  background-color: var(--color-success-tint);
  color: var(--color-success-ink);
}

/* Warning / attention / unverified — a semantic axis distinct from --queued's
   run-lifecycle "waiting"; shares the warning triad colours. */
.status-badge--warning {
  background-color: var(--color-warning-tint);
  color: var(--color-warning-ink);
}

/* Informational phrase badge — a generic, non-lifecycle status (e.g. the comparability
   verdict). Reuses the AA-verified info triad. */
.status-badge--info {
  background-color: var(--color-info-tint);
  color: var(--color-info-ink);
}

.status-badge--running {
  background-color: var(--color-info-tint);
  color: var(--color-info-ink);
}

.status-badge--queued {
  background-color: var(--color-warning-tint);
  color: var(--color-warning-ink);
}

.status-badge--error {
  background-color: var(--color-error-tint);
  color: var(--color-error-ink);
}

/* Cancelled — amber palette per "user took deliberate action"
   honest signal. Distinct from --queued (lighter amber tint)
   and from --error (red); cancelled is neither failure nor
   in-progress. */
.status-badge--cancelled {
  background-color: var(--color-cancelled-tint);
  color: var(--color-cancelled-ink);
}

.status-badge--draft {
  background-color: var(--color-sandstone);
  color: var(--color-slate);
}

/* ---- Project effective-state badges (the My-Projects list) ----
   A richer pill than .status-badge (which stays for the cockpit /
   home / results surfaces). Ten states + the live engine caveat.
   Treatment sub-elements are scoped under .badge so the generic
   dot / ring / pulse names never leak globally. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.8125rem;
  font-weight: 650;
  line-height: 1;
  padding: 6px 13px 6px 11px;
  border-radius: var(--radius-full, 9999px);
  border: 1px solid transparent; /* bordered variants don't shift layout */
  white-space: nowrap;
  letter-spacing: 0.005em;
}
.badge .badge-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}
.badge .badge-ring {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 2px solid currentColor;
  background: transparent;
  flex: 0 0 auto;
}
.badge svg {
  width: 13px;
  height: 13px;
  flex: 0 0 auto;
}
/* Active phases pulse a soft ring; stilled for reduced-motion users. */
.badge .badge-dot--pulse {
  position: relative;
}
.badge .badge-dot--pulse::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.28;
  animation: badge-pulse 1.6s ease-out infinite;
}
@keyframes badge-pulse {
  0% { transform: scale(0.6); opacity: 0.4; }
  100% { transform: scale(1.9); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .badge .badge-dot--pulse::after { animation: none; display: none; }
}

.badge--draft {
  color: var(--color-badge-draft-fg, #6B7280);
  background: var(--color-badge-draft-bg, #EFEEEB);
}
.badge--preparing {
  color: var(--color-badge-preparing-fg, #8B5E3C);
  background: var(--color-badge-preparing-bg, #F4EBE1);
}
.badge--ready {
  color: var(--color-badge-ready-fg, #1E4D33);
  background: var(--color-badge-ready-bg, #E7F0EA);
}
.badge--running {
  color: var(--color-badge-running-fg, #1E4D33);
  background: var(--color-badge-running-bg, #D4E8DC);
  font-weight: 700;
}
.badge--results {
  color: var(--color-badge-results-fg, #0B8A5A);
  background: var(--color-badge-results-bg, #E3F5EC);
  font-weight: 700;
}
.badge--partial {
  color: var(--color-badge-partial-fg, #B5730D);
  background: var(--color-badge-partial-bg, #FBF1E0);
}
.badge--prepfailed {
  color: var(--color-badge-failed-fg, var(--color-error-ink));
  background: var(--color-badge-failed-bg, #FBECEA);
}
.badge--runfailed {
  color: var(--color-badge-failed-fg, var(--color-error-ink));
  background: var(--color-badge-failed-bg, #FBECEA);
}
.badge--cancelled {
  color: var(--color-badge-draft-fg, #6B7280);
  background: var(--color-badge-draft-bg, #EFEEEB);
}
/* Ready to rebuild (C1 evicted): the positive ready-family fill, set
   apart from Ready-to-run by a defined sage edge + a refresh glyph. */
.badge--rebuild {
  color: var(--color-badge-rebuild-fg, #1E4D33);
  background: var(--color-badge-rebuild-bg, #E7F0EA);
  border-color: var(--color-badge-rebuild-border, #C4DBCB);
}

/* The blocked-engine caveat — a LIVE annotation beside a Ready-to-run
   badge (never a stored state); rendered only while the engine is off,
   self-clears when it turns on. */
.badge-caveat {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-badge-caveat-fg, #8A6D3B);
  background: var(--color-badge-caveat-bg, #FBF4E6);
  border: 1px solid var(--color-badge-caveat-border, #ECD9B5);
  border-radius: var(--radius-full, 9999px);
  padding: 4px 10px;
}
.badge-caveat svg {
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
}

/* Row badge cell — the effective-state badge + optional live caveat. */
.library-row-badge {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

/* ---- Platform facet (the My-Projects toolbar) ----
   One compact multi-select dropdown beside sort + search; scales to
   more engines than a second chip row would. */
.library-facet {
  position: relative;
}
.library-facet-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--color-sandstone-300, #E8E2D9);
  border-radius: 8px;
  padding: 8px 12px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-granite-700, #374151);
  background: var(--color-white, #FFFFFF);
  cursor: pointer;
  white-space: nowrap;
}
.library-facet-btn i,
.library-facet-btn svg {
  color: var(--color-muted, #637082);
}
.library-facet-btn--active {
  background: var(--color-sage-wash, #D4E8DC);
  border-color: var(--color-success-border);
  color: var(--color-canopy-dark, #1E4D33);
}
.library-facet-btn--active i,
.library-facet-btn--active svg {
  color: var(--color-canopy, #2D5F3F);
}
.library-facet-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #CFE1D5;
  color: var(--color-canopy-dark, #1E4D33);
  font-size: 12px;
  cursor: pointer;
}
.library-facet-caret {
  color: var(--color-muted, #637082);
  font-size: 11px;
}
.library-facet-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 260px;
  background: var(--color-white, #FFFFFF);
  border: 1px solid var(--color-sandstone-300, #E8E2D9);
  border-radius: var(--radius-md);
  box-shadow: 0 4px 10px rgba(26, 58, 42, 0.07), 0 20px 44px rgba(26, 58, 42, 0.14);
  padding: 8px;
  z-index: 40;
}
.library-facet-head {
  font-family: var(--font-mono, monospace);
  font-size: 10px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--color-muted, #637082);
  padding: 8px 10px 7px;
}
.library-facet-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: none;
  background: transparent;
  border-radius: 8px;
  cursor: pointer;
  text-align: left;
}
.library-facet-row:hover {
  background: var(--color-sage-wash, #D4E8DC);
}
.library-facet-box {
  width: 16px;
  height: 16px;
  border: 1.6px solid #C4CBC9;
  border-radius: 5px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
}
.library-facet-box svg {
  width: 11px;
  height: 11px;
}
.library-facet-row--on .library-facet-box {
  background: var(--color-canopy, #2D5F3F);
  border-color: var(--color-canopy, #2D5F3F);
}
.library-facet-name {
  flex: 1 1 auto;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-deep-forest, #1A3A2A);
}
.library-facet-count {
  font-family: var(--font-mono, monospace);
  font-size: 12px;
  color: var(--color-muted, #637082);
  font-variant-numeric: tabular-nums;
}

/* Filtered-count line — honest "Showing X of Y" with the active facets. */
.library-showing {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 16px;
  font-size: 0.8125rem;
  color: var(--color-muted, #637082);
}
.library-showing-count {
  color: var(--color-deep-forest, #1A3A2A);
  font-weight: 660;
  font-variant-numeric: tabular-nums;
}
.library-showing-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--color-white, #FFFFFF);
  border: 1px solid var(--color-sandstone-300, #E8E2D9);
  border-radius: var(--radius-full, 9999px);
  padding: 3px 10px;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--color-charcoal, #374151);
}
.library-showing-clear {
  color: var(--color-canopy, #2D5F3F);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid var(--color-success-border);
}

/* ---- Footer CTA ---- */

.cta-section {
  text-align: center;
}

.cta-heading {
  color: var(--color-white);
  margin-bottom: var(--space-5);
}

/* ---- Responsive ---- */

@media (max-width: 768px) {
  .hero-split {
    flex-direction: column;
    min-height: auto;
  }

  .hero-text {
    flex: none;
    max-width: 100%;
    padding: var(--space-6) var(--space-4);
  }

  .hero-headline {
    font-size: 2rem;
  }

  .hero-map-wrap {
    flex: none;
    max-width: 100%;
  }

  #hero-map {
    min-height: 350px;
  }

  .btn-cta {
    width: 100%;
    justify-content: center;
  }

  .pain-grid {
    grid-template-columns: 1fr;
  }

  .platform-strip {
    grid-template-columns: repeat(2, 1fr);
  }

  .steps-timeline {
    flex-direction: column;
    align-items: center;
  }

  .step-connector {
    width: 2px;
    height: 32px;
    flex: 0 0 32px;
    margin-top: 0;
  }

  .step-node {
    flex: none;
  }
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  font-family: var(--font-primary);
  font-size: 0.9375rem;
  font-weight: 600;
  border: none;
  border-radius: var(--radius-md);
  cursor: pointer;
  text-decoration: none;
  transition: background-color 0.15s ease, transform 0.1s ease;
}

.btn:active {
  transform: scale(0.98);
}

.btn-primary {
  background-color: var(--color-canopy);
  color: var(--color-white);
}

.btn-primary:hover {
  background-color: var(--color-canopy-dark);
}

.btn-secondary {
  background-color: var(--color-white);
  color: var(--color-canopy);
  border: 1px solid var(--color-canopy);
}

.btn-secondary:hover {
  background-color: var(--color-sage-wash);
}

.btn-lg {
  padding: var(--space-3) var(--space-5);
  font-size: 1.0625rem;
}

/* ---- Cards ---- */

.card {
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin-bottom: var(--space-4);
}

/* Large surface card (SSOT §4.3) — the radius-lg + roomier-pad variant for
   standalone page surfaces (auth cards, etc.). Compose as ``card card--lg``. */
.card--lg {
  border-radius: var(--radius-lg);
  padding: var(--space-6) var(--space-5);
}

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

.form-group {
  margin-bottom: var(--space-4);
}

.form-label {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-charcoal);
  margin-bottom: var(--space-1);
}

.form-input,
.form-select {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-primary);
  /* The canonical input font: Body size on the authored type scale (16px), not
     a bespoke 15px. adv-input and the other input variants inherit it. */
  font-size: 1rem;
  color: var(--color-charcoal);
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  transition: border-color 0.15s ease;
}

input[type="number"].form-input {
  padding-right: var(--space-5);
}

.form-input:focus,
.form-select:focus {
  outline: none;
  border-color: var(--color-canopy);
  box-shadow: 0 0 0 3px rgba(45, 95, 63, 0.15);
}

/* ---- Wizard ---- */

.wizard {
  max-width: 800px;
  margin: 0 auto;
}

.wizard-progress {
  display: flex;
  justify-content: space-between;
  margin-bottom: var(--space-6);
  position: relative;
}

.wizard-progress::before {
  content: '';
  position: absolute;
  top: 18px;
  left: 40px;
  right: 40px;
  height: 2px;
  background-color: var(--color-sandstone);
}

.wizard-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  position: relative;
  z-index: 1;
}

.wizard-step-number {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  background-color: var(--color-sandstone);
  color: var(--color-slate);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 0.875rem;
}

.wizard-step--active .wizard-step-number {
  background-color: var(--color-terracotta);
  color: var(--color-white);
}

.wizard-step--done .wizard-step-number {
  background-color: var(--color-sage-wash);
  color: var(--color-canopy);
}

.wizard-step-label {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-muted);
}

.wizard-step--active .wizard-step-label {
  color: var(--color-terracotta);
  font-weight: 600;
}


/* ---- Footer ---- */

.footer {
  background-color: var(--color-parchment);
  padding: var(--space-4) var(--space-5);
  margin-top: auto;
}

.footer-inner {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.footer-text {
  font-size: 0.8125rem;
  color: var(--color-slate);
}

.footer-link {
  font-size: 0.8125rem;
  color: var(--color-canopy);
  text-decoration: none;
  font-weight: 500;
}

.footer-link:hover {
  text-decoration: underline;
}

/* ============================================================
   Region Wizard Page
   ============================================================ */

.wizard-page {
  display: flex;
  flex-direction: column;
  flex: 1;
}

/* Progress bar for wizard pages with split layout */
.wizard-bar {
  background-color: var(--color-white);
  border-bottom: 1px solid var(--color-sandstone);
  padding: var(--space-3) var(--space-5);
  position: sticky;
  top: 57px;
  z-index: 50;
}

@media (max-width: 768px) {
  .wizard-bar {
    position: sticky;
    top: 0;
    z-index: 100;
  }
}

.wizard-bar-inner {
  max-width: 600px;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  position: relative;
}

.wizard-bar-inner::before {
  content: '';
  position: absolute;
  top: 18px;
  left: 40px;
  right: 40px;
  height: 2px;
  background-color: var(--color-sandstone);
}

/* Region split layout */
.region-split {
  display: flex;
  flex: 1;
  min-height: calc(100vh - 57px - 73px);
}

.region-panel {
  flex: 0 0 40%;
  max-width: 40%;
  padding: var(--space-5);
  overflow-y: auto;
  background-color: var(--color-parchment);
  border-right: 1px solid var(--color-sandstone);
}

.region-title {
  margin-bottom: var(--space-2);
}

.region-subtitle {
  color: var(--color-slate);
  margin-bottom: var(--space-5);
}

.region-map-wrap {
  flex: 0 0 60%;
  max-width: 60%;
  position: relative;
  z-index: 2;
}

#region-map {
  width: 100%;
  height: 100%;
  min-height: 500px;
  background-color: var(--color-warm-white);
  /* Navbar-overlay containment — anchor Leaflet's internal
     stacking context, clip overflow, stay below navbar
     (z-index: 100+). Mirrors .portrait-map pattern. */
  position: relative;
  overflow: hidden;
  z-index: 1;
}

/* Map-idle D — loading overlay for gadm-geometry / gadm-boundaries
   fetches. Absolute-positioned inside .region-map-wrap so the
   overlay sits ON TOP of the Leaflet container, blocks pointer
   events while visible, and stacks above the Leaflet controls
   (zoom buttons live at z-index 1000; we win at 1001). Hidden by
   default — region-wizard.js toggles display:flex after the
   150 ms flash-suppression window. */
.map-loading-overlay {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  background-color: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(1.5px);
  z-index: 1001;
  pointer-events: auto;
}

.map-loading-spinner {
  width: 36px;
  height: 36px;
  border: 3px solid var(--color-sandstone);
  border-top-color: var(--color-canopy);
  border-radius: 50%;
  animation: map-loading-spin 0.9s linear infinite;
}

.map-loading-text {
  margin: 0;
  font-family: var(--font-primary);
  font-size: 0.9375rem;
  color: var(--color-canopy-dark);
  text-align: center;
  max-width: 28ch;
  line-height: 1.4;
}

@keyframes map-loading-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* Searchable country dropdown */
.select-wrap {
  position: relative;
}

.dropdown-list {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  max-height: 280px;
  overflow-y: auto;
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-top: none;
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  list-style: none;
  z-index: 50;
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}

.dropdown-item {
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  font-size: 0.9375rem;
  color: var(--color-charcoal);
  transition: background-color 0.1s ease;
}

.dropdown-item:hover {
  background-color: var(--color-sage-wash);
}

.dropdown-empty {
  padding: var(--space-2) var(--space-3);
  font-size: 0.875rem;
  color: var(--color-muted);
}

[x-cloak] {
  display: none !important;
}

/* Loading state */
.select-loading {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  font-size: 0.875rem;
  color: var(--color-muted);
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
}

.spinner {
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 2px solid var(--color-sandstone);
  border-top-color: var(--color-canopy);
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
}

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

/* Summary card */
.summary-card {
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin-bottom: var(--space-4);
}

.summary-row {
  font-size: 0.875rem;
  color: var(--color-charcoal);
  padding: var(--space-1) 0;
}

.summary-row strong {
  color: var(--color-slate);
  font-weight: 600;
}

/* Next button disabled state */
.btn-next {
  width: 100%;
  justify-content: center;
  padding: 12px var(--space-4);
}

.btn--disabled {
  background-color: var(--color-sandstone);
  color: var(--color-muted);
  cursor: not-allowed;
  /* pointer-events: none is a STANDING INVARIANT (Group E R9). Blocks
     click events on disabled buttons so JS click-handlers never fire on
     gated state. Wizard hints are Alpine x-show / reactive-reveal, NOT
     onClick/onNext triggered. Removing this line would resurrect dead
     click paths that were designed around it. */
  pointer-events: none;
  /* WCAG 2.5.5 hit target floor (preserved from H.4). Even in disabled
     state, the button retains a 32×32 touch target so screen readers and
     keyboard users can focus it without scrolling past. */
  min-width: 32px;
  min-height: 32px;
}

.btn-next[aria-disabled="true"] {
  background-color: var(--color-sandstone);
  color: var(--color-muted);
  cursor: not-allowed;
}

/* Region page map tooltip */
.region-map-wrap .map-tooltip {
  font-family: var(--font-primary);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-deep-forest);
}

/* Responsive */
@media (max-width: 768px) {
  .region-split {
    flex-direction: column;
    min-height: auto;
  }

  .region-panel {
    flex: none;
    max-width: 100%;
  }

  .region-map-wrap {
    flex: none;
    max-width: 100%;
  }

  #region-map {
    min-height: 350px;
  }
}

/* ============================================================
   Crop Wizard Page
   ============================================================ */

.crop-page {
  max-width: 800px;
  margin: 0 auto;
  padding: var(--space-5);
}

.crop-title {
  margin-bottom: var(--space-1);
}

.crop-subtitle {
  color: var(--color-slate);
  margin-bottom: var(--space-5);
}

/* Crop Cards Grid */
.crop-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

.crop-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-1);
  padding: var(--space-4);
  background-color: var(--color-white);
  border: 2px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  font-family: var(--font-primary);
  font-size: inherit;
}

.crop-card:hover {
  border-color: var(--color-canopy);
  box-shadow: 0 2px 8px rgba(45, 95, 63, 0.1);
}

.crop-card--selected {
  border-color: var(--color-canopy);
  box-shadow: 0 0 0 3px rgba(45, 95, 63, 0.15);
}

.crop-card-icon {
  color: var(--color-canopy);
  margin-bottom: var(--space-1);
}

.crop-card-icon i {
  width: 28px;
  height: 28px;
}

.crop-card-check {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  color: var(--color-canopy);
}

.crop-card-check i {
  width: 20px;
  height: 20px;
}

.crop-card-name {
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-deep-forest);
}

.crop-card-latin {
  font-size: 0.8125rem;
  font-style: italic;
  color: var(--color-muted);
}

.crop-card-season {
  font-size: 0.75rem;
  color: var(--color-slate);
  margin-top: var(--space-1);
}

/* Rice Irrigation Question */
.rice-question {
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin-bottom: var(--space-5);
}

.rice-question-title {
  font-size: 1rem;
  margin-bottom: var(--space-2);
}

.rice-hint {
  font-size: 0.875rem;
  color: var(--color-slate);
  font-style: italic;
  margin-bottom: var(--space-3);
}

.rice-options {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

.rice-option {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3);
  background-color: var(--color-warm-white);
  border: 2px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  cursor: pointer;
  font-family: var(--font-primary);
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--color-charcoal);
  transition: border-color 0.15s ease;
}

.rice-option:hover {
  border-color: var(--color-canopy);
}

.rice-option--selected {
  border-color: var(--color-canopy);
  background-color: var(--color-sage-wash);
  color: var(--color-deep-forest);
}

.rice-option i {
  width: 20px;
  height: 20px;
  color: var(--color-canopy);
}

/* Crop Calendar */
.calendar-section {
  margin-bottom: var(--space-5);
}

.calendar-title {
  font-size: 1rem;
  margin-bottom: var(--space-3);
}

.calendar-bar-wrap {
  position: relative;
  margin-bottom: var(--space-2);
}

.calendar-months {
  display: flex;
  justify-content: space-between;
  margin-bottom: var(--space-1);
}

.calendar-months span {
  font-size: 0.6875rem;
  color: var(--color-muted);
  text-align: center;
  flex: 1;
}

.calendar-track {
  position: relative;
  height: 24px;
  background-color: var(--color-sandstone);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.calendar-fill {
  position: absolute;
  top: 0;
  height: 100%;
  background-color: rgba(139, 94, 60, 0.30);
  border-left: 2px solid var(--color-terracotta);
  border-right: 2px solid var(--color-terracotta);
}

.calendar-labels {
  position: relative;
  height: 52px;
  margin-top: var(--space-1);
}

.calendar-label {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: 0.75rem;
  color: var(--color-charcoal);
  transform: translateX(-50%);
}

.calendar-arrow {
  font-size: 0.5rem;
  color: var(--color-terracotta);
  line-height: 1;
}

.calendar-label span {
  color: var(--color-slate);
}

.calendar-label strong {
  color: var(--color-deep-forest);
  font-size: 0.8125rem;
}

/* Maturity is a model-derived read-out - muted vs the definite, user-set planting value. */
.calendar-label--derived strong {
  color: var(--color-text-muted);
  font-weight: 500;
}

/* Operable maturity info-disclosure: focus/hover opens, click toggles, Escape/blur/outside dismiss. */
.calendar-tip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.calendar-tip-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: help;
  color: var(--color-text-muted, #637082);
  border-radius: 50%;
}
.calendar-tip-btn:hover,
.calendar-tip-btn:focus-visible {
  color: var(--color-text-primary, #374151);
  outline: 2px solid var(--color-canopy, #2D5F3F);
  outline-offset: 1px;
}
.calendar-tip-pop {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 20;
  margin-top: 6px;
  max-width: 260px;
  background: var(--color-white, #FFFFFF);
  border: 1px solid var(--color-sandstone, #D6CEC4);
  border-radius: var(--radius-md, 8px);
  box-shadow: var(--shadow-dropdown, 0 4px 16px rgba(0, 0, 0, 0.12));
  padding: var(--space-2, 8px) var(--space-3, 16px);
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--color-charcoal, #374151);
}

.calendar-duration {
  font-size: 0.875rem;
  color: var(--color-slate);
  text-align: center;
  margin-bottom: 0;
}

.calendar-drag-hint {
  font-size: 0.75rem;
  color: var(--color-muted);
  margin-left: var(--space-2);
}

/* Draggable handles */
.calendar-handle {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background-color: var(--color-terracotta);
  border: 2px solid var(--color-white);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  cursor: grab;
  z-index: 10;
  transition: transform 0.1s ease;
}

.calendar-handle:hover {
  transform: translate(-50%, -50%) scale(1.2);
}

.calendar-handle--dragging {
  cursor: grabbing;
  transform: translate(-50%, -50%) scale(1.3);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

.calendar-track--warning .calendar-fill {
  background-color: rgba(217, 119, 6, 0.25);
  border-left-color: var(--color-warning);
  border-right-color: var(--color-warning);
}

.calendar-track--warning .calendar-handle {
  background-color: var(--color-warning);
}

.calendar-warning {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background-color: var(--color-warning-tint);
  border: 1px solid var(--color-warning-border);
  border-radius: var(--radius-md);
  margin-top: var(--space-2);
  font-size: 0.8125rem;
  color: var(--color-warning-ink);
}

.calendar-warning i {
  flex-shrink: 0;
  color: var(--color-warning);
}

/* Recommendation Card */
.recommendation-card {
  overflow: hidden;
  padding: 0;
  margin-bottom: var(--space-5);
}

.recommendation-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background-color: var(--color-warm-white);
  border-bottom: 1px solid var(--color-sandstone);
}

.recommendation-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-deep-forest);
}

/* Quality/provenance badge — adopts the .status-badge structure (12px floor,
   radius, padding); keeps text-transform:none because its labels are
   descriptive sentence-case phrases, not single-word statuses. Colors stay as
   JS-driven deltas pending the badge-taxonomy follow-up. */
.quality-badge {
  text-transform: none;
}

.quality-badge--green {
  background-color: var(--color-success-tint);
  color: var(--color-success-ink);
}

.quality-badge--blue {
  background-color: var(--color-info-tint);
  color: var(--color-info-ink);
}

.quality-badge--neutral {
  background-color: var(--color-sandstone);
  color: var(--color-slate);
}

.recommendation-body {
  padding: var(--space-3) var(--space-4);
}

.rec-row {
  font-size: 0.875rem;
  color: var(--color-charcoal);
  padding: var(--space-1) 0;
}

.rec-label {
  color: var(--color-slate);
  font-weight: 500;
}

.rec-source {
  color: var(--color-muted);
  font-style: italic;
}

.rec-note {
  font-size: 0.8125rem;
  color: var(--color-muted);
  margin-top: var(--space-2);
  margin-bottom: var(--space-2);
}

/* Customize Panel — 3-section structure */
.customize-section {
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-sandstone);
}

.customize-section:last-of-type {
  margin-bottom: var(--space-3);
}

.customize-section-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-deep-forest);
  margin-bottom: var(--space-3);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.customize-section-title i {
  color: var(--color-canopy);
  flex-shrink: 0;
}

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

.customize-current-value {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--color-charcoal);
  margin: 0;
}

/* Month + Day date selects (no year — seasonal dates) */
.month-day-row {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.month-day-select {
  flex: 1;
  min-width: 0;
  font-weight: 500;
  color: var(--color-deep-forest);
}

.month-day-day {
  width: 72px;
  flex-shrink: 0;
  font-weight: 600;
  color: var(--color-deep-forest);
}

.customize-season-length {
  font-size: 0.8125rem;
  color: var(--color-slate);
  margin: 0;
}

.customize-info-note {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: 0.8125rem;
  color: var(--color-muted);
  margin: 0;
  font-style: italic;
}

.customize-info-note i {
  flex-shrink: 0;
  color: var(--color-canopy);
}

/* Cultivar selection feedback */
.cultivar-feedback {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-success);
  padding: var(--space-2) var(--space-3);
  background-color: var(--color-success-tint);
  border-radius: var(--radius-md);
}

/* Fertilizer expander in Management section */
.customize-fert-section {
  margin-top: var(--space-2);
}

.customize-fert-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  background-color: var(--color-warm-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  color: var(--color-charcoal);
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.customize-fert-summary:hover {
  background-color: var(--color-parchment);
}

/* Apply-fertilizer intent toggle — the question plus a segmented Yes/No that reuses the .adv-toggle-row canon. */
.fert-apply-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2);
}

.fert-apply-q {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-charcoal);
}

/* Keep the segmented control compact beside the question rather than full-width. */
.fert-apply-row {
  flex: 0 0 auto;
  width: 140px;
}

/* Unfertilized state — shown when "No" is chosen; native-soil-N framing, calm and honest. */
.fert-unfertilized {
  margin-top: var(--space-2);
  padding: var(--space-3);
  background-color: var(--color-sage-green-100);
  border: 1px solid var(--color-success-border);
  border-radius: var(--radius-md);
}

.fert-unfertilized-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-canopy);
}

.fert-unfertilized-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-deep-forest);
}

.fert-unfertilized-sub {
  margin: var(--space-1) 0 0;
  font-size: 0.875rem;
  color: var(--color-charcoal);
}

/* Ambient sensitivity note — sandstone-cream fill plus an amber left-stripe: a fact, not an alarm. */
.fert-unfertilized-note {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background-color: var(--color-warning-tint);
  border-left: 3px solid var(--color-warning);
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--color-warning-ink);
}

.fert-unfertilized-note i {
  color: var(--color-warning);
  margin-top: 1px;
}

.fert-unfertilized-foot {
  margin: var(--space-2) 0 0;
  font-size: 0.75rem;
  font-style: italic;
  color: var(--color-muted);
}

.customize-fert-expand {
  background: none;
  border: none;
  color: var(--color-slate);
  cursor: pointer;
  padding: 0;
  display: flex;
}

/* Fine-tune collapsed note */
.finetune-collapsed-note {
  font-size: 0.8125rem;
  color: var(--color-muted);
  margin: var(--space-2) 0 0 0;
  padding: 0 var(--space-4);
  font-style: italic;
}

.customize-source-subtitle {
  font-size: 0.8125rem;
  color: var(--color-muted);
  padding: 0 var(--space-4);
  margin: 0;
  font-style: italic;
}

.customize-reset-row {
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-sandstone);
  display: flex;
  justify-content: flex-end;
}

.btn-reset-ghost {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  background: none;
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  font-family: var(--font-primary);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-slate);
  cursor: pointer;
  padding: var(--space-1) var(--space-3);
  transition: border-color 0.15s ease, color 0.15s ease;
}

.btn-reset-ghost:hover {
  border-color: var(--color-canopy);
  color: var(--color-canopy);
}

.customize-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  background: none;
  border: none;
  font-family: var(--font-primary);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-canopy);
  cursor: pointer;
  padding: 0;
}

.customize-toggle:hover {
  text-decoration: underline;
}

.customize-panel {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-sandstone);
}

.customize-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

/* Crop Navigation */
.ai-skip-confirm {
  padding: var(--space-3) var(--space-4);
  background-color: var(--color-parchment);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-3);
  text-align: center;
}

.ai-skip-text {
  font-size: 0.9375rem;
  color: var(--color-slate);
  margin-bottom: var(--space-3);
}

.ai-skip-actions {
  display: flex;
  gap: var(--space-2);
  justify-content: center;
}

.crop-nav {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
}

.crop-nav .btn-next {
  flex: 1;
  max-width: 280px;
}

/* Responsive */
@media (max-width: 768px) {
  .crop-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .rice-options {
    grid-template-columns: 1fr;
  }

  .customize-row {
    grid-template-columns: 1fr;
  }

  .crop-nav {
    flex-direction: column;
  }

  .crop-nav .btn-next {
    max-width: none;
    width: 100%;
    justify-content: center;
  }
}

@media (max-width: 480px) {
  .crop-grid {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   Platform Wizard Page
   ============================================================ */

.platform-page {
  max-width: 900px;
  margin: 0 auto;
  padding: var(--space-5);
}

.platform-title {
  margin-bottom: var(--space-1);
}

.platform-subtitle {
  color: var(--color-slate);
  margin-bottom: var(--space-5);
}

/* Platform Cards Grid */
.plat-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

.plat-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--space-4);
  background-color: var(--color-white);
  border: 2px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
}

.plat-card:hover {
  border-color: var(--color-canopy);
}

.plat-card--selected {
  border-color: var(--color-canopy);
  box-shadow: 0 0 0 3px rgba(45, 95, 63, 0.15);
}

.plat-card--recommended {
  border-left: 4px solid var(--color-success);
}

.plat-card--limited {
  border-left: 4px solid var(--color-warning);
}

.plat-card--incompatible {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

.plat-card--incompatible:hover {
  border-color: var(--color-sandstone);
}

/* Checkbox */
.plat-checkbox {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: 18px;
  height: 18px;
  accent-color: var(--color-canopy);
  cursor: pointer;
}

/* Card Header */
.plat-card-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
  padding-right: var(--space-5);
}

.plat-card-name {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--color-deep-forest);
}

/* Badges */
.plat-badge {
  flex-shrink: 0;
  font-size: 0.6875rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--radius-full);
}

.plat-badge--green {
  background-color: var(--color-success-tint);
  color: var(--color-success-ink);
}

.plat-badge--amber {
  background-color: var(--color-warning-tint);
  color: var(--color-warning-ink);
}

.plat-badge--grey {
  background-color: var(--color-sandstone);
  color: var(--color-slate);
}

/* Card Description */
.plat-card-desc {
  font-size: 0.875rem;
  color: var(--color-slate);
  margin-bottom: var(--space-3);
}

/* Card Specs */
.plat-card-specs {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.plat-spec {
  font-size: 0.8125rem;
  color: var(--color-charcoal);
}

.plat-spec-label {
  color: var(--color-muted);
  font-weight: 500;
}

/* Rice Irrigation Note */
.plat-rice-note {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background-color: var(--color-sage-wash);
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
  color: var(--color-deep-forest);
}

/* Cultivar-shadow banner — fires below the platform grid
   when the user picked a cultivar in the prior wizard step
   AND the active platform sources its cultivar from a
   platform-native catalog (GAEZ for ACEA, calibrated YAML
   for SARRA-Py). The banner explains the shadow-out so the
   honest-signal trust contract holds across the wizard /
   platform handoff. */
.plat-cultivar-shadow {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  /* Per Sprint E.1 visual Gate B C1 — the banner sits between
     the platform card grid and the Back / Next nav. The
     ``margin-top`` separates it from the grid; the
     ``margin-bottom`` carves a rest-stop before the nav so
     the persona's eye reads the banner as its own block
     instead of folding it into the CTA cluster. */
  margin-top: var(--space-4);
  margin-bottom: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background-color: var(--color-info-tint);
  border: 1px solid var(--color-canopy, #2D5F3F);
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  color: var(--color-deep-forest);
}

.plat-cultivar-shadow-text {
  margin: 0;
  line-height: 1.5;
}

.plat-cultivar-shadow-code {
  display: inline-block;
  padding: 1px 6px;
  font-family: var(--font-mono, 'SFMono-Regular', monospace);
  font-size: 0.8125rem;
  background-color: var(--color-sandstone, #F0EAE0);
  border-radius: var(--radius-sm);
}

/* Incompatible Note */
.plat-incompatible-note {
  margin-top: var(--space-3);
  font-size: 0.8125rem;
  color: var(--color-muted);
  font-style: italic;
}

/* Multi-select Note */
.plat-multi-note {
  font-size: 0.875rem;
  color: var(--color-slate);
  text-align: center;
  margin-bottom: var(--space-4);
}

/* Responsive */
@media (max-width: 768px) {
  .plat-grid {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   Time Wizard Page
   ============================================================ */

.time-page {
  max-width: 600px;
  margin: 0 auto;
  padding: var(--space-5);
}

/* V2-22b Group H BLOCKER-L1 fix — container for the #wizard-error
   target so the inline error banner stays within step-content bounds
   instead of stretching edge-to-edge. Matches `.time-page`'s max-width
   + auto-centering so wizard errors on region.html and time.html
   visually align with the step body. The target DIV must sit OUTSIDE
   `{% if missing_steps %}` per H.3.9 (tab-race copy must render even
   when session is cleared); this frame keeps that placement while
   constraining the width. Zero vertical padding keeps the frame from
   adding visual space when no error is active. */
.wizard-notice-frame {
  max-width: 600px;
  margin: 0 auto;
  padding: 0 var(--space-5);
}

/* V2-22b Group H H.3 / BLOCKER-S2 — resume card sits inside
   `.region-panel` (Parchment bg). Using Parchment for the card too
   produced bg-on-bg — user couldn't differentiate card from panel.
   Warm White bg + sandstone perimeter gives a clear lift; the 4px
   Warning left border stays as the "notice" affordance shared with
   the wizard error banner. Rendered via `_wizard_resume.html` when
   the resume helper returns non-None. */
.wizard-resume-card {
  margin: var(--space-3) 0;
  padding: var(--space-4);
  background-color: var(--color-warm-white);
  border: 1px solid var(--color-sandstone);
  border-left: 4px solid var(--color-warning);
  border-radius: var(--radius-md);
  color: var(--color-warning-ink);
}

.wizard-resume-copy {
  margin: 0 0 var(--space-3);
  font-size: 0.9375rem;
  line-height: 1.5;
}

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

.time-title {
  margin-bottom: var(--space-1);
}

.time-subtitle {
  color: var(--color-slate);
  margin-bottom: var(--space-5);
}

/* Year Inputs */
.year-inputs {
  display: flex;
  align-items: flex-end;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.year-inputs .form-group {
  flex: 1;
  margin-bottom: 0;
}

.year-dash {
  font-size: 1.25rem;
  color: var(--color-muted);
  padding-bottom: var(--space-2);
}

.year-error {
  font-size: 0.875rem;
  color: var(--color-error);
  margin-bottom: var(--space-3);
}

.year-info {
  margin-bottom: var(--space-3);
}

.year-info-line {
  font-size: 0.9375rem;
  color: var(--color-charcoal);
  margin-bottom: var(--space-1);
}

.year-info-note {
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.data-hint {
  font-size: 0.8125rem;
  color: var(--color-muted);
  margin-bottom: var(--space-5);
}

/* V2-22b Group H F-4 — selector targets `svg` because Lucide replaces the
   `<i data-lucide="...">` element with an `<svg>` at runtime. The old
   `.wizard-warning-banner i` selector never matched on rendered pages. */
.wizard-warning-banner svg {
  color: var(--color-warning);
  margin-top: 2px;
}

/* Sprint F crop-region mismatch banner — bucket-5
   (MANUAL_OVERRIDE_WITH_EVIDENCE) decision surface.

   Visual language matches the bucket reclass: parchment background +
   sandstone separator + charcoal body text (matches the
   ``methodology-banner`` informational pattern below — same parchment
   palette, NOT the red / yellow ``wizard-warning-banner`` palette).
   The shield-alert icon stays in warning #D97706 so the
   "needs-attention" signal lands without the visual screaming of a
   hard-stop banner. Bucket 3 was a hard stop; bucket 5 is a
   documented-decision moment, and the palette tracks that shift.

   ``.wizard-decision-banner`` is the new shared shell (parchment +
   sandstone + charcoal) so future Bucket-5 / Bucket-2 surfaces can
   inherit the same honest-signal palette without re-deriving each
   selector. The current consumer is the crop-region mismatch banner;
   adding a sibling bucket-2 banner in V2-23 would extend
   ``.wizard-decision-banner`` rather than re-defining the palette. */

/* Canonical banner shell (SSOT §4.4) — box geometry only; severity modifiers carry the fill. Authored before the methodology mobile-hide media block below so that hide keeps cascade precedence over the base banner display. */
.banner,
.wizard-decision-banner {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-4);
  font-size: 0.9375rem;
  line-height: 1.5;
}
/* Informational severity — parchment fill + WCAG-AA dark ink (charcoal on parchment ~8.9:1). The wizard decision banner shares this same fill (it is the extracted source), so it is grouped here rather than re-copied. */
.banner--info,
.wizard-decision-banner {
  background-color: var(--color-parchment);
  border: 1px solid var(--color-sandstone);
  color: var(--color-charcoal);
}
/* Error severity — danger-triad tint fill + dark error ink (P1 triad tokens). */
.banner--error {
  background-color: var(--color-error-tint);
  border: 1px solid var(--color-error-border);
  color: var(--color-error-ink);
}
/* Success severity — success-triad tint fill + dark success ink. */
.banner--success {
  background-color: var(--color-success-tint);
  border: 1px solid var(--color-success-border);
  color: var(--color-success-ink);
}
/* Warning severity — warning-triad tint fill + dark warning ink. */
.banner--warning {
  background-color: var(--color-warning-tint);
  border: 1px solid var(--color-warning-border);
  color: var(--color-warning-ink);
}
/* Wizard consumer deltas over the shared banner shell — defined after the shell
   so the shell stays the first banner-shell rule the pin regex matches; the
   compound selectors stay order-independent so the warning border shorthand
   cannot reset the left accent, and the error banner keeps its centered icon. */
.banner.wizard-error-banner {
  align-items: center;
}
.banner.wizard-warning-banner {
  border-left: 4px solid var(--color-warning);
}
/* Wizard-specific right-padding delta over the shared .banner shell —
   preserves this banner's existing inner spacing on the right edge. */
.wizard-decision-banner {
  padding-right: calc(var(--space-4) + 32px);
}
/* Scope the warning fill to the leading shield-alert icon only.
   ``.wizard-decision-banner svg`` would have tinted every Lucide
   icon inside the banner (CTA arrows, external-link, mobile
   monitor) the warning amber, drowning out the honest-signal
   intent of the icon palette. */
.wizard-decision-banner .crop-region-mismatch-icon {
  color: var(--color-warning);
  margin-top: 2px;
  flex-shrink: 0;
}
.crop-region-mismatch-banner {
  flex-direction: row;
  align-items: flex-start;
}
.crop-region-mismatch-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.crop-region-mismatch-title {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--color-charcoal);
}
.crop-region-mismatch-explanation {
  margin: 0;
  font-size: 0.9375rem;
  color: var(--color-charcoal);
}
.crop-region-mismatch-source {
  margin: 0;
  font-size: 0.875rem;
}
.crop-region-mismatch-source a {
  color: var(--color-canopy-dark);
  text-decoration: underline;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.crop-region-mismatch-source a:focus-visible {
  outline: 2px solid var(--color-canopy);
  outline-offset: 2px;
}
.crop-region-mismatch-technical {
  margin-top: var(--space-1);
}
.crop-region-mismatch-technical summary {
  cursor: pointer;
  color: var(--color-charcoal);
  font-weight: 500;
}
.crop-region-mismatch-technical-line {
  margin: var(--space-1) 0 0 0;
  font-size: 0.875rem;
  color: var(--color-slate);
}
.crop-region-mismatch-cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-sandstone);
}
.crop-region-mismatch-cta-row .btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.crop-region-mismatch-override-container {
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-sandstone);
}
.crop-region-mismatch-override-prompt {
  margin: 0 0 var(--space-2) 0;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--color-charcoal);
}
.crop-region-mismatch-override-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.crop-region-mismatch-override-form .form-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.crop-region-mismatch-override-form .form-checkbox {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}
.crop-region-mismatch-form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-1);
}
/* Mobile defer-to-desktop hint per ux-expert verdict — surfaces under
   the rationale textarea on viewports ≤ 480px so a phone-first reader
   sees the soft nudge to switch to desktop for long override
   rationale. Hidden on wider viewports. */
.crop-region-mismatch-mobile-hint {
  display: none;
  margin: 4px 0 0 0;
  font-size: 0.8125rem;
  color: var(--color-slate);
}
@media (max-width: 480px) {
  .crop-region-mismatch-mobile-hint {
    display: block;
  }
}

/* F-R Sprint B AC-10 — methodology banner shown on /results/ for legacy
   projects whose pipeline ran under the AgMIP-canonical bbox-intersects
   rule. Informational tone (parchment background, role="status", lucide
   info icon) — distinct from the warning palette above. Suppressed for
   centroid-strict opt-in; the Methods paragraph from AC-8 carries the
   disclosure for that variant. */
/* .methodology-banner is now a bare behavior-marker — its visual is the
   canonical .banner .banner--info on the same element. The class stays only
   as the HTMX dismiss target and the sub-767px mobile-hide hook (both below),
   plus the close-button padding reservation in the shared .notice-close list. */

.methodology-banner .methodology-banner-icon {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
}

.methodology-banner svg {
  color: var(--color-slate);
}

/* Inline ``<code>`` markers in the banner copy (e.g. SharePercent,
   provenance.json) keep the monospace rendering and the slight
   font-size de-emphasis but skip a tinted surface — the parchment
   background already tones the banner down enough that an extra
   tint would make the inline code visually heavier than the
   surrounding prose, the opposite of the affordance intent. */
.methodology-banner code {
  padding: 0 4px;
  border-radius: var(--radius-sm);
  font-size: 0.875em;
}

.methodology-banner-text {
  flex: 1;
}

/* Defensive mobile carve-out per AC-E2/D17 redirect (primary) plus this
   belt-and-suspenders rule (secondary). The /results/ surface itself is
   redirected at sub-768px breakpoints; this CSS guards against any
   leak path that lands the partial in a mobile DOM anyway. */
@media (max-width: 767px) {
  /* Compound selector (specificity 0,2,0) beats the base .banner display rule (0,1,0) regardless of source order — the mobile-hide is order-independent, not dependent on .banner being authored before this block. */
  .methodology-banner.banner {
    display: none;
  }
}

/* V2-22b Group H H.4 — universal × close button for dismissable notices.
   Positioned absolute top-right on every banner so placement is
   consistent regardless of whether the host banner uses a flex, grid,
   or block internal layout. Each banner carrying `data-dismiss-key`
   gets `position: relative` so the absolute × anchors to the banner's
   own box. 32px hit target meets WCAG AA for touch.
   `.notice-close svg` overrides the parent banner's `svg` rules so
   the × icon isn't tinted with the parent's warning color. */
.notice-close {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  background: transparent;
  border: 0;
  padding: 4px;
  cursor: pointer;
  color: inherit;
  opacity: 0.65;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  min-height: 32px;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  z-index: 1;
}
.notice-close:hover,
.notice-close:focus-visible {
  opacity: 1;
  background: rgba(0, 0, 0, 0.05);
  outline: none;
}
.notice-close:focus-visible {
  box-shadow: 0 0 0 2px var(--color-warning);
}
.notice-close svg {
  color: inherit;
  margin-top: 0;
  width: 18px;
  height: 18px;
}

/* Positioning context for every banner that carries a .notice-close.
   The banner's padding-right gets bumped so text doesn't slide under
   the × button at narrow viewports (375px Aminata reference). */
.methodology-banner,
.wizard-resume-card,
.wizard-warning-banner,
.wizard-error-banner,
.ref-section--tier3,
.queue-panel,
.n3-warning {
  position: relative;
  padding-right: calc(var(--space-4) + 32px);
}
/* .htmx-toast is already `position: fixed`, which IS a positioning
   context for descendants — no extra `position: relative` needed.
   Attribute selector avoids shadowing the palette-scoped `.htmx-toast`
   block that tests/test_htmx_timeout.py pins on first-match. */
.htmx-toast[data-dismiss-key] {
  padding-right: calc(16px + 32px);
}

/* Missing Steps Card */
.missing-steps-card {
  text-align: center;
  padding: var(--space-7) var(--space-5);
}

.missing-steps-card h2 {
  margin-top: var(--space-3);
  margin-bottom: var(--space-2);
}

.missing-steps-card p {
  color: var(--color-slate);
  margin-bottom: var(--space-4);
}

/* Project Summary Card */
.summary-project-card {
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin-bottom: var(--space-5);
}

.summary-project-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-deep-forest);
  margin-bottom: var(--space-3);
}

.summary-project-rows {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.summary-project-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.9375rem;
  color: var(--color-charcoal);
}

.summary-project-row--note {
  font-size: 0.875rem;
  color: var(--color-slate);
  margin-top: var(--space-1);
}

.summary-project-row i {
  color: var(--color-canopy);
  flex-shrink: 0;
}

/* Prepare My Data Button */
.btn-go {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  padding: 14px var(--space-4);
  font-family: var(--font-primary);
  font-size: 1.0625rem;
  font-weight: 700;
  background-color: var(--color-success);
  color: var(--color-white);
  border: none;
  border-radius: var(--radius-md);
  cursor: pointer;
  height: 52px;
  transition: background-color 0.15s ease, transform 0.1s ease;
}

.btn-go:hover {
  background-color: #047857;
}

.btn-go:active {
  transform: scale(0.98);
}

.btn-go.btn--disabled {
  background-color: var(--color-sandstone);
  color: var(--color-muted);
  cursor: not-allowed;
}

/* Responsive */
@media (max-width: 480px) {
  .year-inputs {
    flex-direction: column;
    align-items: stretch;
  }

  .year-dash {
    display: none;
  }
}

/* ============================================================
   Processing Page
   ============================================================ */

.processing-page {
  max-width: 700px;
  margin: 0 auto;
  padding: var(--space-5) var(--space-5) var(--space-7);
}

.processing-header {
  text-align: center;
  margin-bottom: var(--space-4);
}

.processing-title {
  margin-bottom: var(--space-1);
}

.processing-context {
  font-size: 0.9375rem;
  color: var(--color-slate);
  margin-bottom: 0;
}

.processing-sep {
  margin: 0 2px;
  color: var(--color-sandstone);
}

.processing-elapsed {
  font-size: 0.8125rem;
  color: var(--color-muted);
  text-align: right;
  margin-bottom: var(--space-1);
  font-family: var(--font-mono);
}

.processing-eta {
  font-size: 0.8125rem;
  color: var(--color-slate);
  text-align: right;
  margin-bottom: var(--space-3);
}

/* Progress bar */
.progress-bar-track {
  height: 4px;
  background-color: var(--color-sandstone);
  border-radius: 2px;
  margin-bottom: var(--space-5);
  overflow: hidden;
}

.progress-bar-fill {
  height: 100%;
  background-color: var(--color-terracotta);
  border-radius: 2px;
  width: 0%;
  transition: width 0.5s ease;
}

.progress-bar-fill--error {
  background-color: var(--color-error);
}

/* Stage cards */
.stage-card {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-2);
  background-color: var(--color-white);
  transition: border-color 0.2s ease;
}

.stage-card--complete {
  border-left: 3px solid var(--color-success);
}

.stage-card--running {
  border-left: 3px solid var(--color-info);
}

.stage-card--error {
  border-left: 3px solid var(--color-error);
}

/* Cancelled — amber border per "user took deliberate action"
   honest signal. Distinct from --error (red) so the processing
   page surfaces user-cancel separately from a real failure. */
.stage-card--cancelled {
  border-left: 3px solid var(--color-warning);
}

.stage-card--skipped {
  opacity: 0.5;
}

.stage-card--upcoming {
  opacity: 0.6;
}

/* Stage icon */
.stage-icon {
  flex-shrink: 0;
  padding-top: 2px;
}

.stage-icon i {
  width: 20px;
  height: 20px;
}

.stage-card--complete .stage-icon {
  color: var(--color-success);
}

.stage-card--running .stage-icon {
  color: var(--color-info);
}

.stage-card--error .stage-icon {
  color: var(--color-error);
}

.stage-card--cancelled .stage-icon {
  color: var(--color-warning);
}

.stage-card--upcoming .stage-icon,
.stage-card--skipped .stage-icon {
  color: var(--color-muted);
}

.spin-icon {
  animation: spin 1s linear infinite;
}

/* Stage body */
.stage-body {
  flex: 1;
}

.stage-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.stage-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-charcoal);
}

.stage-duration {
  font-size: 0.75rem;
  color: var(--color-muted);
  font-family: var(--font-mono);
}

.stage-desc {
  font-size: 0.8125rem;
  color: var(--color-slate);
  margin: var(--space-1) 0 0;
}

.stage-error {
  font-size: 0.8125rem;
  color: var(--color-error);
  margin: var(--space-1) 0 0;
}

.stage-timer {
  font-size: 0.75rem;
  color: var(--color-info);
  font-family: var(--font-mono);
  font-weight: 600;
}

.stage-duration--error {
  color: var(--color-error);
  text-transform: uppercase;
  font-weight: 600;
  letter-spacing: 0.05em;
  font-family: var(--font-primary);
  font-size: 0.6875rem;
}

.stage-desc--muted {
  color: var(--color-muted);
}

/* V2-22d/A1 A.5 — cancelled-stage rendering for processing + results
   pages. Uses --color-warning (amber) so "Cancelled" reads as a human
   action, not a system error. Distinct from --color-error (red) used
   for stage failures. --color-muted alone would conflate with skipped. */
.stage-desc--cancelled {
  color: var(--color-warning);
  font-weight: 600;
}

/* V2-22d/A1 A.5 — muted detail-item variant for skipped stages. The
   `stage-detail-item--ok` / `--warn` / `--err` family didn't cover the
   "this stage never ran" case; results.html would fall through to the
   "Completed successfully" banner (M2 Gate A R1 misrender). */
.stage-detail-item--muted {
  color: var(--color-muted);
}

.stage-detail-item--muted i {
  color: var(--color-muted);
  flex-shrink: 0;
  margin-top: 2px;
}

/* Substage progress (within a running stage) */
.substage-progress {
  margin-top: var(--space-1);
}

.substage-text {
  font-size: 0.8125rem;
  color: var(--color-slate);
}

.substage-bar {
  height: 4px;
  background-color: var(--color-sandstone);
  border-radius: 2px;
  margin-top: var(--space-1);
  overflow: hidden;
}

.substage-fill {
  height: 100%;
  background-color: var(--color-canopy);
  border-radius: 2px;
  transition: width 0.5s ease;
}

/* Dual pipeline indicators — premium UX */
.stage-indicators {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
  font-size: 0.8rem;
  flex-wrap: wrap;
}

.thread-indicator {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 10px 2px 8px;
  /* Pill shape — at this element's height the browser
     clamps the radius to half-height, so the visual is
     identical to the prior literal 12px. The token says
     "this IS a pill" rather than "this happens to render
     as one". */
  border-radius: var(--radius-full);
  background: rgba(var(--color-success-rgb, 34,197,94), 0.08);
  border: 1px solid rgba(var(--color-success-rgb, 34,197,94), 0.2);
}

.thread-indicator--dead {
  background: rgba(var(--color-danger-rgb, 239,68,68), 0.08);
  border-color: rgba(var(--color-danger-rgb, 239,68,68), 0.25);
}

.thread-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}

.thread-dot--alive {
  background: var(--color-success);
  animation: threadPulse 2s ease-in-out infinite;
}

@keyframes threadPulse {
  0%, 100% { box-shadow: 0 0 3px var(--color-success); transform: scale(1); }
  50% { box-shadow: 0 0 10px var(--color-success), 0 0 20px rgba(var(--color-success-rgb, 34,197,94), 0.2); transform: scale(1.15); }
}

.thread-dot--dead {
  background: var(--color-danger);
  box-shadow: 0 0 6px var(--color-danger);
}

.thread-label {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--color-success);
}

.thread-indicator--dead .thread-label {
  color: var(--color-danger);
}

/* Progress age indicator — color shifts with staleness */
.progress-age {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  transition: color 0.5s ease;
}

.progress-age--fresh {
  color: var(--color-success);
}

.progress-age--warm {
  color: var(--color-muted);
}

.progress-age--aging {
  color: var(--color-warning);
}

.progress-age--stale {
  color: var(--color-warning);
  font-weight: 600;
}

.progress-age--stale::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-warning);
  margin-right: 2px;
}

/* Retry-aware substage (PRI-9). A transient-failure backoff replaces the
   determinate bar — which would falsely imply forward progress — with a
   rotating refresh icon + attempt counter (the "still working" signal) and
   a calm reassurance line (the wait expectation). */
.substage-progress--retry {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.substage-retry-headline {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-charcoal);
}

.substage-retry-icon {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  color: var(--color-canopy);
  /* Calm rotation (2s/rev) — distinct from the faster 1s .spin-icon so the
     retry reads as patient, not frantic. */
  animation: spin 2s linear infinite;
}

.substage-retry-reassurance {
  margin: 0;
  font-size: 0.75rem;
  color: var(--color-slate);
}

/* Fifth freshness tier — retry is event-driven, so its pill reads calm sage
   (active) rather than the amber "--stale" mis-signal a paused backoff would
   otherwise trip. */
.progress-age--retrying {
  color: var(--color-canopy);
  font-weight: 500;
}

@media (prefers-reduced-motion: reduce) {
  .substage-retry-icon {
    animation: none;
  }
}

/* Partial-progress slot (PRI-8) — informational context above the error
   itself; muted info glyph, not the alarmist error treatment. */
.stage-partial-progress {
  display: flex;
  align-items: flex-start;
  gap: var(--space-1);
  margin: 0 0 var(--space-1);
  padding-left: var(--space-1);
  font-size: 0.8125rem;
  color: var(--color-charcoal);
}

.stage-partial-progress i {
  color: var(--color-muted);
  flex-shrink: 0;
  margin-top: 2px;
}

/* Support reference — caption-tier, de-emphasized so it never competes with
   the actionable error copy. */
.stage-error-reference {
  margin: var(--space-1) 0 0;
  padding-left: var(--space-1);
  font-size: 0.75rem;
  color: var(--color-muted);
  font-variant-numeric: tabular-nums;
}

/* V2-22a 1.2 Gap 2 — neutral "Working on X" label shown during stages
   with no substage emissions, in place of the stall-warning counter. */
.stage-working-label {
  display: inline-flex;
  align-items: center;
  font-size: 0.75rem;
  font-style: italic;
  color: var(--color-muted);
  font-variant-numeric: tabular-nums;
}

/* Stage expand button */
.stage-expand-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: var(--space-1);
  background: none;
  border: none;
  padding: 0;
  font-family: var(--font-primary);
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--color-canopy);
  cursor: pointer;
}

.stage-expand-btn:hover {
  text-decoration: underline;
}

/* Stage sub-details */
.stage-details {
  margin-top: var(--space-2);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.stage-detail-item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-1);
  font-size: 0.8125rem;
  margin-bottom: 0;
  padding-left: var(--space-1);
}

.stage-detail-item--ok {
  color: var(--color-charcoal);
}

.stage-detail-item--ok i {
  color: var(--color-success);
  flex-shrink: 0;
  margin-top: 2px;
}

.stage-detail-item--warn {
  color: var(--color-warning-ink);
}

.stage-detail-item--warn i {
  color: var(--color-warning);
  flex-shrink: 0;
  margin-top: 2px;
}

.stage-detail-item--err {
  color: var(--color-error);
}

.stage-detail-item--err i {
  color: var(--color-error);
  flex-shrink: 0;
  margin-top: 2px;
}

/* Background banner */
.processing-banner {
  margin-top: var(--space-5);
  padding: var(--space-4);
  background-color: var(--color-parchment);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  text-align: center;
}

.processing-banner-text {
  font-size: 0.9375rem;
  color: var(--color-slate);
  margin-bottom: var(--space-3);
}

.stage-complete-msg {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  text-align: center;
  padding: var(--space-3);
  font-size: 0.875rem;
  color: var(--color-canopy);
  font-weight: 500;
}

/* Processing actions */
.processing-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  justify-content: center;
  margin-top: var(--space-4);
}

.processing-actions .btn {
  height: 48px;
  padding: 0 var(--space-5);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  box-sizing: border-box;
}

.processing-cancel {
  text-align: center;
  margin-top: var(--space-4);
}

.cancel-link {
  background: none;
  border: none;
  color: var(--color-muted);
  font-family: var(--font-primary);
  font-size: 0.875rem;
  cursor: pointer;
  text-decoration: underline;
  padding: var(--space-2);
}

.cancel-link:hover {
  color: var(--color-slate);
}

/* ============================================================
   Results Page
   ============================================================ */

.results-page {
  max-width: 700px;
  margin: 0 auto;
  padding: var(--space-5);
}

.results-header {
  text-align: center;
  margin-bottom: var(--space-4);
}

.results-icon {
  width: 48px;
  height: 48px;
  color: var(--color-success);
  margin-bottom: var(--space-3);
}

.results-project-name {
  font-size: 0.9375rem;
  color: var(--color-slate);
}

/* ============================================================
   Results Dashboard
   ============================================================ */

.results-page {
  max-width: 900px;
  margin: 0 auto;
  padding: var(--space-5);
}

/* ── Completion Certificate (V2-22b) ────────────────────── */
.cert {
  background: #FAFAF7;
  border: 1px solid #D6CEC4;
  /* Primary surface on /results/ — top-of-page section
     container the operator's eye lands on first. Same
     family classification as ``.cockpit-col``. */
  border-radius: var(--radius-lg);
  padding: 24px;
  border-left: 4px solid var(--color-success);
  margin-bottom: var(--space-3);
}
.cert-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-4);
}
/* Low-action composition rule. The 2-column body|actions layout degrades as the
   action count drops: with 0-1 actions the lone button forces the `auto` column
   wide, starving the body into a narrow column and opening a purposeless void where
   a second column would be. A `.cert--notice` cert (a low-action state:
   integrity-unavailable, a terminal error/cancelled, import failure, restore
   invalid/unavailable) collapses to a single full-width column — headline + message
   span the card at a readable measure, the single action (if any) below. A results
   cert (Download + View = 2+ actions) keeps the balanced 2-column layout.
   Plain CSS (no `:has()`) so it degrades gracefully on an older mobile browser —
   every persona, including a rural mobile-first one, sees the void-free layout. Its
   application is enforced by a lint (test_cert_notice_lint): any ≤1-action cert must
   carry `.cert--notice`, so it cannot recur. */
.cert--notice .cert-row {
  grid-template-columns: 1fr;
}
.cert--notice .cert-body {
  max-width: 62ch;   /* a readable measure, not the full wide card */
}
.cert--notice .cert-actions {
  justify-self: start;
  margin-top: var(--space-4);
}
.cert--fail {
  border-left-color: var(--color-error);
}
/* Cancelled — amber border per "user took deliberate action"
   honest signal. The certificate body uses --cancelled-specific
   copy (no retry-package fallback) so the user sees a clear
   "you cancelled this" framing, not a "something failed"
   misclassification. */
.cert--cancelled {
  /* Cancellation is a deliberate user action, not a caution: neutral
     gray rail, never the amber warning family. */
  border-left-color: var(--color-muted, #637082);
}
/* Usable-with-gaps + expired share the amber attention tier with --cancelled
   (all reuse the warning tokens), differentiated by headline + Download-primary CTA + gap-summary, never a new color token. */
.cert--review {
  border-left-color: var(--color-warning);
}
/* Results-coherence — the single Review unit. Replaces the former
   cert-digest + gap-summary + cockpit chip; reuses the warning tokens
   (no new colour). A defect run shifts the accent to the fail tokens;
   a legacy degrade note uses the neutral parchment tone. */
.cert-review-unit {
  margin-top: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--color-warning-tint);
  border: 1px solid var(--color-warning-border);
  border-radius: var(--radius-md);
}
.cert-review-unit--defect {
  background: var(--color-error-tint);
  border-color: var(--color-error-border);
}
.cert-review-unit--legacy {
  background: #F5EDE4;
  border-color: #E5D9C8;
}
.cert-review-unit-lead {
  margin: 0 0 var(--space-1);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-warning-ink);
}
.cert-review-unit--defect .cert-review-unit-lead { color: var(--color-error-ink); }
.cert-review-unit-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.cert-review-unit-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  flex-wrap: wrap;
}
.cert-review-unit-text {
  font-size: 0.8125rem;
  color: var(--color-warning-ink);
}
.cert-review-unit--defect .cert-review-unit-text { color: var(--color-error-ink); }
.cert-review-unit-item.is-primary .cert-review-unit-text { font-weight: 600; }
.cert-review-unit-affordance { margin-left: auto; }
.cert-review-unit-cta {
  font-size: 14px;
  font-weight: 500;
  color: var(--color-canopy, #2D5F3F);
  background: none;
  border: none;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  padding: 0;
}
.cert-review-unit-cta:hover { text-decoration: underline; }
.cert-review-unit-note {
  font-size: 13px;
  color: var(--color-muted);
  white-space: nowrap;
}
.cert-review-unit-understand {
  display: inline-block;
  margin-top: var(--space-2);
  font-size: 14px;
  font-weight: 500;
  color: var(--color-canopy, #2D5F3F);
  text-decoration: none;
}
.cert-review-unit-understand:hover { text-decoration: underline; }
.cert-body { min-width: 0; max-width: 58ch; }
.cert-headline {
  font-family: 'Inter', sans-serif;
  font-size: 24px;
  line-height: 32px;
  font-weight: 600;
  color: var(--color-deep-forest);
  margin: 0 0 var(--space-1) 0;
}
.cert-headline--fail { color: var(--color-error-ink); }
.cert-headline--cancelled { color: var(--color-deep-forest, #1A3A2A); }
.cert-headline--review { color: var(--color-warning-ink); }
.cert-no-runnable-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.cert-no-runnable-inspect {
  display: inline-block;
  margin-top: var(--space-2);
  font-size: 14px;
  font-weight: 500;
  color: var(--color-slate, var(--color-slate, #5A6B7F));
  text-decoration: none;
}
.cert-no-runnable-inspect:hover { text-decoration: underline; }
.cert-summary {
  font-size: 16px;
  line-height: 24px;
  font-weight: 400;
  color: #374151;
  margin: 0 0 var(--space-1) 0;
}
.cert-meta {
  font-size: 14px;
  line-height: 20px;
  font-weight: 400;
  color: #637082;
  margin: 16px 0 0;
  padding-top: 8px;
  border-top: 1px solid var(--color-sandstone, #D6CEC4);
}
.cert-digest {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: #F5EDE4;
  border-radius: 8px;
  padding: var(--space-2) var(--space-3);
  margin-top: var(--space-2);
  width: 100%;
}
.cert-digest-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-warning);
  flex-shrink: 0;
}
.cert-digest-text {
  font-size: 14px;
  font-weight: 500;
  color: #374151;
}
.cert-digest-link {
  font-size: 14px;
  font-weight: 500;
  color: #2D5F3F;
  text-decoration: none;
  margin-left: auto;
  white-space: nowrap;
}
.cert-digest-link:hover { text-decoration: underline; }
.cert-actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: stretch;
  flex-shrink: 0;
}
.cert-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: 48px;
  padding: 0 var(--space-4);
  border-radius: 8px;
  font-size: 16px;
  font-weight: 500;
  text-decoration: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
}
/* Cockpit-aesthetic alignment: route cert-btn colors through the
 * same canopy / sandstone / charcoal tokens the cockpit panel
 * buttons read (see cockpit.css ``.cockpit-panel__action-*``).
 * Keeps the results-page primary/secondary CTAs visually
 * coherent with the cockpit panel chrome on the same screen.
 * Hex fallbacks preserve the prior renders when tokens miss. */
.cert-btn--download {
  background: var(--color-sage-green-500, var(--color-canopy, #2D5F3F));
  color: var(--color-white, #ffffff);
}
.cert-btn--download:hover {
  background: var(--color-canopy-dark, #1A3A2A);
}
.cert-btn--retry {
  background: var(--color-sage-green-500, var(--color-canopy, #2D5F3F));
  color: var(--color-white, #ffffff);
}
.cert-btn--retry:hover {
  background: var(--color-canopy-dark, #1A3A2A);
}
.cert-btn--secondary {
  background: transparent;
  color: var(--color-granite-900, var(--color-charcoal, #374151));
  border: 1px solid var(--color-sandstone-400, var(--color-sandstone, #D6CEC4));
}
.cert-btn--secondary:hover {
  background: var(--color-sandstone-100, var(--color-warm-white, #FAFAF7));
  border-color: var(--color-slate, var(--color-slate, #5A6B7F));
}

/* Run entry-point + version switcher. The version chip is neutral (lineage
 * position only) — no better/worse verdict color. */
.cert-btn--run {
  background: var(--color-sage-green-500, #2D5F3F);
  color: var(--color-white, #ffffff);
}
.cert-btn--run:hover { background: var(--color-canopy-dark, #1A3A2A); }
/* The non-default (original) run confirmation, muted, riding inside the button. */
.xr-run-confirm { font-weight: 400; opacity: .82; }

/* The flagged-baseline review guidance — calm, recommending, never alarming. */
.xr-guide { font-size: .92rem; color: var(--color-slate, #5A6B7F); margin: 0 0 var(--space-2); }

/* Restore states — honest amber for the failed / can't-regenerate message
   (reuses the B-1 honest-state warning tokens), and the in-flight spinner. */
.xr-restore-failed {
  margin: 0 0 var(--space-2);
  padding: 8px 12px;
  font-size: .92rem;
  color: var(--color-warning-ink);
  background: var(--color-warning-tint);
  border: 1px solid var(--color-warning-border);
  border-radius: 8px;
}
.xr-restore-inflight { gap: 8px; opacity: .9; cursor: default; }
.xr-spin { animation: spin 0.8s linear infinite; }

.xr-run-blocked {
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--space-2) var(--space-3);
  background: var(--color-sandstone-50, #F8F5EF);
  border: 1px solid var(--color-sandstone-300, #E0D9CF);
  border-radius: 8px;
}
.xr-run-reason { font-weight: 600; color: var(--color-deep-forest, #1A3A2A); }
.xr-run-next { font-size: .85rem; color: var(--color-slate, #5A6B7F); }

.xr-verbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3);
  margin-top: var(--space-3);
}
.xr-verchip {
  display: inline-flex; align-items: center;
  padding: 4px 12px; border-radius: var(--radius-full, 9999px);
  background: var(--color-sandstone-100, #F0EBE4);
  border: 1px solid var(--color-sandstone-300, #E0D9CF);
  color: var(--color-granite-900, #374151);
  font-size: .74rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
}
.xr-veralt {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--color-slate, #5A6B7F); font-size: .9rem; font-weight: 600;
  text-decoration: none;
}
.xr-veralt:hover {
  color: var(--color-deep-forest, #1A3A2A);
  text-decoration: underline; text-underline-offset: 3px;
}
.xr-veralt--expired { font-weight: 500; cursor: default; }
.xr-veralt:hover.xr-veralt--expired { text-decoration: none; color: var(--color-slate, #5A6B7F); }
.xr-verbar svg { width: 15px; height: 15px; flex: 0 0 auto; }
.cert-btn--run svg { width: 18px; height: 18px; }

/* ================================================================
   N-cycle computed-verdict display — the A+C fusion: a
   computed-verdict hero + robust flow-grouped ledger rows, driven
   from context['n_cycle']. Generic across crop/region/engine.
   FONT FLOOR: nothing below 12px (0.75rem) on this surface.
   No-collision rows: label flex+ellipsis, value fixed-right tabular.
   ================================================================ */
.ncycle { margin-top: var(--space-4); }

.ncycle-head { display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-2); }
.ncycle-meta { font-size: 0.8125rem; color: var(--color-muted); font-family: var(--font-mono); }
.ncycle-chip { font-size: 0.75rem; font-family: var(--font-mono); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 2px 8px; border-radius: var(--radius-sm); background: var(--color-sage-green-100); color: var(--color-canopy); }

/* verdict hero — tint + accent keyed on verdict_type */
.ncycle-hero { border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); border: 1px solid; }
.ncycle-hero--loss { background: var(--color-verdict-loss-bg); border-color: var(--color-verdict-loss-border); }
.ncycle-hero--mining { background: var(--color-verdict-mining-bg); border-color: var(--color-verdict-mining-border); }
.ncycle-hero--build, .ncycle-hero--clean { background: var(--color-verdict-build-bg); border-color: var(--color-verdict-build-border); }
.ncycle-hero--neutral { background: var(--color-verdict-neutral-bg); border-color: var(--color-verdict-neutral-border); }
.ncycle-hero--partial { background: var(--color-verdict-partial-bg); border-color: var(--color-verdict-partial-border); }
.ncycle-eyebrow { font-size: 0.75rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.ncycle-hero--loss .ncycle-eyebrow { color: var(--color-verdict-loss-fg); }
.ncycle-hero--mining .ncycle-eyebrow { color: var(--color-verdict-mining-fg); }
.ncycle-hero--build .ncycle-eyebrow, .ncycle-hero--clean .ncycle-eyebrow { color: var(--color-verdict-build-fg); }
.ncycle-hero--neutral .ncycle-eyebrow { color: var(--color-verdict-neutral-fg); }
.ncycle-hero--partial .ncycle-eyebrow { color: var(--color-verdict-partial-fg); }
.ncycle-headline { font-size: 1.1875rem; font-weight: 700; color: var(--color-deep-forest); letter-spacing: -.01em; margin: 2px 0 3px; line-height: 1.28; }
.ncycle-evidence { font-size: 0.875rem; color: var(--color-charcoal); font-family: var(--font-mono); }

/* "Why this reading?" expander */
.ncycle-why { margin-top: var(--space-2); }
.ncycle-why-toggle { font-size: 0.75rem; font-family: var(--font-mono); color: var(--color-muted); background: none; border: none; cursor: pointer; padding: 0; display: inline-flex; align-items: center; gap: 4px; }
.ncycle-why-toggle:hover { color: var(--color-charcoal); }
.ncycle-why-body { font-size: 0.8125rem; color: var(--color-muted); margin-top: 4px; line-height: 1.6; }

/* budget strip */
.ncycle-budget { display: flex; margin-top: var(--space-3); background: var(--color-white); border: 1px solid var(--color-sandstone-200); border-radius: var(--radius-md); overflow: hidden; flex-wrap: wrap; }
.ncycle-bcol { flex: 1 1 120px; padding: var(--space-2) var(--space-3); border-right: 1px solid var(--color-sandstone-100); }
.ncycle-bcol:last-child { border-right: 0; }
.ncycle-bcol-label { font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: .04em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 4px; }
.ncycle-bcol-value { font-family: var(--font-mono); font-size: 1.0625rem; font-weight: 600; color: var(--color-deep-forest); }
.ncycle-bcol-sub { font-size: 0.75rem; color: var(--color-muted); margin-top: 1px; }
.ncycle-bcol--deficit .ncycle-bcol-value { color: var(--color-verdict-loss-fg); }
.ncycle-bcol--surplus .ncycle-bcol-value { color: var(--color-verdict-build-fg); }
.ncycle-bcol--falling .ncycle-bcol-value { color: var(--color-verdict-mining-fg); }
.ncycle-bcol--rising .ncycle-bcol-value { color: var(--color-verdict-build-fg); }
.ncycle-bcol--holding .ncycle-bcol-value { color: var(--color-verdict-partial-fg); }
.ncycle-bcol--indeterminate .ncycle-bcol-value { color: var(--color-muted); }
.ncycle-bcol-value--absent { color: var(--color-muted); }

/* flow-grouped ledger rows — no-collision invariant */
.ncycle-rows { margin-top: var(--space-3); border: 1px solid var(--color-sandstone-200); border-radius: var(--radius-md); overflow: hidden; background: var(--color-white); }
.ncycle-grp { background: var(--color-sandstone-50); padding: 6px var(--space-3); font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: .04em; text-transform: uppercase; color: var(--color-muted); font-weight: 700; }
.ncycle-grp-caption { font-size: 0.75rem; font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--color-muted); padding: 2px var(--space-3) 4px; font-family: var(--font-primary); }
.ncycle-row { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); border-top: 1px solid var(--color-sandstone-100); }
.ncycle-row-head { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 7px; }
.ncycle-row-name { font-size: 0.8125rem; font-weight: 600; color: var(--color-deep-forest); }
.ncycle-row-info { display: inline-flex; align-items: center; justify-content: center; align-self: center; flex: 0 0 auto; width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--color-badge-caveat-fg); color: var(--color-badge-caveat-fg); font-family: var(--font-mono); font-size: 0.75rem; font-weight: 700; font-style: normal; cursor: help; }
.ncycle-row-unit { font-size: 0.75rem; color: var(--color-muted); font-family: var(--font-mono); font-weight: 400; }
.ncycle-spark { flex: 0 0 auto; width: 70px; height: 22px; color: var(--color-canopy); line-height: 0; }
.ncycle-trend { flex: 0 0 auto; width: 20px; text-align: center; font-family: var(--font-mono); font-size: 0.75rem; }
.ncycle-trend--rising { color: var(--color-canopy); }
.ncycle-trend--falling { color: var(--color-verdict-mining-fg); }
.ncycle-trend--holding { color: var(--color-verdict-partial-fg); }
.ncycle-trend--none { color: var(--color-muted); }
.ncycle-trend--indeterminate { color: var(--color-muted); }
.ncycle-row-value { flex: 0 0 78px; text-align: right; font-family: var(--font-mono); font-size: 0.875rem; font-weight: 600; color: var(--color-deep-forest); font-variant-numeric: tabular-nums; }
.ncycle-row--absent .ncycle-row-name, .ncycle-row--absent .ncycle-row-value { color: var(--color-sandstone-500); font-weight: 500; }
.ncycle-row--absent .ncycle-row-value { font-style: italic; font-size: 0.75rem; }
.ncycle-tag { display: inline-flex; font-size: 0.75rem; font-family: var(--font-mono); color: var(--color-badge-caveat-fg); background: var(--color-badge-caveat-bg); border-radius: var(--radius-sm); padding: 0 5px; margin-left: 5px; vertical-align: middle; }
.ncycle-tag--zero { color: var(--color-verdict-partial-fg); background: var(--color-verdict-partial-bg); }

/* engine-gate (whole-engine honest-absent) */
.ncycle-gate { margin-top: var(--space-3); background: var(--color-verdict-partial-bg); border: 1px solid var(--color-verdict-partial-border); border-radius: var(--radius-md); padding: var(--space-4); display: flex; gap: var(--space-3); align-items: flex-start; }
.ncycle-gate svg { width: 26px; height: 26px; flex: 0 0 auto; color: var(--color-verdict-partial-fg); margin-top: 2px; }
.ncycle-gate-title { font-size: 0.9375rem; font-weight: 700; color: var(--color-deep-forest); }
.ncycle-gate-body { font-size: 0.8125rem; color: var(--color-charcoal); margin-top: 4px; line-height: 1.6; }
.ncycle-gate-mover { margin-top: 10px; display: inline-flex; align-items: center; gap: 6px; background: none; border: 0; padding: 0; cursor: pointer; font-family: var(--font-primary); font-size: 0.8125rem; font-weight: 600; color: var(--color-verdict-partial-fg); }
.ncycle-gate-mover:hover { text-decoration: underline; }

.ncycle-coverage { margin: 8px 0 0; font-size: 0.75rem; color: var(--color-muted); font-family: var(--font-mono); }
.ncycle-caveats { margin-top: var(--space-2); font-size: 0.75rem; color: var(--color-muted); line-height: 1.6; }

@media (max-width: 768px) {
  .ncycle-budget { flex-direction: column; }
  .ncycle-bcol { border-right: 0; border-bottom: 1px solid var(--color-sandstone-100); }
  .ncycle-bcol:last-child { border-bottom: 0; }
}

/* ACEA Water tab — mirrors the .ncycle-* shell on the SHIPPED design tokens (content swap, not a new
   surface). The one bespoke extension is the .wtr-foot* Hoekstra green/blue crop-water-use bar. */
.wtr { margin-top: var(--space-4); }
.wtr-head { display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-2); }
.wtr-meta { font-size: 0.8125rem; color: var(--color-muted); font-family: var(--font-mono); }
/* the scenario label reuses the shared .ncycle-chip (one-per-job); no bespoke water chip. */

.wtr-hero { border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); border: 1px solid; }
.wtr-hero--loss { background: var(--color-verdict-loss-bg); border-color: var(--color-verdict-loss-border); }
.wtr-hero--good { background: var(--color-verdict-build-bg); border-color: var(--color-verdict-build-border); }
.wtr-hero--warning { background: var(--color-verdict-partial-bg); border-color: var(--color-verdict-partial-border); }
.wtr-hero--neutral { background: var(--color-verdict-neutral-bg); border-color: var(--color-verdict-neutral-border); }
.wtr-eyebrow { font-size: 0.75rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.wtr-hero--loss .wtr-eyebrow { color: var(--color-verdict-loss-fg); }
.wtr-hero--good .wtr-eyebrow { color: var(--color-verdict-build-fg); }
.wtr-hero--warning .wtr-eyebrow { color: var(--color-verdict-partial-fg); }
.wtr-hero--neutral .wtr-eyebrow { color: var(--color-verdict-neutral-fg); }
.wtr-headline { font-size: 1.1875rem; font-weight: 700; color: var(--color-deep-forest); letter-spacing: -.01em; margin: 2px 0 3px; line-height: 1.28; font-variant-numeric: tabular-nums; }
.wtr-hero-unit { font-size: 0.8125rem; font-weight: 600; color: var(--color-muted); font-family: var(--font-mono); }
.wtr-evidence { font-size: 0.875rem; color: var(--color-charcoal); font-family: var(--font-mono); }
.wtr-ambient { margin-top: 5px; font-size: 0.8125rem; color: var(--color-charcoal); display: flex; align-items: center; gap: 6px; line-height: 1.5; }
.wtr-info { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--color-badge-caveat-fg); color: var(--color-badge-caveat-fg); font-family: var(--font-mono); font-size: 0.75rem; font-weight: 700; font-style: normal; cursor: help; }
.wtr-absent { color: var(--color-muted); font-style: italic; font-size: 0.9375rem; }

.wtr-coverage { margin: 8px 0 0; font-size: 0.75rem; color: var(--color-muted); font-family: var(--font-mono); }
.wtr-num { font-variant-numeric: tabular-nums; }

.wtr-budget { display: flex; margin-top: var(--space-3); background: var(--color-white); border: 1px solid var(--color-sandstone-200); border-radius: var(--radius-md); overflow: hidden; flex-wrap: wrap; }
.wtr-bcol { flex: 1 1 120px; padding: var(--space-2) var(--space-3); border-right: 1px solid var(--color-sandstone-100); }
.wtr-bcol:last-child { border-right: 0; }
.wtr-bcol-label { font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: .04em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 4px; }
.wtr-bcol-value { font-family: var(--font-mono); font-size: 1.0625rem; font-weight: 600; color: var(--color-deep-forest); font-variant-numeric: tabular-nums; }
.wtr-bcol-unit { font-size: 0.75rem; color: var(--color-muted); font-weight: 400; }
.wtr-bcol-value--absent { color: var(--color-muted); font-size: 0.875rem; font-style: italic; }

/* Hoekstra green/blue crop-water-use bar (the one bespoke extension) — defensive fallbacks so an
   undefined token never renders invisible. */
.wtr-foot { margin-top: var(--space-3); }
.wtr-foot-bar { display: flex; height: 14px; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--color-sandstone-200); }
.wtr-foot-seg { height: 100%; }
.wtr-foot-seg--green { background: var(--color-canopy, #4a7c3f); }
.wtr-foot-seg--blue { background: var(--color-info, #2b6cb0); }
.wtr-foot-legend { margin-top: 5px; font-size: 0.75rem; color: var(--color-muted); font-family: var(--font-mono); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.wtr-foot-key { display: inline-block; width: 10px; height: 10px; border-radius: 2px; }
.wtr-foot-key--green { background: var(--color-canopy, #4a7c3f); }
.wtr-foot-key--blue { background: var(--color-info, #2b6cb0); }

.wtr-rows { margin-top: var(--space-3); border: 1px solid var(--color-sandstone-200); border-radius: var(--radius-md); overflow: hidden; background: var(--color-white); }
.wtr-grp { background: var(--color-sandstone-50); padding: 6px var(--space-3); font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: .04em; text-transform: uppercase; color: var(--color-muted); font-weight: 700; }
.wtr-row { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); border-top: 1px solid var(--color-sandstone-100); }
.wtr-row-name { flex: 1 1 auto; min-width: 0; font-size: 0.8125rem; font-weight: 600; color: var(--color-deep-forest); }
.wtr-row-value { flex: 0 0 auto; text-align: right; font-family: var(--font-mono); font-size: 0.875rem; font-weight: 600; color: var(--color-deep-forest); font-variant-numeric: tabular-nums; }
.wtr-row-unit { font-size: 0.75rem; color: var(--color-muted); font-weight: 400; }
.wtr-row--absent .wtr-row-name, .wtr-row--absent .wtr-row-value { color: var(--color-sandstone-500); font-weight: 500; }
.wtr-row--absent .wtr-row-value { font-style: italic; font-size: 0.75rem; }

.wtr-gate { margin-top: var(--space-3); background: var(--color-verdict-partial-bg); border: 1px solid var(--color-verdict-partial-border); border-radius: var(--radius-md); padding: var(--space-4); display: flex; gap: var(--space-3); align-items: flex-start; }
.wtr-gate svg { width: 26px; height: 26px; flex: 0 0 auto; color: var(--color-verdict-partial-fg); margin-top: 2px; }
.wtr-gate-title { font-size: 0.9375rem; font-weight: 700; color: var(--color-deep-forest); }
.wtr-gate-body { font-size: 0.8125rem; color: var(--color-charcoal); margin-top: 4px; line-height: 1.6; }
.wtr-gate-mover { margin-top: 10px; display: inline-flex; align-items: center; gap: 6px; background: none; border: 0; padding: 0; cursor: pointer; font-family: var(--font-primary); font-size: 0.8125rem; font-weight: 600; color: var(--color-verdict-partial-fg); }
.wtr-gate-mover:hover { text-decoration: underline; }
.wtr-caveats { margin-top: var(--space-2); font-size: 0.75rem; color: var(--color-muted); line-height: 1.6; }

@media (max-width: 768px) {
  .wtr-budget { flex-direction: column; }
  .wtr-bcol { border-right: 0; border-bottom: 1px solid var(--color-sandstone-100); }
  .wtr-bcol:last-child { border-bottom: 0; }
}

/* ================================================================
   V2-21 DATA PORTRAIT
   ================================================================ */

.data-portrait {
  margin-bottom: var(--space-4);
}

.portrait-grid {
  /* Legacy 2-column grid — preserved as a no-op selector in case
     any extension/template still references it. The new BIG MAP
     layout below is single-column flow with stat tiles top, map
     middle, bottom row 30/70. */
  display: block;
}

/* --- Data Quality panel: single full-width container with a
   compact Effective Resolution context band stacked above the
   Quality Checks val-strip. The prior dual-panel grid had a
   structural content-density asymmetry — ER content stayed at
   ~152 px while the QC val-strip wrapped variably (160 / 212 px
   depending on viewport width and label localization). Collapsing
   to a single panel removes the asymmetry-by-construction and
   keeps the panel height invariant ~185 px regardless of badge
   wrap behavior. */

.portrait-data-quality {
  background: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  margin-top: var(--space-3);
}

/* Effective Resolution context band — label, summary, drawer cue
   on a single baseline-aligned row. The summary takes flex:1 so
   it expands to fill the available width while the cue stays
   compact at the right end via white-space:nowrap. */
.portrait-dq-grid-band {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}

.portrait-dq-grid-label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-deep-forest);
  display: flex;
  align-items: center;
  gap: 6px;
}

.portrait-dq-grid-summary {
  font-size: 14px;
  line-height: 22px;
  color: var(--color-slate);
  flex: 1;
  min-width: 0;
}

.portrait-dq-drawer-cue {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.78rem;
  color: var(--color-canopy);
  font-weight: 500;
  white-space: nowrap;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
}

.portrait-dq-drawer-cue:focus-visible {
  outline: 2px solid var(--color-canopy);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.portrait-dq-divider {
  height: 1px;
  background: var(--color-sandstone);
  margin: 16px 0;
  border: 0;
}

.portrait-dq-checks-h4 {
  margin: 0 0 8px 0;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-deep-forest);
}

/* Tablet boundary at 1023 px — the panel already stacks vertically
   inside the data-portrait grid; nothing further to flip. The
   Region Health card replaces the panel at <=767 px per the mobile
   crossover. */

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

.portrait-map {
  height: 220px;
  border-radius: var(--radius-md);
  background: var(--color-sandstone);
  position: relative;
  overflow: hidden;
  z-index: 1; /* Below navbar (z-index: 100+) */
}

/* BIG MAP — 900×540 at desktop, replaces the 320×220 thumbnail.
   Sits centred (max-width 900 px) below the stat tiles in the
   data-portrait single-column flow. The 540 px height honours
   the 5:3 aspect ratio at the 900 px max-width. The Sandstone
   border matches the canonical card edge (Stage 2 mockup B.1)
   so the map reads as a discrete card on Parchment instead of
   bleeding into the surrounding surface. */
/* The integrated map+legend card carries the chrome the
   map used to own (max-width, margin, border, radius). The
   nested map sheds its own border + max-width to avoid
   doubled edges; a 1-pixel sandstone seam at its bottom
   separates the map area from the legend strip without
   adding a visual frame around the map itself. Cross-
   surface parity with the cockpit map's integrated card
   pattern. */
.portrait-map-card {
  max-width: 900px;
  margin: var(--space-3) auto;
  background: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.portrait-map--big {
  height: 540px;
  max-width: none;
  margin: 0;
  border: none;
  border-radius: 0;
  border-bottom: 1px solid var(--color-sandstone);
}

/* Tablet boundary at 1023 px so a 1024 px viewport stays on the
   desktop rule. The mobile-omit rule below at ≤ 767 px keeps the
   240 px stub regardless of which tablet rule matches. */
@media (max-width: 1023px) {
  .portrait-map--big {
    height: 432px;  /* 720×432 at tablet, 5:3 preserved */
  }
}

/* Per-cell hover tooltip on the BIG MAP (results) and the
   cockpit cell layer. Stage 2.5 §4.6 lock: white bg, 1 px
   Sandstone border, 8 px radius, 8/12 padding, subtle shadow.
   Line 1 (cell id + coords) renders in JetBrains Mono so the
   numeric coords stay in a calibrated tabular form; lines 2 + 3
   render in Inter so the status word + cascade arrow read as
   prose. Three structural classes — `cell-tooltip-line1`, `-line2`,
   `-line3` — are emitted by tooltip-template.js; styling is anchored
   to those, not to nth-child, so reordering or omitting a line
   does not break typography. */
/* Use .leaflet-tooltip.cell-tooltip for specificity above
   Leaflet's own .leaflet-tooltip defaults (which set their own
   border, padding, and shadow at the same single-class
   specificity our prior .cell-tooltip rule had — without this
   bump the new Stage 2.5 §4.6 visuals lose to Leaflet's defaults
   wherever source-order goes the wrong way). */
.leaflet-tooltip.cell-tooltip {
  font-size: 0.75rem;
  line-height: 1.4;
  background: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: 8px;
  padding: 8px 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  color: var(--color-text);
  white-space: normal;
  /* Bound the tooltip width so Leaflet's auto-constrain near
     viewport edges cannot shrink it below the readable floor.
     The min-width keeps the cell ID + coords on a single line
     consistently; the max-width lets line 2 + line 3 wrap when
     they carry longer strings without forcing line 1 to wrap
     mid-coordinate. */
  min-width: 240px;
  max-width: 320px;
}

.cell-tooltip-line {
  display: block;
}

.cell-tooltip-line1 {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 0.78rem;
  color: var(--color-text);
  /* Line 1 (cell ID + coords) is the visual anchor of the
     tooltip and must never wrap mid-pair — wrapping at the ` · `
     separator looked unfinished on right-edge cells where
     Leaflet's auto-constrain kicked in. The non-breaking-space
     separators in `_formatCoords` and the cell-id concatenation
     give the browser no wrap candidates within line 1; this
     rule pins the contract at the CSS layer too. */
  white-space: nowrap;
}

.cell-tooltip-line2 {
  font-family: var(--font-primary);
  margin-top: 2px;
  color: var(--color-text);
}

.cell-tooltip-line3 {
  font-family: var(--font-primary);
  margin-top: 2px;
  font-size: 0.72rem;
  color: var(--color-text-muted);
}

/* 5-swatch inline legend inside the BIG MAP card per Stage
   2.5 §2.6 + cross-surface parity with the cockpit map's
   integrated legend. Swatches use the v2.0 severity-count
   palette fills + outlines (byte-identical to
   ``cell-layer.js`` STATUS_PALETTE so the legend never
   mis-encodes a cell). Labels carry the semantic for
   color-blind / screen-reader readers. The legend is left-
   justified inside the card chrome (parity with the cockpit
   pattern); flex wraps on narrow viewports so each item
   stays on its own line rather than truncating. */
.portrait-map-legend {
  list-style: none;
  margin: 12px 16px 16px 16px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  /* Centered inside the bordered map card. Per F36 v2.1
     (2026-05-01 family-rule revisit) all map-legend
     surfaces — /results/ portrait + cockpit — use
     justify-content: center. The prior v2 family-member
     deviation (cockpit left-justified for column-axis
     reading) was over-modeled; persona-gaze sees the
     map's centered geographic subject as the dominant
     context. Cross-surface alignment parity is the
     locked invariant. */
  justify-content: center;
  gap: 12px;
  font-size: 12px;
  color: var(--color-charcoal);
}

.portrait-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Swatches changed from 10×10 circles to 14×14 squares with
   3 px radius for cross-surface parity with the cockpit
   legend (``cockpit-legend-swatch`` at the same dimensions).
   The class name ends in ``-swatch`` (matching the shape +
   the cockpit's vocabulary) so a future grep can detect
   stale references to the prior circle-named class. */
.portrait-legend-swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  border: 1px solid transparent;
  flex-shrink: 0;
}

/* F-CR — Observed / Imputed swatches for the cockpit-redesign
   legend that now reuses ``portrait-map-legend`` chrome verbatim.
   The Observed chip is a plain bone fill matching the cockpit map's
   non-imputed cell background; the Imputed chip carries the same
   45° diagonal-hatch the on-map imputed cells render via
   ``<pattern id="hatch-imputed">`` in ``_map_centerpiece.html``,
   so the swatch is the literal key for the cell visual. Lives in
   the portrait section because the cockpit legend now shares the
   portrait class family (durable §24 cross-surface vocabulary). */
.portrait-legend-swatch--observed {
  background: var(--color-bone, var(--color-warm-white, #FAFAF7));
  border-color: var(--color-sandstone-400, var(--color-sandstone, #D6CEC4));
}

.portrait-legend-swatch--imputed {
  background-image: linear-gradient(
    45deg,
    transparent 0,
    transparent 4px,
    var(--color-granite-700, var(--color-charcoal, #4A5568)) 4px,
    var(--color-granite-700, var(--color-charcoal, #4A5568)) 5px,
    transparent 5px,
    transparent 9px
  );
  background-size: 9px 9px;
  background-color: var(--color-bone, var(--color-warm-white, #FAFAF7));
  border-color: var(--color-sandstone-400, var(--color-sandstone, #D6CEC4));
}

/* F-CR — vertical divider between the Observed/Imputed convention
   pair and the verdict-state swatches in the cockpit legend.
   Renders as a thin sandstone bar inline with the surrounding chips
   (the legend's flex layout keeps every <li> on the same row /
   wraps as needed). Sized for visual separation without competing
   with the swatches for attention. */
.portrait-legend-divider {
  display: inline-block;
  width: 1px;
  height: 14px;
  background: var(--color-sandstone-300, var(--color-sandstone, #D6CEC4));
  margin: 0 4px;
  list-style: none;
}

/* The legend's check-vs-decision group headings ("What the check
   found" / "What you decided") — quiet uppercase markers so the
   split reads at a glance without competing with the chips. */
.portrait-legend-group-header {
  display: inline-block;
  font: 600 10px/1.4 var(--font-primary, 'Inter', sans-serif);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-slate, var(--color-slate, #5A6B7F));
  margin: 0 6px 0 10px;
  list-style: none;
}

.portrait-legend-group-header:first-child {
  margin-left: 0;
}

.portrait-legend-swatch--pass {
  background: var(--color-map-status-pass-fill);
  border-color: var(--color-map-status-pass-ink);
}

.portrait-legend-swatch--info {
  background: var(--color-map-status-info-fill);
  border-color: var(--color-map-status-info-ink);
}

.portrait-legend-swatch--warn-1 {
  /* F-BU canonical-source lift — both surfaces (results legend +
     cockpit grid map) read from `--color-warn-1-fill` per durable
     §24 so a future palette adjustment lands in ONE place. */
  background: var(--color-map-status-warn-1-fill);
  border-color: var(--color-map-status-warn-1-ink);
}

.portrait-legend-swatch--warn-2-plus {
  /* F18 — amber-500 instead of amber-200 (#fde68a) for stronger
     differentiation from WARN-1 (yellow-200). The deeper saturation
     reads as "more urgent" at glance — persona walk: Aminata sees
     WARN-2+ stand out distinctly from WARN-1 on the BIG MAP without
     re-reading the legend.

     Sprint E.3 cycle-4 Phase 4.5 fixup +15 F-BU canonical-source
     lift — reads from `--color-warn-2-plus-fill` per durable §24. */
  background: var(--color-map-status-warn-2-plus-fill);
  border-color: var(--color-map-status-warn-2-plus-ink);
}

.portrait-legend-swatch--fail {
  background: var(--color-map-status-fail-fill);
  border-color: var(--color-map-status-fail-ink);
}

/* Sprint E.3 cycle-4 Phase 4.5 fixup +15 F-CD — decision-aware
   legend swatches. Both surfaces (/results/ legend + cockpit
   grid-map cell fills) consume the same canonical vars per
   durable §24 canonical-source-or-pin. */
.portrait-legend-swatch--acknowledged {
  background: var(--color-map-status-acknowledged-fill);
  border-color: var(--color-map-status-acknowledged-ink);
}

.portrait-legend-swatch--overridden-value,
.portrait-legend-swatch--overridden {
  background: var(--color-map-status-overridden-value-fill);
  border-color: var(--color-map-status-overridden-value-ink);
}

.portrait-legend-swatch--interpolated {
  background: var(--color-map-status-interpolated-fill);
  border-color: var(--color-map-status-interpolated-ink);
}

/* Unavailable swatch — matches the cockpit-map contract:
   sandstone-100 (#F5EFE2) fill at 0.75 opacity, granite-500
   (#6B7280) 1 px border, granite-500 ±45° stripes at 0.30
   opacity. The 4 px pitch + 1 px stripe scales the texture
   down to the 14 px swatch size so the legend anchors "what
   does that pattern mean?" against the same chrome the map
   paints on excluded cells. */
.portrait-legend-swatch--unavailable {
  background-color: color-mix(in srgb, var(--color-map-status-unavailable-fill) 75%, transparent);
  background-image:
    repeating-linear-gradient(
      45deg,
      transparent 0,
      transparent 1px,
      color-mix(in srgb, var(--color-map-status-unavailable-ink) 30%, transparent) 1px,
      color-mix(in srgb, var(--color-map-status-unavailable-ink) 30%, transparent) 2px,
      transparent 2px,
      transparent 4px
    ),
    repeating-linear-gradient(
      -45deg,
      transparent 0,
      transparent 1px,
      color-mix(in srgb, var(--color-map-status-unavailable-ink) 30%, transparent) 1px,
      color-mix(in srgb, var(--color-map-status-unavailable-ink) 30%, transparent) 2px,
      transparent 2px,
      transparent 4px
    );
  border-color: var(--color-map-status-unavailable-ink);
}

/* Region Health card (mobile ≤ 767 px) per AC-F5 + D17 + Stage 2 B.3.
   Hidden on desktop; the BIG MAP carries the visual at ≥ 768 px.
   Parchment bg + 8 px radius + 16/24 padding read as a figure card
   inside the mobile section — same shape token as the desktop
   ``.portrait-data-quality`` panel and the ``.portrait-map-card``
   wrapper that this card replaces at mobile. Title is uppercase
   letter-spaced per the dossier's mobile typography lock. */
.portrait-region-health {
  display: none;
  background: var(--color-parchment);
  /* Figure-card-within-mobile-section semantic — replaces the BIG
     MAP card (also ``--radius-md``) at ≤767 px. */
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  margin: var(--space-3) 0;
}

.portrait-region-health-title {
  margin: 0 0 var(--space-2);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-charcoal);
}

.portrait-region-health-list {
  list-style: none;
  margin: 0 0 var(--space-3);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.portrait-region-health-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.875rem;
  color: var(--color-charcoal);
}

.portrait-region-health-meta {
  font-size: 0.8125rem;
  color: var(--color-slate);
}

/* Touch-target sized to the 44 px floor + Canopy focus ring per
   Stage 2 B.3 mockup (line 1708). The link is the only
   interactive affordance on the mobile card; missing the floor
   would leave Ibrahim's thumb without a reliable hit area. */
.portrait-region-health-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--space-2);
  font-size: 0.875rem;
  color: var(--color-canopy);
  text-decoration: none;
  font-weight: 500;
  border-radius: var(--radius-sm);
}

.portrait-region-health-link:hover {
  text-decoration: underline;
}

.portrait-region-health-link:focus-visible {
  outline: 2px solid var(--color-canopy);
  outline-offset: 2px;
  text-decoration: underline;
}

/* Top-left anchor (was bottom-left) per the cartographic-convention
   §2.6 lock — Leaflet's scale bar takes bottom-left, the location
   chip is custom UI with no fixed convention, and the F-pattern
   eye-flow puts the identifier at first-orientation. The corner
   flip also resolves the empirical scale-bar / location-label
   collision the bottom-left placement produced at certain zooms. */
.portrait-map-label {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  background: rgba(255,255,255,0.92);
  padding: 4px 10px;
  border-radius: var(--radius-sm);
  font-size: 0.8rem;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 4px;
  z-index: 500;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

/* The pre-F8 ``.portrait-eff-res`` /
   ``.portrait-eff-res-trigger`` / ``.portrait-eff-res-summary`` /
   ``.portrait-drawer-cue`` rules are now subsumed by the
   ``.portrait-data-quality`` panel + ``.portrait-dq-*`` sub-rules
   above. The single-panel restructure replaces the prior dual-
   panel surface; structural-binding tests update accordingly. */

/* Fetch-unavailable banners per G7 §3 + ux-expert v2.3 mockup.
   Two severity tiers — prominent (≥80% of cells unavailable)
   sits between the cert and the stat tiles with cert-family
   vocabulary; info (≥10% < 80%) sits between the BIG MAP and
   the bottom-row with subordinate styling. Both tiers carry the
   ICASA MISDAT cite inline so the magnitude AND methodology
   rationale read at a glance. */
.fetch-banner {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  margin: var(--space-3) auto;
  max-width: 900px;
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  background: var(--color-parchment);
  padding: 12px;
}

.fetch-banner--prominent {
  border-radius: var(--radius-lg);
  background: var(--color-warm-white, #FAFAF7);
  border-left: 4px solid var(--color-warning);
  padding: 16px;
}

.fetch-banner--info {
  border-left: 2px solid var(--color-warning);
}

.fetch-banner-icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.fetch-banner--prominent .fetch-banner-icon {
  color: var(--color-warning);
}

.fetch-banner--info .fetch-banner-icon {
  color: var(--color-muted);
}

.fetch-banner-body {
  flex: 1 1 auto;
  min-width: 0;
}

.fetch-banner-headline {
  margin: 0 0 4px;
  font-size: 18px;
  line-height: 26px;
  font-weight: 600;
  color: var(--color-deep-forest);  /* Deep Forest per ux-expert v2.3 */
}

.fetch-banner-summary {
  margin: 0;
  font-size: 14px;
  line-height: 22px;
  color: var(--color-charcoal);
}

.fetch-banner-info-line {
  margin: 0;
  font-size: 14px;
  line-height: 22px;
  font-weight: 500;
  color: var(--color-charcoal);
}

.fetch-banner-inline-link {
  color: var(--color-slate);
  text-decoration: none;
  margin-left: 4px;
}

.fetch-banner-inline-link:hover,
.fetch-banner-inline-link:focus-visible {
  text-decoration: underline;
}

.fetch-banner-actions {
  flex-shrink: 0;
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.fetch-banner-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: 0 12px;
  background: var(--color-sandstone);
  color: var(--color-canopy);
  border: 1px solid var(--color-canopy);
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
}

.fetch-banner-cta:hover,
.fetch-banner-cta:focus-visible {
  background: var(--color-canopy);
  color: var(--color-warm-white, #FAFAF7);
  outline: none;
}

@media (max-width: 767px) {
  /* Mobile: prominent banner stacks body + actions vertically;
     info banner remains single-line + collapses inline link
     onto its own line via natural wrap. Both stay full-width
     within the cert/portrait gutter. */
  .fetch-banner--prominent {
    flex-wrap: wrap;
  }
  .fetch-banner-actions {
    width: 100%;
    flex-wrap: wrap;
  }
}

.portrait-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.portrait-section-header h4 {
  margin: 0;
  font-size: 0.85rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 6px;
}

.eff-res-table {
  width: 100%;
  font-size: 0.78rem;
  margin-top: var(--space-2);
  border-collapse: collapse;
}

.eff-res-table th {
  text-align: left;
  font-weight: 500;
  color: var(--color-text-muted);
  padding: 4px 6px;
  border-bottom: 1px solid var(--color-sandstone);
}

.eff-res-table td {
  padding: 6px;
}

.eff-res-shared td {
  color: var(--color-warning-ink);
  background: #fffbeb;
}

.eff-res-type {
  display: inline-block;
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  margin-right: 4px;
}

.eff-res-note {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  margin-top: var(--space-2);
  display: flex;
  align-items: flex-start;
  gap: 4px;
  line-height: 1.4;
}

/* --- Right column: KPIs + Range Bars + Validation --- */

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

.portrait-section-title {
  margin: 0 0 var(--space-2) 0;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-text-primary);
}

/* KPI Cards */

.portrait-kpis {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-3);
}

@media (max-width: 640px) {
  .portrait-kpis {
    grid-template-columns: 1fr;
  }
}

.kpi-card {
  background: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  text-align: center;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.kpi-card:hover {
  border-color: var(--color-canopy);
  box-shadow: 0 2px 8px rgba(0,0,0,0.06);
}

.kpi-card--pass { border-top: 3px solid var(--color-success); }
.kpi-card--warning { border-top: 3px solid var(--color-warning); }

.kpi-icon {
  color: var(--color-text-muted);
  margin-bottom: var(--space-1);
}

.kpi-value {
  font-size: 2rem;
  font-weight: 700;
  color: var(--color-text-primary);
  line-height: 1.1;
}

.kpi-label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--color-text-primary);
  margin-top: 2px;
  /* F21 — KPI label may carry an inline ⓘ disclosure button
     for tiles that need methodology disclosure (e.g., the Soil
     Profile Classes tile shows HOW the dedup works). The flex
     wrap keeps the label + button on the same baseline. */
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.kpi-tooltip-btn {
  /* Inline ⓘ icon adjacent to the KPI label — opens the
     disclosure tooltip on hover via the native ``title``
     attribute. Aria-label carries the same content for
     screen-reader users. The button is purely a tooltip
     anchor; no click action. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: help;
  color: var(--color-text-muted);
  border-radius: 50%;
}

.kpi-tooltip-btn:hover,
.kpi-tooltip-btn:focus-visible {
  color: var(--color-text-primary);
  outline: 1px solid var(--color-canopy, #2D5F3F);
}

.kpi-subtitle {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  margin-top: 2px;
}

/* Climate Range Bars */

.portrait-ranges {
  background: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  padding: var(--space-3);
}

.range-bar-row {
  margin-bottom: var(--space-2);
}

.range-bar-row:last-child {
  margin-bottom: 0;
}

.range-bar-label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 4px;
}

.range-bar-name {
  font-size: 0.78rem;
  font-weight: 500;
}

.range-bar-values {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.range-bar-track {
  height: 8px;
  background: var(--color-sandstone);
  border-radius: 4px;
  position: relative;
  overflow: hidden;
}

.range-bar-fill {
  position: absolute;
  top: 0;
  height: 100%;
  border-radius: 4px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.range-bar-fill--animated {
  transform: scaleX(1);
}

.range-bar-fill--pass {
  background: var(--color-success);
}

.range-bar-fill--warning {
  background: linear-gradient(90deg, #f59e0b, #d97706);
}

.range-bar-fill--fail {
  background: linear-gradient(90deg, #ef4444, #dc2626);
}

.range-bar-fill--info {
  background: var(--color-text-muted);
  opacity: 0.4;
}

.range-bar-bounds {
  display: flex;
  justify-content: space-between;
  font-size: 0.75rem;
  color: var(--color-text-muted);
  margin-top: var(--space-1);
}

/* Effective Resolution drawer + backdrop. The backdrop is a
   transparent click-eater (no dim) so the page behind stays
   readable; the drawer slides in from the right edge with a
   single-property transform transition for jank-free motion.
   z-index: 1010/1011 stack the drawer + backdrop above the
   navbar (100) and the map spinner (1001) but below any future
   modal layer. Mobile ≤ 480 px takes full viewport width so the
   table is readable on phones; tablet/desktop stay at 360 px. */
.portrait-res-drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1010;
  background: transparent;
}

.portrait-res-drawer {
  position: fixed;
  /* F26+F27 chrome-respect — top anchors below the .nav
     (sticky permanent top chrome) so the navbar stays
     accessible while the drawer is open; bottom anchors above
     any per-page sticky bottom CTA. Drawer height = viewport
     - nav-height - sticky-cta-height. */
  top: var(--nav-height);
  right: 0;
  bottom: var(--sticky-cta-height);
  width: 360px;
  max-width: 100vw;
  z-index: 1011;
  background: var(--color-white);
  border-left: 1px solid var(--color-sandstone);
  box-shadow: -4px 0 24px rgba(0, 0, 0, 0.08);
  transform: translateX(100%);
  transition: transform 280ms cubic-bezier(0.4, 0, 0.2, 1);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.portrait-res-drawer--open {
  transform: translateX(0);
}

.portrait-res-drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3);
  border-bottom: 1px solid var(--color-sandstone);
}

.portrait-res-drawer-header h4 {
  margin: 0;
  font-size: 0.9rem;
  font-weight: 600;
}

.portrait-res-drawer-close {
  background: transparent;
  border: 0;
  padding: 4px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
}

.portrait-res-drawer-close:hover,
.portrait-res-drawer-close:focus-visible {
  background: var(--color-sandstone);
  color: var(--color-text);
  outline: none;
}

.portrait-res-drawer-body {
  padding: var(--space-3);
  overflow-y: auto;
  flex: 1 1 auto;
}

@media (max-width: 480px) {
  .portrait-res-drawer {
    width: 100vw;
    border-left: 0;
  }
}

/* Per-cell inspection drawer (F14 P2). Geometry / a11y / dismiss
   parity with the ER drawer above — same 360 px width, same
   transition curve, same z-index stack (1010 backdrop / 1011
   drawer), same mobile carve-out (full viewport ≤ 480 px). The
   single-drawer-slot enum at the data-portrait Alpine root makes
   the two drawers mutually exclusive so they cannot stack. */
.portrait-cell-drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1010;
  background: transparent;
  /* F25 — pointer-events: none so the backdrop does NOT
     intercept clicks on the Leaflet map underneath. The
     dismiss-on-outside-click path lives on the drawer's
     ``@click.outside`` with a map-area exclusion so clicks
     on cells trigger smooth-swap (rect handler → openCellDrawer
     updates ``activeCell``) rather than close-then-reopen.
     The previous backdrop @click="closeCellDrawer()" caught
     cell clicks first, forcing a two-click pattern. */
  pointer-events: none;
}

.portrait-cell-drawer {
  position: fixed;
  /* F26+F27 chrome-respect — same anchoring as
     .portrait-res-drawer; both drawers share the chrome-
     respect contract via the --nav-height + --sticky-cta-height
     custom properties. */
  top: var(--nav-height);
  right: 0;
  bottom: var(--sticky-cta-height);
  width: 360px;
  max-width: 100vw;
  z-index: 1011;
  background: var(--color-white);
  border-left: 1px solid var(--color-sandstone);
  /* 12 px top-left radius per the drawer-family vocabulary
     (D40 / Step-13 parity catalog). The cockpit cell drawer
     carries the same radius for cross-surface family
     parity. */
  border-top-left-radius: 12px;
  box-shadow: -4px 0 24px rgba(0, 0, 0, 0.08);
  transform: translateX(100%);
  transition: transform 280ms cubic-bezier(0.4, 0, 0.2, 1);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.portrait-cell-drawer--open {
  transform: translateX(0);
}

.portrait-cell-drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3);
  border-bottom: 1px solid var(--color-sandstone);
}

.portrait-cell-drawer-header h4 {
  margin: 0;
  font-size: 0.9rem;
  font-weight: 600;
  font-family: var(--font-mono);
}

.portrait-cell-drawer-close {
  background: transparent;
  border: 0;
  padding: 4px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
}

.portrait-cell-drawer-close:hover,
.portrait-cell-drawer-close:focus-visible {
  background: var(--color-sandstone);
  color: var(--color-text);
  outline: none;
}

.portrait-cell-drawer-body {
  padding: var(--space-3);
  overflow-y: auto;
  flex: 1 1 auto;
}

.cell-drawer-section {
  margin-bottom: var(--space-3);
}

.cell-drawer-section:last-child {
  margin-bottom: 0;
}

.cell-drawer-section-title {
  margin: 0 0 4px 0;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}

/* Step-14 — drawer affirmation when the user clicks a cell
   with no flagged checks. Mirrors the cockpit welcome
   banner phrasing (cross-surface parity per AC-E1) so the
   passive-read drawer doesn't render an empty void where
   the "Flagged checks" section would have appeared. */
.cell-drawer-clean-cell {
  /* Inherit the section margin-bottom; no custom block
     spacing needed. */
}

.cell-drawer-clean-cell-affirmation {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  background: var(--color-sage-wash);
  border-radius: 6px;
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 13px;
  line-height: 1.4;
  color: var(--color-charcoal);
}

.cell-drawer-clean-cell-icon {
  flex-shrink: 0;
  color: var(--color-success);
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
}

.cell-drawer-coords {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  margin: 0;
  color: var(--color-charcoal);
}

.cell-drawer-status-pill {
  display: inline-block;
  padding: 4px 10px;
  /* Pill shape — at this element's height the browser
     clamps the radius to half-height; visual identical
     to the prior literal 12px. */
  border-radius: var(--radius-full);
  font-size: 0.75rem;
  font-weight: 600;
  font-family: var(--font-mono);
  background: var(--color-sandstone);
  color: var(--color-charcoal);
}

.cell-drawer-status-pill--pass {
  background: var(--color-success-tint);
  color: var(--color-success-ink);
}

.cell-drawer-status-pill--info {
  background: var(--color-info-tint);
  color: var(--color-info-ink);
}

.cell-drawer-status-pill--warn-1 {
  /* F-BU canonical-source lift — pill background reads from the
     same `--color-warn-1-fill` var as the map cell fill so the
     pill ↔ rectangle pairing stays in sync across surfaces.
     Previously: hardcoded `#fef3c7` (amber-100) which drifted from
     the map's `#fef08a` (yellow-200) Renaissance. */
  background: var(--color-warn-1-fill);
  color: var(--color-warning-ink);
}

.cell-drawer-status-pill--warn-2-plus,
.cell-drawer-status-pill--warn-2\+ {
  /* F18 — amber-500 fill matches the BIG MAP rectangle palette so
     the cell drawer's status pill mirrors the rectangle the user
     just clicked.

     F-BU canonical-source lift — reads from
     `--color-warn-2-plus-fill` per durable §24. */
  background: var(--color-warn-2-plus-fill);
  color: var(--color-warning-ink);
}

.cell-drawer-status-pill--fail {
  background: var(--color-error-tint);
  color: var(--color-error-ink);
}

.cell-drawer-check-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.cell-drawer-check-row {
  /* F23 — row stacks the head (severity icon + tech name + help
     button) on top + description body below it. Was a single
     flex line pre-F23 (no description); the head now lives in a
     wrapper div so the description body can flow underneath. */
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px 0;
  border-bottom: 1px solid var(--color-sandstone);
  font-size: 0.78rem;
}

.cell-drawer-check-row-head {
  display: flex;
  align-items: center;
  gap: 6px;
}

.cell-drawer-check-desc {
  /* F23 — plain-language description body. Inter (not Mono),
     muted color, indented under the tech name. Max-width
     constrains the wrap so long descriptions stay readable. */
  margin: 0 0 0 24px;
  font-family: var(--font-primary);
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--color-text-muted);
  line-height: 1.5;
  max-width: 280px;
}

.cell-drawer-check-link {
  /* F23 — optional [Learn more →] affordance. Canopy color +
     Inter; indents under the description body. */
  display: inline-block;
  margin: 4px 0 0 24px;
  font-family: var(--font-primary);
  font-size: 0.75rem;
  color: var(--color-canopy, #2D5F3F);
  text-decoration: none;
}

.cell-drawer-check-link:hover,
.cell-drawer-check-link:focus-visible {
  text-decoration: underline;
  outline: none;
}

.cell-drawer-check-row:last-child {
  border-bottom: 0;
}

.cell-drawer-check-label {
  flex: 1 1 auto;
  font-weight: 600;
  word-break: normal;
}

.cell-drawer-check-result {
  font-size: 0.7rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  flex-shrink: 0;
}

.cell-drawer-check-result--fail {
  background: var(--color-error-tint);
  color: var(--color-error-ink);
}

.cell-drawer-check-result--warning {
  background: #fef3c7;
  color: var(--color-warning-ink);
}

.cell-drawer-check-id {
  display: block;
  margin-top: 2px;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  color: var(--color-muted, #637082);
  word-break: break-all;
}

.cell-drawer-check-anchor {
  background: transparent;
  border: 0;
  padding: 4px;
  cursor: pointer;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

.cell-drawer-check-anchor:hover,
.cell-drawer-check-anchor:focus-visible {
  background: var(--color-sandstone);
  color: var(--color-text);
  outline: none;
}

.cell-drawer-sources-cascade,
.cell-drawer-coverage-text {
  margin: 0;
  font-size: 0.78rem;
  color: var(--color-charcoal);
  line-height: 1.5;
}

@media (max-width: 480px) {
  .portrait-cell-drawer {
    width: 100vw;
    border-left: 0;
  }
}

/* Q5 absorption — mobile suppression. The BIG MAP is hidden at
   ≤ 767 px (Region Health card replaces it per AC-F5 + D17), so
   the cell-drawer's host surface is gone. Hide the drawer +
   backdrop entirely at this breakpoint so a future contributor
   adding a mobile cell-click trigger cannot land an off-screen
   drawer on a phone-class viewport. The Alpine `matchMedia` gate
   in `openCellDrawer` is the JS-side belt; this is the CSS
   braces. */
@media (max-width: 767px) {
  .portrait-cell-drawer,
  .portrait-cell-drawer-backdrop {
    display: none !important;
  }
}

/* F16 soil profile records chip + drawer detail — sits below
   the BIG MAP + legend, above the bottom-row split. Chip line
   surfaces the cell count Aminata reads first; the detail
   paragraph surfaces the record math + platform context
   Dr. Kofi can verify against DSSAT SOL convention. Severity
   variants share the same layout shell; only the left-border
   color differentiates pass / warning / fail. */
.portrait-soil-records {
  margin: var(--space-2) auto 0;
  max-width: 900px;
  padding: 10px 14px;
  border-left: 4px solid var(--color-sandstone);
  background: var(--color-parchment, #FAF7F0);
  border-radius: var(--radius-sm);
}

.portrait-soil-records--warning {
  border-left-color: var(--color-warning);
}

.portrait-soil-records--fail {
  border-left-color: var(--color-error);
}

.portrait-soil-records--pass {
  border-left-color: var(--color-success);
}

.portrait-soil-records-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-charcoal);
}

.portrait-soil-records-detail {
  margin: 4px 0 0 0;
  font-size: 0.78rem;
  color: var(--color-text-muted);
  line-height: 1.5;
  max-width: 720px;
}

/* Validation Strip — the prior ``.portrait-validation`` panel
   wrapper is now part of ``.portrait-data-quality`` (see the
   single-panel rules above). The strip uses a deterministic grid:
   3 + 2 at desktop, 2 + 2 + 1 at tablet, and one badge per row on
   mobile. */

.val-strip {
  /* Grid keeps the 5 quality-check badges on deterministic rows
     across viewports rather than letting flex-wrap orphan a single
     badge on a second row. At desktop (~802 px panel content) the
     5 badges divide cleanly across two rows of 3 + 2; the tablet
     band shifts to 2 columns; mobile stacks vertically. Each cell
     gets a flexible 1fr slot bounded by minmax(0, 1fr) so longer
     localized labels (Hausa / French) cannot blow out the column
     widths. */
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
}

@media (min-width: 641px) and (max-width: 1023px) {
  .val-strip {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .val-strip {
    grid-template-columns: 1fr;
    gap: 6px;
  }
  .val-badge {
    font-size: 0.72rem;
    padding: 6px 10px;
  }
}

.val-badge {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: var(--radius-md);
  font-size: 0.78rem;
  font-weight: 500;
  text-decoration: none;
  transition: transform 0.15s, box-shadow 0.15s;
  cursor: pointer;
  min-height: 44px; /* WCAG touch target */
}

.val-badge:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}

.val-badge--pass {
  background: var(--color-success-tint);
  color: var(--color-success-ink);
  border: 1px solid var(--color-success-border);
}

.val-badge--warning {
  background: #fffbeb;
  color: var(--color-warning-ink);
  border: 1px solid var(--color-warning-border);
}

.val-badge--fail {
  background: var(--color-error-tint);
  color: var(--color-error-ink);
  border: 1px solid var(--color-error-border);
}

.val-badge--info {
  background: var(--color-info-tint);
  color: var(--color-info-ink);
  border: 1px solid var(--color-info-border);
}

.val-badge-label {
  white-space: nowrap;
}

.results-summary-line {
  font-size: 0.9375rem;
  color: var(--color-charcoal);
  margin-bottom: var(--space-1);
}

.results-meta {
  font-size: 0.8125rem;
  color: var(--color-muted);
  margin-bottom: 0;
}

/* Bookmark */
.results-bookmark {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.copy-url-btn {
  background: none;
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-sm);
  padding: 2px 8px;
  font-family: var(--font-primary);
  font-size: 0.75rem;
  color: var(--color-canopy);
  cursor: pointer;
}

.copy-url-btn:hover { background-color: var(--color-sage-wash); }

/* Tabs */
.tab-bar {
  display: flex;
  border-bottom: 2px solid var(--color-sandstone);
  margin-bottom: var(--space-4);
  gap: 0;
}

.tab-btn {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-primary);
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-muted);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}

.tab-btn:hover { color: var(--color-charcoal); }

.tab-btn--active {
  color: var(--color-canopy);
  border-bottom-color: var(--color-canopy);
}

.tab-btn--active i { color: var(--color-canopy); }

.tab-panel {
  min-height: 200px;
}

.tab-panel h3 {
  margin-bottom: var(--space-3);
}

/* Summary tab — stage list */
.results-stages {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.results-stage {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-sm);
}

.results-stage--complete .results-stage-icon { color: var(--color-success); }
.results-stage--error .results-stage-icon { color: var(--color-error); }
.results-stage--cancelled .results-stage-icon { color: var(--color-warning); }
.results-stage--skipped .results-stage-icon { color: var(--color-muted); }

.results-stage-icon { flex-shrink: 0; }
.results-stage-icon i { width: 18px; height: 18px; }

.results-stage-title {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-charcoal);
}

.results-stage-duration {
  font-size: 0.75rem;
  color: var(--color-muted);
  font-family: var(--font-mono);
}

.results-stage-warnings,
.results-stage-errors {
  width: 100%;
  padding-left: 26px;
}

.results-warning {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: 0.8125rem;
  color: var(--color-warning);
  margin-bottom: 0;
}

.results-error-text {
  font-size: 0.8125rem;
  color: var(--color-error);
  margin-bottom: 0;
}

/* Validation tab */
.validation-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.validation-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.9375rem;
  padding: var(--space-2) 0;
}

.validation-item--pass i { color: var(--color-success); }
.validation-item--warning i { color: var(--color-warning); }
.validation-item--error i { color: var(--color-error); }

/* Warning-free run note in the Validation tab — short Success
   prelude that anchors the Climate Data Ranges section per AC-G3
   fallback. Lighter visual weight than the info banner so
   the tab reads as "all clear" rather than "data missing". */
.validation-empty-note {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
  font-size: 0.9rem;
  color: var(--color-text-muted);
}

/* Climate Data Ranges card lives in the Validation tab per AC-G3.
   Adds top spacing to separate from the validation cards above. */
.validation-ranges {
  margin-top: var(--space-3);
}

/* Provenance tab */
.provenance-narrative {
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--color-charcoal);
  margin-bottom: var(--space-4);
}

.provenance-actions {
  margin-bottom: var(--space-4);
}

.btn-sm {
  padding: var(--space-1) var(--space-3);
  font-size: 0.8125rem;
}

.provenance-raw {
  margin-top: var(--space-4);
}

.provenance-raw summary {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-canopy);
  cursor: pointer;
  margin-bottom: var(--space-2);
}

.provenance-json {
  background-color: var(--color-warm-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  overflow-x: auto;
  max-height: 400px;
  overflow-y: auto;
}

/* Download tab */
/* .download-card composes the canonical .card (identical surface spec); the
   class stays only as a template marker. */

.download-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--space-3);
}

.download-card-name {
  font-weight: 600;
  color: var(--color-deep-forest);
}

.download-card-size {
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.download-group {
  margin-bottom: var(--space-2);
}

.download-group-name {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-slate);
  font-family: var(--font-mono);
}

.download-file-list {
  list-style: none;
  padding-left: var(--space-4);
}

.download-file-list li {
  font-size: 0.8125rem;
  color: var(--color-charcoal);
  font-family: var(--font-mono);
  padding: 2px 0;
}

.download-empty {
  text-align: center;
  padding: var(--space-6);
  color: var(--color-muted);
}

.download-empty p {
  margin-top: var(--space-2);
}

.download-footer {
  display: flex;
  gap: var(--space-3);
  justify-content: center;
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-sandstone);
}

/* Responsive */
@media (max-width: 768px) {
  .tab-bar {
    overflow-x: auto;
  }
}

/* Quick stats bar */
.results-stats-bar {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-3) var(--space-4);
  background-color: var(--color-warm-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-4);
  flex-wrap: wrap;
}

.results-stat {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-charcoal);
}

.results-stat i {
  color: var(--color-canopy);
}

.results-stat-sep {
  color: var(--color-sandstone);
  margin: 0 var(--space-1);
}

/* Results stage — clickable rows */
.results-stage-main {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
}

.results-stage-body {
  flex: 1;
  display: flex;
  justify-content: space-between;
  align-items: center;
  min-width: 0;
}

.results-stage-chevron {
  flex-shrink: 0;
  color: var(--color-muted);
  display: flex;
  align-items: center;
}

.results-stage-details {
  padding: var(--space-2) 0 0 26px;
}

/* Validation health card */
.val-health-card {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-4);
}

.val-health-card--success {
  border-left: 4px solid var(--color-success);
}

.val-health-card--success .val-health-icon {
  color: var(--color-success);
}

.val-health-card--warning {
  border-left: 4px solid var(--color-warning);
}

.val-health-card--warning .val-health-icon {
  color: var(--color-warning);
}

.val-health-card--error {
  border-left: 4px solid var(--color-error);
}

.val-health-card--error .val-health-icon {
  color: var(--color-error);
}

.val-health-icon {
  flex-shrink: 0;
}

.val-copy-btn {
  flex-shrink: 0;
  align-self: flex-start;
}

.val-health-headline {
  font-size: 1.125rem;
  margin-bottom: var(--space-1);
}

.val-health-meta {
  font-size: 0.875rem;
  color: var(--color-slate);
  margin-bottom: 0;
}

/* Validation category cards */
.val-category-card {
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-2);
  overflow: hidden;
}

.val-category-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
  transition: background-color 0.1s ease;
}

.val-category-header:hover {
  background-color: var(--color-warm-white);
}

.val-category-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-charcoal);
}

.val-category-body {
  padding: 0 var(--space-4) var(--space-3);
}

.val-detail-row {
  display: flex;
  justify-content: space-between;
  padding: var(--space-1) 0;
  font-size: 0.875rem;
  border-bottom: 1px solid var(--color-warm-white);
}

.val-detail-label {
  color: var(--color-slate);
}

.val-detail-value {
  font-weight: 600;
  color: var(--color-charcoal);
}

.val-detail-value--error {
  color: var(--color-error);
}

.val-detail-value--warning {
  color: var(--color-warning);
}

.val-detail-note {
  font-size: 0.8125rem;
  color: var(--color-muted);
  font-style: italic;
  margin-top: var(--space-2);
  margin-bottom: 0;
}

/* Source cards (provenance) */
.source-cards {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* Data-source card — canon .card shell + a tighter vertical pad; no margin
   (lives in the .source-cards grid). Compose as ``card source-card``. */
.source-card {
  padding: var(--space-3) var(--space-4);
  margin-bottom: 0;
}

.source-card-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.source-card-name {
  font-weight: 600;
  color: var(--color-deep-forest);
}

.source-card-version {
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.source-card-category {
  margin-left: auto;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
  background-color: var(--color-warm-white);
  padding: 2px 8px;
  border-radius: var(--radius-full);
}

.source-card-desc {
  font-size: 0.875rem;
  color: var(--color-slate);
  margin-bottom: var(--space-1);
}

.source-card-meta {
  font-size: 0.8125rem;
  color: var(--color-muted);
  margin-bottom: var(--space-2);
}

.btn-copy-bibtex {
  display: inline-flex;
  align-items: center;
  padding: 2px 10px;
  font-family: var(--font-primary);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-canopy);
  background: none;
  border: 1px solid var(--color-canopy);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.btn-copy-bibtex:hover {
  background-color: var(--color-sage-wash);
}

/* Methods text tabs + box */
.methods-tabs {
  display: flex;
  gap: 0;
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: var(--space-3);
}

.methods-tab {
  flex: 1;
  padding: var(--space-2);
  font-family: var(--font-primary);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-slate);
  background-color: var(--color-warm-white);
  border: none;
  border-right: 1px solid var(--color-sandstone);
  cursor: pointer;
  text-align: center;
  transition: background-color 0.15s ease;
}

.methods-tab:last-child {
  border-right: none;
}

.methods-tab--active {
  background-color: var(--color-canopy);
  color: var(--color-white);
}

/* Methods text box — canon .card shell + warm-white tone & reading typography;
   no margin. Compose as ``card methods-text-box``. */
.methods-text-box {
  background-color: var(--color-warm-white);
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--color-charcoal);
  margin-bottom: 0;
}

.methods-text-box p {
  margin-bottom: 0;
}

.methods-detailed-pre {
  white-space: pre-wrap;
  font-family: var(--font-primary);
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--color-charcoal);
  margin: 0;
}

/* Download — folder groups with expand */
.download-group-header {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin-bottom: var(--space-1);
}

.download-group-count {
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--color-muted);
}

.download-file-list li {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.download-file-name {
  font-size: 0.8125rem;
  color: var(--color-charcoal);
  font-family: var(--font-mono);
}

.download-file-size {
  font-size: 0.75rem;
  color: var(--color-muted);
  font-family: var(--font-mono);
}

.download-show-all {
  display: block;
  margin-top: var(--space-1);
  background: none;
  border: none;
  font-family: var(--font-primary);
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--color-canopy);
  cursor: pointer;
  padding: 0 0 0 var(--space-4);
}

.download-show-all:hover {
  text-decoration: underline;
}

/* ============================================================
   Examples Gallery
   ============================================================ */

.gallery-page {
  max-width: 1000px;
  margin: 0 auto;
}

.gallery-title {
  margin-bottom: var(--space-2);
}

.gallery-subtitle {
  color: var(--color-slate);
  margin-bottom: var(--space-6);
  max-width: 600px;
}

.gallery-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}

/* Example gallery card — canon .card shell + flex/transition deltas; no margin
   (lives in .gallery-grid). Compose as ``card example-card``. */
.example-card {
  display: flex;
  flex-direction: column;
  transition: box-shadow 0.15s ease;
  margin-bottom: 0;
}

.example-card:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.example-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.example-flag {
  font-size: 1.5rem;
}

.example-region {
  font-size: 0.875rem;
  color: var(--color-slate);
  font-weight: 500;
}

.example-title {
  margin-bottom: var(--space-2);
}

.example-meta {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  flex-wrap: wrap;
}

.example-crop {
  font-size: 0.8125rem;
  color: var(--color-charcoal);
}

.example-platform-badge {
  font-size: 0.75rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--radius-full);
  background-color: var(--color-sage-wash);
  color: var(--color-canopy);
}

.example-desc {
  font-size: 0.875rem;
  color: var(--color-slate);
  line-height: 1.6;
  flex: 1;
}

.example-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-sandstone);
}

@media (max-width: 768px) {
  .gallery-grid {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   Nav Auth Elements
   ============================================================ */

.btn-nav-register {
  display: inline-flex;
  align-items: center;
  padding: 6px 16px;
  font-family: var(--font-primary);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-deep-forest);
  background-color: var(--color-sage-wash);
  border: none;
  border-radius: var(--radius-md);
  text-decoration: none;
  transition: background-color 0.15s ease;
}

.btn-nav-register:hover {
  background-color: var(--color-white);
}

.nav-dropdown {
  position: relative;
}

.nav-dropdown-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}

.nav-dropdown-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 160px;
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-dropdown);
  z-index: 200;
  overflow: hidden;
}

.nav-dropdown-item {
  display: block;
  padding: var(--space-2) var(--space-3);
  font-size: 0.9375rem;
  color: var(--color-charcoal);
  text-decoration: none;
  transition: background-color 0.1s ease;
}

.nav-dropdown-item:hover {
  background-color: var(--color-sage-wash);
}

/* ============================================================
   In-app notification center (Canon §4.12) — the nav bell + live
   counter, the dropdown, one row, the My Notifications page, and the
   mobile bottom-sheet. Light theme only; every size >= 0.75rem (12px).
   ============================================================ */
/* the bell + its dropdown/toast scope; it sits inside the right-anchored .nav-personal cluster, so
   it carries no self-margin — the cluster positions it and leaves its left edge open for #201 */
.notification-center-root { position: relative; display: inline-flex; }

.notification-bell {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  background: none;
  border: none;
  border-radius: var(--radius-full);
  color: var(--color-sage-wash);
  cursor: pointer;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.notification-bell:hover { background-color: rgba(255, 255, 255, 0.12); color: var(--color-white); }
.notification-bell:focus-visible { outline: 2px solid var(--color-sage-wash); outline-offset: 2px; }
.notification-bell > svg { width: 24px; height: 24px; }

/* the unread badge rides the bell; geometry is reserved so a change never shifts layout */
.notification-bell .count-badge {
  position: absolute;
  top: 0;
  right: 0;
  transform: translate(30%, -30%);
  pointer-events: none;
}

.notification-bell--wiggle { animation: notif-wiggle 0.5s ease; }
@keyframes notif-wiggle {
  0%, 100% { transform: rotate(0); }
  20% { transform: rotate(-12deg); }
  45% { transform: rotate(9deg); }
  70% { transform: rotate(-5deg); }
  90% { transform: rotate(2deg); }
}
/* The loud bell glow is retired — the on-screen toast is now the salient signal; the bell
   keeps only its single gentle wiggle. */

/* The run-finished toast (Inc-3) — desktop: top-right under the bell; mobile: top banner. A
   distinct anchor from #htmx-toast (the connection-status toast) so the two never cover each
   other; reuses the notification tone medallion + palette. */
.notification-toast {
  position: fixed;
  top: 72px;
  right: 24px;
  width: 360px;
  max-width: calc(100vw - 48px);
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: 14px var(--space-3);
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-sandstone);
  border-left: 3px solid var(--color-canopy);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  z-index: 1200;
  animation: notif-toast-in 240ms ease-out;
}
.notification-toast--attention { border-left-color: var(--color-terracotta); }
.notification-toast__body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  text-decoration: none;
  color: var(--color-charcoal);
}
.notification-toast__text { flex: 1 1 auto; min-width: 0; }
.notification-toast__title {
  font-size: 0.9375rem; font-weight: 600; line-height: 1.35; color: var(--color-charcoal);
}
.notification-toast__reason {
  display: block; margin-top: 2px; font-size: 0.8125rem; color: var(--color-muted);
}
.notification-toast__dismiss {
  flex: none;
  width: 44px;
  height: 44px;
  margin: -10px -8px -10px 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: var(--radius-full);
  color: var(--color-muted);
  cursor: pointer;
}
.notification-toast__dismiss:hover { background: var(--color-sage-wash); color: var(--color-charcoal); }
@keyframes notif-toast-in {
  from { opacity: 0; transform: translateX(16px); }
  to { opacity: 1; transform: translateX(0); }
}
@media (max-width: 860px) {
  .notification-toast {
    top: 64px; left: 12px; right: 12px; width: auto; max-width: none;
    animation: notif-toast-in-mobile 240ms ease-out;
  }
  @keyframes notif-toast-in-mobile {
    from { opacity: 0; transform: translateY(-16px); }
    to { opacity: 1; transform: translateY(0); }
  }
}

/* a fresh row slides into the dropdown — only newly-keyed rows animate */
.notification-center__list .notification-item { animation: notif-slide-in 0.25s ease; }
/* an APPENDED My-Notifications page row ("Load older") — only the newly-appended rows carry the class */
.notification-item.notif-slide-in { animation: notif-slide-in 0.25s ease; }
@keyframes notif-slide-in {
  from { transform: translateY(-6px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

/* the dropdown — reuses .nav-dropdown-menu, widened for the row list. Re-asserts
   absolute + a light background so the tablet-width responsive .nav-dropdown-menu
   rule (static, translucent-dark for the mobile menu) can't wash the panel out. */
.notification-center {
  position: absolute;
  width: 360px;
  max-width: calc(100vw - 32px);
  padding: 0;
  background-color: var(--color-white);
}
.notification-center__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3);
  border-bottom: 1px solid var(--color-sandstone);
}
.notification-center__title { font-size: 0.9375rem; font-weight: 700; color: var(--color-charcoal); }
.notification-center__markall {
  font-size: 0.8125rem;
  color: var(--color-canopy);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}
.notification-center__markall:hover { text-decoration: underline; }
.notification-center__head-actions { display: inline-flex; align-items: center; gap: var(--space-2); }
.notification-center__close {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--color-muted);
  padding: 0 var(--space-1);
}
.notification-center__handle { display: none; }
.notification-center__list { max-height: 380px; overflow-y: auto; }
.notification-center__foot {
  display: block;
  text-align: center;
  padding: var(--space-3);
  border-top: 1px solid var(--color-sandstone);
  font-size: 0.8125rem;
  color: var(--color-canopy);
  text-decoration: none;
}
.notification-center__foot:hover { background-color: var(--color-sage-wash); }
.notification-center__empty {
  padding: 40px var(--space-3);
  text-align: center;
  color: var(--color-muted);
  font-size: 0.875rem;
}

/* Ongoing-activity affordance — a calm, DISTINCT in-flight surface left of the bell. */
.ongoing-activity { position: relative; display: inline-flex; }
.ongoing-activity__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border: none;
  border-radius: var(--radius-full);
  /* calm sage/canopy — deliberately NOT the bell's attention terracotta (in-flight is not an alarm) */
  background: var(--color-sage-wash);
  color: var(--color-canopy-dark);
  cursor: pointer;
  font-size: 0.8125rem;
  font-weight: 600;
  min-height: 32px;
}
.ongoing-activity__trigger:hover { filter: brightness(0.96); }
.ongoing-activity__spinner { width: 15px; height: 15px; animation: ongoing-spin 1.4s linear infinite; }
.ongoing-activity__count { font-variant-numeric: tabular-nums; line-height: 1; }
@keyframes ongoing-spin { to { transform: rotate(360deg); } }

/* Right-anchored so it opens LEFTWARD within the viewport + a max-width clamp — viewport-safe by
   construction so the panel can never run off the far-right cluster edge. */
.ongoing-activity__panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  left: auto;
  width: 320px;
  max-width: calc(100vw - 32px);
  background: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 32px rgba(26, 58, 42, 0.16);
  z-index: 100;
  overflow: hidden;
}
.ongoing-activity__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: var(--space-3);
  border-bottom: 1px solid var(--color-sandstone);
}
.ongoing-activity__title { font-size: 0.9375rem; font-weight: 700; color: var(--color-charcoal); }
.ongoing-activity__asof { font-size: 0.75rem; color: var(--color-muted); }
.ongoing-activity__list { max-height: 360px; overflow-y: auto; }
.ongoing-activity__item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-3);
  border-bottom: 1px solid var(--color-sandstone);
  text-decoration: none;
  color: var(--color-charcoal);
}
.ongoing-activity__item:last-child { border-bottom: none; }
.ongoing-activity__item:hover { background: var(--color-sage-wash); }
.ongoing-activity__subject { font-weight: 600; font-size: 0.875rem; }
.ongoing-activity__line {
  display: flex; align-items: baseline; gap: var(--space-2);
  font-size: 0.8125rem; color: var(--color-canopy-dark);
}
.ongoing-activity__line--dim { color: var(--color-muted); font-size: 0.75rem; }
.ongoing-activity__progress { font-variant-numeric: tabular-nums; }
.ongoing-activity__stalled { color: var(--color-clay); }
.ongoing-activity__seeall {
  display: block;
  text-align: center;
  padding: var(--space-3);
  border-top: 1px solid var(--color-sandstone);
  font-size: 0.8125rem;
  color: var(--color-canopy);
  text-decoration: none;
}
.ongoing-activity__seeall:hover { background: var(--color-sage-wash); }

/* Mobile: the panel becomes a full-width bottom-sheet. */
@media (max-width: 640px) {
  .ongoing-activity__panel {
    position: fixed;
    left: 0; right: 0; bottom: 0; top: auto;
    width: 100%;
    max-width: 100%;
    max-height: 80vh;
    border-radius: var(--radius-lg, 16px) var(--radius-lg, 16px) 0 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .ongoing-activity__spinner { animation: none; }
}

/* The My Runs "In progress" band — the live surface above the history; items reuse the affordance's
   calm .ongoing-activity__item render so the two never diverge. */
.ongoing-band {
  margin-bottom: var(--space-5);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  background: var(--color-white);
  overflow: hidden;
}
.ongoing-band__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  background: var(--color-sage-wash);
  border-bottom: 1px solid var(--color-sandstone);
}
.ongoing-band__title { font-size: 1rem; font-weight: 700; color: var(--color-canopy-dark); margin: 0; }
.ongoing-band__asof { font-size: 0.75rem; color: var(--color-muted); }

/* one notification row (Canon §4.12) */
.notification-item {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: 13px var(--space-3);
  border-bottom: 1px solid var(--color-sandstone-50, var(--color-sandstone));
  text-decoration: none;
  color: var(--color-charcoal);
  cursor: pointer;
  transition: background-color 0.1s ease;
  text-align: left;
  width: 100%;
  background: none;
  border-left: 3px solid transparent;
}
.notification-item:hover { background-color: var(--color-sage-wash); }
.notification-item:focus-visible { outline: 2px solid var(--color-canopy); outline-offset: -2px; }
.notification-item--unread {
  background-color: var(--color-sage-green-100);
  border-left-color: var(--color-canopy);
}
.notification-item__tone {
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
}
.notification-item__tone > svg { width: 18px; height: 18px; }
.notification-item__tone--calm { background: var(--color-sage-wash); color: var(--color-canopy-dark); }
.notification-item__tone--attention { background: var(--color-warning-tint); color: var(--color-terracotta); }
.notification-item__body { flex: 1 1 auto; min-width: 0; }
.notification-item__title { font-size: 0.875rem; font-weight: 500; line-height: 1.35; color: var(--color-charcoal); }
.notification-item--unread .notification-item__title { font-weight: 700; }
.notification-item__reason { display: block; font-size: 0.8125rem; color: var(--color-muted); margin-top: 2px; }
.notification-item__time { display: block; font-size: 0.75rem; color: var(--color-muted); margin-top: 4px; }
.notification-item__dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--color-canopy);
  margin-top: 6px;
}

/* the full My Notifications page */
.notifications-page { max-width: 720px; margin: 0 auto; padding: var(--space-5, 32px) var(--space-4); }
.notifications-page__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-4);
  flex-wrap: wrap;
  gap: var(--space-2);
}
.notifications-page__title { font-size: 1.5rem; font-weight: 700; color: var(--color-charcoal); }
.notifications-page__filters { display: inline-flex; gap: var(--space-2); }
.notifications-page__filter {
  font-size: 0.8125rem;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  border: 1px solid var(--color-sandstone);
  background: var(--color-white);
  color: var(--color-charcoal);
  text-decoration: none;
}
.notifications-page__filter--active { background: var(--color-canopy); color: var(--color-white); border-color: var(--color-canopy); }
.notifications-page .notification-item {
  border: 1px solid var(--color-sandstone);
  border-left-width: 3px;
  border-radius: var(--radius-md);
  margin-bottom: var(--space-2);
}
.notifications-page__empty { text-align: center; color: var(--color-muted); padding: 64px var(--space-3); }
.notifications-page__more {
  display: block;
  margin: var(--space-3) auto 0;
  padding: var(--space-2) var(--space-4);
  font-size: 0.875rem;
  color: var(--color-canopy);
  background: none;
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  cursor: pointer;
}
/* the in-flight "Load older" fetch — dim + inert while loading (single-flight is also enforced in JS) */
.notifications-page__more--loading { opacity: 0.6; pointer-events: none; }

/* mobile: the dropdown becomes a bottom-sheet */
.notification-sheet-scrim { display: none; }
@media (max-width: 640px) {
  /* .nav-personal scope raises specificity to beat the cluster's `.nav-dropdown-menu` absolute-position rule, so the sheet actually engages at <=640 */
  .nav-personal .notification-center {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    top: auto;
    width: 100%;
    max-width: 100%;
    max-height: 85vh;
    border-radius: var(--radius-lg, 16px) var(--radius-lg, 16px) 0 0;
    display: flex;
    flex-direction: column;
    z-index: 200;
  }
  .notification-center__list { flex: 1 1 auto; max-height: none; }
  .notification-center__handle {
    display: block;
    width: 36px;
    height: 4px;
    margin: 8px auto 4px;
    border-radius: var(--radius-full);
    background: var(--color-sandstone);
  }
  .notification-center__close { display: inline-flex; align-items: center; }
  .notification-sheet-scrim {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 199;
  }
  /* while the sheet is up, only the sheet's list scrolls — the page is locked */
  body.notif-sheet-open { overflow: hidden; }
}

@media (prefers-reduced-motion: reduce) {
  .notification-bell--wiggle,
  .notification-item.notif-slide-in,
  .notification-center__list .notification-item { animation: none; }
  .notification-item { transition: none; }
  /* the toast entrance/exit collapse to an opacity-only fade */
  .notification-toast { animation: none; transition: opacity 120ms ease; }
}

/* ============================================================
   Auth Pages (Login, Register)
   ============================================================ */

/* ===== Email verification surfaces — status medallion, verify banner, status card.
   The medallion + status card are design-system canon-candidates (they recur on
   auth/status surfaces); all colours resolve through defined semantic tokens. ===== */
.status-medallion {
  width: 72px;
  height: 72px;
  flex: none;
  border-radius: var(--radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
}
.status-medallion > svg { width: 34px; height: 34px; }
.status-medallion--sm { width: 52px; height: 52px; }
.status-medallion--sm > svg { width: 24px; height: 24px; }
/* success mark carries a soft green->gold refracted-light halo (sage ring + warm-gold glow) */
.status-medallion--ok {
  background: var(--color-canopy);
  color: #fff;
  box-shadow: 0 6px 16px rgba(45, 95, 63, .28), 0 0 0 6px rgba(212, 232, 220, .55), 0 0 34px 10px rgba(200, 169, 78, .20);
}
.status-medallion--neutral { background: var(--color-sage-wash); color: var(--color-canopy-dark); }
.status-medallion--warn { background: var(--color-warning-tint); color: var(--color-terracotta); }
.status-medallion--mute { background: var(--color-sandstone-50); color: var(--color-muted); border: 1px solid var(--color-sandstone); }
.status-medallion--info { background: var(--color-info-tint); color: var(--color-info-ink); }

/* Verify banner — a two-level soft-verify strip layered over .banner.banner--info. */
.verify-banner {
  display: block;
  position: relative;
  padding: 0;
  margin-bottom: 0;
  border: 0;
  border-bottom: 1px solid var(--color-sandstone);
  border-radius: 0;
  background: var(--color-parchment);
}
.verify-banner::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--color-canopy);
}
.vb-inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 14px var(--space-4);
  display: flex;
  align-items: center;
  gap: 16px;
}
.vb-medallion {
  width: 38px;
  height: 38px;
  flex: none;
  border-radius: var(--radius-full);
  background: var(--color-sage-wash);
  color: var(--color-canopy-dark);
  display: flex;
  align-items: center;
  justify-content: center;
}
.vb-medallion > svg { width: 18px; height: 18px; }
.vb-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.vb-lead { font-size: 14.5px; font-weight: 600; color: var(--color-deep-forest); }
.vb-sub { font-size: 13px; color: var(--color-slate); }
.vb-actions { margin-left: auto; display: flex; align-items: center; gap: 6px; }

/* Confirm-page stage + card — the 5 honest states share one composition. */
.verify-stage {
  background:
    radial-gradient(1100px 420px at 50% -160px, var(--color-sage-green-100) 0%, rgba(224, 235, 226, 0) 60%),
    var(--color-warm-white);
}
.verify-card {
  max-width: 468px;
  margin: 0 auto;
  text-align: center;
  position: relative;
  overflow: hidden;
}
.verify-cap-mark {
  position: absolute;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  width: 22px;
  height: 22px;
  opacity: .9;
}
.verify-card .status-medallion { margin: 14px auto 22px; }
.verify-heading {
  font-size: var(--font-size-display-l);
  font-weight: 600;
  color: var(--color-deep-forest);
  letter-spacing: -0.015em;
}
.verify-card .card-note { max-width: 34ch; margin-left: auto; margin-right: auto; }
.verify-card .btn { margin-top: 24px; }

/* Glyph support for the profile status chips — icon reads with the label, not colour alone
   (the .status-badge base is inline-flex + gap + nowrap, so the glyph never wraps off its label). */
.status-badge > svg { width: 13px; height: 13px; }

/* Profile Email row — address on its own line, the verify chip whole on the line below. */
.profile-info-value--email { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); }
.verify-chip-row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

.auth-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-7) var(--space-5);
  background-color: var(--color-warm-white);
}

.auth-illustration {
  height: 80px;
  width: auto;
  margin-bottom: var(--space-3);
}

.auth-logo {
  height: 50px;
  width: auto;
  display: block;
  margin: 0 auto var(--space-2);
}

/* Auth-page width constraint only — the card SURFACE is the canon
   ``card card--lg``; this class just caps the width of the auth form. */
.auth-card {
  width: 100%;
  max-width: 440px;
}

.auth-heading {
  text-align: center;
  font-size: var(--font-size-display-l);
  font-weight: 600;
  color: var(--color-deep-forest);
  letter-spacing: 0.12em;
  margin-bottom: var(--space-1);
}

.auth-subheading {
  text-align: center;
  font-size: 1rem;
  color: var(--color-slate);
  margin-bottom: var(--space-5);
}

.auth-submit {
  width: 100%;
  justify-content: center;
  padding: 12px var(--space-4);
  height: 44px;
  margin-top: var(--space-2);
}

/* Per-message text rows inside the canonical .banner .banner--error box. */
.auth-error {
  font-size: 0.875rem;
  color: var(--color-error-ink);
  margin-bottom: 0;
}

.field-error,
.form-error {
  font-size: 0.8125rem;
  color: var(--color-error);
  margin-top: var(--space-1);
  margin-bottom: 0;
}

/* Wizard-only min-height reserve on the inline hint. Scoped to
   `.wizard-page` so the reserve doesn't inflate auth forms
   (login/register/profile) that use `.form-error` for per-field
   validation without needing the vertical stability guarantee. The
   Next-button layout-shift risk exists only on the 4 wizard steps at
   375 px mobile — Group E E.1 evaluator amendment 2. */
.wizard-page .form-error {
  min-height: 48px;
}

.auth-remember-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.auth-checkbox-label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.875rem;
  color: var(--color-charcoal);
  cursor: pointer;
}

.auth-checkbox-label input[type="checkbox"] {
  accent-color: var(--color-canopy);
}

.auth-forgot {
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.auth-value-prop {
  text-align: center;
  font-size: 0.8125rem;
  color: var(--color-muted);
  margin-top: var(--space-4);
  margin-bottom: var(--space-3);
}

.auth-alt-link {
  text-align: center;
  font-size: 0.9375rem;
  color: var(--color-slate);
  margin-bottom: 0;
}

.auth-alt-link a {
  color: var(--color-canopy);
  font-weight: 600;
  text-decoration: none;
}

.auth-alt-link a:hover {
  text-decoration: underline;
}

/* Hero actions row */
.hero-actions {
  display: flex;
  gap: var(--space-3);
  align-items: center;
}

@media (max-width: 768px) {
  .hero-actions {
    flex-direction: column;
    align-items: stretch;
  }
}

/* ============================================================
   Profile Page
   ============================================================ */

.profile-page {
  max-width: 700px;
  margin: 0 auto;
  padding: var(--space-5);
}

.profile-heading {
  margin-bottom: var(--space-5);
}

/* Horizontal button-row utility with token gap (extracted from inline styles). */
.btn-row {
  display: flex;
  gap: var(--space-2);
}
/* Muted note paragraph inside a card (extracted from an inline style). */
.card-note {
  color: var(--color-slate);
  margin-bottom: var(--space-3);
}

.profile-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-3);
}

.profile-card-title {
  font-size: 1.125rem;
  margin-bottom: var(--space-3);
}

.profile-card-header .profile-card-title {
  margin-bottom: 0;
}

/* Email-notification preference toggles (registry-driven rows). */
.notif-prefs-saved {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--color-forest, #2D5F3F);
  font-size: 0.875rem;
  margin: 0 0 var(--space-3, 12px);
}
.notif-prefs-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3, 12px);
}
.notif-pref-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--color-border, #E0D9CF);
  border-radius: 8px;
  cursor: pointer;
}
.notif-pref-row:hover {
  background: var(--color-sandstone-50, #FAFAF7);
}
.notif-pref-check {
  margin-top: 2px;
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  accent-color: var(--color-forest, #2D5F3F);
}
.notif-pref-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.notif-pref-label {
  font-weight: 600;
  color: var(--color-ink, #1A3A2A);
}
.notif-pref-desc {
  font-size: 0.8125rem;
  color: var(--color-muted, #637082);
}

.profile-info-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
}

.profile-info-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.profile-info-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.profile-info-value {
  font-size: 0.9375rem;
  color: var(--color-charcoal);
}

.profile-project-list {
  display: flex;
  flex-direction: column;
}

.profile-project-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-2);
  text-decoration: none;
  border-bottom: 1px solid var(--color-sandstone);
  transition: background-color 0.1s ease;
}

.profile-project-row:last-child {
  border-bottom: none;
}

.profile-project-row:hover {
  background-color: var(--color-warm-white);
}

.profile-project-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.profile-project-name {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--color-deep-forest);
}

.profile-project-date {
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.profile-empty {
  text-align: center;
  padding: var(--space-5) var(--space-4);
}

.profile-empty p {
  color: var(--color-slate);
  margin-bottom: var(--space-3);
}

.profile-pw-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

@media (max-width: 768px) {
  .profile-info-grid {
    grid-template-columns: 1fr;
  }

  .profile-pw-row {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   Bounding Box Drawing UI
   ============================================================ */

/* Boundary mode tabs */
.boundary-mode-tabs {
  display: flex;
  gap: 0;
  margin-bottom: var(--space-4);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.boundary-tab {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding: 10px var(--space-3);
  font-family: var(--font-primary);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-slate);
  background-color: var(--color-warm-white);
  border: none;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.boundary-tab:first-child {
  border-right: 1px solid var(--color-sandstone);
}

.boundary-tab:hover {
  background-color: var(--color-sage-wash);
  color: var(--color-canopy);
}

.boundary-tab--active {
  background-color: var(--color-canopy);
  color: var(--color-white);
}

.boundary-tab--active:hover {
  background-color: var(--color-canopy-dark);
  color: var(--color-white);
}

.boundary-tab i {
  flex-shrink: 0;
}

.bbox-panel {
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin-bottom: var(--space-4);
}

.bbox-intro {
  font-size: 0.9375rem;
  color: var(--color-slate);
  margin-bottom: var(--space-4);
}

.bbox-draw-btn {
  width: 100%;
  justify-content: center;
  margin-bottom: var(--space-4);
  height: 44px;
}

.bbox-draw-btn.btn--active {
  background-color: var(--color-sage-wash);
  border-color: var(--color-canopy);
  color: var(--color-canopy);
}

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

.bbox-coord-row {
  display: flex;
  gap: var(--space-3);
  justify-content: center;
}

.bbox-coord-row--top,
.bbox-coord-row--bottom {
  max-width: 50%;
  margin: 0 auto;
}

.bbox-coord-row--middle {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
  max-width: 100%;
}

.bbox-coord-grid .form-group {
  margin-bottom: 0;
}

.bbox-coord-grid .form-label {
  font-size: 0.75rem;
  color: var(--color-muted);
}

.bbox-coord-grid .form-input {
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.875rem;
}

.bbox-area-summary {
  text-align: center;
  font-size: 0.875rem;
  color: var(--color-slate);
  margin-top: var(--space-3);
  margin-bottom: 0;
}

/* Detected country badge */
.bbox-detected-country {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding: var(--space-3);
  background-color: var(--color-sage-wash);
  border-radius: var(--radius-md);
}

.bbox-detected-label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-canopy);
}

.bbox-detected-value {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--color-deep-forest);
}

/* Every Leaflet map establishes its OWN stacking context so its internal high z-index
   panes (z-400) and controls (z-800/1000) stay contained and never paint over the sticky
   navbar (z-100). Leaflet leaves .leaflet-container at z-index:auto (no context), so on
   scroll the zoom controls bled above the navbar/logo on any surface that didn't add its
   own per-container containment; this fixes them all at the shared layer. `isolation`
   creates the context without touching Leaflet's own position/overflow/z-index, and the
   internal ordering (controls above tiles, popups above panes) is preserved. */
.leaflet-container {
  isolation: isolate;
}

/* Ensure Leaflet.draw controls are visible above map layers */
.leaflet-draw-section,
.leaflet-draw-toolbar {
  z-index: 1000 !important;
}

/* Leaflet.draw tooltip (the crosshair hint label) */
.leaflet-draw-tooltip {
  z-index: 1000 !important;
}

/* ============================================================
   Delete Project UI
   ============================================================ */

/* Profile page — delete button per project */
.profile-project-row-wrap {
  position: relative;
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--color-sandstone);
}

.profile-project-row-wrap:last-child {
  border-bottom: none;
}

.profile-project-row-wrap .profile-project-row {
  flex: 1;
  border-bottom: none;
}

.profile-delete-btn {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  background: none;
  color: var(--color-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: color 0.15s ease, background-color 0.15s ease;
}

.profile-delete-btn:hover {
  color: var(--color-error);
  background-color: var(--color-error-tint);
}

/* Delete confirmation */
.delete-confirm {
  display: block;
  padding: var(--space-3);
  margin-bottom: var(--space-2);
}

.delete-confirm-text {
  display: block;
  font-size: 0.875rem;
  color: var(--color-error-ink);
  margin-bottom: var(--space-2);
}

.delete-confirm-actions {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.btn-danger {
  background-color: var(--color-error);
  color: var(--color-white);
}

.btn-danger:hover {
  background-color: var(--color-error);
}

/* Results page — ghost delete button */
.results-actions-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-5);
}

.btn-delete-ghost {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  font-family: var(--font-primary);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-muted);
  background: none;
  border: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: color 0.15s ease;
}

.btn-delete-ghost:hover {
  color: var(--color-error);
}

.delete-confirm--inline {
  margin-top: var(--space-2);
}

/* Auth gate on Time wizard step */
.auth-gate {
  text-align: center;
  padding: var(--space-4);
  background-color: var(--color-sage-wash);
  border: 1px solid var(--color-canopy);
  border-radius: var(--radius-md);
}

.auth-gate-text {
  font-size: 0.9375rem;
  color: var(--color-deep-forest);
  margin-bottom: var(--space-4);
}

.auth-gate-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
}

.auth-gate-actions .btn,
.auth-gate-actions .btn-go {
  width: auto;
  height: 48px;
  padding: 0 var(--space-5);
  box-sizing: border-box;
  line-height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
}

/* ============================================================
   Advanced Crop Parameters
   ============================================================ */

.advanced-section {
  margin-top: var(--space-4);
  margin-bottom: var(--space-4);
}

.advanced-toggle {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  font-family: var(--font-primary);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-canopy);
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.advanced-toggle:hover {
  background-color: var(--color-sage-wash);
}

.advanced-panels {
  margin-top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.advanced-panel {
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  padding: var(--space-4);
}

.advanced-panel-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-deep-forest);
  margin-bottom: var(--space-3);
}

.adv-field-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

.adv-field {
  display: flex;
  flex-direction: column;
}

.adv-field .form-label {
  font-size: 0.75rem;
}

.adv-input-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.adv-input {
  width: 110px;
  text-align: right;
  font-family: var(--font-primary);
  /* Inherits the on-scale 1rem input size from .form-input — no bespoke 15px. */
  font-weight: 600;
  color: var(--color-deep-forest);
  padding: var(--space-2) var(--space-4) var(--space-2) var(--space-3);
  -moz-appearance: textfield;
}

/* The Management number-inputs share one wider, non-shrinking width, sized for
   the largest value (planting density, up to ~6 digits like 500000) so NONE
   clips its value (10000, a rain threshold) AND they align. flex-shrink:0 stops
   the 2-column grid squeezing them narrower than the value needs. */
.adv-input--wide {
  width: 150px;
  flex-shrink: 0;
}

.adv-input::-webkit-inner-spin-button,
.adv-input::-webkit-outer-spin-button {
  opacity: 1;
  margin-left: var(--space-2);
}

.adv-unit {
  font-size: 0.75rem;
  color: var(--color-muted);
  white-space: nowrap;
}

.adv-hint {
  font-size: 0.6875rem;
  color: var(--color-muted);
  margin-top: 2px;
  font-style: italic;
}

/* Sowing mode toggle */
.adv-toggle-row {
  display: flex;
  gap: 0;
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.adv-toggle-btn {
  flex: 1;
  padding: var(--space-2) var(--space-2);
  font-family: var(--font-primary);
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--color-slate);
  background-color: var(--color-warm-white);
  border: none;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.adv-toggle-btn:first-child {
  border-right: 1px solid var(--color-sandstone);
}

.adv-toggle-btn--active {
  background-color: var(--color-canopy);
  color: var(--color-white);
}

/* Fertilizer Timeline */
.fert-timeline {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.fert-app-card {
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.fert-app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  background-color: var(--color-warm-white);
  border-bottom: 1px solid var(--color-sandstone);
}

.fert-app-timing {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-charcoal);
}

.fert-app-remove {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: none;
  background: none;
  color: var(--color-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
}

.fert-app-remove:hover {
  color: var(--color-error);
  background-color: var(--color-error-tint);
}

.fert-app-fields {
  padding: var(--space-3);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

.fert-app-fields .form-group {
  margin-bottom: 0;
}

.fert-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-sandstone);
  font-size: 0.875rem;
  color: var(--color-charcoal);
}

@media (max-width: 768px) {
  .adv-field-grid {
    grid-template-columns: 1fr;
  }

  .fert-app-fields {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 768px) {
  .bbox-coord-row--top,
  .bbox-coord-row--bottom {
    max-width: 100%;
  }

  .bbox-coord-row--middle {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   Cultivar Browser
   ============================================================ */

.cultivar-browser {
  position: relative;
}

.cultivar-results {
  max-height: 300px;
  overflow-y: auto;
  border: 1px solid var(--color-sandstone);
  border-top: none;
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  background-color: var(--color-white);
}

.cultivar-results:empty {
  border: none;
}

.cultivar-section {
  padding: var(--space-2) 0;
}

.cultivar-section-title {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: var(--space-1) var(--space-3);
  margin-bottom: 0;
}

.cultivar-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  background: none;
  border: none;
  border-bottom: 1px solid var(--color-sandstone);
  cursor: pointer;
  font-family: var(--font-primary);
  text-align: left;
  transition: background-color 0.1s ease;
}

.cultivar-item:last-child {
  border-bottom: none;
}

.cultivar-item:hover {
  background-color: var(--color-sage-wash);
}

.cultivar-item--recommended {
  border-left: 3px solid var(--color-canopy);
}

.cultivar-item-main {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.cultivar-item-name {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--color-charcoal);
}

.cultivar-item-code {
  font-size: 0.6875rem;
  font-family: var(--font-mono);
  color: var(--color-muted);
}

.cultivar-item-meta {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.cultivar-item-confidence {
  font-size: 0.6875rem;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: var(--radius-full);
}

.cultivar-item-confidence--exact {
  background-color: var(--color-success-tint);
  color: var(--color-success-ink);
}

.cultivar-item-confidence--approximate {
  background-color: var(--color-info-tint);
  color: var(--color-info-ink);
}

.cultivar-item-confidence--proxy {
  background-color: var(--color-warning-tint);
  color: var(--color-warning-ink);
}

.cultivar-item-source {
  font-size: 0.6875rem;
  color: var(--color-muted);
  font-style: italic;
}

.cultivar-empty {
  padding: var(--space-3);
  text-align: center;
  font-size: 0.875rem;
  color: var(--color-muted);
}

.cultivar-empty p {
  margin-bottom: 0;
}

/* ============================================================
   AI Parameter Advisor
   ============================================================ */

.ai-loading {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-4);
  font-size: 0.9375rem;
  color: var(--color-slate);
}

.ai-card {
  overflow: hidden;
  padding: 0;
}

.ai-badge {
  background-color: var(--color-info-tint);
  color: var(--color-info-ink);
}

.ai-explanation {
  margin-top: var(--space-3);
  padding: var(--space-3);
  background-color: var(--color-warm-white);
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  color: var(--color-charcoal);
  line-height: 1.6;
}

.ai-explanation p {
  margin-bottom: 0;
}

.ai-sources {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  margin-top: var(--space-3);
}

.ai-source-tag {
  font-size: 0.6875rem;
  font-style: italic;
  color: var(--color-slate);
  padding: 2px 8px;
  background-color: var(--color-warm-white);
  border-radius: var(--radius-full);
  border: 1px solid var(--color-sandstone);
}

.ai-confidence {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
  font-size: 0.875rem;
}

.ai-confidence-label {
  color: var(--color-muted);
  font-weight: 500;
}

.ai-confidence-value {
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--radius-full);
  font-size: 0.75rem;
}

.ai-confidence--high {
  background-color: var(--color-success-tint);
  color: var(--color-success-ink);
}

.ai-confidence--medium {
  background-color: var(--color-warning-tint);
  color: var(--color-warning-ink);
}

.ai-confidence--low {
  background-color: var(--color-error-tint);
  color: var(--color-error-ink);
}

.ai-disclaimer {
  margin-top: var(--space-3);
  font-size: 0.8125rem;
  color: var(--color-muted);
  font-style: italic;
  margin-bottom: var(--space-3);
}

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

/* Verified reference tiers */
.ref-section {
  margin-top: var(--space-3);
  padding: var(--space-3);
  border-radius: var(--radius-md);
}

.ref-section--tier1 {
  background-color: var(--color-success-tint);
  border: 1px solid var(--color-success-border);
}

.ref-section--tier2 {
  background-color: #FFFBEB;
  border: 1px solid var(--color-warning-border);
}

.ref-section--tier3 {
  background-color: var(--color-error-tint);
  border: 1px solid var(--color-error-border);
}

.ref-section-title {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-charcoal);
  margin-bottom: var(--space-2);
}

.ref-tier-note {
  font-size: 0.75rem;
  color: var(--color-slate);
  font-style: italic;
  margin-bottom: var(--space-2);
}

.ref-tier-warning {
  font-size: 0.8125rem;
  color: var(--color-error-ink);
  margin-bottom: 0;
}

.ref-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) 0;
}

.ref-citation {
  font-size: 0.8125rem;
  color: var(--color-charcoal);
}

.ref-doi {
  font-size: 0.6875rem;
  color: var(--color-canopy);
  text-decoration: none;
  font-weight: 600;
}

.ref-doi:hover {
  text-decoration: underline;
}

.ref-verified-badge {
  font-size: 0.6875rem;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: var(--radius-full);
  background-color: var(--color-success-tint);
  color: var(--color-success-ink);
}

.ref-verified-badge--zone {
  background-color: var(--color-warning-tint);
  color: var(--color-warning-ink);
}

.ref-citation-link {
  font-size: 0.8125rem;
  color: var(--color-canopy);
  text-decoration: none;
  font-weight: 500;
}

.ref-citation-link:hover {
  text-decoration: underline;
}

.ref-citation-text {
  font-size: 0.8125rem;
  color: var(--color-charcoal);
}

/* AI card collapsed states */
.ai-collapsed {
  padding: var(--space-3) var(--space-4);
  font-size: 0.9375rem;
  font-weight: 500;
}

.ai-collapsed--accepted {
  color: var(--color-success);
}

.ai-collapsed--customizing {
  color: var(--color-terracotta);
}

/* ============================================================
   Project Library
   ============================================================ */

.library-page {
  /* A data-dense list page earns more width than the ~1000px prose width. */
  max-width: 1180px;
  margin: 0 auto;
}

.library-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-5);
}

.library-header-left {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.library-count {
  font-size: 0.9375rem;
  color: var(--color-muted);
  font-weight: 400;
}

/* Toolbar: filters + sort + search */
.library-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  flex-wrap: wrap;
}

.library-filters {
  display: flex;
  gap: var(--space-1);
}

.filter-pill {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-3);
  font-family: var(--font-primary);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-slate);
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-full);
  text-decoration: none;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.filter-pill:hover {
  border-color: var(--color-canopy);
  color: var(--color-canopy);
}

.filter-pill--active {
  background-color: var(--color-canopy);
  color: var(--color-white);
  border-color: var(--color-canopy);
}

.filter-pill--active:hover {
  background-color: var(--color-canopy-dark);
}

.library-controls {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.library-sort {
  width: auto;
  min-width: 140px;
  padding: var(--space-1) var(--space-2);
  font-size: 0.8125rem;
}

.library-page-size {
  width: auto;
  min-width: 96px;
  padding: var(--space-1) var(--space-2);
  font-size: 0.8125rem;
}

.library-search-form {
  display: flex;
}

.library-search {
  width: 180px;
  padding: var(--space-1) var(--space-2) var(--space-1) 30px;
  font-size: 0.8125rem;
}

/* Inset search glyph — an affordance inside the input. */
.library-search-wrap {
  position: relative;
  display: flex;
}
.library-search-icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  color: var(--color-muted);
  pointer-events: none;
}

/* Align the three toolbar controls to a single 32px floor so the
   select/input intrinsic-height delta (browser form-control defaults)
   doesn't produce the 2px baseline wobble evaluator measured. Matches
   the WCAG 2.5.5 hit-target floor standardized in Group H. */
.library-toolbar .form-input,
.library-toolbar .form-select {
  min-height: 32px;
  box-sizing: border-box;
}

/* Project Rows */
.library-list {
  display: flex;
  flex-direction: column;
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  overflow: hidden;
}

/* V2-22b/P P.1 — library pagination control. Wraps cleanly on 375px
   mobile (flex-wrap) and preserves the 32×32 hit target floor. */
.library-pagination {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  justify-content: center;
  align-items: center;
  margin-top: var(--space-4);
}

.pagination-page {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  min-height: 32px;
  padding: var(--space-1) var(--space-3);
  font-size: 0.9375rem;
  color: var(--color-charcoal);
  background-color: var(--color-white);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-sm);
  text-decoration: none;
}
.pagination-page:hover {
  background-color: var(--color-parchment);
  border-color: var(--color-canopy-dark);
}
.pagination-page:focus-visible {
  outline: 2px solid var(--color-canopy);
  outline-offset: 2px;
}
.pagination-page--active {
  /* `--color-primary` is not defined in the design-system token set;
     the original Group P P.1 commit referenced it and fell back to
     the invalid-var default (transparent), which made the active page
     invisible. `--color-canopy` is the brand-green token and matches
     the vocabulary used for primary buttons + active states elsewhere. */
  background-color: var(--color-canopy);
  color: var(--color-white);
  border-color: var(--color-canopy);
  cursor: default;
}
.pagination-page--disabled {
  color: var(--color-muted);
  cursor: not-allowed;
  opacity: 0.55;
}

/* Pagination footer meta: current-page count beside the page-size
   control (a pagination concern, grouped with the nav). Centered
   under the page nav; wraps to two lines on narrow widths. */
.library-pagination-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-3);
}

.library-pagination-count {
  text-align: center;
  margin: 0;
  font-size: 0.875rem;
  color: var(--color-muted);
}

.library-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-sandstone);
  transition: background-color 0.1s ease, opacity 0.3s ease;
}

.library-row:last-child {
  border-bottom: none;
}

.library-row:hover {
  background-color: var(--color-warm-white);
}

.library-row-link {
  display: flex;
  align-items: center;
  flex: 1;
  gap: var(--space-3);
  text-decoration: none;
  min-width: 0;
}

.library-row-main {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: 1;
  min-width: 0;
}

.library-row-icon {
  flex-shrink: 0;
  color: var(--color-canopy);
}

.library-row-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.library-row-name {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-deep-forest);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.library-row-meta {
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.library-row-cloned {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.75rem;
  color: var(--color-slate);
  font-style: italic;
}

/* Row actions */
.library-row-actions {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex-shrink: 0;
}

.library-action-btn {
  padding: var(--space-1) var(--space-2);
  font-size: 0.75rem;
}

.library-action-btn--delete {
  background: none;
  border: 1px solid transparent;
  color: var(--color-muted);
}

.library-action-btn--delete:hover {
  color: var(--color-error);
  border-color: var(--color-error-border);
  background-color: var(--color-error-tint);
}

.library-delete-wrap {
  position: relative;
}

/* Empty state */
.library-empty-filter {
  text-align: center;
  padding: var(--space-5) var(--space-4);
}

.library-empty-filter p {
  color: var(--color-slate);
  margin-bottom: var(--space-3);
}

.library-empty {
  text-align: center;
  padding: var(--space-7) var(--space-5);
}

.library-empty h2 {
  margin-top: var(--space-3);
  margin-bottom: var(--space-2);
}

.library-empty p {
  color: var(--color-slate);
  margin-bottom: var(--space-4);
}

/* ============================================================
   Modal (shared)
   ============================================================ */

.modal-overlay {
  position: fixed;
  inset: 0;
  background-color: rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 500;
  padding: var(--space-4);
}

.modal-card {
  background-color: var(--color-white);
  border-radius: var(--radius-lg);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
  width: 100%;
  max-width: 480px;
  max-height: 90vh;
  overflow-y: auto;
}

/* Native <dialog> reuses the modal-card tokens: reset the UA chrome and move the backdrop to the native ::backdrop. */
dialog.modal-card {
  border: none;
  padding: 0;
  max-width: min(480px, calc(100vw - 2rem));
  margin: auto;   /* restore the UA centering a global margin reset zeroes (the flex-overlay .modal-card stays margin:0) */
}
dialog.modal-card::backdrop {
  /* Token first; raw fallback because ::backdrop does not inherit :root vars in every target browser. */
  background-color: var(--backdrop-modal, rgba(34, 41, 51, 0.45));
}

.replace-list {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-4);
}
.replace-list li {
  margin-bottom: var(--space-1);
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-4) var(--space-2);
}

.modal-title {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--color-deep-forest);
}

.modal-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  background: none;
  color: var(--color-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
}

.modal-close:hover {
  color: var(--color-charcoal);
  background-color: var(--color-warm-white);
}

.modal-body {
  padding: var(--space-2) var(--space-4) var(--space-3);
}

.modal-body p {
  font-size: 0.9375rem;
  color: var(--color-charcoal);
}

.modal-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4) var(--space-4);
  border-top: 1px solid var(--color-sandstone);
}

/* Clone modal specifics */
.clone-source-name {
  font-weight: 600;
  color: var(--color-deep-forest);
  margin-bottom: var(--space-3);
}

.clone-section-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: var(--space-2);
}

.clone-keep-section {
  margin-bottom: var(--space-4);
}

.clone-keep-items {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.clone-keep-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.875rem;
  color: var(--color-charcoal);
}

.clone-change-section {
  margin-bottom: var(--space-3);
}

.clone-change-section .form-group {
  margin-bottom: 0;
}

.clone-warning {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background-color: var(--color-warning-tint);
  border: 1px solid var(--color-warning-border);
  border-radius: var(--radius-md);
  font-size: 0.8125rem;
  color: var(--color-warning-ink);
}

/* Responsive — mid-range: collapse the balanced two-cluster toolbar to a
   stack so a wrap never strands a void. The two clusters need the full
   ~1180px container to share one row; below it they wrap and strand a void,
   so the stack takes over at the container width. Filters become a
   horizontal scroll-rail (season-rail parity); the controls fill a
   full-width row with the search growing to fill it. */
@media (max-width: 1180px) {
  .library-toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .library-filters {
    flex-wrap: nowrap;
    overflow-x: auto;
    /* Hide the scrollbar (Firefox + WebKit); the edge-fade signals scroll. */
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }

  .library-filters::-webkit-scrollbar {
    display: none;
  }

  .filter-pill {
    flex: 0 0 auto;
    white-space: nowrap;
  }

  .library-controls {
    width: 100%;
    flex-wrap: wrap;
  }

  .library-search-form {
    flex: 1;
  }

  /* The glyph wrapper is the form's flex child — it must grow too, else the
     input (width:100% of the wrap) stays at its desktop 180px. */
  .library-search-wrap {
    flex: 1;
  }

  .library-search {
    width: 100%;
  }
}

/* Responsive */
@media (max-width: 768px) {
  .library-header {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
  }

  .library-toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .library-controls {
    flex-direction: column;
    align-items: stretch;
  }

  .library-search {
    width: 100%;
  }

  .library-row {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
  }

  .library-row-link {
    flex-direction: column;
    align-items: flex-start;
  }

  .library-row-actions {
    justify-content: flex-end;
  }
}

/* ================================================================
   V2-21 B-GROUP: VALIDATION CARDS
   ================================================================ */

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

.val-card {
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.val-card--pass { border-left: 3px solid var(--color-success); }
.val-card--warning { border-left: 3px solid var(--color-warning); background: var(--color-amber-50); }
.val-card--fail { border-left: 3px solid var(--color-error); background: var(--color-error-tint); }

.val-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
  background: none;
  border: none;
  width: 100%;
  text-align: left;
  font: inherit;
  min-height: 44px;
}

.val-card-header:hover { background: rgba(0,0,0,0.02); }

.val-card-header-left {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.val-card-label {
  font-weight: 600;
  font-size: 0.9rem;
  display: block;
}

.val-card-subtitle {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  display: block;
}

.val-card-header-right {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.val-card-badge {
  font-size: 0.72rem;
  font-weight: 500;
  padding: 2px 8px;
  /* Pill / badge shape — clamped to half-height at this
     element's size; visual identical to the prior literal
     12px. */
  border-radius: var(--radius-full);
}

.val-card-badge--pass { background: var(--color-success-tint); color: var(--color-success-ink); }
.val-card-badge--warn { background: var(--color-warning-tint); color: var(--color-warning-ink); }
.val-card-badge--fail { background: var(--color-error-tint); color: var(--color-error-ink); }

.val-card-body {
  padding: 0 var(--space-4) var(--space-3);
  border-top: 1px solid var(--color-sandstone);
}

.val-check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: 1px solid rgba(0,0,0,0.04);
}

.val-check:last-child { border-bottom: none; }

.val-check-status { flex-shrink: 0; padding-top: 2px; }

.val-check-summary {
  font-size: 0.8rem;
  display: block;
}

.val-check-range {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  display: block;
  margin-top: 2px;
}

/* ================================================================
   V2-21 B-GROUP: DECISION TIMELINE
   ================================================================ */

.decision-timeline {
  margin-top: var(--space-4);
  overflow: visible; /* U2: ensure filter toggle never clips scroll */
}

.dt-summary {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
  font-size: 0.85rem;
}

.dt-summary-stat { color: var(--color-text-primary); }

.dt-summary-filter {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border-radius: 16px;
  border: 1px solid var(--color-warning-border);
  background: #fffbeb;
  color: var(--color-warning-ink);
  font-size: 0.78rem;
  cursor: pointer;
  transition: background 0.15s;
}

.dt-summary-filter:hover { background: var(--color-warning-tint); }
.dt-summary-filter--active { background: var(--color-warning-border); border-color: var(--color-warning); }

.dt-stage { margin-bottom: var(--space-2); }

.dt-stage-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  background: var(--color-parchment, #faf8f4);
  border-radius: var(--radius-sm);
  cursor: pointer;
  border: none;
  width: 100%;
  font: inherit;
  text-align: left;
  min-height: 44px;
}

.dt-stage-header:hover { background: var(--color-sandstone); }

.dt-stage-left {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.dt-stage-label {
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--color-text-primary);
}

.dt-stage-badge {
  background: var(--color-canopy, #2d5016);
  color: white;
  font-size: 0.65rem;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: 8px;
}

.dt-stage-right {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.dt-stage-duration {
  font-size: 0.72rem;
  /* Slate (the Parchment-muted token) keeps the label secondary while
     clearing WCAG-AA 4.5:1 on the Parchment stage-header (4.71:1);
     the plain muted token lands 4.34:1 at this 11.5px size. */
  color: var(--color-slate, #5A6B7F);
  font-variant-numeric: tabular-nums;
}

.dt-decisions {
  padding-left: var(--space-4);
  border-left: 2px solid var(--color-sandstone);
  margin-left: 28px;
  overflow-y: visible !important; /* U2: prevent filter toggle from blocking scroll */
  max-height: none !important;
}

.dt-node {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  position: relative;
}

.dt-node-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  position: absolute;
  left: calc(-1 * var(--space-4) - 5px);
  top: calc(var(--space-2) + 4px);
  border: 2px solid var(--color-white);
  box-shadow: 0 0 0 1px var(--color-sandstone);
}

.dt-node--info .dt-node-dot { background: var(--color-canopy, #2d5016); }
.dt-node--warning .dt-node-dot { background: var(--color-warning); }
.dt-node--error .dt-node-dot { background: var(--color-error); }

.dt-node--highlight {
  animation: dtHighlight 2s ease-out;
}
@keyframes dtHighlight {
  0%, 30% { background: var(--color-warning-tint); }
  100% { background: transparent; }
}

.dt-stage:last-child { margin-bottom: 2rem; }

.dt-node-content { flex: 1; min-width: 0; }

.dt-node-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  width: 100%;
  text-align: left;
  font: inherit;
}

.dt-node-label {
  font-size: 0.8rem;
  color: var(--color-text-primary);
}

/* F-CJ — multiplier pill on a folded decision row. Identical
   decisions emitted once per cell collapse to a single timeline
   row carrying ``count`` ≥ 2; the consumer surfaces the
   multiplier so the audit trail is preserved without flooding
   the surface. Subdued pill chrome so it reads as a count badge
   rather than another label. */
.dt-node-count {
  display: inline-flex;
  align-items: center;
  margin-left: var(--space-2);
  padding: 0 var(--space-2);
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--color-text-muted, #6b7280);
  background: var(--color-sandstone-100);
  border: 1px solid var(--color-sandstone);
  border-radius: var(--radius-sm, 4px);
  white-space: nowrap;
}

.dt-node-detail {
  margin-top: var(--space-2);
  padding: var(--space-3);
  background: var(--color-warm-white, #fdfcfa);
  border-radius: var(--radius-sm);
  border-left: 2px solid var(--color-canopy, #2d5016);
}

.dt-node--warning .dt-node-detail { border-left-color: var(--color-warning); }
.dt-node--error .dt-node-detail { border-left-color: var(--color-error); }

.dt-node-rationale {
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--color-text-primary);
  margin: 0 0 var(--space-2) 0;
}

.dt-node-alts {
  margin-top: var(--space-2);
}

.dt-node-alts-label {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--color-text-muted);
}

.dt-node-alts ul {
  margin: var(--space-1) 0 0 var(--space-3);
  padding: 0;
  font-size: 0.75rem;
  color: var(--color-text-primary);
}

.dt-node-alts li { margin-bottom: 2px; }

.dt-alt-reason {
  color: var(--color-text-muted);
  font-style: italic;
}

.dt-node-ref {
  display: block;
  margin-top: var(--space-2);
  font-size: 0.68rem;
  color: var(--color-text-muted);
  font-family: monospace;
}

/* ================================================================
   V2-21 B-GROUP: FLOATING METHODS BUTTON
   ================================================================ */

.methods-fab {
  position: fixed;
  bottom: var(--space-4);
  right: var(--space-4);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-2);
}

.methods-fab-btn {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--color-canopy, #2d5016);
  color: white;
  border: none;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  transition: transform 0.15s, box-shadow 0.15s;
}

.methods-fab-btn:hover {
  transform: scale(1.08);
  box-shadow: 0 6px 20px rgba(0,0,0,0.2);
}

.methods-fab-btn--active {
  background: var(--color-text-primary);
}

.methods-fab-label {
  font-size: 0.55rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  margin-top: -2px;
}

.methods-panel {
  width: 340px;
  max-height: 60vh;
  background: var(--color-white);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 30px rgba(0,0,0,0.12);
  border: 1px solid var(--color-sandstone);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

@media (max-width: 640px) {
  .methods-panel {
    width: calc(100vw - 32px);
    right: 16px;
  }
}

.methods-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-sandstone);
}

.methods-panel-header h4 {
  margin: 0;
  font-size: 0.9rem;
}

.methods-panel-close {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-text-muted);
  padding: 4px;
}

.methods-panel-options {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-sandstone);
}

.methods-option {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
  flex: 1;
  text-align: center;
  transition: background 0.15s;
}

.methods-option input { display: none; }

.methods-option span:first-of-type {
  font-size: 0.8rem;
  font-weight: 600;
}

.methods-option-desc {
  font-size: 0.65rem;
  color: var(--color-text-muted);
}

.methods-option:hover { background: var(--color-parchment, #faf8f4); }
.methods-option--active {
  background: var(--color-canopy, #2d5016) !important;
  color: white;
}
.methods-option--active .methods-option-desc { color: rgba(255,255,255,0.7); }

.methods-panel-preview {
  padding: var(--space-3) var(--space-4);
  max-height: 160px;
  overflow-y: auto;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--color-text-primary);
  border-bottom: 1px solid var(--color-sandstone);
}

.methods-panel-actions {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
}

/* ================================================================
   V2-21 D-GROUP: MICRO-INTERACTIONS + POLISH
   ================================================================ */

/* Staggered range bar animations */
.range-bar-row:nth-child(1) .range-bar-fill { transition-delay: 0ms; }
.range-bar-row:nth-child(2) .range-bar-fill { transition-delay: 100ms; }
.range-bar-row:nth-child(3) .range-bar-fill { transition-delay: 200ms; }
.range-bar-row:nth-child(4) .range-bar-fill { transition-delay: 300ms; }

/* Staggered validation badge fade-in */
.val-badge {
  opacity: 0;
  animation: fadeSlideUp 300ms ease-out forwards;
}
.val-badge:nth-child(1) { animation-delay: 0ms; }
.val-badge:nth-child(2) { animation-delay: 80ms; }
.val-badge:nth-child(3) { animation-delay: 160ms; }
.val-badge:nth-child(4) { animation-delay: 240ms; }
.val-badge:nth-child(5) { animation-delay: 320ms; }

@keyframes fadeSlideUp {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Staggered KPI card fade-in */
.kpi-card {
  opacity: 0;
  animation: fadeSlideUp 400ms ease-out forwards;
}
.kpi-card:nth-child(1) { animation-delay: 100ms; }
.kpi-card:nth-child(2) { animation-delay: 200ms; }
.kpi-card:nth-child(3) { animation-delay: 300ms; }

/* Tab underline animation — already handled by existing .tab-btn
   border-bottom transition at line ~2985. No ::after needed. */

/* Amber banner advisory list */
.banner-advisories {
  list-style: none;
  margin: var(--space-2) 0 0 0;
  padding: 0;
  font-size: 0.78rem;
  color: var(--color-warning-ink);
}
.banner-advisories li {
  padding: 2px 0;
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.banner-advisories li::before {
  content: '⚠';
  flex-shrink: 0;
  font-size: 0.7rem;
}

/* Scroll-triggered sticky bar */
.sticky-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 48px;
  background: var(--color-white);
  border-bottom: 1px solid var(--color-sandstone);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--space-4);
  z-index: 900;
  transform: translateY(-100%);
  transition: transform 200ms ease;
  box-shadow: 0 2px 8px rgba(0,0,0,0.06);
}
.sticky-bar--visible {
  transform: translateY(0);
}
.sticky-bar-title {
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--color-text-primary);
}
.sticky-bar-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* ================================================================
   V2-21 D-GROUP: RESPONSIVE REFINEMENTS
   ================================================================ */

@media (max-width: 767px) {
  /* Per AC-F5 + D17: BIG MAP is omitted on phone-class viewports
     (a 375 px-wide map at ≥30 cells per side is unreadable per
     Stage 2 B.3 density rationale). The map + legend + desktop
     data-quality panel hide; the Region Health text card surfaces
     in their place with the same five-category status read in a
     form Ibrahim can scan with one thumb. */
  /* The integrated map+legend card hides as a unit at
     ≤767 px so AC-F5 + D17 mobile carve-out preserves
     identically: the BIG MAP + its legend disappear and
     the Region Health text card surfaces in their place.
     The nested map + legend rules below remain (defense-
     in-depth so a future refactor that drops the wrapper
     still hides the inner elements). */
  .portrait-map-card {
    display: none;
  }

  .portrait-map--big {
    display: none;
  }

  .portrait-map-legend {
    display: none;
  }

  .portrait-region-health {
    display: block;
  }

  .portrait-data-quality {
    display: none;
  }
}

@media (max-width: 768px) {
  /* Scoped via :not(--big) so the BIG MAP modifier rule above is not
     overridden by source-order. Legacy thumbnail callers (no `--big`
     modifier) still shrink to 200 px on tablet/mobile as before. */
  .portrait-map:not(.portrait-map--big) {
    height: 200px;
  }

  .portrait-ranges {
    padding: var(--space-2);
    overflow: hidden;
  }
  .portrait-kpis {
    padding: var(--space-2);
  }
  .range-bar-bounds {
    font-size: 0.75rem;
  }

  .dt-decisions {
    margin-left: 16px;
    padding-left: var(--space-3);
  }
  .dt-node-dot {
    left: calc(-1 * var(--space-3) - 5px);
  }

  .dt-node-rationale {
    font-size: 0.75rem;
  }

  .cert-row {
    grid-template-columns: 1fr;
    align-items: stretch;
    gap: var(--space-3);
  }
  .cert-body {
    max-width: none;
  }
  .cert-actions {
    width: 100%;
  }
  .cert-btn {
    width: 100%;
    justify-content: center;
  }
  .results-actions-bar {
    flex-direction: column;
    gap: var(--space-2);
    align-items: stretch;
  }
  .results-bookmark {
    flex-direction: column;
    gap: var(--space-2);
  }
  .copy-url-btn, .btn-delete-ghost {
    width: 100%;
    justify-content: center;
  }
}

@media (max-width: 640px) {
  .methods-fab {
    bottom: var(--space-3);
    right: var(--space-3);
  }

  .methods-fab-btn {
    width: 44px;
    height: 44px;
  }

  .methods-fab-label {
    display: none;
  }

  .dt-stage-header {
    padding: var(--space-2);
  }

  .val-card-header {
    padding: var(--space-2) var(--space-3);
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  /* Tab buttons: ensure touch targets ≥44px and prevent overflow */
  .tab-btn {
    min-height: 44px;
    padding: var(--space-2);
    font-size: 0.78rem;
  }

  /* Prevent horizontal overflow */
  .results-page {
    overflow-x: hidden;
    max-width: 100vw;
  }

  .range-bar-track {
    max-width: 100%;
  }

  .sticky-bar {
    padding: 0 var(--space-3);
  }
}

/* ────────────────────────────────────────────────────────────────
   V2-22d Tier 1 D.4 — HTMX retry / timeout toast
   Palette: Warm White background, Sandstone border, Slate text.
   WCAG AA: Slate #5A6B7F on Warm White #FAFAF7 = 5.35:1 ratio.
   No drop shadow, no emoji, no exclamation (D.4.5).
   ──────────────────────────────────────────────────────────────── */
.htmx-toast {
  position: fixed;
  bottom: 24px;
  right: 24px;
  z-index: 9999;
  max-width: 360px;
  padding: var(--space-2) var(--space-3);
  background-color: var(--color-warm-white);
  border: 1px solid var(--color-sandstone);
  border-radius: 6px;
  color: var(--color-slate);
  font-size: 0.9375rem;
  line-height: 1.4;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 150ms ease-out, transform 150ms ease-out;
  pointer-events: none;
}

.htmx-toast--visible {
  opacity: 1;
  transform: translateY(0);
}

@media (max-width: 640px) {
  .htmx-toast {
    bottom: 16px;
    right: 16px;
    left: 16px;
    max-width: none;
  }
}

/* ────────────────────────────────────────────────────────────────
   V2-22d Tier 1 D.1 — queue visibility panel + N-3 warning.
   Palette: Parchment bg, Warning left border, WCAG-AA body text.
   No drop shadow, no gradient, no decorative icon (D.1.2).
   ──────────────────────────────────────────────────────────────── */
.queue-panel {
  margin: 0 0 var(--space-3, 16px);
  padding: 14px 18px;
  background-color: var(--color-parchment);
  border-left: 4px solid var(--color-warning); /* Warning — matches frozen palette */
  border-radius: 4px;
  color: var(--color-warning-ink); /* WCAG AA on Parchment = 6.0:1 */
}

.queue-panel-copy {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.45;
}

.queue-panel-copy--escalated {
  margin-top: 6px;
  font-weight: 500;
}

.queue-panel-meta {
  margin: 6px 0 0;
  font-size: 0.8125rem;
  opacity: 0.85;
}

.queue-panel-eta {
  margin: 4px 0 0;
  font-size: 0.8125rem;
  opacity: 0.85;
}

/* V2-22d/A1 A.3 — queued-state modifier. Distinct from the peer-context
   panel: Slate left border (institutional, matches Moussa's persona read)
   instead of the peer-context Warning amber. Parchment background kept so
   the two panel variants share visual rhythm on the processing page.
   Queued-state is fired when the user's OWN run is capacity-deferred or
   waiting behind older queued rows (A.3.2 precedence).

   A.3.5 Gate B (ux-expert fixup) — body text overrides the peer-context
   amber (--color-warning-ink, "hesitation/friction" read under Moussa's
   stakeholder-demo + Aminata's first-time-anxiety personae) to Deep
   Forest (--color-deep-forest, institutional/stable). Contrast on
   Parchment rises from 6.0:1 → ~9.8:1 (AAA); §6 #12 "AAA is a floor"
   + §6 #16 "persona-gaze over metrics-alone". Meta text stays Slate
   via .queue-panel-meta. */
.queue-panel--queued-state {
  border-left-color: var(--color-slate);
  color: var(--color-deep-forest);
}

/* Meta + ETA lines inside the queued-state variant stay Slate (per
   ux-expert A.3.5: body = Deep Forest, meta = Slate). Without this
   explicit override they'd inherit the Deep Forest we set on the
   modifier above; the peer-context panel's meta rules are unchanged.
   Slate on Parchment = ~6.5:1 (AA normal, AAA large). */
.queue-panel--queued-state .queue-panel-meta,
.queue-panel--queued-state .queue-panel-eta {
  color: var(--color-slate);
}

.queue-panel-copy--queued-heading {
  font-weight: 600;
}

/* D.1.9 — N-3 eviction warning. Uses the same palette as the queue
   panel but without the left border rail, so Kofi can tell the two
   pieces of context apart at a glance. */
.n3-warning {
  margin: 0 0 var(--space-3, 16px);
  padding: 12px 16px;
  background-color: var(--color-parchment);
  border-radius: 4px;
  color: var(--color-warning-ink);
  font-size: 0.875rem;
  line-height: 1.45;
}

.n3-warning p {
  margin: 0;
}

@media (max-width: 640px) {
  .queue-panel,
  .n3-warning {
    padding: 12px;
  }
}

/* HTMX retry/timeout toast escalated modifier: base is the neutral toast above; escalated supplies the warning chrome. */
.htmx-toast--escalated {
  background-color: var(--color-parchment);
  border-left: 4px solid var(--color-warning);
  box-shadow: 0 6px 18px rgba(31, 54, 39, 0.18);
  color: var(--color-warning-ink);
  font-weight: 500;
}

@media (prefers-reduced-motion: reduce) {
  .htmx-toast { transition: none; }
}

/* ===========================================================================
   V2-22c PR-B Step 1 — cockpit landing shell (AC-A2 + AC-A2.1 + D43).

   The cockpit page renders three responsive bands at once and lets
   CSS pick the right one by viewport width. CSS-driven (not JS-
   driven) per D43 so an in-session resize transitions cleanly:

   * >=1024 px — `.cockpit-shell` 3-column grid via minmax floor
     widths 240/540/180 (D43); proportional shrink between 1024
     and 1280.
   * 768-1023 px — `.cockpit-tablet-redirect` Parchment card per
     AC-A2.1; URL params preserved via `data-cockpit-full-url`.
   * <=767 px — `.cockpit-mobile-redirect` placeholder; full A.6
     card lands at Step 11 (AC-E2).

   Anti-mutation: the three sections each declare `display: none`
   by default; only one media query at a time turns them on. A
   >=1024 px viewport NEVER renders the tablet card; a 1024-1279
   viewport NEVER renders the spec 280/720/240 grid (it renders
   the proportional minmax).
   =========================================================================== */

.cockpit-shell,
.cockpit-tablet-redirect,
.cockpit-mobile-redirect {
  display: none;
}

/* Cockpit-grid-map base rule — navbar-overlay containment
   pattern. Lives OUTSIDE any media query so the containment
   applies even if a future viewport-band change exposes the
   element below 1024 px. The desktop sizing layer (width,
   aspect-ratio, max-width, background, borders) lives in
   the >=1024 px @media block below. Mirrors the .portrait-map
   pattern at line 3197. The 3 properties (position: relative,
   overflow: hidden, z-index: 1) anchor Leaflet's internal
   stacking context, clip overflow at the container edge, and
   stay below the navbar (z-index: 100+). */
.cockpit-grid-map {
  position: relative;
  overflow: hidden;
  z-index: 1;
}

/* >=1200 px — full cockpit shell. Floor raised from 1024 →
   1200 per ux-expert revised spec — the prior 1024 floor
   produced an empirical drawer-vs-queue overlap at 1280 /
   1366 / 1440 viewports because the Refinement Queue column
   collapsed below readable width and the cell drawer (now
   280 px wide) overlapped the queue's right edge. The 1200
   px floor leaves enough horizontal room for the queue
   column at its minmax floor + the 280 px drawer.

   Grid template columns: ``minmax(240px, 1fr) minmax(360px,
   2fr) minmax(220px, 1fr)`` per ux-expert spec — fluid
   widths that scale with viewport instead of clamping at
   the prior 280/720/240 spec. Floors are persona-fit: 240
   for FLAGGED CELLS column copy, 360 for the cell map,
   220 for REFINEMENT QUEUE. The fr-based growth past floor
   keeps the proportions readable as the viewport scales
   1200 → 1920.

   Drawer-open coupling: when the cell drawer is open,
   ``.cockpit-shell.has-drawer-open`` adds ``padding-right:
   var(--drawer-width)`` so the queue column is pushed left
   off the drawer's footprint instead of being overlapped.
   The transition lives on the base shell rule so the push
   animates smoothly with the drawer slide-in (200 ms ease-
   out matches the drawer's 250 ms transform; the slight
   overlap is intentional — content settles before drawer
   anchor lands).

   Range syntax (``width >= 1200px`` rather than the older
   ``min-width: 1200px``) is intentional — paired with the
   tablet and mobile bands below, the three media queries form
   an exhaustive partition of the viewport-width axis with no
   sub-pixel gap between bands. */
@media (width >= 1200px) {
  .cockpit-shell {
    display: grid;
    grid-template-columns:
      minmax(240px, 1fr)
      minmax(360px, 2fr)
      minmax(220px, 1fr);
    gap: 16px;
    padding: 16px;
    max-width: 1280px;
    margin: 0 auto;
    align-items: stretch;
    /* Drawer-open transition — see has-drawer-open rule
       below. The transition lives on the base cockpit
       shell so an open-then-close sequence animates both
       directions. */
    transition: padding-right 200ms ease-out;
  }

  .cockpit-shell.has-drawer-open {
    /* Padding-right matches the drawer's fixed width
       (var(--drawer-width)) so the column grid stays
       inside the available horizontal frame and the
       Refinement Queue's right edge does not overlap the
       drawer's left edge. The drawer itself is fixed-
       positioned at right:0; the shell pushes its content
       LEFT to make room. */
    padding-right: var(--drawer-width);
  }

  .cockpit-col {
    background: var(--color-white, #ffffff);
    border: 1px solid var(--color-sandstone);
    /* Design-system token, byte-equivalent to the prior
       literal 12px. Cockpit columns are primary-workspace
       surfaces per the F-G family classification — the
       large-radius semantic. Other surfaces in the codebase
       still carry literal 12px pending per-site
       classification by ux-expert; the test file pins the
       count of remaining literal sites so any new bypass
       additions surface at CI time. */
    border-radius: var(--radius-lg);
    /* No outer padding — child elements own their own
       insets so the map track's inner content width matches
       the grid-template-columns minmax floor. With padding
       on the column, a 540 px floor would shrink the inner
       map to ~506 px and break the contract. */
    padding: 0;
    min-height: 480px;
  }

  .cockpit-col-title {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-charcoal, #374151);
    margin: 16px 16px 12px 16px;
  }

  .cockpit-col-placeholder {
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 13px;
    line-height: 1.5;
    color: var(--color-slate, #5A6B7F);  /* WCAG AA on Parchment — ~4.71:1 vs the failing ~4.17:1 of #6b7280; see commit log for the sweep */
    margin: 0 16px 16px 16px;
  }

  /* Cockpit grid-map column: encode-by toolbar (top) /
     map area (middle) / legend (bottom-of-column per the
     map-side contract). At 1280+ the map sits at the spec
     600x360; between 1024 and 1279 the column shrinks
     proportionally; the map's aspect-ratio holds 5:3 via
     CSS so the inner Canvas paint never overflows. */
  .cockpit-map-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 16px 16px 8px 16px;
  }

  .cockpit-encode-by-label {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-charcoal, #374151);
  }

  .cockpit-encode-by-select {
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 14px;
    line-height: 1.4;
    padding: 6px 10px;
    background: var(--color-white, #ffffff);
    border: 1px solid var(--color-sandstone);
    border-radius: 6px;
    color: var(--color-charcoal, #374151);
  }

  .cockpit-grid-map {
    /* Width spans the full column track so the inner map
       gets the D43 540 px floor at 1024 px viewport (640 px
       before column borders subtract 2 px) and the 720 px
       max at the spec viewport. The 5:3 aspect ratio gives
       the proportional 360 px height at the spec width. */
    width: 100%;
    aspect-ratio: 5 / 3;
    max-width: 720px;
    margin: 0;
    background: var(--color-parchment);
    border-top: 1px solid var(--color-sandstone);
    border-bottom: 1px solid var(--color-sandstone);
  }

  .cockpit-legend {
    list-style: none;
    margin: 12px 16px 16px 16px;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    /*
     * F36 v2.1 family rule: all map-legend surfaces use
     * justify-content: center. Cross-surface consistency
     * over container-hierarchy context-distinction. Chrome-
     * parity + swatch-shape (14×14 / 3px radius) + Status
     * palette parity (5 hex pairs) + alignment parity (center)
     * — single uniform pattern across the drawer-family.
     *
     * Supersedes F36 v2 deviation (cockpit flex-start) per
     * user empirical revisit 2026-05-01: persona-gaze sees
     * map's centered geographic subject as dominant context,
     * not the toolbar's left-anchored axis (over-modeled in
     * v2). Family-rule meta-lesson: empirical user signal
     * usually wins over modeled context-distinction because
     * users see the WHOLE context at once.
     */
    justify-content: center;
    gap: 12px;
    /* Subtle fade transition on encode-by mode swap; matches
       the LEGEND_FADE_MS constant in cockpit/grid-map.js so
       the JS and CSS sides stay in sync. */
    transition: opacity 150ms ease-in-out;
  }

  .cockpit-legend--fading {
    opacity: 0;
  }

  /* Informational variant — surfaces in place of the
     actionable copy when the active Encode-by mode is
     informational only (Cascade-Fallback). Slightly muted
     accent so the user doesn't read it as a Skip-class call
     to action. */
  .cockpit-col-placeholder--informational {
    border-left: 3px solid var(--color-canopy, #2D5F3F);
    padding-left: 8px;
  }

  .cockpit-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 12px;
    line-height: 1.4;
    color: var(--color-charcoal, #374151);
  }

  .cockpit-legend-swatch {
    display: inline-block;
    width: 14px;
    height: 14px;
    border: 1px solid;
    border-radius: 3px;
    flex-shrink: 0;
  }

  .cockpit-legend-label {
    white-space: nowrap;
  }

  /* Step-14 empty-flag welcome banner per AC-E1 + Stage 2
     §A.5 (line 1513). Sage Wash bg + Charcoal text +
     Success ✓ icon. Spans the full grid width via
     ``grid-column: 1 / -1`` so the banner sits as a 1st
     row above the 3-column workspace. Renders only when
     ``flaggedCategories.length === 0``; the Alpine
     ``x-show`` directive on the section hides it
     otherwise. */
  .cockpit-empty-flag-banner {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    background: var(--color-sage-wash);
    border-radius: 8px;
  }

  .cockpit-empty-flag-banner-icon {
    flex-shrink: 0;
    color: var(--color-success);
    font-size: 18px;
    font-weight: 700;
    line-height: 1;
  }

  .cockpit-empty-flag-banner-text {
    margin: 0;
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 14px;
    line-height: 1.4;
    color: var(--color-charcoal);
  }

  /* Step-14 empty-flag rail copy per Stage 2 §A.5 lines
     1521-1531. "All clean ✓ N / N PASS" headline +
     muted-slate secondary line explaining the absent
     [Skip N] buttons. Replaces the prior brief "No
     flagged categories on the active platform." copy. */
  .cockpit-col-placeholder--empty-flag {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 12px 16px 16px;
  }

  .cockpit-empty-flag-rail-headline {
    margin: 0;
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--color-charcoal);
  }

  .cockpit-empty-flag-rail-check {
    color: var(--color-success);
    margin: 0 4px;
  }

  .cockpit-empty-flag-rail-count {
    font-size: 16px;
    color: var(--color-deep-forest, #1A3A2A);
  }

  .cockpit-empty-flag-rail-secondary {
    margin: 0;
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 13px;
    line-height: 1.5;
    /* Slate on white is WCAG AA — same token used
       elsewhere on Parchment-bg empty-state copy. */
    color: var(--color-slate);
  }

  /* Run lineage rail per AC-A5 + D27. Spans all 3 grid
     columns via ``grid-column: 1 / -1`` so the rail sits
     as a 4th row below the cockpit's 3-column workspace
     without re-templating the grid. Parchment background
     keeps the rail visually distinct from the white
     cockpit columns (the rail is reference data, not a
     primary work surface). */
  .cockpit-lineage-rail {
    grid-column: 1 / -1;
    background: var(--color-parchment, #F5EDE4);
    border-radius: 8px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
  }

  .cockpit-lineage-rail-title {
    /* Inherits the .cockpit-col-title typography but renders
       as the rail's own header — Inter 600 12 / 16 uppercase
       letter-spaced. */
    margin: 0;
  }

  .cockpit-lineage-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
  }

  .cockpit-lineage-row {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 44px;
    padding: 8px 12px;
    border-radius: 6px;
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 14px;
    line-height: 1.4;
    color: var(--color-charcoal, #374151);
    background: var(--color-white, #ffffff);
    border: 1px solid var(--color-sandstone, #D6CEC4);
  }

  .cockpit-lineage-row--root {
    /* Visual anchor — slightly stronger border so the
       original run reads as the family root. */
    border-color: var(--color-canopy, #2D5F3F);
  }

  .cockpit-lineage-marker {
    flex-shrink: 0;
    width: 20px;
    text-align: center;
    color: var(--color-canopy, #2D5F3F);
    font-size: 16px;
  }

  .cockpit-lineage-row--child .cockpit-lineage-marker {
    color: var(--color-slate, #5A6B7F);  /* WCAG AA on Parchment — ~4.71:1 vs the failing ~4.17:1 of #6b7280; see commit log for the sweep */
  }

  .cockpit-lineage-link {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 12px;
    color: inherit;
    text-decoration: none;
  }

  .cockpit-lineage-link:hover,
  .cockpit-lineage-link:focus-visible {
    background: var(--color-sage-wash, #D4E8DC);
    border-radius: 4px;
    margin: -4px -8px;
    padding: 4px 8px;
  }

  .cockpit-lineage-link:focus-visible {
    outline: 2px solid var(--color-canopy, #2D5F3F);
    outline-offset: 2px;
  }

  .cockpit-lineage-label {
    flex: 1;
    font-weight: 500;
  }

  .cockpit-lineage-status {
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 11px;
    line-height: 1.2;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 4px 8px;
    border-radius: 4px;
    font-weight: 600;
    flex-shrink: 0;
  }

  /* Status pill palette — anchors the rail's status badges to
     the existing PASS / INFO / WARN / FAIL semantics. The
     ``running`` and ``queued`` mid-flight states get muted
     chrome-only treatments so they don't compete visually with
     completed-run badges. */
  .cockpit-lineage-status--complete {
    background: var(--color-success-tint);
    color: var(--color-success-ink);
  }

  .cockpit-lineage-status--running,
  .cockpit-lineage-status--queued {
    background: var(--color-sandstone, #D6CEC4);
    color: var(--color-charcoal, #374151);
  }

  .cockpit-lineage-status--error,
  .cockpit-lineage-status--failed {
    background: var(--color-error-tint);
    color: var(--color-error-ink);
  }

  /* Cancelled — amber palette per "user took deliberate
     action" honest signal. Sibling-sweep parity with
     status-badge--cancelled; matches the F-Y' Project-status
     parity contract (cancel writer transitions both run and
     project to 'cancelled'). */
  .cockpit-lineage-status--cancelled {
    background: var(--color-cancelled-tint);
    color: var(--color-cancelled-ink);
  }

  .cockpit-lineage-timestamp {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: 13px;
    line-height: 1.4;
    color: var(--color-slate, #5A6B7F);  /* WCAG AA on Parchment — ~4.71:1 vs the failing ~4.17:1 of #6b7280; see commit log for the sweep */
    flex-shrink: 0;
  }

  .cockpit-lineage-more {
    align-self: flex-start;
    margin-top: 8px;
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 13px;
    line-height: 1.4;
    color: var(--color-canopy, #2D5F3F);
    text-decoration: none;
    padding: 4px 0;
    min-height: 32px;
    display: inline-flex;
    align-items: center;
  }

  .cockpit-lineage-more:hover,
  .cockpit-lineage-more:focus-visible {
    text-decoration: underline;
  }

  .cockpit-lineage-more:focus-visible {
    outline: 2px solid var(--color-canopy, #2D5F3F);
    outline-offset: 2px;
    border-radius: 2px;
  }

  .cockpit-lineage-empty {
    margin: 0;
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 14px;
    line-height: 1.5;
    /* Slate on Parchment is 5.0:1 (AA); the
       ``--color-text-muted`` slate-cousin we use elsewhere
       drops to 4.17:1 on Parchment which fails the 4.5:1
       WCAG 2.1 AA threshold for normal text per the
       Step-13 axe-core scan. */
    color: var(--color-slate, #5A6B7F);
    padding: 8px 12px;
  }

  /* Step-12 codex absorption — corrupt-state placeholder
     reads as a warning, not a chrome-only message. The
     red-tinted bg + bold-er weight signals "investigate"
     rather than "you haven't done anything yet". */
  .cockpit-lineage-corrupt {
    background: var(--color-error-tint);
    color: var(--color-error-ink);
    border: 1px solid var(--color-error-border);
    border-radius: 6px;
    font-weight: 500;
  }
}

/* ===========================================================================
   Cockpit cell drawer — D40 family-member, width via the
   ``--drawer-width`` token (resolves to 280 px at :root per
   the Sprint E.1 ux-expert revised spec).

   Shares the drawer-family vocabulary with the results-page
   surfaces: right-side slide-in via translateX, sandstone
   left border, top-left radius, no backdrop dim, native
   inert focus-trap, chrome-respect anchoring (top + bottom
   anchored to the page chrome custom properties), single-
   drawer-slot enum at the cockpit shell. The token width
   (280 px) is narrower than the 360 px default and fits the
   cockpit's 3-column grid; the rest of the vocabulary is
   identical. The same token drives the
   ``.cockpit-shell.has-drawer-open`` push padding-right so
   the shell push and drawer width never drift.

   The smooth-swap pattern lives in the Alpine
   ``openCockpitDrawer`` / ``closeCockpitDrawer`` methods in
   ``static/js/cockpit-alpine.js``; CSS only needs to keep
   transitioning the transform property — no class-toggle
   choreography on click-another-cell.
   =========================================================================== */

.cockpit-cell-drawer-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 999;
  /* Click-eater that sits over the page so an outside-click
     dismisses the drawer reliably — paired with the cockpit
     map exclusion in the @click.outside handler so map clicks
     still reach the cell rectangles underneath. */
  pointer-events: none;
}

.cockpit-cell-drawer {
  position: fixed;
  top: var(--nav-height, 56px);
  bottom: var(--sticky-cta-height, 0px);
  right: 0;
  /* Width raised 240 → 280 per Sprint E.1 ux-expert revised
     spec — the prior 240 was too cramped for cell body content
     (footer buttons wrapped + methods preview wrapped mid-word
     per empirical Chrome MCP probe). Token at :root means the
     shell push (``.cockpit-shell.has-drawer-open``) and drawer
     width always match. Off-canvas translateX MUST also use
     the token so the drawer fully clears the viewport on
     close (a fixed-pixel translate that's smaller than the
     width leaves a visible drawer edge). */
  width: var(--drawer-width, 280px);
  z-index: 1000;
  background: var(--color-white, #ffffff);
  border-left: 1px solid var(--color-sandstone);
  border-top-left-radius: 12px;
  transform: translateX(var(--drawer-width, 280px));
  transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.cockpit-cell-drawer--open {
  transform: translateX(0);
}

.cockpit-cell-drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px;
  border-bottom: 1px solid var(--color-sandstone);
  flex-shrink: 0;
}

.cockpit-cell-drawer-header h4 {
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 14px;
  font-weight: 600;
  color: var(--color-charcoal, #374151);
  margin: 0;
}

.cockpit-cell-drawer-close {
  /* 44 px touch target per the drawer-family a11y contract. */
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  border-radius: 6px;
  cursor: pointer;
  color: var(--color-charcoal, #374151);
}

.cockpit-cell-drawer-close:hover,
.cockpit-cell-drawer-close:focus-visible {
  background: var(--color-parchment, #F5EDE4);
  outline: 2px solid var(--color-canopy, #2D5F3F);
  outline-offset: -2px;
}

.cockpit-cell-drawer-body {
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.cockpit-cell-drawer-body .cell-drawer-section-title {
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-slate, #5A6B7F);  /* WCAG AA on Parchment — ~4.71:1 vs the failing ~4.17:1 of #6b7280; see commit log for the sweep */
  margin: 0 0 6px 0;
}

.cockpit-cell-drawer-body .cell-drawer-decision-sentence {
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 13px;
  line-height: 1.5;
  color: var(--color-charcoal, #374151);
  margin: 0 0 12px 0;
}

.cockpit-cell-drawer-body .cell-drawer-decision-actions {
  display: flex;
  gap: 8px;
}

.cockpit-cell-drawer-body .cell-drawer-decision-skip,
.cockpit-cell-drawer-body .cell-drawer-decision-keep {
  flex: 1;
}

.cockpit-cell-drawer-body .cell-drawer-neighbors-svg {
  display: block;
  margin: 8px 0;
}

.cockpit-cell-drawer-body .cell-drawer-neighbors-summary {
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 12px;
  line-height: 1.4;
  color: var(--color-slate, #5A6B7F);  /* WCAG AA on Parchment — ~4.71:1 vs the failing ~4.17:1 of #6b7280; see commit log for the sweep */
  margin: 0;
}

.cockpit-cell-drawer-body .cell-drawer-methods-text {
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 12px;
  line-height: 1.5;
  color: var(--color-charcoal, #374151);
  margin: 6px 0 0 0;
}

/* ===========================================================================
   Cockpit FLAGGED CELLS panel + bulk skip-by-category modal.

   Per-category list lives in the left rail; clicking a [Skip N]
   button opens the modal which previews the Methods text dual-
   paths (with-skip vs without-skip) before the user commits.
   The modal is non-dismissable per D15: ESC focuses Cancel
   instead of closing directly, click-outside is not handled.
   The Cancel button is the only path that closes without
   action (Apply / Inspect close after their respective
   commit / drawer-open paths).
   =========================================================================== */

.cockpit-flagged-list {
  list-style: none;
  margin: 0 16px 16px 16px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.cockpit-flagged-item {
  display: flex;
  align-items: center;
  /* Sprint E.1 PR #47 iteration-2 sibling-sweep — wrap-fix
     propagated from ``.cockpit-bucket-item`` per
     ``feedback_ux_design_principles_stunning_polish.md`` §4
     compose-don't-list + §8 family-coherence. The legacy
     flagged-categories rail at the top of the column shares
     the SAME chrome as the bucket entries below; both
     surfaces compose label + count + action inline at
     column widths down to ~220 px. ``flex-wrap: nowrap`` +
     per-child ``min-width: 0`` enables the ellipsis. */
  flex-wrap: nowrap;
  gap: 8px;
  padding: 8px 10px;
  background: var(--color-parchment);
  border: 1px solid var(--color-sandstone);
  border-radius: 6px;
}

.cockpit-flagged-label {
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 12px;
  font-weight: 500;
  color: var(--color-granite-900, var(--color-charcoal, #374151));
  flex: 1 1 auto;
  /* ``min-width: 0`` lets the label shrink inside the flex
     row when the column is narrow, while ``word-break +
     overflow-wrap`` allow the label to span multiple lines
     for long names rather than ellipsing. Per the user's
     iteration-2 verdict, hidden label names are NOT stunning;
     readability beats inline-on-one-line at narrow widths.
     The action button stays right-aligned via ``flex: 1 1
     auto`` on the label; the row simply gets taller. */
  min-width: 0;
  word-break: break-word;
  overflow-wrap: anywhere;
}

.cockpit-flagged-count {
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 11px;
  /* Slate on Parchment is WCAG 2.1 AA-compliant (5.0:1).
     The count label sits inside ``.cockpit-flagged-item``
     which carries a Parchment background, so the slate-
     cousin ``--color-text-muted`` would drop below the
     4.5:1 threshold for normal text. */
  color: var(--color-slate, #5A6B7F);
}

.cockpit-flagged-skip-btn,
.cockpit-flagged-rerun-link {
  font-size: 12px;
  padding: 4px 10px;
}

.cockpit-flagged-rerun-link {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  border: 1px solid var(--color-sandstone);
  border-radius: 6px;
  background: var(--color-white, #ffffff);
  color: var(--color-canopy, #2D5F3F);
}

.cockpit-flagged-rerun-link:hover,
.cockpit-flagged-rerun-link:focus-visible {
  background: var(--color-parchment);
  outline: 2px solid var(--color-canopy, #2D5F3F);
  outline-offset: -2px;
}

/* ============================================================
   Cockpit override panel — Sprint E.1 PR #47 iteration-2.

   The override panel was authored at the HTML + Alpine layer
   in Sprint E.1 AC-E1-8 but its CSS was never written; the
   ``<aside>`` rendered as ``position: static`` block flow at
   the page bottom (empirical Chrome MCP probe by ux-expert
   on Project 3a0d2da3 — clicking the documented-overrides
   button scrolled to a raw form below the cockpit shell).
   This block authors the modal chrome.

   Pattern: the ``<aside class="cockpit-override-panel">``
   becomes the full-viewport positioning surface; a child
   ``<div class="cockpit-override-card">`` frames the form
   contents as a centered card with Bone bg + Sandstone-300
   border + 12 px radius + 16 px shadow. The backdrop sits
   underneath as a separate fixed dim-overlay with a 2 px
   blur. Per ``feedback_ux_design_principles_drawer_family.md``
   the dismiss surface is 3-path (ESC + close-button + click-
   outside-card); the click-outside-card wires through the
   panel's @click handler with @click.stop on the card so
   card-internal clicks do NOT propagate to the dismiss path.
   ============================================================ */

.cockpit-override-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1100;
  background: rgba(31, 41, 55, 0.45);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  pointer-events: auto;
}

.cockpit-override-panel {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1101;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  /* Pointer events route through the panel container so the
     ``@click`` outside-card handler fires on backdrop area
     clicks; the card itself uses ``@click.stop`` to keep
     internal clicks from triggering close. */
  pointer-events: auto;
}

.cockpit-override-card {
  position: relative;
  width: min(560px, 100%);
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  padding: 24px;
  background: var(--color-warm-white, #FAFAF7);
  border: 1px solid var(--color-sandstone-300, var(--color-sandstone, #D6CEC4));
  /* ``--radius-lg`` per the F-G family-rule classification:
     the override card is the primary workspace surface for
     the documented-overrides flow, so the design-system
     token rather than a literal 12 px. */
  border-radius: var(--radius-lg);
  box-shadow: 0 16px 48px rgba(31, 41, 55, 0.18);
  /* The card's own pointer-events stay default so the form
     fields inside are interactive while the @click.stop on
     the card prevents the outside-click handler from
     consuming card-internal clicks. */
}

.cockpit-override-panel-header {
  position: relative;
  margin: 0 0 16px 0;
  padding-right: 36px;
}

.cockpit-override-panel-header h3 {
  margin: 0 0 6px 0;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--color-granite-900, var(--color-charcoal, #374151));
}

.cockpit-override-panel-subtitle {
  margin: 0;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 13px;
  line-height: 1.45;
  color: var(--color-slate, var(--color-slate, #5A6B7F));
}

.cockpit-override-close-btn {
  position: absolute;
  top: 0;
  right: 0;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--color-slate, var(--color-slate, #5A6B7F));
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.cockpit-override-close-btn:hover {
  background: var(--color-sandstone-100, #EFEAE3);
  color: var(--color-granite-900, var(--color-charcoal, #374151));
}

.cockpit-override-close-btn:focus-visible {
  outline: none;
  border-color: var(--color-canopy, #2D5F3F);
  box-shadow: 0 0 0 3px rgba(45, 95, 63, 0.15);
}

.cockpit-override-close-icon {
  width: 18px;
  height: 18px;
  stroke-width: 1.75;
}

/* Form fields inside the override card — Sprint E.1 PR #47
   iteration-2. The cockpit-override-panel-* class names
   stay (existing structural pins reference them); rules
   inherit visual vocabulary from the global ``.form-*``
   family at lines 875-911 so the wizard + cockpit forms
   read as one design-system family. Per durable §6.4 the
   shared ``.form-*`` family is the canonical spec; this
   block extends rather than duplicates. */

.cockpit-override-panel-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.cockpit-override-panel-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.cockpit-override-panel-label {
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 13px;
  font-weight: 600;
  color: var(--color-granite-900, var(--color-charcoal, #374151));
}

.cockpit-override-panel-optional {
  font-weight: 400;
  font-size: 12px;
  color: var(--color-slate, var(--color-slate, #5A6B7F));
}

.cockpit-override-panel-input,
.cockpit-override-panel-select,
.cockpit-override-panel-textarea {
  width: 100%;
  padding: 8px 12px;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-granite-900, var(--color-charcoal, #374151));
  background: var(--color-white, #FFFFFF);
  border: 1px solid var(--color-sandstone, #D6CEC4);
  border-radius: 6px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.cockpit-override-panel-textarea {
  min-height: 96px;
  resize: vertical;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
}

.cockpit-override-panel-input:focus,
.cockpit-override-panel-select:focus,
.cockpit-override-panel-textarea:focus {
  outline: none;
  border-color: var(--color-canopy, #2D5F3F);
  box-shadow: 0 0 0 3px rgba(45, 95, 63, 0.15);
}

.cockpit-override-panel-hint {
  margin: 0;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 12px;
  line-height: 1.4;
  color: var(--color-slate, var(--color-slate, #5A6B7F));
}

.cockpit-override-panel-hint--error {
  color: var(--color-error, var(--color-error-ink));
}

.cockpit-override-panel-zones {
  margin: 0;
  padding: 12px;
  border: 1px solid var(--color-sandstone, #D6CEC4);
  border-radius: 6px;
  background: var(--color-parchment, #F5EDE4);
}

.cockpit-override-panel-legend {
  padding: 0 4px;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 13px;
  font-weight: 600;
  color: var(--color-granite-900, var(--color-charcoal, #374151));
}

.cockpit-override-panel-zones-list {
  list-style: none;
  margin: 8px 0 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.cockpit-override-panel-zone-row {
  margin: 0;
}

.cockpit-override-panel-zone-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 13px;
  color: var(--color-granite-900, var(--color-charcoal, #374151));
  cursor: pointer;
}

.cockpit-override-panel-zone-checkbox {
  width: 16px;
  height: 16px;
  margin: 0;
  cursor: pointer;
}

.cockpit-override-panel-error {
  margin: 0;
  padding: 8px 12px;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 13px;
  color: var(--color-error, var(--color-error-ink));
  background: var(--color-error-tint);
  border: 1px solid var(--color-error-border);
  border-radius: 6px;
}

.cockpit-override-panel-footer {
  display: flex;
  flex-direction: row-reverse;
  align-items: center;
  gap: 12px;
  margin-top: 8px;
}

/* Modal — centered overlay; backdrop carries pointer-events:
   auto (modal IS dismissable via Cancel only, but the
   backdrop must intercept clicks so the page underneath
   can't be clicked through). The modal width respects the
   1024 px laptop floor; max-width caps it at 720 px so a
   wide desktop doesn't stretch the dual-paths preview into
   illegibility. */
.cockpit-bulk-modal-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1100;
  background: rgba(0, 0, 0, 0.45);
  pointer-events: auto;
}

.cockpit-bulk-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1101;
  width: calc(100% - 64px);
  max-width: 720px;
  max-height: calc(100vh - 64px);
  overflow-y: auto;
  background: var(--color-white, #ffffff);
  border: 1px solid var(--color-sandstone);
  /* Transient primary surface — the modal owns user
     attention while open. Same family classification as
     ``.modal-card``. */
  border-radius: var(--radius-lg);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
  display: flex;
  flex-direction: column;
}

.cockpit-bulk-modal-header {
  padding: 16px 20px;
  border-bottom: 1px solid var(--color-sandstone);
}

.cockpit-bulk-modal-header h3 {
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 18px;
  font-weight: 600;
  color: var(--color-charcoal, #374151);
  margin: 0;
}

.cockpit-bulk-modal-body {
  padding: 16px 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.cockpit-bulk-modal-elevation {
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-charcoal, #374151);
  margin: 0;
  padding: 10px 12px;
  background: var(--color-parchment);
  border-left: 3px solid var(--color-canopy, #2D5F3F);
  border-radius: 4px;
}

.cockpit-bulk-modal-methods-preview {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.cockpit-bulk-modal-methods-preview > article {
  padding: 12px;
  background: var(--color-parchment);
  border: 1px solid var(--color-sandstone);
  border-radius: 6px;
}

.cockpit-bulk-modal-methods-heading {
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  /* Per axe-core WCAG 2.1 AA — the prior color
     ``var(--color-text-muted, #6b7280)`` resolved to the
     fallback (no token by that name exists in :root) and
     #6b7280 on the Parchment #F5EDE4 article background
     gives only 4.17 contrast, below the 4.5 normal-text
     bar. ``--color-slate`` (#5A6B7F) is the design system's
     muted-text token; it lands at ~5.5 on Parchment so the
     uppercase heading reads clearly without dropping to
     body-weight charcoal. */
  color: var(--color-slate, #5A6B7F);
  margin: 0 0 6px 0;
}

.cockpit-bulk-modal-methods-text {
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 13px;
  line-height: 1.5;
  color: var(--color-charcoal, #374151);
  margin: 0;
}

.cockpit-bulk-modal-cells {
  border-top: 1px solid var(--color-sandstone);
  padding-top: 12px;
}

.cockpit-bulk-modal-cells-heading {
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-slate, #5A6B7F);  /* WCAG AA on Parchment — ~4.71:1 vs the failing ~4.17:1 of #6b7280; see commit log for the sweep */
  margin: 0 0 8px 0;
}

.cockpit-bulk-modal-cells-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.cockpit-bulk-modal-cell-id {
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 11px;
  color: var(--color-charcoal, #374151);
  background: var(--color-white, #ffffff);
  border: 1px solid var(--color-sandstone);
  border-radius: 4px;
  padding: 2px 6px;
}

.cockpit-bulk-modal-cells-more {
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 12px;
  color: var(--color-slate, #5A6B7F);  /* WCAG AA on Parchment — ~4.71:1 vs the failing ~4.17:1 of #6b7280; see commit log for the sweep */
  margin: 8px 0 0 0;
}

.cockpit-bulk-modal-footer {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  padding: 12px 20px;
  border-top: 1px solid var(--color-sandstone);
}

.cockpit-bulk-modal-cancel.btn-tertiary {
  background: transparent;
  border: 1px solid var(--color-sandstone);
  color: var(--color-charcoal, #374151);
}

.cockpit-bulk-modal-cancel.btn-tertiary:hover,
.cockpit-bulk-modal-cancel.btn-tertiary:focus-visible {
  background: var(--color-parchment);
  outline: 2px solid var(--color-canopy, #2D5F3F);
  outline-offset: -2px;
}

/* ===========================================================================
   F32 cockpit-routing chip on /results/.

   Sage Wash background + amber warning icon + count + Canopy
   arrow per the ux-expert F32 verdict. The chip is
   secondary-weight visually so the cert digest's "Review in
   Validation" understand-path stays as the dual partner.
   The arrow shifts 4 px on hover for a small affordance
   nudge. Focus ring uses the Canopy outline so keyboard
   users see the same visual language as the cert buttons
   above.
   =========================================================================== */

.cert-cockpit-chip {
  /* Full-width band + L/R-split rhythm so the chip matches
     the parent card's other rows (header + ``.cert-digest``
     advisory band). Previously ``inline-flex`` auto-width
     left-aligned, which created a rhythm break visible as
     blank space on the right edge. */
  display: flex;
  width: 100%;
  align-items: center;
  gap: 8px;
  height: 48px;
  padding: 12px 16px;
  margin-top: 12px;
  background: #D4E8DC;
  border-radius: 8px;
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-weight: 500;
  font-size: 14px;
  line-height: 22px;
  color: var(--color-charcoal, #374151);
  text-decoration: none;
  transition: background 150ms ease-in-out, outline-color 150ms ease-in-out;
}

.cert-cockpit-chip:hover {
  outline: 1px solid var(--color-canopy, #2D5F3F);
}

.cert-cockpit-chip:focus-visible {
  outline: 2px solid var(--color-canopy, #2D5F3F);
  outline-offset: 2px;
}

.cert-cockpit-chip-icon-warn {
  color: var(--color-warning);
  flex-shrink: 0;
}

.cert-cockpit-chip-icon-arrow {
  color: var(--color-canopy, #2D5F3F);
  flex-shrink: 0;
  margin-left: 4px;
  transition: transform 150ms ease-in-out;
}

.cert-cockpit-chip:hover .cert-cockpit-chip-icon-arrow {
  transform: translateX(2px);
}

.cert-cockpit-chip-label {
  flex: 1;
}

/* Right-side CTA closes the destination naming gap — the
   arrow alone signals "navigate" but doesn't name where.
   Adding "Open the cockpit" makes the destination explicit
   per Designer Principle 6 honest signals. ``margin-left:
   auto`` was redundant once the label took ``flex: 1`` —
   the CTA naturally sits adjacent to the arrow at the
   right edge. */
.cert-cockpit-chip-cta {
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 14px;
  font-weight: 500;
  color: var(--color-canopy, #2D5F3F);
  white-space: nowrap;
}

/* 768-1199 px — tablet-edge Parchment card. Floor raised 1024
   → 1200 per Sprint E.1 ux-expert revised spec; tablet-defer
   covers everything below the cockpit-shell's 1200 px floor
   so the partition stays exhaustive (no sub-pixel gap). */
@media (width >= 768px) and (width < 1200px) {
  .cockpit-tablet-redirect {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: calc(100vh - var(--nav-height, 56px));
    padding: 32px 24px;
  }

  .cockpit-tablet-card {
    background: var(--color-parchment);
    border: 1px solid var(--color-sandstone);
    /* Primary surface for the tablet viewport band — the
       whole-page graceful-degrade card the user lands on
       when cockpit isn't desktop-fit. Same family
       classification as ``.auth-card``. */
    border-radius: var(--radius-lg);
    padding: 32px;
    max-width: 560px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  }

  .cockpit-tablet-card-title {
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 22px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--color-charcoal, #374151);
    margin: 0 0 12px 0;
  }

  .cockpit-tablet-card-body {
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 15px;
    line-height: 1.5;
    color: var(--color-charcoal, #374151);
    margin: 0 0 16px 0;
  }

  .cockpit-tablet-card-url {
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 13px;
    line-height: 1.5;
    /* Slate on Parchment is WCAG 2.1 AA-compliant (5.0:1)
       where the slate-cousin ``--color-text-muted`` drops
       to 4.17:1 on Parchment. */
    color: var(--color-slate, #5A6B7F);
    margin: 0 0 20px 0;
    word-break: break-all;
  }

  .cockpit-tablet-card-url-label {
    display: block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-slate, #5A6B7F);
    margin-bottom: 4px;
  }

  .cockpit-tablet-card-url code {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: 12px;
    background: var(--color-white, #ffffff);
    border: 1px solid var(--color-sandstone);
    border-radius: 6px;
    padding: 6px 10px;
    display: inline-block;
  }

  .cockpit-tablet-card-actions {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
  }
}

/* Lightweight visual signal that the URL was copied. The button
   keeps its original label; the post-click attribute surfaces a
   tooltip-style indicator without a layout shift. Lives outside
   any media query so the indicator fires on the mobile and
   tablet buttons identically. */
[data-cockpit-copy-url][data-copied="true"]::after {
  content: " checked";
  color: var(--color-canopy, #2D5F3F);
}

/* <=767 px — mobile redirect card per AC-E2 + D17. Mobile band
   carries its own copy ("optional polish" tone) distinct from
   the 768-1023 px tablet-edge card ("best on desktop or
   laptop") so each band addresses its viewers honestly. URL
   preservation per D39: ``cockpit_full_url`` echoes
   ``request.build_absolute_uri()`` exactly, including any
   ``?cell=`` / ``?category=`` deep-link params, so copying on
   phone and pasting on desktop drops the user back at the
   same intended cell. */
@media (width < 768px) {
  .cockpit-mobile-redirect {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: calc(100vh - var(--nav-height, 56px));
    padding: 24px 16px;
  }

  .cockpit-mobile-card {
    background: var(--color-parchment);
    border: 1px solid var(--color-sandstone);
    /* Primary surface for the mobile viewport band —
       same pattern as the tablet card; whole-page
       graceful-degrade. */
    border-radius: var(--radius-lg);
    padding: 24px;
    text-align: left;
    max-width: 480px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  }

  .cockpit-mobile-card-title {
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 20px;
    font-weight: 600;
    line-height: 1.3;
    margin: 0 0 12px 0;
    color: var(--color-charcoal, #374151);
  }

  .cockpit-mobile-card-body {
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 14px;
    line-height: 1.5;
    color: var(--color-charcoal, #374151);
    margin: 0 0 16px 0;
  }

  .cockpit-mobile-card-url {
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 13px;
    line-height: 1.5;
    /* Slate on Parchment is WCAG 2.1 AA-compliant (5.0:1).
       ``--color-text-muted`` would drop to 4.17:1 on
       Parchment and fail the 4.5:1 normal-text threshold. */
    color: var(--color-slate, #5A6B7F);
    margin: 0 0 20px 0;
    word-break: break-all;
  }

  .cockpit-mobile-card-url-label {
    display: block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-slate, #5A6B7F);
    margin-bottom: 4px;
  }

  .cockpit-mobile-card-url code {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    font-size: 12px;
    background: var(--color-white, #ffffff);
    border: 1px solid var(--color-sandstone);
    border-radius: 6px;
    padding: 6px 10px;
    display: inline-block;
    word-break: break-all;
  }

  .cockpit-mobile-card-actions {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 20px;
  }

  /* 44 px tap-target floor for both CTAs per A.6 spec. */
  .cockpit-mobile-card-actions .btn {
    min-height: 44px;
    width: 100%;
    text-align: center;
  }

  .cockpit-mobile-card-honest-signal {
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 13px;
    line-height: 1.5;
    color: var(--color-slate, #5A6B7F);
    margin: 0;
    padding-top: 16px;
    border-top: 1px solid var(--color-sandstone);
  }

  /* Sprint E.1 AC-E1-14 — restricted-secure-context fallback
     hint. Hidden by default; the Copy URL handler stamps
     ``data-clipboard-fallback="manual"`` on the section when
     navigator.clipboard.writeText is unavailable / rejects
     (Safari iOS at non-https, restricted embed contexts), at
     which point the hint becomes visible to walk the user
     through the long-press manual-copy path. */
  .cockpit-mobile-card-clipboard-fallback {
    display: none;
    font-family: var(--font-primary, 'Inter', sans-serif);
    font-size: 13px;
    line-height: 1.5;
    color: var(--color-slate, #5A6B7F);
    margin: 8px 0 0;
    padding: 8px 12px;
    background: var(--color-sandstone, #F0EAE0);
    border-radius: 6px;
  }

  .cockpit-mobile-redirect[data-clipboard-fallback="manual"]
    .cockpit-mobile-card-clipboard-fallback {
    display: block;
  }
}

/* ============================================================
   Cockpit bucket sections — visible chrome per ux-expert
   corrected redesign (Sprint E.1 PR #47 follow-up).

   Buckets are UNFRAMED structural sections, NOT cards. A
   3 px Sandstone left rail is the only chrome at the section
   level (4 px Charcoal-tinted for the Documented-overrides
   variant). This avoids the double-chrome that the prior
   pass introduced when card-on-card nesting put a Sandstone-
   bg bucket frame around Sandstone-bg entry rows. House-
   style has ONE level of card chrome — the entry rows. The
   bucket sits between the column wrapper and the entry
   cards as a structural group, signaled by the rail + count.

   Entry rows (``.cockpit-bucket-item``) mirror the
   ``.cockpit-flagged-item`` reference verbatim: Parchment
   bg + 1 px Sandstone border + 6 px radius + 8/10 px
   padding + flex-row + flex-wrap + 6 px gap. The class is
   the same family, so a refactor that drifts either away
   from the other will fail the parity smell test in code
   review. Buttons in entry rows compose
   ``btn btn-secondary cockpit-flagged-skip-btn`` so the
   one source of truth for skip-button language stays
   centralized.

   Token chains: spec references ``--color-sandstone-300``
   / ``--color-sandstone-100`` / ``--color-granite-*``
   which are not (yet) defined at :root in
   this codebase. Each reference falls back through the
   defined house-style tokens, then to a literal hex / pixel
   value, so the rendering is correct under the current token
   set and forward-compatible if the design system later
   defines the granite/sandstone-shade ladder. Per durable
   §7 + ``feedback_verify_css_tokens.md``: every var(...)
   reference here was diffed against the :root token block
   (lines 14-117) before authoring.
   ============================================================ */

.cockpit-bucket {
  padding-inline-start: 12px;
  border-left: 3px solid var(--color-sandstone-300, var(--color-sandstone, #D6CEC4));
  margin-block-end: 16px;
}

/* Sprint E.1 PR #47 iteration-2 — bucket-type weight ladder.
   The rail thickness + color matches semantic urgency per
   ``feedback_ux_design_principles_stunning_polish.md`` §7
   honest-signals: --info (3 px Sandstone) reads as
   conversational; --exclude (4 px Sage-green) ties the rail
   color to the action button color so the eye reads "this
   bucket TRIGGERS the green Skip-from-analysis button"; -
   -override (5 px Granite-900) reads as consent-stamp
   gravity. Inner content edge stays consistent at ~15 px
   from section's left edge regardless of rail thickness. */
.cockpit-bucket--exclude {
  border-left: 4px solid var(--color-sage-green-500, var(--color-canopy, #2D5F3F));
  padding-inline-start: 11px;
}

.cockpit-bucket--override {
  border-left: 5px solid var(--color-granite-900, var(--color-charcoal, #374151));
  padding-inline-start: 10px;
}

.cockpit-bucket--empty {
  margin-block-end: 12px;
}

.cockpit-bucket--empty .cockpit-bucket-title {
  color: var(--color-muted);
}

/* Sprint E.1 PR #47 iteration-2 — empty-bucket count keeps
   pill structure but drops one shade. The chip stays
   visible (still a real pill per
   ``feedback_ux_design_principles_stunning_polish.md`` §6)
   yet reads as dimmer than the active counts. Granite-700
   on Sandstone-100 = ~7.2:1 contrast, well above the WCAG
   AA 4.5:1 small-text floor; the earlier iteration-1
   contrast bug (Muted on Sandstone-100 = ~4.2:1) is
   structurally avoided. */
.cockpit-bucket--empty .cockpit-bucket-count {
  background: var(--color-sandstone-100, #EFEAE3);
  color: var(--color-granite-700, #4A5568);
  font-weight: 500;
}

.cockpit-bucket-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  min-height: 24px;
}

.cockpit-bucket-title {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  /* Sprint E.1 PR #47 iteration-2 — bucket title bumped to
     14 px / 600 weight / -0.005em letter-spacing per
     ``feedback_ux_design_principles_stunning_polish.md`` §2
     visual hierarchy. Reads as Display-level instead of
     body-level; signals the section's identity rather than
     a row identifier. Granite-900 fallback to Charcoal so
     the contrast stays well above 4.5:1 on the column's
     light backgrounds. */
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.005em;
  text-transform: none;
  color: var(--color-granite-900, var(--color-charcoal, #374151));
}

/* --override gets +100 weight on the title per §7 honest-
   signals — the consent-stamp affordance is the heaviest
   surface in the column. */
.cockpit-bucket--override .cockpit-bucket-title {
  font-weight: 700;
}

.cockpit-bucket-title .lucide {
  /* Icon scales with title (14 → 16 px) so the visual
     proportion stays balanced; stroke-width 1.75 reads as
     research-grade rather than utility-app default (2.0). */
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  stroke-width: 1.75;
}

.cockpit-bucket-count {
  flex-shrink: 0;
  /* Sprint E.1 PR #47 iteration-2 — count chip earns visual
     presence as a real pill component per
     ``feedback_ux_design_principles_stunning_polish.md`` §6.
     Sandstone-200 background (one shade tinted up from -100)
     gives the chip enough fill to read as composed structure
     rather than bare text floating at the right edge. The
     min-width / padding / radius proportions stay; only the
     bg saturation lifts. */
  min-width: 24px;
  padding: 4px 10px;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  text-align: center;
  color: var(--color-granite-900, var(--color-charcoal, #374151));
  background: var(--color-sandstone-200, #E5DBCC);
  border-radius: var(--radius-full, var(--radius-full, 9999px));
}

/* Sprint E.1 PR #47 iteration-2 — empty-state earns presence
   per ``feedback_ux_design_principles_stunning_polish.md`` §5
   ("zero is information, not absence"). The state composes a
   subtle icon + microcopy on a flex row with intentional
   min-height so the empty bucket sits at ~60% of a populated
   bucket's vertical footprint — present enough to affirm the
   workflow shape, dimmer enough to read as zero. The italic
   weight + Granite-blue color earn the de-emphasized read
   without collapsing the section. */
.cockpit-bucket-empty-state {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 52px;
  margin: 8px 0 0 0;
  padding: 4px 0;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
  font-style: italic;
  color: var(--color-slate, var(--color-slate, #5A6B7F));
}

.cockpit-bucket-empty-icon {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  opacity: 0.7;
  stroke-width: 1.5;
}

.cockpit-bucket-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Entry row — composes inline as identity (label) + meta
   (count) + action (button) per
   ``feedback_ux_design_principles_stunning_polish.md`` §4
   compose-don't-list. ``flex-wrap: nowrap`` + per-child
   ``min-width: 0`` + label-truncation lets the row hold all
   three regions on one line at column widths down to
   ~220 px; a long label ellipses rather than dropping the
   action below. Sandstone/Parchment fills mirror the
   ``.cockpit-flagged-item`` reference verbatim so the eye
   reads bucket entries + the refinement queue as one
   family. */
.cockpit-bucket-item {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 8px;
  padding: 8px 10px;
  background: var(--color-parchment, #F5EDE4);
  border: 1px solid var(--color-sandstone, #D6CEC4);
  border-radius: 6px;
}

.cockpit-bucket-item-label {
  flex: 1 1 auto;
  /* ``min-width: 0`` lets the label shrink inside the flex
     row when the column is narrow, but the label TEXT now
     wraps to additional lines instead of ellipsing — per
     user iteration-2 verdict, hidden label names are NOT
     stunning. The label keeps the action button to the
     right via ``flex: 1 1 auto`` while the row simply gets
     taller for long labels. */
  min-width: 0;
  margin: 0;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 12px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--color-granite-900, var(--color-charcoal, #374151));
  word-break: break-word;
  overflow-wrap: anywhere;
}

/* Sprint E.1 PR #47 iteration-4a A5 — when the cell drawer is
   open, the cockpit shell adds a ``has-drawer-open`` class and
   the FLAGGED CELLS column shrinks toward its 240 px floor. At
   that width the wrap behavior trips the original §4 violation
   (label flowing to 3 lines + button wrapping to 2). Tighten:
   nowrap + ellipsis for both bucket-item AND legacy
   flagged-item label rows; keep the action buttons fixed-width
   so the row never grows past one line. The ``title``
   attribute on the label preserves discoverability — hover
   reveals the full string. */
.cockpit-shell.has-drawer-open .cockpit-bucket-item,
.cockpit-shell.has-drawer-open .cockpit-flagged-item {
  flex-wrap: nowrap;
}

.cockpit-shell.has-drawer-open .cockpit-bucket-item-label,
.cockpit-shell.has-drawer-open .cockpit-flagged-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: normal;
  overflow-wrap: normal;
}

.cockpit-shell.has-drawer-open .cockpit-flagged-skip-btn,
.cockpit-shell.has-drawer-open .cockpit-flagged-rerun-link {
  flex-shrink: 0;
  white-space: nowrap;
}

.cockpit-bucket-item-count {
  flex-shrink: 0;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 11px;
  font-weight: 400;
  line-height: 1.4;
  color: var(--color-slate, var(--color-slate, #5A6B7F));
}

/* Bucket 5 affected-zones gloss — same family as item-count
   so the override entry row reads as the same shape as the
   skip / acknowledge variants. */
.cockpit-bucket-item-zones {
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 11px;
  font-weight: 400;
  line-height: 1.4;
  color: var(--color-slate, var(--color-slate, #5A6B7F));
}

/* Sprint E.1 AC-E1-6 — Bucket 2 acknowledge inline chip per
   evaluator counter-add #5. Replaces the bucket row's
   interior on POST 200 OK; carries role="status" so the
   ARIA live region announces the recorded acknowledgment to
   screen readers. The chip stays visible until the user
   navigates away; the bucket count + lineage rail refresh on
   the next render. */
.cockpit-bucket-row-acknowledged-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px;
  font-family: var(--font-primary, 'Inter', sans-serif);
  font-size: 13px;
  line-height: 1.4;
  color: var(--color-canopy, #2D5F3F);
  background: var(--color-success-tint);
  border: 1px solid var(--color-canopy, #2D5F3F);
  /* Pill shape per the F-G eradication contract — chips
     use --radius-full (9999px clamped to half-height by
     the browser) so the boundary stays a true pill across
     viewport widths. */
  border-radius: var(--radius-full);
}

.cockpit-bucket-row-acknowledged-chip::before {
  content: '✓';
  font-weight: 600;
}

/* Sprint E.1 — bucket-3 only carries a subhead because its
   per-row affordance is multi-shaped (Skip vs Re-run with
   fuller sources, depending on the (check_id, platform) pair
   per ``core/cockpit_affordances.py``). The subhead reads as
   a per-bucket gloss to the persona — Aminata reads the
   bucket title + subhead together to know the action surface
   is heterogeneous. Sibling buckets (2 / 4 / 5) carry single-
   affordance imperatives in their headers and do not need the
   subhead. Slate-on-Bone palette per durable lesson #12 (≥
   4.5 contrast).
*/
.cockpit-bucket-subhead {
  /* Top margin raised 4 → 8 px per ux-expert corrected
     redesign so the subhead reads as a separate paragraph
     under the header rather than as a tight caption.
     Granite-blue token resolves to #5A6B7F (= Slate), so the
     contrast / palette read is unchanged from the prior rule. */
  margin: 8px 0 12px 0;
  font-family: var(--font-primary, var(--font-primary, 'Inter', sans-serif));
  font-size: 12px;
  font-weight: 400;
  line-height: 1.45;
  color: var(--color-slate, var(--color-slate, #5A6B7F));
}

/* ============ Outcome banner: chips + Block 2 ============ */
/* Advisory chips: subordinate notices under the cert headline.
   Deep-forest on sandstone measures ~8.4:1 (AA); the dismiss target
   stays >=44px on touch via padding + the mobile rule below. */
.banner-chip-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 10px 0 2px;
}
.banner-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--color-sandstone-100, #F0EBE4);
  border: 1px solid var(--color-sandstone, #D6CEC4);
  border-radius: var(--radius-full);
  padding: 4px 6px 4px 12px;
  font-size: 0.82rem;
  color: var(--color-deep-forest, #1A3A2A);
}
.banner-chip-info {
  width: 13px;
  height: 13px;
  color: var(--color-deep-forest, #1A3A2A);
}
.banner-chip-dismiss {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: none;
  background: transparent;
  border-radius: 50%;
  cursor: pointer;
  color: var(--color-deep-forest, #1A3A2A);
}
.banner-chip-dismiss:hover {
  background: var(--color-sandstone, #D6CEC4);
}
.banner-chip-dismiss i, .banner-chip-dismiss svg {
  width: 13px;
  height: 13px;
}
.banner-access-link {
  font-size: 0.85rem;
  color: var(--color-canopy, #2D5F3F);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Block 2: conditional second block. The cert above paints instantly;
   everything here animates transform/opacity only, so Block 1 never
   shifts (no layout jump). Full rhythm scale: tight 8 / group 12 /
   cert-to-block 16 / block-to-section 32 — the beat gets room to
   settle before the page's data sections begin. */
.banner-block2 {
  margin-top: 16px;
  margin-bottom: 32px;
}
.banner-greendiv-cta {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--color-canopy, #2D5F3F);
  color: var(--color-white, #ffffff);
  border-radius: var(--radius-md);
  padding: 9px 16px;
  font-weight: 600;
  font-size: 0.9rem;
  text-decoration: none;
}
.banner-greendiv-cta:hover {
  background: var(--color-canopy-dark, #1A3A2A);
}

/* The celebration green-div: enters with a gentle rise + fade after the
   cert has painted, plays ONE accent beat on the check icon, then rests
   (no loop — a one-time moment, never perpetual motion). */
.banner-greendiv {
  display: flex;
  align-items: center;
  gap: 14px;
  background: var(--color-decision-acknowledged-fill, #ECF6EF);
  border: 1px solid var(--color-success, var(--color-success));
  border-left-width: 4px;
  border-radius: var(--radius-lg);
  padding: 16px 18px;
  animation: banner-greendiv-enter 400ms ease-out 100ms both;
}
.banner-greendiv-icon {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  color: var(--color-success, var(--color-success));
  animation: banner-greendiv-beat 400ms ease-out 300ms both;
}
.banner-greendiv-lead {
  margin: 0;
  flex: 1;
  color: var(--color-deep-forest, #1A3A2A);
  font-size: 0.95rem;
}
@keyframes banner-greendiv-enter {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes banner-greendiv-beat {
  0%   { opacity: 0; transform: scale(0.6); }
  70%  { opacity: 1; transform: scale(1.12); }
  100% { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .banner-greendiv,
  .banner-greendiv-icon {
    animation: none;
  }
}

/* Mobile 375px: stacked full-width actions; chips wrap to their own
   rows with >=44px dismiss targets; Block 2 goes full-width. */
@media (max-width: 480px) {
  .banner-chip {
    width: 100%;
    justify-content: space-between;
  }
  .banner-chip-dismiss {
    width: 44px;
    height: 44px;
  }
  .banner-greendiv-cta {
    justify-content: center;
    min-height: 44px;
  }
  .banner-greendiv {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* Canonical-count breakdown popover: composition of the one number;
   excluded/estimated render under the "Separately" divider, never
   summed into it. Click/tap toggled (hover styling is enhancement). */
.banner-count-breakdown {
  position: relative;
  display: inline-flex;
  vertical-align: middle;
  margin-left: 6px;
}
.banner-count-breakdown-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: none;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  color: var(--color-muted, #637082);
}
.banner-count-breakdown-btn:hover {
  background: var(--color-sandstone-100, #F0EBE4);
}
.banner-count-breakdown-btn i,
.banner-count-breakdown-btn svg {
  width: 15px;
  height: 15px;
}
.banner-count-breakdown-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 230px;
  padding: 12px 14px;
  background: var(--color-warm-white);
  border: 1px solid var(--color-sandstone, #D6CEC4);
  border-radius: var(--radius-md);
  font-size: 0.82rem;
  font-weight: 400;
  color: var(--color-deep-forest, #1A3A2A);
  text-align: left;
}
.banner-count-breakdown-title {
  font-weight: 600;
}
.banner-count-breakdown-sep {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--color-sandstone, #D6CEC4);
  color: var(--color-muted, #637082);
  font-size: 0.78rem;
}
@media (max-width: 480px) {
  .banner-count-breakdown-btn {
    width: 44px;
    height: 44px;
  }
}

/* Reconciled banner rhythm: the message cluster (headline + sub-copy)
   and the metadata cluster (run-identity label + chips) read as two
   groups — 8px inside a group, 12px between the clusters. */
.cert-headline + .cert-summary {
  margin-top: 8px;
}
.cert-summary + .cert-version {
  margin-top: var(--space-2);
}
.cert-version + .banner-chip-row,
.cert-version + .cert-provenance {
  margin-top: 8px;
}

/* Run identity is metadata, not a sentence: a quiet 13px muted label
   (deep-enough gray for AA at this size on parchment/warm-white). */
.cert-version {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--color-muted, #637082);
}

/* The headline's count tail never wraps apart from its breakdown
   trigger: the line breaks at the em-dash, keeping "N cells worth a
   look (i)" together. */
.cert-headline-tail {
  white-space: nowrap;
}

/* ============================================================
   Execution-progress surface (in-flight run)
   Reuses the prep processing page's bar / header / queue / stage
   classes; only the pieces below are execution-specific.
   ============================================================ */

/* Indeterminate bar: a sliding sliver shown before any real percentage arrives
   and again while a run is stalled — honest motion, never a frozen or
   fabricated fill. When a real percentage is known the template sets an inline
   width instead and this class is removed. */
.progress-bar-fill--indeterminate {
  width: 30%;
  animation: execution-indeterminate 1.4s ease-in-out infinite;
}
@keyframes execution-indeterminate {
  0%   { margin-left: -32%; }
  100% { margin-left: 100%; }
}

.execution-stages {
  margin: var(--space-4, 24px) 0;
}
.execution-stages .stage-card {
  align-items: center;
}
.stage-phase {
  margin-left: var(--space-2, 8px);
  font-size: 0.8125rem;
  color: var(--color-slate, #5A6B7F);
}

.execution-forks {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2, 8px);
  margin-bottom: var(--space-3, 16px);
}
.execution-fork-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 10px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-granite-700, #4E5865);
  background-color: var(--color-sandstone, #D6CEC4);
  border-radius: 999px;
}

.execution-liveness {
  display: flex;
  align-items: center;
  gap: var(--space-2, 8px);
  padding: var(--space-2, 8px) var(--space-3, 16px);
  margin-bottom: var(--space-3, 16px);
  font-size: 0.875rem;
  border-radius: var(--radius-md, 8px);
  color: var(--color-granite-900, #374151);
  background-color: rgba(217, 119, 6, 0.08);
  border: 1px solid var(--color-warning, var(--color-warning));
}

.execution-cancel {
  margin: var(--space-4, 24px) 0 var(--space-3, 16px);
}
.execution-cancelling {
  font-size: 0.875rem;
  color: var(--color-slate, #5A6B7F);
}

/* --- Execution card anatomy + honest, motion-gated polish --- */

/* Center + tighten the stack so the surface doesn't trail into empty space (B4). */
.execution-progress {
  max-width: 640px;
  margin: 0 auto;
}
.execution-stages {
  display: flex;
  flex-direction: column;
  gap: var(--space-2, 8px);
}
.stage-running-body {
  margin-top: var(--space-1, 4px);
}

/* The runner's real (jargon-translated) message line on the running card. */
.stage-message {
  margin: var(--space-1, 4px) 0 0;
  font-size: 0.8125rem;
  color: var(--color-slate, #5A6B7F);
  font-variant-numeric: tabular-nums;
}

/* B1 — a translucent light sweep over the EXISTING determinate fill. It travels
   over the fill and never implies the fill grew; gated on motionAllowed by the
   template (class only present while fresh + connected). */
.progress-bar-fill--live {
  position: relative;
  overflow: hidden;
}
.progress-bar-fill--live::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.45), transparent);
  transform: translateX(-100%);
  animation: progress-sheen 2.5s ease-in-out infinite;
}
@keyframes progress-sheen {
  to { transform: translateX(100%); }
}

/* B2 — the active card lifts off the page (faint blue wash + soft shadow), a
   purely decorative "you are here". */
.execution-stages .stage-card--running {
  background-color: rgba(59, 130, 246, 0.05);
  box-shadow: 0 2px 8px rgba(59, 130, 246, 0.12);
  transform: translateY(-1px);
}

/* B3 — a brief scale-bounce when a stage flips to complete. */
.execution-stages .stage-card--complete .stage-icon {
  animation: stage-complete-pop 200ms ease-out;
}
@keyframes stage-complete-pop {
  0%   { transform: scale(0.7); }
  60%  { transform: scale(1.15); }
  100% { transform: scale(1); }
}

/* Honesty + accessibility: settle every decorative animation for reduced-motion. */
@media (prefers-reduced-motion: reduce) {
  .progress-bar-fill--live::after,
  .progress-bar-fill--indeterminate,
  .execution-stages .stage-card--complete .stage-icon,
  .execution-progress .spin-icon,
  .execution-progress .thread-dot--alive {
    animation: none;
  }
}

/* Standalone error pages (404 / 500). Extracted from the inline blocks so both consume the design tokens; the pages still render usable plain HTML if the stylesheet fails to load. */
.error-body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
.error-nav {
  background-color: var(--color-deep-forest);
  padding: 12px 32px;
}
.error-nav a {
  color: var(--color-white);
  text-decoration: none;
  font-weight: 600;
  font-size: 1.125rem;
  letter-spacing: 0.12em;
}
.error-page {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
  text-align: center;
}
.error-code {
  font-size: 5rem;
  font-weight: 700;
  color: var(--color-sandstone);
  line-height: 1;
  margin-bottom: 8px;
}
.error-heading {
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--color-deep-forest);
  margin-bottom: 12px;
}
.error-message {
  font-size: 1rem;
  color: var(--color-muted);
  max-width: 440px;
  margin-bottom: 32px;
  line-height: 1.6;
}
.error-actions {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
}
.error-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 24px;
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  border-radius: 8px;
  text-decoration: none;
  transition: background-color 0.15s ease;
}
.error-btn--primary {
  background-color: var(--color-canopy);
  color: var(--color-white);
  border: none;
}
.error-btn--primary:hover { background-color: var(--color-canopy-dark); }
.error-btn--secondary {
  background-color: transparent;
  color: var(--color-charcoal);
  border: 1px solid var(--color-sandstone);
}
.error-btn--secondary:hover { background-color: var(--color-parchment); }
.error-footer {
  padding: 16px 32px;
  text-align: center;
  font-size: 0.8125rem;
  color: var(--color-muted);
  border-top: 1px solid var(--color-sandstone);
}

/* ── Run history "My Runs" ────────────────────────────────────────
   Collapsible selection-groups: each group is an accordion whose collapsed
   header is a real summary (count, outcome distribution, engines, pair, latest),
   and whose open body clusters runs by engine and gives every run a distinguishing
   identity. Reuses the library toolbar/header classes + the shared status tokens;
   literal hexes match the approved design mockup where a token has no equivalent. */
.runs-page .mono { font-family: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, monospace; font-variant-numeric: tabular-nums; }
.runs-sort-note { font-size: 0.8125rem; color: var(--color-muted); padding: 0 var(--space-2); white-space: nowrap; }
.runs-list { display: flex; flex-direction: column; gap: var(--space-3); margin-top: var(--space-4); }

/* Collapse-all / Expand-all — local controls styled on the bare <button> element
   (no new component class; the canonical button family stays the SSOT). */
.runs-allctl { display: flex; gap: var(--space-1); align-items: center; margin-left: auto; }
.runs-allctl button { font: inherit; font-size: 0.8125rem; color: var(--color-canopy-dark); background: var(--color-white); border: 1px solid var(--color-sandstone); border-radius: var(--radius-full); padding: 6px 13px; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; transition: background .15s, border-color .15s; }
.runs-allctl button:hover { background: var(--color-sage-green-100, #E0EBE2); border-color: var(--color-sage-wash); }
.runs-allctl button i { width: 15px; height: 15px; }

/* ── group card ── */
.runs-group { border: 1px solid var(--color-sandstone); border-radius: var(--radius-lg); background: var(--color-white); overflow: hidden; box-shadow: 0 1px 2px rgba(31, 45, 35, .03); }

/* header = the accordion trigger (a reset button) */
.runs-group-head { display: flex; align-items: center; gap: var(--space-3); width: 100%; margin: 0; text-align: left; font: inherit; cursor: pointer; background: linear-gradient(180deg, var(--color-sage-green-100, #E0EBE2), var(--color-sage-wash)); color: var(--color-deep-forest); border: none; border-bottom: 1px solid transparent; padding: 13px 18px; }
.runs-group-head:focus-visible { outline: 2px solid var(--color-canopy); outline-offset: -2px; }
.runs-group.is-open .runs-group-head { border-bottom-color: rgba(30, 77, 51, .10); }
.runs-group-layers { color: var(--color-canopy); flex: none; display: inline-flex; }
.runs-group-layers i { width: 19px; height: 19px; }
.runs-group-id { font-size: 0.9375rem; font-weight: 600; color: #1c3326; min-width: 0; }
.runs-group-sep { color: var(--color-canopy); opacity: .5; }
.runs-group-dim { font-weight: 500; color: #3f5a49; }
.runs-group-spring { flex: 1 1 auto; min-width: 8px; }

/* collapsed-and-open summary cluster */
.runs-group-summary { display: flex; align-items: center; gap: 16px; flex: none; }
/* progressive disclosure: the rich summary is the COLLAPSED scan layer; when the group
   is EXPANDED it drops (the rows + notes carry it) and a light latest anchor remains. */
.runs-group.is-open .runs-group-summary { display: none; }
.runs-group-latest-open { display: none; font-size: 0.78rem; color: var(--color-muted); white-space: nowrap; flex: none; }
.runs-group.is-open .runs-group-latest-open { display: inline-flex; align-items: center; }
.runs-group-count { font-size: 0.8125rem; color: #2f4a3a; font-weight: 600; white-space: nowrap; }
.runs-group-count .mono { font-size: 0.84rem; }

/* outcome-distribution mini-chart (a producibility fact, never a yield) */
.runs-dist { display: flex; align-items: center; gap: 9px; }
.runs-distbar { width: 104px; height: 9px; border-radius: var(--radius-full); overflow: hidden; display: flex; background: #dfe7e1; box-shadow: inset 0 0 0 1px rgba(30, 77, 51, .06); }
.runs-distbar i { display: block; height: 100%; }
.runs-seg--ready { background: #2E9E6B; }
.runs-seg--failed { background: #CF4A3C; }
.runs-seg--cancelled { background: #B4BAC2; }
.runs-seg--running { background: #8AA0C8; }
.runs-distlab { font-size: 0.75rem; color: var(--color-muted); white-space: nowrap; display: flex; gap: 8px; }
.runs-distlab s { text-decoration: none; display: inline-flex; align-items: center; gap: 4px; }
.runs-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }
.runs-dot--ready { background: #2E9E6B; }
.runs-dot--failed { background: #CF4A3C; }
.runs-dot--cancelled { background: #B4BAC2; }
.runs-dot--running { background: #8AA0C8; }

/* engine tags + pair / unverified summary markers + latest date (local
   presentational labels, kept off the component-suffix vocabulary) */
.runs-engines { display: flex; gap: 5px; }
.runs-engine { font-size: 0.75rem; font-weight: 600; letter-spacing: .02em; color: var(--color-canopy-dark); background: var(--color-white); border: 1px solid #CFE0D5; padding: 2px 8px; border-radius: var(--radius-full); white-space: nowrap; }
.runs-summary-pair { display: inline-flex; align-items: center; gap: 5px; font-size: 0.75rem; font-weight: 600; color: var(--color-canopy-dark); background: #EAF3ED; border: 1px solid #CFE0D5; padding: 3px 9px; border-radius: var(--radius-full); white-space: nowrap; }
.runs-summary-pair i { width: 13px; height: 13px; }
.runs-summary-unv { display: inline-flex; align-items: center; gap: 5px; font-size: 0.75rem; font-weight: 600; color: #7A6A4E; background: #F3EFE6; border: 1px solid #E4DAC6; padding: 3px 9px; border-radius: var(--radius-full); white-space: nowrap; }
.runs-summary-unv i { width: 13px; height: 13px; }
.runs-latest-date { font-size: 0.78rem; color: var(--color-muted); white-space: nowrap; }

/* chevron + collapsible body (grid-rows height transition, reduced-motion-safe) */
.runs-group-chev { color: var(--color-canopy); flex: none; display: inline-flex; transition: transform .28s cubic-bezier(.4, 0, .2, 1); }
.runs-group-chev i { width: 19px; height: 19px; }
.runs-group.is-open .runs-group-chev { transform: rotate(180deg); }
.runs-group-body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .3s cubic-bezier(.4, 0, .2, 1); }
.runs-group.is-open .runs-group-body { grid-template-rows: 1fr; }
.runs-group-body-inner { overflow: hidden; min-height: 0; }

/* engine cluster divider — re-runs of one engine sit together */
.runs-cluster { display: flex; align-items: center; gap: 10px; padding: 10px 18px 8px; background: #FBFBF8; border-top: 1px solid var(--color-sandstone); }
.runs-cluster-tag { font-size: 0.75rem; font-weight: 700; letter-spacing: .02em; color: var(--color-canopy-dark); display: inline-flex; align-items: center; gap: 6px; }
.runs-cluster-fv { font-weight: 500; color: var(--color-charcoal); }
.runs-cluster-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--color-canopy); }
.runs-cluster-n { font-size: 0.75rem; color: var(--color-muted); }
.runs-cluster-line { flex: 1; height: 1px; background: var(--color-sandstone); opacity: .5; }

/* run row — a two-line identity + a right meta cluster */
.runs-row { display: flex; align-items: center; gap: var(--space-3); padding: 13px 18px 13px 30px; border-top: 1px solid rgba(214, 206, 196, .5); }
.runs-cluster + .runs-row { border-top: none; }
/* a single identity line — engine·family/version only where no cluster header carries
   them; otherwise just the distinguishing run N of M · id (see the row partial). */
.runs-row-idn { display: flex; align-items: center; gap: 9px; min-width: 0; flex-wrap: wrap; font-size: 0.8125rem; }
.runs-row-engine { font-weight: 700; color: var(--color-canopy-dark); }
.runs-row-fv { font-weight: 500; color: var(--color-charcoal); }
.runs-row-ord { font-weight: 600; color: var(--color-charcoal); }
.runs-row-rid { color: var(--color-muted); letter-spacing: .02em; }
.runs-row-sep { color: var(--color-muted); opacity: .6; }
.runs-row-latest { display: inline-flex; align-items: center; font-size: 0.75rem; font-weight: 700; letter-spacing: .04em; color: var(--color-badge-results-fg); background: var(--color-badge-results-bg); padding: 2px 8px; border-radius: var(--radius-full); text-transform: uppercase; }
.runs-row-spring { flex: 1 1 auto; min-width: 8px; }
.runs-row-meta { display: flex; align-items: center; gap: var(--space-3); flex: none; }
.runs-row-time { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; min-width: 96px; }
.runs-row-t { font-size: 0.78rem; color: var(--color-charcoal); font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; }
.runs-row-d { font-size: 0.75rem; color: var(--color-muted); white-space: nowrap; }
.runs-row-actions { flex: 0 0 auto; }
.runs-row-actions .btn { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.runs-row-actions .btn i { width: 14px; height: 14px; }
.runs-row-recover { color: var(--color-terracotta); border-color: #E7D9C4; }
.runs-row-recover:hover { background: #FBF3E7; border-color: #E0CBA8; }

/* within-group truncation ("show all N") */
.runs-hidden-rows { display: none; }
.runs-group.show-all .runs-hidden-rows { display: block; }
.runs-more { border-top: 1px solid var(--color-sandstone); padding: 11px 18px; display: flex; align-items: center; gap: 8px; justify-content: center; flex-wrap: wrap; }
.runs-more button { font: inherit; font-size: 0.8125rem; font-weight: 500; color: var(--color-canopy-dark); background: none; border: none; cursor: pointer; display: inline-flex; align-items: center; gap: 7px; padding: 5px 10px; border-radius: var(--radius-full); }
.runs-more button:hover { background: var(--color-sage-green-100, #E0EBE2); }
.runs-more button i { width: 15px; height: 15px; }
.runs-more-few { display: none; }
.runs-group.show-all .runs-more-show { display: none; }
.runs-group.show-all .runs-more-few { display: inline-flex; }
.runs-more-hint { font-size: 0.75rem; color: var(--color-muted); }

/* pair / lone / unverified note */
.runs-group-note { display: flex; align-items: flex-start; gap: var(--space-2); padding: 11px 18px; font-size: 0.8125rem; border-top: 1px solid var(--color-sandstone); line-height: 1.5; }
.runs-group-note i { width: 16px; height: 16px; flex: none; margin-top: 1px; }
.runs-group-note--pair { color: var(--color-canopy-dark); background: #EAF3ED; font-weight: 500; }
.runs-group-note--pair .btn { margin-left: auto; align-self: center; flex: none; padding: 5px 12px; font-size: 0.8125rem; }
.runs-group-note--pair .btn i { margin-top: 0; }
.runs-group-note--lone { color: var(--color-muted); background: #FBFAF5; }
.runs-group-note--unv { color: #5f5236; background: #F3EFE6; }

/* pick-2 compare: a per-row select box on 3+-run selection groups + the armed "Compare selected" bar.
   The selected row gets a quiet sage wash; the box fills canopy via the native accent-color (real
   checkbox, so keyboard + focus stay native). ``[hidden]`` (0,2,0) outranks ``.btn``'s display. */
.runs-row-pick { display: inline-flex; align-items: center; flex: none; }
.runs-row-pick-cb { width: 16px; height: 16px; cursor: pointer; accent-color: var(--color-canopy, #2D5F3F); }
.runs-row--picked { background: var(--color-sage-green-100, #E0EBE2); }
.runs-pick { flex-wrap: wrap; }
.runs-pick-go[hidden] { display: none; }

.runs-empty { text-align: center; padding: var(--space-7) var(--space-4); color: var(--color-muted); }
.runs-empty p { margin-bottom: var(--space-4); }

@media (max-width: 720px) {
  .runs-group-summary { gap: 10px; }
  .runs-engines, .runs-latest-date { display: none; }
  .runs-distbar { width: 70px; }
  /* Stack the row: identity on top, the meta cluster (badge · time · action)
     full-width below — so the action is never clipped by the group's overflow. */
  .runs-row { flex-wrap: wrap; padding-left: 18px; }
  .runs-row-spring { display: none; }
  .runs-row-idn { flex: 1 1 100%; }
  .runs-row-meta { width: 100%; justify-content: space-between; flex-wrap: wrap; gap: var(--space-2); }
  .runs-row-time { min-width: 0; }
  .runs-row-rid { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .runs-group-body, .runs-group-chev, .runs-allctl button { transition: none; }
}
