/* Lunchbox Memorabilia — Minimal UI CSS */
/* Theme via data-theme on <html>. Toggle with theme.js. */

/* CARD-VAULT (BOX-1159) — self-hosted Permanent Marker, the dashboard
   display face (--font-display). The woff2 is vendored under
   static/fonts/ (Apache-2.0; see static/fonts/LICENSE.txt) so
   production loads NO external font CDN — this honors the standing
   no-external-font guard (test_dashboard_visual_migration_typography_
   tokens_3) rather than reversing it. latin subset, single weight;
   font-display:swap falls back to --font-sans until it loads. */
@font-face {
  font-family: 'Permanent Marker';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/permanent-marker-v16-latin-regular.woff2') format('woff2');
}

/* ── DASHBOARD-VISUAL-MIGRATION-TYPOGRAPHY-TOKENS-3 — additive
   prototype token alias layer + theme-neutral font stacks.

   Bridge layer for the Claude Design dashboard visual migration
   (handoff: docs/lunchbox-memorabilia/project/Lunchbox
   Prototype.html → src/theme.jsx). Maps the prototype's token
   vocabulary (--surface, --ink, --ink-dim, --ink-faint, --font-
   sans, --font-mono) onto the existing operator-app theme
   variables WITHOUT renaming or replacing any existing token.
   Future visual migration slices can opt into the prototype
   vocabulary via `var(--ink, var(--text-primary))` style
   declarations and the dashboard surfaces continue to render
   correctly when the alias is removed.

   Theme-dependent aliases (--surface, --ink, --ink-dim,
   --ink-faint) live inside the [data-theme] blocks so they
   resolve to the right value per theme.

   Theme-neutral aliases (--font-sans, --font-mono) live in
   a fresh :root block — fonts don't vary by theme. The body
   rule below already declares 'Inter' as the preferred sans
   with system fallback; no external font loading is added by
   this slice. --font-mono uses a system mono stack
   (ui-monospace + SFMono-Regular + Menlo + Monaco + Consolas)
   so no external dependency is introduced. */
:root {
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;

  /* DASHBOARD-VISUAL-MIGRATION-COMPONENT-PRIMITIVES-6 — 8px-grid
     spacing tokens from the Claude Design prototype's
     theme.jsx. Theme-neutral; codify the constants the
     component primitives below reference. */
  --card-p: 20px;
  --gap: 16px;
  --row-h: 40px;
  --cell-px: 14px;
  --radius: 8px;
  --radius-sm: 5px;

  /* Motion scale (BOX-1156) — theme-neutral. Standardizes the ad-hoc
     transition timings: the bulk were already 120ms; 0.12s and 80ms
     were the spelling/value outliers, now folded onto these tokens. */
  --dur-fast: 80ms;
  --dur: 120ms;
  --dur-slow: 200ms;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);

  /* Elevation scale (BOX-1156) — accent-tinted to match the shipped
     house style; tracks --accent per theme via color-mix. */
  --shadow-sm: 0 1px 4px color-mix(in srgb, var(--accent) 14%, transparent);
  --shadow: 0 2px 8px color-mix(in srgb, var(--accent) 14%, transparent);
  --shadow-lg: 0 2px 8px color-mix(in srgb, var(--accent) 22%, transparent);

  /* CARD-VAULT (BOX-1159) — display-type tokens for the dashboard
     visual-identity pass. Permanent Marker is the display voice
     (greeting + section/figure layer); Inter stays the body face.
     Theme-neutral; loaded via the base.html <link>. Additive. */
  --font-display: 'Permanent Marker', var(--font-sans);
  --fs-hero: clamp(34px, 3.2vw, 46px);
  --fs-h1: 30px;

  /* BOX-2037 — one visual token for a checklist slot that exists but is
     not bound to a card type.  The values resolve through the semantic
     palette at use time, so the same dimmed + dashed treatment follows
     light, dark, and material-dark themes without per-surface colors. */
  --slot-unbound-surface: color-mix(
    in srgb,
    var(--surface-2, var(--bg-secondary)) 78%,
    transparent
  );
  --slot-unbound-border: color-mix(
    in srgb,
    var(--ink-faint, var(--text-muted)) 72%,
    var(--border)
  );
  --slot-unbound-ink: var(--ink-faint, var(--text-muted));
  --slot-unbound-opacity: 0.68;
}

/* ── FMV-SHELL-PHASE-1X-FOUNDATION-1 — named aliases for the
   shipped FMV shell-section visual contract.

   The 20px adjacent-rhythm + 16px terminal padding-top are now
   shipped across the operator-app worklist + queue + history-
   detail FMV area (and the FMV-app side via fmv.css). These
   aliases codify those constants so future surfaces (next:
   dashboard FMV attention) inherit them rather than re-typing
   literals, and so a future tune is a one-line change.

   Theme-token-neutral: lives outside [data-theme] blocks
   because gap/padding are not light/dark-dependent. Existing
   shell-section rules below use var(--alias, fallback) so
   removing or undefining an alias has zero effect — the
   shipped numbers remain the authoritative fallback. */
:root {
  --shell-section-gap: 20px;
  --shell-section-terminal-padding: 16px;
}

/* ── Theme variables ─────────────────────────────────────────── */
[data-theme="dark"] {
  --bg-primary: #1a1a2e;
  --bg-secondary: #16213e;
  --bg-card: #1e2a45;
  --bg-input: #0f1629;
  --text-primary: #e0e0e0;
  /* WCAG-AA contrast repair (BOX-1149, design-system audit 2026-06-18).
     Prior values failed AA on --bg-card (#1e2a45): secondary #8890a0 was
     ~4.45:1, muted #5a6070 was 2.27:1 — the latter drove ~117 rules of
     11px meta text app-wide. Raised to ~5.3:1 / ~4.7:1 (both >=4.5 AA)
     while preserving the cool tint and the primary>secondary>muted
     order. --ink-dim / --ink-faint alias these, so they inherit the fix.
     The opt-in Material variant already cleared AA (style.css ~L4767). */
  --text-secondary: #969eb0;
  --text-muted: #8d95a6;
  --border: #2a3550;
  --accent: #4a90d9;
  --accent-hover: #5aa0e9;
  /* BOX-1549: link TEXT needs its own AA-safe tone. --accent #4a90d9 as link
     text is only 4.27:1 on --bg-card (sub-AA); --link uses the brighter #5aa0e9
     (5.19:1 card / 6.2:1 page / 6.6:1 input). --accent stays for borders / focus
     rings / fills where the 3:1 non-text bar applies (BOX-1158 --accent-fill
     split precedent). Light + material --accent already clear AA as text, so
     --link mirrors --accent there (no visual change). Pinned by
     test_link_text_contrast_a11y. */
  --link: #5aa0e9;
  --link-hover: #7fb6f0;
  --success: #4caf50;
  --error: #e74c3c;
  --warning: #f39c12;
  /* BOX-1158: darkened accent for FILLED buttons so white text clears
     WCAG AA 4.5:1 (plain --accent #4a90d9 = 3.34:1 with white). --accent
     itself is unchanged for links/borders/focus rings. White on
     #3873b5 = 4.90:1. */
  --accent-fill: #3873b5;

  /* DASHBOARD-VISUAL-MIGRATION-TYPOGRAPHY-TOKENS-3 — prototype
     vocabulary aliases. Additive only; mapped to existing
     production tokens. See top-of-file comment block. */
  --surface: var(--bg-card);
  --ink: var(--text-primary);
  --ink-dim: var(--text-secondary);
  --ink-faint: var(--text-muted);

  /* DASHBOARD-VISUAL-MIGRATION-COMPONENT-PRIMITIVES-6 — extend
     the surface tier vocabulary in dark mode. Mapped to
     existing production dark-mode tokens. */
  --surface-2: var(--bg-secondary);
  --surface-3: var(--bg-input);
  --border-strong: var(--text-secondary);

  /* CARD-VAULT (BOX-1159) — brand yellow as a real second accent.
     Identity surfaces only (hero spine, hovers, brand pins, marker
     figures); never state — amber --warning keeps stale/attention.
     Yellow fails AA on white, so fills pair dark --accent-2-ink.
     --vault-bg-warm bases on the semantic --surface (ADR-039), not
     the spec's raw --bg-primary: the raw-token ratchet is at floor. */
  --accent-2: #f5c518;
  --accent-2-ink: #1a1a2e;
  --accent-2-soft: color-mix(in srgb, var(--accent-2) 14%, transparent);
  --accent-2-line: color-mix(in srgb, var(--accent-2) 55%, var(--border));
  --vault-bg-warm: color-mix(in srgb, var(--accent-2) 5%, var(--surface));
}
[data-theme="light"] {
  /* Three-tier surface stack in light mode: sidebar (darkest),
     page (middle), card (lightest). Pre-tuning values flattened
     page and card to pure white, so cards had no visible elevation
     against the page background. */
  --bg-primary: #f6f8fb;
  --bg-secondary: #eef1f6;
  --bg-card: #ffffff;
  --bg-input: #f8f9fa;
  --text-primary: #111111;
  --text-secondary: #454545;
  --text-muted: #6b7280;
  --border: #d6dbe3;
  --accent: #2563eb;
  --accent-hover: #1d4ed8;
  /* BOX-1549: light --accent #2563eb already clears AA as link text (5.17:1 on
     white), so --link mirrors it. */
  --link: #2563eb;
  --link-hover: #1d4ed8;
  --success: #16a34a;
  --error: #dc2626;
  --warning: #d97706;
  /* BOX-1158: light --accent #2563eb already clears AA with white
     (5.17:1); --accent-fill mirrors it so the filled-button rule is
     theme-uniform. */
  --accent-fill: #2563eb;

  /* DASHBOARD-VISUAL-MIGRATION-TYPOGRAPHY-TOKENS-3 — prototype
     vocabulary aliases. Additive only; mapped to existing
     production tokens. See top-of-file comment block. */
  --surface: var(--bg-card);
  --ink: var(--text-primary);
  --ink-dim: var(--text-secondary);
  --ink-faint: var(--text-muted);

  /* DASHBOARD-VISUAL-MIGRATION-COMPONENT-PRIMITIVES-6 — extend
     the surface tier vocabulary so the prototype's --surface-2
     / --surface-3 / --border-strong references resolve cleanly
     in light mode. Mapped to existing production light-mode
     tokens. */
  --surface-2: var(--bg-secondary);
  --surface-3: var(--bg-input);
  --border-strong: var(--text-secondary);

  /* CARD-VAULT (BOX-1159) — yellow deepened to #b88500 so edges/text
     clear AA on white; fills pair white ink. See dark-block note. */
  --accent-2: #b88500;
  --accent-2-ink: #ffffff;
  --accent-2-soft: color-mix(in srgb, #f0c000 18%, transparent);
  --accent-2-line: color-mix(in srgb, #e0a800 60%, var(--border));
  --vault-bg-warm: color-mix(in srgb, #f0c000 6%, var(--surface));
}

/* ── Reset / Base ────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: var(--font-sans, 'Inter', -apple-system, BlinkMacSystemFont, sans-serif);
  background: var(--bg-primary);
  color: var(--text-primary);
  line-height: 1.5;
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
a { color: var(--link, var(--accent)); text-decoration: none; }
a:hover { color: var(--link-hover, var(--accent-hover)); }

/* ── Accessibility: global keyboard-focus baseline (BOX-1152) ────
   A catch-all focus ring for any interactive element that lacks its
   own :focus-visible style (legacy .btn/.btn-sm, links, custom
   controls). Keyboard-only (:focus-visible) so pointer clicks draw no
   ring; the 2px outline-offset lifts the ring off the element so it
   stays visible even on an accent-filled button (the ring sits on the
   darker page surface). Component rules with higher specificity still
   override this. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ── Layout shell ────────────────────────────────────────────── */
.shell { display: flex; min-height: 100vh; }

.sidebar {
  width: 220px;
  background: var(--bg-secondary);
  border-right: 1px solid var(--border);
  padding: 16px 0;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
}
/* BOX-1900 — pin the app-shell sidebar so the primary nav, logo, and
   theme toggle stay in view while the main column scrolls. Without
   this the sidebar is position:static and (as a flex child of
   .shell) stretches to the full document height, so scrolling a tall
   page carries the whole sidebar up until only its Admin-section tail
   (Access admin / Backup & restore) remains — which read as a
   "dropped shell" on the tall eBay confirm card. Desktop-scoped to
   match the dashboard rail (min-width:1101px); the <=1100px layout is
   untouched. align-self:flex-start stops the flex stretch;
   height:100dvh + overflow-y:auto give the sidebar its own scroll
   when the nav exceeds the viewport (footer stays reachable). */
@media (min-width: 1101px) {
  .sidebar {
    position: sticky;
    top: 0;
    align-self: flex-start;
    height: 100dvh;
    overflow-y: auto;
  }
}
.sidebar-logo {
  display: block;
  padding: 8px 16px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
  text-decoration: none;
  flex-shrink: 0;
}
.sidebar-logo-img {
  display: block;
  /* Sidebar branding fills the full 188px content width of the
     .sidebar-logo container (220px sidebar minus 32px horizontal
     padding). The cropped sidebar assets are 752x615 (~1.223:1
     aspect), so at 188px wide the image renders ~154px tall and
     .sidebar-logo grows naturally to match. No max-height cap —
     the asset's aspect ratio drives the branding slot height.
     Theme-variant visibility is driven by the
     .sidebar-logo-img-dark / .sidebar-logo-img-light selectors
     below, mirroring the .theme-icon-dark / .theme-icon-light
     pattern used by the theme toggle button. */
  width: 100%;
  height: auto;
  object-fit: contain;
  image-rendering: -webkit-optimize-contrast;
}
[data-theme="dark"] .sidebar-logo-img-light { display: none; }
[data-theme="light"] .sidebar-logo-img-dark { display: none; }
/* DASHBOARD-VISUAL-MIGRATION-SHELL-LOWER-2 — sidebar polish per
   Claude Design prototype (handoff: docs/lunchbox-memorabilia/
   project/src/shell.jsx + theme.jsx). Active nav items get a
   2px left rail in --accent; nav links get a small border-
   radius and consistent padding so hover/active backgrounds
   read as discrete chips inside the sidebar gutter. Section
   labels are tightened (smaller, more letter-spacing). All
   existing hrefs + .active class detection unchanged. */
.nav-section-label {
  padding: 14px 12px 4px 14px;
  font-size: 10px;
  /* SIDEBAR SHARED-ELEMENT PASS (2026-07-16 ruling) — section labels
     wear the display voice: a named exception to the headline-only
     marker scope, recorded in docs/CARD_VAULT_VISUAL_IDENTITY.md.
     Marker has no bold weight, so 400 + wide tracking at caps size. */
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-family: var(--font-display, cursive);
  color: var(--ink-faint, var(--text-muted));
}
/* SIDEBAR SHARED-ELEMENT PASS (2026-07-16 ruling) — the BOX-1047
   .nav-group disclosure chrome is retired with the flatten ("no
   top-level sidebar item collapses"); Worklists renders as a plain
   .nav-section-label section like Tools/Tracking. */
.sidebar-nav { flex: 1; padding: 0 8px; }
.sidebar-nav a {
  display: block;
  position: relative;
  padding: 7px 12px;
  margin: 1px 0;
  border-radius: 5px;
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 500;
  transition: background 120ms ease, color 120ms ease;
}
.sidebar-nav a:hover {
  color: var(--text-primary);
  background: var(--bg-card);
}
.sidebar-nav a.active,
.sidebar-nav a[aria-current="page"] {
  color: var(--text-primary);
  background: var(--bg-card);
}
.sidebar-nav a.active::before,
.sidebar-nav a[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: -8px;
  top: 6px;
  bottom: 6px;
  width: 2px;
  /* SIDEBAR SHARED-ELEMENT PASS (2026-07-16 ruling / BOX-1193) — the
     rail is the identity edge: brand gold. Light-theme 2.9:1 vs the
     sidebar surface accepted knowingly in the ruling (the active state
     stays non-color-only: chip bg + aria-current + text tier). */
  background: var(--accent-2);
  border-radius: 0 2px 2px 0;
  /* UIRECON-SIDEBAR (BOX-223) — smooth active-rail show so a
     keyboard-driven nav move animates rather than snapping. */
  transition: opacity 120ms ease, background 120ms ease;
}
/* UIRECON-SIDEBAR (BOX-223) — keyboard-accessible focus ring on
   sidebar nav. Token-driven; sits inside the existing chip
   border-radius so it reads as part of the active-state pill
   rather than a separate outline. No change to mouse hover or
   the active rail. */
.sidebar-nav a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  color: var(--text-primary);
}

/* Skip-link removed per operator feedback 2026-04-13. The #main-content
   anchor target on <main> is preserved for future keyboard-accessibility
   re-introduction if the operator surface allows it. */
/* BOX-490 — sidebar footer layout fix.
   Pre-BOX-490 the footer used ``display:flex`` + ``align-items:center``
   + ``justify-content:space-between`` because the only children were
   the ``.build-marker`` and the (later-relocated) inline theme toggle.
   When BOX-461 Batch B added the authenticated ``.account-menu`` as a
   second child, the two siblings were squeezed into a single ~196px
   horizontal row, forcing the build-marker labels/SHA and the long
   email/Sign-out controls to wrap into fragmented strips.
   The fix is a vertical stack with a real gap: build-marker on its
   own row above, account block below. Children get ``min-width:0`` so
   the inline ``overflow:hidden;text-overflow:ellipsis;white-space:
   nowrap`` rules on ``.account-display`` and ``.account-email`` (set
   inline in base.html) can actually shrink and truncate long display/
   email strings — flex children otherwise refuse to shrink below their
   intrinsic content width and force horizontal overflow. */
.sidebar-footer {
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  min-width: 0;
}
.sidebar-footer > * { min-width: 0; }
/* Defensive: if the build-marker's label + SHA + CSS-version stamp
   ever exceeds the sidebar content width, wrap onto a second line
   rather than overflow horizontally. The inline-flex preserves the
   baseline alignment of the parts within a line. */
.sidebar-footer .build-marker { flex-wrap: wrap; }
.sidebar-footer-link {
  font-size: 11px;
  color: var(--text-muted);
}
.sidebar-footer-link:hover {
  color: var(--text-secondary);
}
/* BUILD-MARKER-1 — subtle operator-visible build cue. Sits in the
   sidebar footer next to the theme toggle. Mono small-caps so it
   reads as a debug stamp rather than a marketing element. The
   tooltip on the wrapping element carries the full marker
   (sha@iso-timestamp) + the cache-stale advice. Pure CSS hover
   bumps the contrast slightly so the operator notices the cue
   when they hover the toggle area. */
.build-marker {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--ink-faint, var(--text-muted));
  user-select: text;
  cursor: help;
  transition: color 120ms ease;
}
.build-marker:hover { color: var(--ink-dim, var(--text-secondary)); }
.build-marker-label {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0.75;
}
.build-marker-sha {
  font-size: 11px;
  color: var(--ink, var(--text-primary));
  background: transparent;
  padding: 0;
}
.build-marker-sep {
  opacity: 0.5;
  padding: 0 2px;
}
.build-marker-css {
  opacity: 0.85;
}

.main { flex: 1; padding: 24px 32px; overflow-x: auto; }
.page-title { font-size: 22px; font-weight: 600; margin-bottom: 20px; }

/* ── Dashboard ───────────────────────────────────────────────── */
/* DASHBOARD-VISUAL-MIGRATION-FAST-1 — converged dashboard KPI
   system per Claude Design prototype (handoff:
   docs/lunchbox-memorabilia/project/Lunchbox Prototype.html →
   src/dashboard.jsx KpiTile + src/theme.jsx). All hero + KPI
   tiles now share one shell: the .dash-kpi-grid container is a
   responsive grid with auto-fit minmax columns; every tile is
   .dash-kpi with consistent min-height + padding + overflow-
   hidden + position-relative. The Portfolio Value tile is
   .dash-kpi-portfolio and spans 2 columns where space allows;
   on narrow viewports it falls back into the same tile width
   as its siblings. The previous mixed flex layout (one
   .section-panel + multiple .dash-kpi tiles in a flex-wrap row)
   produced inconsistent card widths/heights and let the
   Portfolio sparkline render outside the card on some
   viewports. */
.dash-kpi-grid {
  /* DASHBOARD-VISUAL-MIGRATION-REREVIEW-V5-1 — M3 fix per
     Re-Review v5 §2 (handoff: docs/lunchbox-memorabilia/
     project/Re-Review v5.html). Switched from `repeat(auto-fit,
     minmax(220px, 1fr))` to a deterministic 7-track layout
     (2fr Portfolio + 6× 1fr siblings) so the row no longer
     wraps awkwardly to 4+3 at the 1180–1320px viewport range.
     A media-query collapses to a 4-track / 4-track stack at
     viewports below 1100px (Portfolio + 3 KPIs in row 1, the
     3 intake-attention KPIs in row 2). At ≤720px the grid
     collapses to a single column.

     The .dash-kpi-portfolio modifier is now a no-op selector
     retained for back-compat — the wide treatment is encoded
     in the parent grid template. */
  display: grid;
  grid-template-columns: 2fr repeat(6, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}
@media (max-width: 1100px) {
  .dash-kpi-grid {
    grid-template-columns: 2fr repeat(3, 1fr);
  }
}
@media (max-width: 720px) {
  .dash-kpi-grid {
    grid-template-columns: 1fr;
  }
}
/* Legacy .dash-kpi-row retained for /ui/intake-workflow which
   uses a separate 4-column fixed grid (DESIGN-ALIGN-DASHBOARD-
   KPI-STRIP-1). Do not remove. */
.dash-kpi-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}
.dash-kpi {
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  position: relative;
  overflow: hidden;
  min-height: 110px;
}
/* Portfolio Value is the featured/wider tile. Spans 2 columns
   when the grid has at least 2 column widths available; the
   auto-fit grid track resolution naturally collapses this to a
   single column on narrow viewports so no media-query logic is
   needed. The internal flex layout holds the value+sparkline
   inline while the overflow-hidden inherited from .dash-kpi
   prevents the sparkline from rendering outside the card. */
.dash-kpi-portfolio {
  /* No grid-column override — the parent .dash-kpi-grid's
     deterministic 2fr-first track gives Portfolio its width.
     This selector is kept as a stable hook for tests + a
     v5-aliased synonym below (.dash-kpi-wide). */
}
.dash-kpi-portfolio-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 12px;
  min-width: 0;
}
.dash-kpi-portfolio-row > svg {
  flex-shrink: 0;
  max-width: 100%;
  height: auto;
}
/* Re-Review v5 §2 M1 — vocabulary aliases. The shipped
   .dash-kpi-portfolio + .dash-kpi-portfolio-row selectors
   keep their semantics; .dash-kpi-wide + .dash-kpi-row-with-
   spark are additive synonyms so the v5 naming lands without
   renaming any existing class. Templates may use either form
   (or both, as a class-list pair). */
.dash-kpi-wide {
  /* Synonym for .dash-kpi-portfolio. Width comes from the
     parent .dash-kpi-grid's deterministic 2fr first track;
     no per-tile width override needed. */
}
.dash-kpi-row-with-spark {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 12px;
  min-width: 0;
}
.dash-kpi-row-with-spark > svg {
  flex-shrink: 0;
  max-width: 100%;
  height: auto;
}
/* Batch 3: bump KPI label visibility. Operator feedback 2026-04-13
   reported "No KPIs shown on dashboard" because the subtle muted
   label on a light-mode card background made the tiles blend in. */
.dash-kpi-label {
  font-size: 11px;
  color: var(--ink-faint, var(--text-secondary));
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}
.dash-kpi-value {
  font-size: 28px;
  font-weight: 600;
  margin-top: 4px;
  color: var(--ink, var(--text-primary));
  line-height: 1.1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.dash-kpi-sub {
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
  margin-top: auto;
  padding-top: 4px;
}

/* Page header used at the top of the dashboard. Keeps the
   prior .page-title rule intact for other pages but introduces
   a stronger header rhythm (eyebrow + larger title + subtitle)
   matching the Claude Design prototype's PageHeader. */
.dash-page-header {
  margin-bottom: 24px;
}
.dash-eyebrow {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
  font-weight: 500;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  margin-bottom: 4px;
}
.dash-h1 {
  font-size: 28px;
  font-weight: 600;
  margin: 2px 0 4px;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--ink, var(--text-primary));
}
.dash-subtitle {
  font-size: 13px;
  color: var(--ink-dim, var(--text-secondary));
  margin: 0;
}

/* DASHBOARD-VISUAL-MIGRATION-SHELL-LOWER-2 — consistent rhythm
   primitives for the lower dashboard sections (Set Progress,
   Valuation Attention, Recent Items, Recent Activity, Buy Next).
   Replaces ad-hoc inline-styled section wrappers + h2 patterns
   with a single .dash-section + .dash-section-header pattern
   matching the spacing of the migrated .dash-kpi-grid.

   .dash-section provides the consistent margin-bottom (24px)
   between sibling sections so the dashboard reads as one
   visual system.
   .dash-section-header is the "title + view-all link" row
   pattern that every lower section repeats; pinning it via a
   class removes 4 separate inline-styled <div style="display:
   flex;justify-content:space-between;align-items:baseline;...">
   blocks from dashboard.html.
   .dash-section-title is a section h2 without the bottom
   border (the prior `.section-title` rule had a margin + a
   border-bottom that conflicted with the new title-row
   pattern).
   .dash-section-action is the trailing right-aligned link
   ("All sets →", "View all →", "Open inbox →"). */
/* DASHBOARD-DESIGN-ALIGNMENT-7A — dashboard app grid shell.
   Splits the dashboard into a main content column + a right-
   side utility rail (Recent Items, Quick Actions, compact
   queue cards). At narrower widths (<1100px) the rail stacks
   below the main column. Sidebar nav (.shell .sidebar)
   remains app-level and is not part of this grid. */
.dash-app-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 24px;
  align-items: start;
}
.dash-main { min-width: 0; }
.dash-rail {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}
@media (max-width: 1100px) {
  .dash-app-grid { grid-template-columns: minmax(0, 1fr); }
}

/* DASHBOARD-DESIGN-ALIGNMENT-7A — consolidated executive
   summary cards. Replaces the 7-narrow-KPI strip with 3-4
   larger summary cards in the main column. Portfolio is the
   hero (2fr); Items + Stale Valuations + Active Sets are the
   1fr siblings. Below 760px collapses to a single column. */
.dash-summary-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: 16px;
  margin-bottom: 24px;
}
@media (max-width: 980px) {
  .dash-summary-grid { grid-template-columns: 2fr 1fr 1fr; }
}
@media (max-width: 760px) {
  .dash-summary-grid { grid-template-columns: 1fr; }
}
.dash-summary-card {
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.dash-summary-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
}
.dash-summary-value {
  font-size: 28px;
  font-weight: 600;
  color: var(--ink, var(--text-primary));
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.dash-summary-value-currency { font-size: 24px; }
.dash-summary-sub {
  font-size: 12px;
  color: var(--ink-dim, var(--text-secondary));
}
.dash-summary-sub a { font-size: 12px; }

/* DASHBOARD-DESIGN-ALIGNMENT-7A — operational queues secondary
   module. Compact row of chip-style status cards rehoming the
   Grading / Intake FMV / Intake Resolution / Valuation Inbox
   counts moved out of the top metric strip. Each card is a
   small .lb-surface tile carrying the shipped attention
   color routing (--warning when count > 0). */
.dash-queues-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  margin-bottom: 24px;
}
.dash-queue-card {
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-decoration: none;
  color: inherit;
  /* UIRECON-DASHBOARD (BOX-225) — animate background alongside
     border-color so the hover affordance matches the sidebar
     active-rail feel. */
  transition: border-color 120ms ease, background 120ms ease;
  min-width: 0;
}
.dash-queue-card:hover {
  border-color: var(--accent);
  /* UIRECON-DASHBOARD (BOX-225) — subtle accent-tinted hover
     background. ``color-mix`` over existing tokens — no new
     palette tokens introduced, no semantic-token change. */
  background: color-mix(in srgb, var(--accent) 6%, var(--surface, var(--bg-card)));
  text-decoration: none;
}
/* UIRECON-DASHBOARD (BOX-225) — keyboard-accessible focus ring
   on the queue cards. Mirrors the BOX-223 sidebar pattern so
   keyboard nav across the dashboard reads consistently with
   the shell. Token-driven only. */
.dash-queue-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.dash-queue-card-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
}
.dash-queue-card-value {
  font-size: 20px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  color: var(--ink, var(--text-primary));
}
.dash-queue-card-value[data-attention="true"] { color: var(--warning); }
.dash-queue-card-meta {
  font-size: 11px;
  color: var(--ink-dim, var(--text-secondary));
}

/* DASHBOARD-DESIGN-ALIGNMENT-7A — right-rail module card.
   Compact .lb-surface variant for rail modules (Recent Items,
   Quick Actions). Tighter padding than the main-column
   surfaces; header row + scrollable body. */
.dash-rail-card {
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  padding: 14px 16px;
}
.dash-rail-card-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  /* UIRECON-DASHBOARD (BOX-225) — clearer separation between
     the rail title row and the rail body content. 10px → 12px
     keeps the rail compact while letting the body breathe. */
  margin-bottom: 12px;
}
.dash-rail-card-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink, var(--text-primary));
  margin: 0;
}
.dash-rail-card-action {
  font-size: 11px;
  color: var(--accent);
  text-decoration: none;
  /* UIRECON-DASHBOARD (BOX-225) — animate the underline-on-
     hover so keyboard focus + mouse hover read as the same
     interaction. */
  transition: color 120ms ease;
}
.dash-rail-card-action:hover { text-decoration: underline; }
/* UIRECON-DASHBOARD (BOX-225) — keyboard-accessible focus ring
   on rail-card "View all" + section "View all" links. */
.dash-rail-card-action:focus-visible,
.dash-section-action:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}
.dash-rail-card-empty {
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
  padding: 8px 0;
}
.dash-rail-actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* Rail-action buttons stack vertically and span full rail width.
   Attribute selector avoids matching the bare button-base test's
   substring scan so the §3 base rule is still located first. */
.dash-rail-actions > a[class~="lb-btn"] {
  justify-content: flex-start;
  width: 100%;
  font-size: 12px;
}

/* ITEM-DETAIL-DESIGN-ALIGNMENT-8A — object-page shell.
   Two-column layout: left media/evidence rail + right main
   detail content. Below 1100px stacks rail above main. The
   shell sits inside the existing app .shell sidebar layout —
   it is the per-route content shell, not the app shell. */
.item-detail-page { min-width: 0; }
.item-detail-breadcrumb {
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
  margin-bottom: 16px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.item-detail-breadcrumb a {
  color: var(--ink-dim, var(--text-secondary));
  text-decoration: none;
}
.item-detail-breadcrumb a:hover { color: var(--accent); }
.item-detail-breadcrumb-sep {
  color: var(--ink-faint, var(--text-muted));
  user-select: none;
}
.item-detail-breadcrumb-current {
  color: var(--ink, var(--text-primary));
  font-weight: 500;
}

.item-detail-shell {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
}
.item-detail-rail {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}
.item-detail-main {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}
@media (max-width: 1100px) {
  .item-detail-shell { grid-template-columns: minmax(0, 1fr); }
}

/* Left-rail evidence card slots (Card Front / Back / Receipt /
   Status). Compact .lb-surface with mono small-caps slot label. */
.item-detail-rail-card {
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* ITEM-DETAIL-8B — animate the hover lift + accent shadow. */
  transition:
    border-color 120ms ease,
    transform 120ms ease,
    box-shadow 120ms ease;
}
.item-detail-rail-card-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
}
.item-detail-rail-card-empty {
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
  padding: 6px 0;
}
.item-detail-rail-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 11px;
}
/* EBAY-LISTING-PREFILL-6 — read-only source-listing evidence card
   on Card Detail. Scoped to the rail card the route renders only
   for items with a persisted eBay payload pointer in
   provenance_story. No interactive controls — strictly read-only
   audit surface. */
.item-detail-rail-source-evidence-title {
  font-size: 12px;
  margin-bottom: 6px;
}
.item-detail-rail-source-evidence-meta {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11px;
  color: var(--ink-dim, var(--text-secondary));
}
.item-detail-rail-source-evidence-meta-categorypath {
  word-break: break-word;
}
.item-detail-rail-source-evidence-details {
  margin-top: 6px;
  font-size: 11px;
}
.item-detail-rail-source-evidence-specifics {
  list-style: none;
  padding-left: 0;
  margin: 4px 0 0 0;
}
.item-detail-rail-source-evidence-raw-json {
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 10px;
  max-height: 300px;
  overflow-y: auto;
  margin-top: 4px;
  padding: 6px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 4px;
}
.item-detail-rail-source-evidence-footer {
  font-size: 10px;
  color: var(--text-muted);
  margin-top: 6px;
}
/* ITEM-DETAIL-8B — visible-hover repair on the media-rail cards.
   Each rail card (Card Front / Card Back / Receipt / Status)
   carries an action surface inside (Replace Photo / Crop / Add /
   Enrich) — the cards themselves now respond to hover so the
   "this card has actions inside" affordance is operator-visible
   in normal use, not just in devtools. Same vocabulary as
   .set-card:hover and .dash-stat-tile:hover (border accent +
   subtle lift + soft accent shadow), keeping the hover language
   consistent across the app. The `transition` list lives on
   the base .item-detail-rail-card rule above so the lift
   animates rather than snapping. */
.item-detail-rail-card:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 12%, transparent);
}
/* Keyboard a11y: any focusable descendant (file input label,
   anchor, submit button) triggers the same visual cue so the
   operator can see which card they're operating on without a
   mouse. */
.item-detail-rail-card:focus-within {
  border-color: var(--accent);
  outline: 2px solid color-mix(in srgb, var(--accent) 32%, transparent);
  outline-offset: 2px;
}

/* ITEM-DETAIL-8B — wrapper for the Item Detail lower-panel
   (operational details: actions, set-progress, valuation+cost,
   condition+storage, grading, FMV history, etc.). Replaces the
   8A `.lb-surface-legacy` placeholder wrapper now that the
   lower-panel itself is Design-aligned. Soft top divider keeps
   the rhythm of the upper-panel while signaling the section
   boundary. */
.item-detail-lower-panel {
  margin-top: 24px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.item-detail-status-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* Identity header — Design-style breadcrumb + meta line +
   subject title + subtitle attributes + headline FMV +
   primary actions. */
.item-detail-header {
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  padding: 22px 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.item-detail-meta-line {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.item-detail-meta-sep {
  color: var(--ink-faint, var(--text-muted));
  user-select: none;
}
.item-detail-title {
  font-size: 26px;
  font-weight: 600;
  color: var(--ink, var(--text-primary));
  margin: 0;
  letter-spacing: -0.005em;
  line-height: 1.15;
}
.item-detail-subtitle {
  font-size: 13px;
  color: var(--ink-dim, var(--text-secondary));
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.item-detail-subtitle-sep { color: var(--ink-faint, var(--text-muted)); }
.item-detail-headline-fmv {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
  padding-top: 4px;
}
.item-detail-headline-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
}
.item-detail-headline-value {
  font-size: 28px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink, var(--text-primary));
  line-height: 1;
}
.item-detail-headline-trend {
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.item-detail-actions-primary {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* Valuation KPI strip — 4 large summary tiles for Cost Basis /
   Insurance Value / Unrealized Gain/Loss / Confidence. */
.item-detail-kpi-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}
@media (max-width: 760px) {
  .item-detail-kpi-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.item-detail-kpi {
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.item-detail-kpi-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
}
.item-detail-kpi-value {
  font-size: 20px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink, var(--text-primary));
  line-height: 1.1;
}
.item-detail-kpi-value-positive { color: var(--success); }
.item-detail-kpi-value-negative { color: var(--error); }
.item-detail-kpi-value-empty {
  color: var(--ink-faint, var(--text-muted));
  font-size: 14px;
  font-weight: 500;
}
.item-detail-kpi-sub {
  font-size: 11px;
  color: var(--ink-dim, var(--text-secondary));
}

/* Section primitive for main-column modules (Identity card,
   Trend Foundation, Recent Comparables, lower operational
   cards). Reuses .lb-surface vocabulary visually. */
.item-detail-section {
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  padding: 18px 20px;
}
.item-detail-section-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 12px;
}
.item-detail-section-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink, var(--text-primary));
  margin: 0;
}
.item-detail-section-action {
  font-size: 12px;
  color: var(--accent);
  text-decoration: none;
}
.item-detail-section-action:hover { text-decoration: underline; }
.item-detail-empty {
  font-size: 13px;
  color: var(--ink-faint, var(--text-muted));
  padding: 8px 0;
}

/* Governed identity grid — multi-column dt/dd pairs. */
.item-detail-identity-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px 18px;
  margin: 0;
}
.item-detail-identity-grid > div { min-width: 0; }
.item-detail-identity-grid dt {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
  margin: 0 0 2px;
}
.item-detail-identity-grid dd {
  font-size: 13px;
  color: var(--ink, var(--text-primary));
  margin: 0;
  word-break: break-word;
}
.item-detail-identity-grid dd.empty {
  color: var(--ink-faint, var(--text-muted));
}

/* Secondary action groups (Research / Manage), kept after the
   header at lower visual weight. */
.item-detail-action-groups {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
}
.item-detail-action-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.item-detail-action-group-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
}
.item-detail-action-group-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

/* ITEM-DETAIL-DESIGN-ALIGNMENT-8C — promotes the lower-panel legacy
   .section-panel + heavy inline-style hotspots into named Item Detail
   primitives. Visual language stays aligned with the 8A/8B section
   primitives: lb-surface treatment, consistent 16px section spacing,
   no border-bottom title underline, no oversized cards. Scoped to
   .item-detail-* classes so Set Detail / Collection / Sets selectors
   are not affected. */

/* Vertical rhythm — every adjacent lower-panel block sits 16px below
   the previous one without inline margin-bottom on each. */
.item-detail-section + .item-detail-section,
.item-detail-section + .item-detail-section-pair,
.item-detail-section-pair + .item-detail-section,
.item-detail-section-pair + .item-detail-section-pair,
.item-detail-section + .item-detail-disclosure,
.item-detail-section-pair + .item-detail-disclosure,
.item-detail-disclosure + .item-detail-section,
.item-detail-disclosure + .item-detail-section-pair,
.item-detail-disclosure + .item-detail-disclosure,
.item-detail-evidence-form + .item-detail-section,
.item-detail-evidence-form + .item-detail-section-pair,
.item-detail-alert + .item-detail-section,
.item-detail-alert + .item-detail-section-pair,
.item-detail-alert + .item-detail-evidence-form {
  margin-top: 16px;
}

/* Two-column section pair (Valuation/Cost, Condition/Storage). */
.item-detail-section-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.item-detail-section-pair > .item-detail-section { padding: 16px 18px; }
@media (max-width: 720px) {
  .item-detail-section-pair { grid-template-columns: 1fr; }
}

/* Set-progress block — denser variant for the single-line summary +
   bar + optional missing-count line. */
.item-detail-section.is-set-progress { padding: 12px 16px; }
.item-detail-set-progress-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 6px;
}
.item-detail-set-progress-meta { font-size: 13px; }
.item-detail-set-progress-link {
  color: var(--ink, var(--text-primary));
  font-weight: 500;
}
.item-detail-set-progress-count {
  color: var(--ink-faint, var(--text-muted));
  margin-left: 6px;
}
.item-detail-set-progress-pct {
  font-size: 13px;
  font-weight: 500;
  color: var(--accent);
}
.item-detail-set-progress-bar { height: 6px; }
.item-detail-set-progress-missing {
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
  margin-top: 6px;
}
.item-detail-set-progress-find { color: var(--accent); }

/* Disposition accent variant — sold-status border highlight. */
.item-detail-section.is-accent { border-color: var(--accent); }
.item-detail-disposition-summary {
  margin-top: 12px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 13px;
  line-height: 1.7;
}

/* Stat list — compact two-column key/value rows. Replaces ~25
   inline `display:flex;justify-content:space-between` instances. */
.item-detail-stat-list {
  font-size: 13px;
  line-height: 2;
}
.item-detail-stat-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}
.item-detail-stat-row.is-summary {
  border-top: 1px solid var(--border);
  padding-top: 4px;
  margin-top: 4px;
}
.item-detail-stat-row.is-positive strong { color: var(--success); }
.item-detail-stat-row.is-negative strong { color: var(--error); }
.item-detail-stat-meta {
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
  font-weight: normal;
}

/* Comp evidence summary block (inside Valuation panel). */
.item-detail-stat-evidence {
  border-top: 1px solid var(--border);
  padding-top: 4px;
  margin-top: 4px;
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
}
.item-detail-stat-evidence-link {
  margin-left: 4px;
  color: var(--accent);
}
.item-detail-stat-evidence-title {
  font-size: 11px;
  color: var(--ink-faint, var(--text-muted));
  margin-top: 2px;
  font-style: italic;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Section-header count chip used by Valuation History. */
.item-detail-section-count {
  font-size: 11px;
  color: var(--ink-faint, var(--text-muted));
}

/* Alert / hint banner — Next-step + missing-checklist warning. */
.item-detail-alert {
  padding: 8px 14px;
  background: var(--bg-card);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  font-size: 13px;
  color: var(--ink-dim, var(--text-secondary));
}
.item-detail-alert.is-warning {
  border: 1px dashed var(--border);
  border-left: 3px solid var(--warning);
  padding: 10px 14px;
}
.item-detail-alert strong { color: var(--ink, var(--text-primary)); }
.item-detail-alert-link {
  color: var(--accent);
  margin-left: 6px;
}

/* Combined-evidence enrichment form (INT-4C) — file pickers + extract
   button. Replaces a large inline-style block. */
.item-detail-evidence-form {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 16px;
}
.item-detail-evidence-form-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-dim, var(--text-secondary));
  margin-bottom: 8px;
}
.item-detail-evidence-form-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: end;
}
.item-detail-evidence-form-row .form-group { margin-bottom: 0; }
.item-detail-evidence-form-row label { font-size: 10px; }
.item-detail-evidence-form-row input[type="file"] { font-size: 11px; }
.item-detail-evidence-form-help {
  font-size: 10px;
  color: var(--ink-faint, var(--text-muted));
  margin-top: 4px;
}

/* Disclosure (<details>) wrapper — Acquisition Details, Recent
   Changes, Governed Snapshot. Replaces inline-styled <details>. */
.item-detail-disclosure { margin: 0; }
.item-detail-disclosure-summary {
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-dim, var(--text-secondary));
  margin-bottom: 4px;
}
.item-detail-disclosure-body { margin-top: 8px; }

/* BOX-992 — "Audit & evidence" footer accordion: a persistent top-level
   collapsible group below the React tab panel that folds the legacy bottom
   disclosures (dup-override / recent changes / audit history / governed
   snapshot) into one low-noise group. Bordered + spaced from the panel so it
   reads as page footer chrome, distinct from the in-flow .item-detail-section. */
.item-detail-footer-accordion {
  margin-top: 20px;
  padding: 12px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  background: var(--surface-2, var(--bg-secondary));
}
.item-detail-footer-accordion-summary {
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink, var(--text-primary));
}
.item-detail-footer-accordion[open] > .item-detail-footer-accordion-summary {
  margin-bottom: 12px;
}

/* COMBINED-EVIDENCE-DESIGN-CLEANUP-1 — promotes the loudest
   evidence-specific inline-style hotspots into the established
   Item Detail / Combined Review primitives. All selectors are
   `.item-detail-evidence-*` / `.item-detail-sale-*` /
   `.item-detail-section-footnote` / `.item-detail-action-row` /
   `.item-detail-inline-form` / `.combined-review-*` scoped — no
   impact on Collection / Sets / Set Detail / Intake selectors. */

/* Sale notes sub-block on the Disposition section. */
.item-detail-sale-notes {
  margin-top: 8px;
  font-size: 12px;
  color: var(--ink-dim, var(--text-secondary));
}

/* Section footnote — small grey caption beneath a section's
   numeric summary (e.g. "Realized P/L is derived from the current
   cost basis"). */
.item-detail-section-footnote {
  margin-top: 8px;
  font-size: 10px;
  color: var(--ink-faint, var(--text-muted));
  line-height: 1.4;
}

/* Sale-evidence list sub-block — divider + label + list +
   per-item card row + thumbnail + delete-button compact variant
   + empty state. Replaces the inline-styled cluster at the tail
   of the Disposition section. */
.item-detail-evidence-list-section {
  margin-top: 12px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}
.item-detail-evidence-list-label {
  font-size: 12px;
  font-weight: 500;
  margin-bottom: 6px;
}
.item-detail-evidence-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.item-detail-evidence-list-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11px;
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 4px 8px;
}
.item-detail-evidence-list-item-meta {
  display: flex;
  align-items: center;
  gap: 8px;
}
.item-detail-evidence-thumbnail-link { flex-shrink: 0; }
.item-detail-evidence-thumbnail {
  width: 40px;
  height: 40px;
  object-fit: cover;
  border-radius: 3px;
  border: 1px solid var(--border);
}
.item-detail-evidence-delete-btn {
  font-size: 10px;
  padding: 1px 6px;
}
.item-detail-evidence-empty {
  font-size: 11px;
  color: var(--ink-faint, var(--text-muted));
}

/* Inline form wrapper — replaces `style="display:inline;margin:0"`
   on the per-item delete form so the button sits on the same row
   as the meta block without a fresh paragraph. */
.item-detail-inline-form {
  display: inline;
  margin: 0;
}

/* Bottom action row — replaces the per-block flex layout used by
   Disposition's edit/upload buttons + by Combined Review's
   confirm/cancel buttons. Two simple primitives stacked: button
   gap + wrap. */
.item-detail-action-row {
  margin-top: 12px;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* CLEANUP-TEST-HEALTH-2 — Card Detail inline-style extraction for
   the EBAY-LISTING-EVIDENCE-EDIT-AND-CONSOLIDATION-BUNDLE-1 form
   row + URL anchor cluster on collection/detail.html. Replaces 9
   inline ``style="…"`` attributes documented in
   test_item_detail_8c_design_alignment.py's BOX-188 docstring
   (3× ``word-break:break-all`` URL/code anchors, 1× compact
   non-FMV disclaimer paragraph, 2× compact flex form-row
   wrappers, 2× flexible URL inputs, 2× muted secondary
   provider-status links). The ``__grow`` and ``__end`` modifiers
   preserve the per-site flex-grow and right-justify behavior the
   inline declarations carried. Distinct from the older
   ``.item-detail-evidence-*`` cluster above (COMBINED-EVIDENCE-
   DESIGN-CLEANUP-1) — that one is for file-picker rows with
   ``gap: 12px; align-items: end``; this one is for the operator-
   facing eBay listing-context attach / replace / status surface
   with ``gap: 6px; align-items: center``. */
.item-detail-url-break-anywhere { word-break: break-all; }

.item-detail-listing-evidence-disclaimer {
  margin: 8px 0 0 0;
  font-size: 11px;
  line-height: 1.4;
}

.item-detail-listing-evidence-form {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: center;
}
.item-detail-listing-evidence-form--grow { flex: 1; }

.item-detail-listing-evidence-url-input {
  flex: 1;
  font-size: 12px;
  min-width: 240px;
}

.item-detail-listing-evidence-status-link { font-size: 11px; }
.item-detail-listing-evidence-status-link--end { margin-left: auto; }

/* CLEANUP-TEST-HEALTH-3 — Card Detail muted-secondary cluster.
   Extracts the three repeated ``font-size:11px`` inline patterns
   that account for the bulk of the activity-feed / image-sources
   list / evidence-row footer drift on collection/detail.html.
   Replaces 16 inline ``style="…"`` attributes across three sub-
   clusters:

     1. Six per-source muted metadata spans inside the image-
        sources ``<ul>`` (eBay-API review / paste / fallback /
        Browse photo-import / manual upload / workflow hub rows)
        — ``<span class="muted" style="font-size:11px;margin-
        left:6px">`` is the canonical "description chip" placed
        next to the source label.
     2. Five evidence-row action wrappers — ``<div class="item-
        detail-evidence-form-help" style="font-size:11px;margin-
        top:8px;display:flex;align-items:center;gap:10px;flex-
        wrap:wrap">`` — host an action button plus a short
        descriptive note. Used by eBay-photo-import, eBay-API
        media-review, eBay-API listing-fallback, and the two
        ACQ-PREFILL acquisition rows. The wrapper RETAINS its
        existing ``.item-detail-evidence-form-help`` class for
        the dim-color inheritance the help class provides; the
        new ``.item-detail-evidence-row-actions`` class layers
        in the flex layout that the inline was carrying.
     3. Five short descriptive notes (``<span class="muted"
        style="font-size:11px">``) inside the wrappers above.

   The new classes are named after their role, not after the
   inline shape, so future additions in the same sub-cluster can
   adopt the class without inventing a new selector. Scoped to
   ``item-detail-*`` so other templates are unaffected. */
.item-detail-image-source-row-meta {
  font-size: 11px;
  margin-left: 6px;
}

.item-detail-evidence-row-actions {
  font-size: 11px;
  margin-top: 8px;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.item-detail-evidence-row-note { font-size: 11px; }

/* CLEANUP-TEST-HEALTH-4 — deferred evidence-state hints pair.
   Extracts the two identical inline styles on the
   all-loaded / empty hint ``<span class="muted">`` siblings
   inside the evidence-state slot region (collection/detail.html
   lines ~1160 + ~1168). Both hints span the full row beneath
   the per-slot chips and add a small top-margin so they don't
   crowd the chips above. Identical 2-occurrence string; safe
   to extract without changing any other site. */
.item-detail-evidence-state-hint {
  font-size: 11px;
  flex-basis: 100%;
  margin-top: 4px;
}

/* CLEANUP-TEST-HEALTH-5 — status-chips badge cluster.
   Extracts the 5 identical ``style="font-size:11px"`` inlines on
   the status-summary ``<span class="badge badge-*">`` chips inside
   ``.item-detail-status-chips`` (collection/detail.html lines
   ~302–310: badge-active / badge-listed / badge-sold /
   badge-archived / badge-dup). The base ``.badge`` cluster ships
   with the default badge font-size; these status-chip variants
   render one size step smaller. Scoped to the status-chips row
   so other ``.badge`` consumers elsewhere on Card Detail (grading
   summary, valuation timeline) are unaffected and stay candidate
   sites for their own future extraction passes. */
.item-detail-status-badge { font-size: 11px; }

/* CLEANUP-TEST-HEALTH-6 — grading-summary badge cluster.
   Extracts the 5 identical ``style="font-size:11px"`` inlines on
   the Grading section's status-summary ``<span class="badge
   badge-*">`` chips (collection/detail.html lines ~1889 / 1898 /
   1905 / 1920 / 1955): badge-active "Graded", 2× badge-needed
   "Submitted" / "Needs Grading", badge-archived "Raw / Ungraded",
   and the badge-grade dynamic ``gs.actual_grade`` chip in the
   Grading Submissions list row. Same font-size shape as the
   status-chips cluster extracted by CLEANUP-TEST-HEALTH-5 but
   lives in a different DOM sub-section; intentionally a separate
   class so future per-section design tweaks can diverge cleanly.
   Does NOT include the ``font-size:13px`` actual-grade chip on
   line 1890 or the ``font-size:10px`` submission-status chips on
   lines 1957–1962 — those are different shapes and stay as
   separate-slice carve-outs. */
.item-detail-grading-badge { font-size: 11px; }

/* CLEANUP-TEST-HEALTH-7 — grading-submissions-list cluster.
   Extracts 5 inline styles from the Grading Submissions ``<a
   class="dash-item-card">`` row body on collection/detail.html
   (lines ~1950 / 1951 + ~1958 / 1960 / 1962):

     * 2× ``<span style="font-size:11px;color:var(--ink-faint,
       var(--text-muted));margin-left:6px">`` muted metadata
       spans for service_level + submission_date — replaced with
       ``.item-detail-grading-submission-meta``.
     * 3× ``<span class="badge badge-*"
       style="font-size:10px">`` submission lifecycle status
       chips for completed/returned, cancelled, and
       submitted/default states — replaced with
       ``.item-detail-grading-submission-badge`` layered
       alongside the existing ``badge badge-*`` classes.

   Both classes are scoped to the grading-submissions list
   so other 10px badge consumers elsewhere (audit log
   ``badge {{ evt.source_badge }}``, valuation history
   ``badge {{ evt.source_badge }}``) and other 11px muted
   meta inlines remain candidates for their own future
   extraction passes. */
.item-detail-grading-submission-meta {
  font-size: 11px;
  color: var(--ink-faint, var(--text-muted));
  margin-left: 6px;
}

.item-detail-grading-submission-badge { font-size: 10px; }

/* CLEANUP-TEST-HEALTH-8 — audit / source-tag badge cluster.
   Extracts the 2 identical ``style="font-size:10px"`` inlines
   on the source-tagging ``<span class="badge ..."`` chips in
   the valuation-history + changelog audit tables on
   collection/detail.html:

     * line ~1995: valuation-history source badge
       (``<span class="badge {{ evt.source_badge }}">``) — names
       the source of a valuation-event row (manual override,
       fmv inbox, etc).
     * line ~2395: changelog source tag (``<span class="badge
       {% if c.source == 'bulk_edit' %}badge-needed{% elif
       c.source == 'ui_edit' %}badge-active{% else
       %}badge-unresolved{% endif %}">``) — names the source of
       an audit/changelog row (bulk_edit, ui_edit, other).

   Same DOM shape (``<span class="badge ..." style="font-size:
   10px">``), same semantic role (audit source-tagging chips
   in audit-style tables). Distinct from the grading-submission
   lifecycle badges (CLEANUP-7) because those are status chips
   on a dash-item-card row, not audit/source tags on a tabular
   evidence row — class names track the surface.

   Deliberately does NOT capture: the evidence-state filename
   ``<code style="font-size:10px">`` at line ~1141 (code
   element, different shape), the valuation-event delta-pct
   inner ``<span style="font-size:10px">`` at line ~1992
   (inside a data-driven color span; one-off composition),
   the sold-comps ``<a style="font-size:10px;color:var(--
   accent)">`` at line ~2017 (anchor with color, different
   shape), and the sold-comps ``<span style="font-size:10px">
   (excluded)``  at line ~2017 (plain span, not a badge).
   Each is a separate-slice candidate. */
.item-detail-audit-source-badge { font-size: 10px; }

/* CLEANUP-TEST-HEALTH-9 — sold-comps mini-cluster on the
   valuation-history comp-evidence row (collection/detail.html
   line ~2017, inside the per-event ``{% for comp in
   evt.comp_evidence %}`` loop). Two distinct shapes side-by-
   side on the same comp row:

     * The external-link arrow (``<a style="font-size:10px;
       color:var(--accent)">&uarr;</a>``) — renders only when
       ``comp.link`` is present; ``--accent`` matches the
       theme's link accent color.
     * The excluded-row label (``<span style="font-size:10px">
       (excluded)</span>``) — renders only when
       ``comp.excluded`` is true; the outer comp ``<div>``
       already applies ``text-decoration:line-through`` for
       excluded rows via its own conditional inline (kept as
       a data-driven inline, NOT extracted in this slice).

   Two classes (font-sizes match but the link variant adds
   color); keeping them named separately tracks the role so a
   future per-shape tweak — e.g. changing only the link accent
   weight — touches one class instead of one shared rule. */
.item-detail-sold-comp-link {
  font-size: 10px;
  color: var(--accent);
}

.item-detail-sold-comp-excluded { font-size: 10px; }

/* CLEANUP-TEST-HEALTH-10 — TCDB Provenance identifier code cluster.
   Extracts the 2 identical ``<code style="font-size:11px">``
   inlines on the TCDB Provenance disclosure (collection/detail.html
   lines ~2326 + 2335): the ``bulk_invocation_id`` and the
   ``bulk_live_execution_id`` identifier displays inside the
   ``tcdb_provenance_view`` panel. Same DOM shape (``<code style=
   "font-size:11px">``), same semantic role (read-only TCDB
   bulk-execution identifier display inside the provenance
   disclosure).

   Intentionally narrow: this class is for the TCDB-provenance
   identifier ``<code>`` cluster only. The other three
   ``<code style="font-size:11px">`` inlines elsewhere on Card
   Detail (audit-row media-archive filename at line ~2488, audit
   row ``was:``/``now:`` value spans at lines ~2539 + 2542) live
   in the audit/changelog disclosure and are a separate-slice
   candidate — they share the font-size but render in a different
   surface and may want a distinct class. */
.item-detail-tcdb-provenance-code { font-size: 11px; }

/* CLEANUP-TEST-HEALTH-11 — audit/changelog row code cluster.
   Extracts the 3 ``<code style="font-size:11px">`` inlines on
   the audit/changelog disclosure row body
   (collection/detail.html lines ~2488 + 2539 + 2542):

     * media-archive filename ``<code data-testid="item-detail-
       audit-row-media-archive-filename" style="font-size:11px">
       {{ _filename }}</code>`` (data-testid preserved verbatim).
     * old-value display ``<code style="font-size:11px">{{
       evt.old_value[:80] }}…</code>``.
     * new-value display ``<code style="font-size:11px">{{
       evt.new_value[:80] }}…</code>``.

   Same DOM shape (``<code style="font-size:11px">``), same
   semantic role (audit-row identifier / before-after value
   display). Distinct from the TCDB-provenance class
   (CLEANUP-10) even though both are font-size:11px — class
   names track the surface (audit/changelog row vs. TCDB
   provenance disclosure) so future per-surface tweaks can
   diverge cleanly. No rendered behavior change intended. */
.item-detail-audit-row-code { font-size: 11px; }

/* CLEANUP-TEST-HEALTH-12 — evidence-state filename code element.
   Extracts the 1 ``<code data-testid="item-detail-evidence-state-
   {{ role }}-filename" style="font-size:10px">`` inline at
   ``collection/detail.html`` line ~1141 — the per-role filename
   display inside the evidence-state rail chip (``front``/``back``/
   ``receipt``). Only remaining ``<code style="font-size:10px">``
   on Card Detail after CLEANUP-10 (TCDB) and CLEANUP-11
   (audit/changelog). Distinct surface (evidence-state rail
   vs. provenance disclosure vs. audit row) — separate class
   keeps future per-surface tweaks isolated. No rendered behavior
   change intended. */
.item-detail-evidence-state-filename-code { font-size: 10px; }

/* CLEANUP-TEST-HEALTH-13 — actual-grade chip on Grading section.
   Extracts the 1 ``<span class="badge badge-grade" style="font-
   size:13px">{{ item.card_grade }}</span>`` chip at
   ``detail.html`` line ~1890. Displays the operator's captured
   numeric / letter card grade beside the ``badge-active
   "Graded"`` chip when ``grading_status == 'COMPLETED'``. Sized
   one step larger than the surrounding 11px grading-summary
   badges so the actual grade reads as the primary visual focus
   of the COMPLETED row. Static font-size:13px — no data-derived
   declarations. No rendered behavior change intended. */
.item-detail-card-grade-chip { font-size: 13px; }

/* CLEANUP-TEST-HEALTH-14 — valuation-event 11px table cells.
   Extracts the 2 identical ``<td style="font-size:11px">`` table
   cells in the valuation-history events table at ``detail.html``
   lines ~1996 + 2000 — the per-row method-and-confidence cell
   and the per-row source/evidence cell. Both render one size
   step smaller than the default valuation-history table font.
   Static font-size:11px on the cells themselves; the inner
   spans / badges carry their own (data-driven or already-
   extracted) inlines. No rendered behavior change intended. */
.item-detail-valuation-event-cell { font-size: 11px; }

/* CLEANUP-TEST-HEALTH-15 — valuation-method badge chip.
   Extracts the 1 ``<span class="badge" style="font-size:9px;
   background:var(--bg-secondary);color:var(--ink-dim, var(--
   text-secondary));border:1px solid var(--border)">`` inline
   at ``detail.html`` line ~1997 — the valuation-event row's
   ``evt.valuation_method`` mini-chip (one size step smaller
   than the surrounding 10–11px badge cluster, with a muted
   token-driven background + border to read as a metadata tag,
   not a primary badge). All 4 declarations are static (CSS
   custom-property references only; no data-derived values).
   Distinct shape from the 9px duplicate-warning chip at line
   ~1146 (different colors, padding, border-radius, margin) —
   that site stays a separate-slice candidate. No rendered
   behavior change intended. */
.item-detail-valuation-method-chip {
  font-size: 9px;
  background: var(--bg-secondary);
  color: var(--ink-dim, var(--text-secondary));
  border: 1px solid var(--border);
}

/* CARD-DETAIL-IMAGE-SOURCES-PANEL-CONTRAST (2026-06-02) —
   ``.item-detail-evidence-card`` is shared by the Card Detail
   "Image sources" panel and the eBay API media provenance card.
   Both previously carried an inline ``background:#f6f4ee`` light
   surface that ignored the theme system; in dark mode the
   inherited ``--text-primary`` heading + body text then rendered
   light-on-light (~1.2:1, fails WCAG AA). Drive surface + border
   from the canonical card tokens — the same ``var(--surface,
   var(--bg-card))`` treatment the other cards on this page use —
   so the panel matches the dark theme and clears AA in both
   themes. The 5 layout/visual props moved off the now-removed
   inline ``style`` unchanged; only the background switches from a
   hard-coded light hex to the token. */
.item-detail-evidence-card {
  margin-top: 10px;
  padding: 10px 12px;
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12px;
}
/* CLEANUP-TEST-HEALTH-16 — image-source-row list cards.
   Extracts the 6 identical ``<li style="margin:4px 0;padding:
   6px 8px;background:#fff;border:1px solid #ddd;border-radius:
   4px">`` cards in the image-sources ``<ul>`` on
   ``detail.html`` (lines ~1282 / 1303 / 1322 / 1353 / 1374 /
   1391) — eBay-API review, eBay-API paste, eBay-API fallback,
   Browse photo-import, manual upload, and workflow-hub rows.
   Each ``<li>`` is the framed card body for one source row,
   already carrying ``data-testid="card-detail-image-sources-
   row"`` plus a per-row ``data-row-kind="..."``.
   CARD-DETAIL-IMAGE-SOURCES-PANEL-CONTRAST (2026-06-02) then
   moved the ``background`` + ``border`` off their original light
   literals (``#fff`` / ``#ddd``) onto the recessed surface
   tokens (``var(--surface-2, var(--bg-secondary))`` /
   ``var(--border)``) so the rows stay theme-consistent inside
   the now-dark evidence card; the 3 geometry declarations remain
   static literals. */
.item-detail-image-source-row-card {
  margin: 4px 0;
  padding: 6px 8px;
  background: var(--surface-2, var(--bg-secondary));
  border: 1px solid var(--border);
  border-radius: 4px;
}

/* CLEANUP-TEST-HEALTH-17 — Grading section row wrappers.
   Extracts the 4 identical ``<div style="display:flex;align-
   items:center;gap:8px;margin-bottom:6px">`` wrappers at
   ``detail.html`` lines ~1888 / 1897 / 1904 / 1919 — the
   chip-and-label flex rows at the top of each Grading section
   conditional branch (COMPLETED / SUBMITTED / NEEDED / Raw).
   Each wraps a status badge + an optional secondary chip /
   label (grade chip, grading company, high-value/grading
   candidate hint). Static 4-declaration inline (display +
   align-items + gap + margin-bottom); no Jinja, no data-
   driven values. No rendered behavior change intended. */
.item-detail-grading-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}

/* Combined Review (collection/combined_review.html) — page-level
   evidence-extraction grid. Scoped to `.combined-review-*` so
   other tables/forms aren't affected. */
.combined-review-panel {
  margin-bottom: 16px;
}
.combined-review-title {
  font-size: 14px;
  font-weight: 600;
  margin: 0 0 10px;
  color: var(--ink, var(--text-primary));
}
.combined-review-title-meta {
  font-size: 11px;
  font-weight: 400;
  color: var(--text-muted);
  margin-left: 4px;
}
.combined-review-status {
  font-size: 13px;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.combined-review-status.is-error {
  color: var(--warning);
}
.combined-review-conflict {
  margin-bottom: 12px;
  font-size: 12px;
}
.combined-review-receipt-summary {
  font-size: 12px;
  color: var(--text-muted);
  margin-bottom: 8px;
}

/* Combined-review extraction table — replaces ~25 inline-style
   attributes on table/cells/inputs across the two panels. Any
   future cleanup of similar pages can subclass these. */
.combined-review-table {
  width: 100%;
  font-size: 13px;
}
.combined-review-table-check { width: 30px; }
.combined-review-table-row { border-bottom: 1px solid var(--border); }
.combined-review-table-row > td { padding: 8px; }
.combined-review-table-row > td.combined-review-table-check-cell { padding: 8px 4px; }
.combined-review-table-label { font-weight: 500; }
.combined-review-table-current { color: var(--text-muted); }
.combined-review-source-tag {
  font-size: 10px;
  display: block;
  color: var(--text-muted);
}
.combined-review-empty-cell { color: var(--text-muted); }
.combined-review-input {
  width: 100%;
  padding: 4px 6px;
  font-size: 12px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text-primary);
}
.combined-review-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}
.combined-review-provenance { margin-bottom: 12px; }
.combined-review-checkbox-label {
  font-size: 12px;
  color: var(--text-secondary);
  cursor: pointer;
}
.combined-review-actions { margin-top: 0; }

/* COLLECTION-SCREEN-DESIGN-ALIGNMENT-9A — collector-facing
   visual grid + table view toggle. The /ui/collection page
   always renders BOTH the grid and the table markup; the
   wrapper's data-view attribute controls visibility so prior
   tests that pin the table testid + classes continue to pass
   without explicit ?view=table. */
.collection-view-toggle {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 5px);
  overflow: hidden;
  background: var(--surface, var(--bg-card));
}
.collection-view-toggle a {
  padding: 6px 12px;
  font-size: 12px;
  text-decoration: none;
  color: var(--ink-dim, var(--text-secondary));
  transition: background 120ms, color 120ms;
}
.collection-view-toggle a + a { border-left: 1px solid var(--border); }
.collection-view-toggle a:hover {
  background: var(--surface-2, var(--bg-secondary));
  color: var(--ink, var(--text-primary));
}
.collection-view-toggle a[data-active="true"] {
  background: var(--accent);
  color: var(--bg-card);
}
/* UIRECON-COLLECTION (BOX-227) — keyboard-accessible focus ring
   on the Grid/Table view toggle so the operator can tab into the
   toggle and see the active state visually. Token-driven; mirrors
   the BOX-223 / BOX-225 / BOX-226 :focus-visible vocabulary. */
.collection-view-toggle a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  /* The toggle's own border-radius is on the wrapping container;
     the inner anchors are flush, so the outline-offset gives the
     ring breathing room without clipping against the segmented
     borders. */
}

/* Wrapper toggles which view is visible. */
.collection-views[data-view="grid"] .collection-table-view { display: none; }
.collection-views[data-view="table"] .collection-grid-view { display: none; }
/* COLLECTION-SCREEN-DESIGN-ALIGNMENT-9C — defense-in-depth.
   The 9A CSS-only hide failed in operator validation. The
   template now also stamps `hidden` + aria-hidden on the
   inactive view; this rule guarantees `display: none` even if
   author CSS elsewhere overrides the UA default for [hidden]. */
.collection-grid-view[hidden],
.collection-table-view[hidden] { display: none !important; }

/* Grid view — collector-facing card grid. Auto-fit responsive
   columns. Cards are .lb-surface-flavored object cards. */
.collection-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}
@media (max-width: 600px) {
  .collection-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
}

.dash-section {
  margin-bottom: 24px;
}
.dash-section-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 12px;
}
.dash-section-title {
  font-size: 16px;
  font-weight: 600;
  margin: 0;
  color: var(--ink, var(--text-primary));
  letter-spacing: -0.005em;
}
.dash-section-action {
  font-size: 12px;
  color: var(--ink-dim, var(--text-secondary));
  white-space: nowrap;
}
.dash-section-action:hover {
  color: var(--accent);
}

/* DASHBOARD-VISUAL-MIGRATION-MICROVIZ-4 — production-safe
   micro-visual layer for the migrated dashboard surfaces per
   Claude Design prototype (handoff: docs/lunchbox-memorabilia/
   project/Lunchbox Prototype.html → src/dashboard.jsx
   ActivityRow + KpiTile + RecentItemCard patterns).

   Strict semantic discipline:
     * No trend chip is rendered unless the underlying data
       (portfolio_trend.comparisons[].delta, delta_pct) exists.
     * KPI meta chips are neutral status labels only when no
       real trend exists ("Current" / "Tracked" / "Cards").
     * Activity event-family marker reuses the existing
       Bulk Edit badge color family — recent_ops are all
       bulk_operations rows in production today; no fake
       multi-family marker rendered.
     * Recent Items marker is purely decorative — accent dot
       when an item carries a valuation, muted dot otherwise
       (semantic: the dot reflects the existing
       estimated_market_value vs. card_grade vs. grading_
       status conditional gate, not a new field).

   Token discipline:
     * Every color reference uses the fc86963 alias chain
       (--ink / --ink-dim / --ink-faint / --surface) with the
       legacy --text-* / --bg-card token as the inline
       fallback so this layer remains readable if the alias
       layer is later removed.
     * Mono font for tiny timestamp / event-id labels via
       --font-mono. */

/* KPI meta-row (chip strip below the value, above the
   sub-link). Inline-flex so chips wrap cleanly on narrow
   tiles. */
.dash-kpi-meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
  align-items: center;
}
.dash-trend-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  border: 1px solid transparent;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.dash-trend-chip-positive {
  color: var(--success);
  border-color: var(--success);
  background: color-mix(in srgb, var(--success) 12%, transparent);
}
.dash-trend-chip-negative {
  color: var(--error);
  border-color: var(--error);
  background: color-mix(in srgb, var(--error) 12%, transparent);
}
.dash-trend-chip-neutral {
  color: var(--ink-dim, var(--text-secondary));
  border-color: var(--border);
  background: var(--bg-secondary);
}
.dash-trend-chip-warning {
  color: var(--warning);
  border-color: var(--warning);
  background: color-mix(in srgb, var(--warning) 14%, transparent);
}
/* Tiny arrow glyph that pairs with positive/negative chips. */
.dash-trend-arrow {
  font-family: var(--font-sans);
  font-size: 9px;
  line-height: 1;
}

/* Recent Activity row polish.
   Pattern: [marker] [content: kind-chip + time + title + meta]
   Marker is a 6px vertical accent rail, color-coded by event
   kind (currently only Bulk Edit; defaults to neutral if a
   future event family lands without an explicit kind). */
.dash-activity-item {
  /* Override the prior padding so the new internal flex layout
     can place the marker flush-left. */
  padding: 0;
  display: block;
}
.dash-activity-row {
  display: grid;
  grid-template-columns: 4px 1fr;
  gap: 12px;
  padding: 12px 14px;
  align-items: stretch;
}
.dash-activity-marker {
  width: 4px;
  border-radius: 2px;
  background: var(--ink-faint, var(--text-muted));
  flex-shrink: 0;
}
.dash-activity-marker-bulk {
  background: var(--warning);
}
/* Re-Review v5 §2 M2 — additive event-family marker variants.
   `-import` for future import-pipeline activity rows;
   `-value` for valuation-edit / per-card override events.
   Today only `-bulk` ships data; the variants stay class-only
   until production data lands the matching event family
   (same discipline as MICROVIZ-4's "render only where data
   exists" contract). */
.dash-activity-marker-import {
  background: var(--success);
}
.dash-activity-marker-value {
  background: var(--accent);
}
/* DASHBOARD-P1 — kind-family markers for the aggregate activity
   timeline. Each maps to one of the four normalized event kinds
   from shared/db/services/dashboard_activity.py. Reuses the
   existing accent / success / warning tokens — no new tokens. */
.dash-activity-marker-intake {
  background: var(--success);
}
.dash-activity-marker-item_change {
  background: var(--accent);
}
.dash-activity-marker-media {
  background: var(--warning);
}
.dash-activity-marker-fmv {
  background: var(--accent);
}
/* BOX-1087 — cost-basis marker for the unified dashboard Activity preview
   (acquisition_envelopes rows). Reuses the --success token (money / green). */
.dash-activity-marker-cost_basis {
  background: var(--success);
}
.dash-activity-content {
  min-width: 0;
}
.dash-activity-kind {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  padding: 1px 6px;
  border-radius: 3px;
  color: var(--ink-dim, var(--text-secondary));
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  vertical-align: middle;
}
.dash-activity-time {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 10px;
  color: var(--ink-faint, var(--text-muted));
  margin-left: 8px;
  vertical-align: middle;
  font-variant-numeric: tabular-nums;
}
.dash-activity-title {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink, var(--text-primary));
  margin-top: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dash-activity-meta {
  font-size: 12px;
  color: var(--ink-dim, var(--text-secondary));
  margin-top: 2px;
}

/* Recent Items row polish.
   Pattern: [marker dot] [content: title + meta] [right cluster:
   value + grade]. */
.dash-item-card {
  padding: 0;
}
.dash-item-row {
  display: grid;
  grid-template-columns: 8px 1fr auto;
  gap: 12px;
  padding: 12px 14px;
  align-items: center;
}
.dash-item-marker {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ink-faint, var(--text-muted));
  margin-top: 6px;
  align-self: start;
}
.dash-item-marker-valued {
  background: var(--accent);
}
.dash-item-content {
  min-width: 0;
}
.dash-item-title {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink, var(--text-primary));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dash-item-meta {
  font-size: 12px;
  color: var(--ink-dim, var(--text-secondary));
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dash-item-right {
  text-align: right;
  flex-shrink: 0;
}
.dash-item-value {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink, var(--text-primary));
  font-variant-numeric: tabular-nums;
}
.dash-item-submeta {
  font-size: 10px;
  color: var(--ink-faint, var(--text-muted));
  margin-top: 2px;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  letter-spacing: 0.04em;
}

/* DASHBOARD-FMV-ATTENTION-1 — scoped alignment for the dashboard
   Intake FMV tile per Re-Review v4 §6 (handoff:
   docs/lunchbox-memorabilia/project/Re-Review v4.html).

   Scoping discipline (D3): every rule in this block is selector-
   pinned to `[data-fmv-area="dashboard-attention"]` so no other
   dashboard tile, kpi tile, section panel, or set/recommendation
   card inherits these declarations. The `.fmv-shell-section`
   vocabulary is intentionally NOT applied here — the dashboard
   FMV-attention surface is a single bounded tile, not a multi-
   section page-shell, and propagating `.fmv-shell-section` into
   the kpi strip would conflict with the strip's flex layout.

   Visual stance (D2 — rhythm only, no terminal section): the
   tile's existing dash-kpi padding (16px 20px) already mirrors
   the codified shell rhythm baseline (--shell-section-terminal-
   padding 16px / --shell-section-gap 20px); the rule below
   re-declares the SAME padding via the aliases so a future
   re-tune of the shell aliases automatically reaches this
   surface. Pure no-visual-change codification — both the
   alias-driven and literal rules resolve to the same pixel
   values with the foundation slice's defaults in place.

   Future expansion (Re-Review v4 §6 mockup): when the dashboard
   FMV-attention area grows to include severity-tier counts +
   per-commit deep-links (richer than the current single tile),
   subsequent slices can add child rules under the same
   `[data-fmv-area="dashboard-attention"]` selector — keeping
   the dashboard non-FMV surfaces untouched. */
[data-fmv-area="dashboard-attention"] {
  padding: var(--shell-section-terminal-padding, 16px) var(--shell-section-gap, 20px);
}

/* Batch 3: Buy Next / Set Progress empty-state block.
   Renders when the associated list is empty so the operator is not
   left wondering whether a section is present at all. */
.dash-empty-state {
  background: var(--bg-card);
  border: 1px dashed var(--border);
  border-radius: 8px;
  padding: 14px 16px;
  color: var(--text-secondary);
  font-size: 13px;
  margin-top: 8px;
}
.dash-empty-state-title { font-weight: 600; color: var(--text-primary); margin-bottom: 2px; }

/* Batch 3: collection list filter label emphasis. Operator feedback
   2026-04-13: "Search headings are too subtle — need to increase
   visibility." Lifts the label weight and color on the primary and
   secondary filter sections without redesigning the filter layout. */
.filter-primary label,
.filter-secondary label,
.filter-section-label {
  font-weight: 600 !important;
  color: var(--text-secondary) !important;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  font-size: 11px !important;
}
.filter-section-label {
  font-size: 12px !important;
  color: var(--text-primary) !important;
}

/* Batch 3: shared identity meta line class — matches detail block
   typography so parallel/color/insert-set and language/country/tags
   lines render consistently with adjacent identity elements. */
.identity-meta {
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.5;
}
.identity-meta .meta-label {
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.3px;
  font-size: 10px;
}
.identity-meta .meta-value {
  color: var(--text-primary);
  font-weight: 500;
}

.dash-two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
}

.dash-activity-list { display: flex; flex-direction: column; gap: 8px; }
.dash-activity-item {
  display: block;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 12px 14px;
  text-decoration: none;
  color: inherit;
}
.dash-activity-item:hover { border-color: var(--accent); }

.dash-items-list { display: flex; flex-direction: column; gap: 8px; }
.dash-item-card {
  display: block;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 12px 14px;
  text-decoration: none;
  color: inherit;
}
.dash-item-card:hover { border-color: var(--accent); }

.dash-set-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 16px;
  margin-bottom: 8px;
  transition: border-color 120ms ease, background 120ms ease;
}
.dash-set-card:hover {
  border-color: var(--accent);
}

/* DASHBOARD-VISUAL-MIGRATION-SHELL-LOWER-2 — minor unification:
   bring .dash-item-card and .dash-activity-item to the same
   8px border-radius as .dash-kpi + .dash-set-card so all
   dashboard surface cards share the same corner rhythm.
   Hover state extended with subtle background lift. */
.dash-item-card,
.dash-activity-item {
  border-radius: 8px;
  transition: border-color 120ms ease, background 120ms ease;
}
.dash-activity-item:hover,
.dash-item-card:hover {
  background: var(--bg-secondary);
}

/* ── Card detail hero ────────────────────────────────────────── */
.card-hero {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 16px;
}
.card-hero-identity { flex: 1; }
.card-hero-name { font-size: 24px; font-weight: 600; margin-bottom: 4px; }
.card-hero-subtitle { font-size: 14px; color: var(--text-secondary); }
.card-hero-value { text-align: right; flex-shrink: 0; }
.card-hero-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.3px; }
.card-hero-fmv { font-size: 28px; font-weight: 600; margin-top: 2px; }

.card-info-block {
  display: grid;
  grid-template-columns: 180px 1fr;
  gap: 20px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 20px;
}
.card-placeholder {
  width: 100%;
  aspect-ratio: 2.5/3.5;
  background: var(--bg-secondary);
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.card-info-meta { display: flex; flex-direction: column; justify-content: center; }
.card-meta-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 12px;
}
.card-meta-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.3px; }
.card-meta-value { font-size: 14px; font-weight: 500; margin-top: 2px; }

/* ── Marketplace cards ────────────────────────────────────────── */
.mp-card-list { display: flex; flex-direction: column; gap: 12px; }
.mp-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px 20px;
  /* UIRECON-MARKETPLACE (BOX-231) — animate hover/focus state
     changes alongside the existing visual chrome. Mirrors the
     ``.set-card`` / ``.dash-stat-tile`` vocabulary so the
     marketplace card reads as part of the same scannable list
     family. */
  transition:
    border-color 120ms ease,
    transform 120ms ease,
    box-shadow 120ms ease;
}
/* UIRECON-MARKETPLACE (BOX-231) — visible-hover delta + keyboard
   focus-within anchor. The card itself is not a single anchor
   (it carries multiple Add / Buy on eBay / Track / Untrack
   actions), so ``:focus-within`` (when any button inside the
   card receives keyboard focus) gets the same accent treatment
   as a mouse hover. Token-driven; no palette change. */
.mp-card:hover,
.mp-card:focus-within {
  border-color: var(--accent);
  transform: translateY(-1px);
  box-shadow: var(--shadow);
}
.mp-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 6px;
  /* UIRECON-RESPONSIVE-AUDIT (BOX-233) — wrap card name + action
     group so the 4 inline action controls (Add / Buy on eBay /
     Track or Untrack) reflow cleanly on narrow viewports
     instead of overflowing horizontally. Token-free additive. */
  flex-wrap: wrap;
  row-gap: 6px;
}
.mp-card-name { font-size: 15px; font-weight: 600; }
.mp-card-meta { font-size: 13px; color: var(--text-muted); margin-bottom: 6px; }
/* UIRECON-RESPONSIVE-AUDIT (BOX-233) — wrap per-card detail
   chips (Parallel / Insert / etc.) so they reflow at narrow
   widths instead of overflowing. Token-free additive. */
.mp-card-details { display: flex; gap: 20px; font-size: 13px; flex-wrap: wrap; row-gap: 6px; }
.mp-card-detail { }
.mp-detail-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.3px; margin-right: 6px; }

/* ── Cards / Panels ──────────────────────────────────────────── */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; margin-bottom: 24px; }
.kpi-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px;
}
.kpi-label { font-size: 12px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
.kpi-value { font-size: 24px; font-weight: 600; margin-top: 4px; }
.kpi-placeholder { color: var(--text-muted); font-style: italic; }

/* ── Tables ──────────────────────────────────────────────────── */
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th { text-align: left; padding: 8px 12px; border-bottom: 2px solid var(--border); color: var(--text-muted); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; }
td { padding: 8px 12px; border-bottom: 1px solid var(--border); }
tr:hover td { background: var(--bg-secondary); }

/* INTAKE-2 — opt-in stronger row-hover variant for dense queue
   tables where the default `tr:hover td` background-only delta
   is too subtle for operator-action confirmation. Apply by adding
   `class="data-table data-table-hover-strong"` on the table.
   Adds an inset accent left-border on the hovered row's first
   cell so the operator's eye locks to the active row before
   clicking Resolve / Open commit. */
table.data-table-hover-strong tbody tr:hover td {
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-secondary));
}
table.data-table-hover-strong tbody tr:hover td:first-child {
  box-shadow: inset 3px 0 0 var(--accent);
}

/* ── Results bar (between filters and table) ─────────────────── */
.results-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
  margin-bottom: 8px;
  font-size: 13px;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border);
}

/* ── Collection table ────────────────────────────────────────── */
.collection-table .col-name { min-width: 180px; }
/* RE-REVIEW-V6 §3 C5 — `.num` standalone utility. Templates
   wrap inline numerics in <span class="num"> for tabular-nums
   alignment outside a table context (page subtitles, summary
   tiles, sale-amount inline cells). Previously only contextual
   rules existed (.lb-dtable td.num, .lb-hover-peek-row > .num);
   this utility makes the bare class work everywhere. */
.num { font-variant-numeric: tabular-nums; }
.collection-table .col-num { text-align: right; font-variant-numeric: tabular-nums; }
.collection-table .col-num:first-line { white-space: nowrap; }
.collection-table th.col-num { text-align: right; }
.item-link { font-weight: 500; }
.item-sub { display: inline-block; font-size: 11px; color: var(--text-muted); margin-left: 6px; }
.item-set { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.badge-grade { background: var(--accent); color: #fff; }
/* RE-REVIEW-V6 §3 C2 — grading-status badge classes aliased
   to the .lb-chip color vocabulary so all status chips share
   one named-token contract. Templates keep the legacy
   class names (no markup churn); the visual moves to the
   tinted-bg + colored-border + colored-text chip pattern. */
.badge-needed {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 8%, transparent);
  border: 1px solid var(--warning);
}
.badge-submitted {
  color: var(--ink-dim, var(--text-secondary));
  background: var(--surface-2, var(--bg-secondary));
  border: 1px solid var(--border);
}
.badge-listed {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border: 1px solid var(--accent);
}
.badge-sold {
  color: var(--ink-faint, var(--text-muted));
  background: var(--surface-2, var(--bg-secondary));
  border: 1px solid var(--border);
}
.badge-archived {
  color: var(--ink-faint, var(--text-muted));
  background: var(--surface-2, var(--bg-secondary));
  border: 1px solid var(--border);
}

/* ── Forms ────────────────────────────────────────────────────── */
.form-group { margin-bottom: 12px; }
.form-group label { display: block; font-size: 12px; font-weight: 500; color: var(--text-secondary); margin-bottom: 4px; }
.form-group input, .form-group select, .form-group textarea {
  width: 100%;
  padding: 8px 10px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text-primary);
  font-size: 13px;
  font-family: inherit;
}
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
  outline: none;
  border-color: var(--accent);
}
/* BOX-1152: restore a visible focus indicator for keyboard users — the
   accent border alone is ~1.17:1 (invisible). Pointer focus keeps the
   clean borderless look via the :focus rule above. */
.form-group input:focus-visible, .form-group select:focus-visible, .form-group textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.form-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }

.btn {
  display: inline-block;
  padding: 8px 16px;
  background: var(--accent-fill);
  color: #fff;
  border: none;
  border-radius: 4px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.btn:hover { background: var(--accent-fill); filter: brightness(1.08); }
.btn-sm { padding: 4px 10px; font-size: 12px; }
.btn-outline { background: var(--bg-input); color: var(--text-primary); border: 1px solid var(--border); }
.btn-outline:hover { background: var(--bg-secondary); color: var(--text-primary); }

/* DESIGN-ALIGN-CSS-CARD-CLASSES-1 — formalize the button-variant
   names templates already write but the stylesheet did not yet
   define. Three additions:

     .btn-primary   — explicit alias of `.btn` for templates that
                      write `class="btn btn-primary"`. No-op
                      visual: the `.btn` base already encodes the
                      accent-background primary style; this rule
                      exists so the class name resolves to a
                      defined selector and templates can drop
                      redundant inline-style attributes that used
                      to compensate for the missing definition.

     .btn-warning   — encodes the inline `style="background:var(
                      --warning); border-color:var(--warning)"`
                      override pattern that fmv_worklist.html and
                      similar templates use for warning-tier
                      actions (Re-derive / Re-run / Review
                      envelope on attention rows). Visual output
                      matches the inline pattern exactly.

     .btn-danger    — encodes the parallel inline pattern using
                      `var(--error)` for error-tier actions
                      (Fix identity on LOOKUP_ERROR rows).

   No new tokens added; reuses existing [data-theme] variables.
   See docs/CLAUDE_DESIGN_PRODUCTION_ALIGNMENT_AUDIT.md §10
   (Slice 1) for the audit context. */
.btn-primary { /* alias of .btn — see comment above */ }
.btn-warning {
  background: var(--warning);
  border-color: var(--warning);
  /* BOX-1158: dark text on the amber warning fill (white was 2.19:1).
     Dark #1a1a1a clears AA on every theme's warning shade (5.46–7.94:1). */
  color: #1a1a1a;
}
.btn-warning:hover { background: var(--warning); filter: brightness(0.92); }
.btn-danger {
  background: var(--error);
  border-color: var(--error);
  color: #fff;
}
.btn-danger:hover { background: var(--error); filter: brightness(0.92); }

/* DESIGN-ALIGN-CSS-CARD-CLASSES-1 — `.status-card` encodes the
   dominant inline pattern used across status-banner uses
   (`<div class="card status-card status-warn" style="padding:8px
   12px;...">` and similar). Templates can drop the inline
   `padding: 8px 12px; border-radius: 4px` once they're confident
   they don't need a per-instance override. CSS specificity
   preserves any inline override that remains in place — visual
   output is unchanged for instances that keep the inline style;
   instances that omit it inherit the encoded defaults. */
.status-card {
  padding: 8px 12px;
  border-radius: 4px;
}

/* DESIGN-ALIGN-FMV-WORKLIST-SHELL-1 — marker classes for the FMV
   worklist app-shell section sequence (per
   docs/FMV_APP_SHELL_UNIFICATION_BRIEF.md §4). The wrappers are
   intentionally visual-no-ops in this slice — every existing
   inner element retains its previous spacing/margins so the
   conversion is operator-visually identical. The classes exist
   primarily as stable hooks for future visual hierarchy
   refinements + as documented-component-vocabulary entry points
   for the queue/inbox/card-detail follow-on slices that will
   share the same naming.
   No new tokens; no [data-theme] block edits. */
.fmv-worklist-shell {
  /* Container marker — no visual rules in this slice. */
}
.fmv-shell-section {
  /* Section marker — no visual rules in this slice. */
}
.fmv-shell-header {
  /* Header section marker — no visual rules in this slice. */
}

/* ── Card Vault visual identity (BOX-1241) — FMV worklist ────── */
/* Fills the design-align shell hooks above with the rollout levers,
   scoped to .fmv-worklist-shell so only the worklist gets them (the
   queue/history shells reuse .fmv-shell-section but not this root).
   Semantic tokens only (ADR-039); no new tokens, no [data-theme] edits.
   The status cards keep their status border colors — the warm hover is
   a shadow LIFT only, never a border recolor. */
.fmv-worklist-shell .fmv-shell-header .page-title {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
}
.fmv-worklist-shell .fmv-shell-header {
  border-left: 3px solid var(--accent-2);
  padding-left: 14px;
}
.fmv-worklist-shell .card {
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--dur) var(--ease);
}
.fmv-worklist-shell .card:hover {
  box-shadow: var(--shadow);
}
@keyframes fmvwRise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: no-preference) {
  .fmv-worklist-shell[data-cv-reveal] > .fmv-shell-section {
    animation: fmvwRise var(--dur-slow, 200ms) var(--ease) both;
  }
  .fmv-worklist-shell[data-cv-reveal] > .fmv-shell-section:nth-of-type(1) { animation-delay: 0ms; }
  .fmv-worklist-shell[data-cv-reveal] > .fmv-shell-section:nth-of-type(2) { animation-delay: 45ms; }
  .fmv-worklist-shell[data-cv-reveal] > .fmv-shell-section:nth-of-type(3) { animation-delay: 90ms; }
  .fmv-worklist-shell[data-cv-reveal] > .fmv-shell-section:nth-of-type(4) { animation-delay: 135ms; }
  .fmv-worklist-shell[data-cv-reveal] > .fmv-shell-section:nth-of-type(5) { animation-delay: 180ms; }
}
/* DESIGN-ALIGN-FMV-QUEUE-SHELL-1 — container marker for the
   cross-commit FMV queue. Same visual-no-op contract as
   .fmv-worklist-shell; reuses .fmv-shell-section + .fmv-shell-
   header from above. Future visual hierarchy refinements can
   target this selector without touching the worklist. */
.fmv-queue-shell {
  /* Container marker — no visual rules in this slice. */
}

/* DESIGN-ALIGN-FMV-HISTORY-DETAIL-FMV-AREA-SHELL-1 — container
   marker for the FMV-bearing slice of the per-commit history
   detail page. Scoped to FMV-related sections only; the rest
   of the page (commit metadata fact-grid, counts, resolution-
   progress, resolve/unresolve forms, correction handoffs,
   summary log, bottom form-actions) deliberately stays outside
   this wrapper. Same visual-no-op contract as the worklist +
   queue shell markers; reuses .fmv-shell-section. */
.fmv-history-shell {
  /* Container marker — no visual rules in this slice. */
}

/* DESIGN-ALIGN-FMV-WORKLIST-SHELL-VISUAL-1 — first visible
   pilot activating the operator FMV worklist shell-section
   hooks shipped in DESIGN-ALIGN-FMV-WORKLIST-SHELL-1.
   Conservative baseline only:
     1. 20px vertical rhythm between adjacent shell sections
        (every section after the first gets `margin-top:20px`).
     2. Subtle separator above the bottom secondary-actions
        section (`border-top` + `padding-top`) so the operator
        visually distinguishes exit-nav from the table content.
   Scoped via the worklist shell container's data-testid so
   no other surface inherits these rules. Uses existing
   [data-theme] tokens only (--border); no new tokens.
   No changes to inner `.card` / `.fmv-tag-*` /
   `.btn-warning` etc. styling. */
[data-testid="fmv-worklist-shell"] .fmv-shell-section + .fmv-shell-section {
  margin-top: var(--shell-section-gap, 20px);
}
[data-testid="fmv-worklist-shell"] .fmv-shell-section + [data-testid="fmv-worklist-shell-secondary-actions"] {
  border-top: 1px solid var(--border);
  padding-top: var(--shell-section-terminal-padding, 16px);
}

/* DESIGN-ALIGN-FMV-QUEUE-SHELL-VISUAL-1 — second visible
   pilot mirroring DESIGN-ALIGN-FMV-WORKLIST-SHELL-VISUAL-1.
   Activates the operator FMV queue shell-section hooks
   shipped in DESIGN-ALIGN-FMV-QUEUE-SHELL-1 with the same
   conservative baseline:
     1. 20px vertical rhythm between adjacent shell sections.
     2. Subtle separator above the bottom secondary-actions
        section (`border-top` + `padding-top`).
   Scoped via the queue shell container's data-testid so no
   other surface inherits these rules. Uses existing
   [data-theme] tokens only (--border); no new tokens. No
   changes to inner `.card` / `.fmv-tag-*` / `.btn-*` etc.
   styling. */
[data-testid="fmv-queue-shell"] .fmv-shell-section + .fmv-shell-section {
  margin-top: var(--shell-section-gap, 20px);
}
[data-testid="fmv-queue-shell"] .fmv-shell-section + [data-testid="fmv-queue-shell-secondary-actions"] {
  border-top: 1px solid var(--border);
  padding-top: var(--shell-section-terminal-padding, 16px);
}

/* DESIGN-ALIGN-FMV-HISTORY-DETAIL-FMV-AREA-SHELL-VISUAL-1 —
   third visible pilot mirroring the worklist + queue pilots.
   Activates the FMV-bearing area of the per-commit history
   detail page (mixed page; the non-FMV commit-detail content
   sits OUTSIDE this shell wrapper per Slice 3's scoping
   decision and is unaffected by these rules). Same
   conservative baseline:
     1. 20px vertical rhythm between adjacent shell sections
        inside the FMV shell wrapper.
     2. Subtle separator (`border-top` + `padding-top`) above
        the audit-trail section (Recent FMV actions). The
        audit-trail is the terminal section of this FMV shell
        area, analogous to secondary-actions on the worklist
        and queue.
   Scoped via the FMV history shell container's data-testid
   so non-FMV commit-detail areas (fact-grid, counts,
   resolution-progress, resolve forms, summary log, bottom
   form-actions) are unaffected. Uses existing [data-theme]
   tokens only (--border); no new tokens. */
[data-testid="fmv-history-shell"] .fmv-shell-section + .fmv-shell-section {
  margin-top: var(--shell-section-gap, 20px);
}
[data-testid="fmv-history-shell"] .fmv-shell-section + [data-testid="fmv-history-shell-audit-trail"] {
  border-top: 1px solid var(--border);
  padding-top: var(--shell-section-terminal-padding, 16px);
}

/* FMV-SHELL-PHASE-1X-FOUNDATION-1 — explicit terminal-section
   attribute hook for the operator-app FMV shells. Mirrors the
   border-top + padding-top treatment from the structural rules
   above so terminal-ness is selectable independently of sibling
   ordering.

   margin-top is intentionally NOT set here — vertical rhythm
   between adjacent sections continues to be owned by the
   structural `+ .fmv-shell-section` rules above. This preserves
   the existing first-section behaviour (no top margin) even if
   a future surface marks its first shell-section as terminal.

   Visual no-op on currently-shipped surfaces: every element
   carrying `data-shell-section-terminal` is the same element
   already matched by the structural border/padding rule above,
   producing identical declarations. */
.fmv-shell-section[data-shell-section-terminal] {
  border-top: 1px solid var(--border);
  padding-top: var(--shell-section-terminal-padding, 16px);
}

/* DESIGN-ALIGN-RECEIPT-ACTION-DENSITY-1 — narrow grouped action
   panel for the rip-sheet commit receipt's bottom-of-page action
   area. Adapts the inspected mockups' button-grouping pattern
   (mockup provenance unverified — see
   docs/CLAUDE_DESIGN_PRODUCTION_ALIGNMENT_AUDIT.md Provenance
   note). Replaces a single 7-button wide row with three small
   labelled clusters (primary / secondary / admin) so the
   operator's most-frequent next step is visually distinct from
   review and admin/exit paths. Reuses existing [data-theme]
   tokens (--border, --text-muted); no new tokens. Scoped to
   the receipt surface only — does not change the more compact
   .form-actions rows used elsewhere on the same page (dry-run
   confirm-live form, correction-handoff form, PO allocation
   follow-up). */
.receipt-action-panel {
  margin-top: 24px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.receipt-action-group {
  margin-bottom: 16px;
}
.receipt-action-group:last-child { margin-bottom: 0; }
.receipt-action-group-title {
  font-size: 11px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.3px;
  margin-bottom: 8px;
}
.receipt-action-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.receipt-action-subtext {
  font-size: 12px;
  color: var(--text-muted);
  margin: 6px 0 0;
}

/* DESIGN-ALIGN-COMMIT-DETAIL-FACT-GRID-1 — narrow 3-column
   fact-grid layout for compact metadata blocks. Adapts the
   card-detail mockup's fact-grid pattern (mockup provenance
   unverified — see docs/CLAUDE_DESIGN_PRODUCTION_ALIGNMENT_AUDIT.md
   Provenance note). First production target is the Commit
   metadata block on /ui/intake-history/{commit_id}. Reuses the
   existing [data-theme] tokens (--bg-input, --border,
   --text-muted, --text-primary); no new tokens. Responsive
   collapse: 3 → 2 columns at <=720px, 2 → 1 column at <=480px.
   .fact-grid-value uses overflow-wrap:anywhere so long IDs/
   hashes/UUIDs don't overflow the cell. */
.fact-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin: 8px 0 0;
}
.fact-grid-cell {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 12px;
  min-width: 0;
}
.fact-grid-label {
  font-size: 11px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.fact-grid-value {
  font-size: 13px;
  color: var(--text-primary);
  margin-top: 4px;
  word-break: break-all;
  overflow-wrap: anywhere;
}
@media (max-width: 720px) {
  .fact-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 480px) {
  .fact-grid { grid-template-columns: 1fr; }
}

/* DESIGN-ALIGN-CSS-CARD-CLASSES-1 — DEFERRED definitions
   (intentionally NOT defined in this batch):

     .card           — bare `<div class="card">` is used 100+
                       times across templates with no consistent
                       inline-style baseline. Defining it would
                       add background+border to every existing
                       use — a meaningful visual change beyond
                       the "same visual output, less scattered
                       styling" intent of this slice. Defer to a
                       follow-on slice that explicitly approves
                       the visual change.

     .status-warn    — currently render as semantic-only markers
     .status-ok        with no consistent inline border-left or
     .status-error     background-tint pattern. Defining them
                       would ADD visual cues that don't exist
                       today (and that the audit's
                       governance-conflict list explicitly warns
                       about: changing FMV-state palette
                       semantics could obscure operator triage).
                       Defer to a follow-on slice that aligns
                       the intended status-emphasis visual with
                       operator-workflow color contracts.

   Documented here so future readers see the deliberate scope
   limit. */

/* ── Messages ────────────────────────────────────────────────── */
.msg { padding: 10px 14px; border-radius: 4px; margin-bottom: 16px; font-size: 13px; }
.msg-error { background: var(--error); color: #fff; }
.msg-success { background: var(--success); color: #fff; }

/* ── Selected card panel (Add Item anchor) ───────────────────── */
.selected-card-panel {
  background: var(--bg-card);
  border: 1px solid var(--accent);
  border-radius: 8px;
  padding: 16px 20px;
  margin-bottom: 20px;
}
.selected-card-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 4px;
}
.selected-card-name {
  font-size: 18px;
  font-weight: 600;
}
.selected-card-meta {
  font-size: 13px;
  color: var(--text-secondary);
}
.selected-card-change {
  font-size: 12px;
  color: var(--text-muted);
}
.selected-card-change:hover {
  color: var(--accent);
}

/* ── Field hints (inline guidance below inputs) ──────────────── */
.field-hint {
  font-size: 10px;
  color: var(--text-muted);
  margin-top: 2px;
  line-height: 1.4;
}

/* ── Flow context (cross-page step guidance) ─────────────────── */
.flow-context {
  background: var(--bg-card);
  border: 1px solid var(--accent);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  padding: 10px 14px;
  margin-bottom: 16px;
  font-size: 13px;
  color: var(--text-secondary);
}

/* ── Detail ──────────────────────────────────────────────────── */
.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 24px; margin-bottom: 24px; }
.detail-item label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; }
.detail-item .val { font-size: 14px; }

.snapshot-toggle { cursor: pointer; color: var(--accent); font-size: 13px; margin-bottom: 8px; }
.snapshot-pre { background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; padding: 12px; font-size: 12px; overflow-x: auto; white-space: pre-wrap; max-height: 400px; overflow-y: auto; display: none; }
.snapshot-pre.open { display: block; }

/* ── Filters ─────────────────────────────────────────────────── */
.filter-primary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: end;
  margin-bottom: 4px;
}
.filter-primary .form-group { margin-bottom: 0; }
.filter-primary input, .filter-primary select {
  width: 120px;
  padding: 6px 8px;
  font-size: 12px;
}
.filter-primary .filter-wide { width: 180px; }
.filter-actions { display: flex; gap: 6px; align-self: end; }

.filter-secondary {
  display: flex;
  gap: 16px;
  margin-bottom: 12px;
  /* UIRECON-RESPONSIVE-AUDIT (BOX-233) — wrap the four
     ``<details>`` filter sections (Storage / Acquisition /
     etc.) so they reflow at narrow widths instead of
     overflowing horizontally. Token-free additive. */
  flex-wrap: wrap;
  row-gap: 12px;
}
.filter-secondary details { flex: 1; }
.filter-section-label {
  cursor: pointer;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 4px 0;
}
.filter-section-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}
.filter-section-fields .form-group { margin-bottom: 0; }
.filter-section-fields input, .filter-section-fields select {
  width: 110px;
  padding: 5px 7px;
  font-size: 11px;
}
.filter-section-fields label {
  font-size: 10px;
}

/* ── Pagination ──────────────────────────────────────────────── */
.pagination { display: flex; gap: 8px; margin-top: 16px; align-items: center; font-size: 13px; color: var(--text-secondary); }

/* ── Theme toggle ────────────────────────────────────────────── */
/* Batch 3: visual-weight bump for discoverability. Operator feedback
   2026-04-13 flagged the toggle as "still hidden at the bottom of
   screen." Remains in the sidebar footer (no IA change) but now
   reads as a deliberate affordance rather than a glyph. */
.theme-toggle {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 7px 12px;
  color: var(--text-primary);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.04);
}
.theme-toggle:hover {
  color: var(--text-primary);
  border-color: var(--accent);
  background: var(--bg-secondary);
}
/* Show sun in dark mode, moon in light mode */
[data-theme="dark"] .theme-icon-light { display: inline; }
[data-theme="dark"] .theme-icon-dark { display: none; }
[data-theme="light"] .theme-icon-light { display: none; }
[data-theme="light"] .theme-icon-dark { display: inline; }

/* ── Section headings ────────────────────────────────────────── */
.section-title { font-size: 14px; font-weight: 600; margin: 20px 0 10px; color: var(--text-secondary); border-bottom: 1px solid var(--border); padding-bottom: 4px; }

/* ── Badge ────────────────────────────────────────────────────── */
.badge { display: inline-block; padding: 2px 6px; border-radius: 3px; font-size: 11px; font-weight: 500; }
.badge-dup { background: var(--warning); color: #000; }
.badge-active { background: var(--success); color: #fff; }
.badge-missing { background: var(--error); color: #fff; }
.badge-unresolved { background: var(--bg-secondary); color: var(--text-muted); border: 1px solid var(--border); }
.badge-mapped { background: var(--accent); color: #fff; }
.badge-unmapped { background: var(--bg-secondary); color: var(--text-muted); border: 1px solid var(--border); }

/* ── Section panels (set detail) ─────────────────────────────── */
.section-panel {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 16px 20px;
  margin-bottom: 20px;
}
.section-panel .section-title { margin-top: 0; }

/* ── Compact table variant ───────────────────────────────────── */
table.compact td { padding: 5px 10px; font-size: 12px; }
table.compact th { padding: 5px 10px; }

/* SETS-SCREEN-DESIGN-ALIGNMENT-2B — set-detail page shell.
   Adds the Design-aligned breadcrumb + identity header + KPI
   strip + primary actions on top of the existing 866-line
   detail page. The legacy hero `.set-card` and 18+ section
   panels below remain intact. */
.set-detail-page { min-width: 0; }
.set-detail-breadcrumb {
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
  margin-bottom: 16px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.set-detail-breadcrumb a {
  color: var(--ink-dim, var(--text-secondary));
  text-decoration: none;
  /* UIRECON-INTAKEHUB (BOX-226) — animate hover/focus colour
     transition so keyboard nav + mouse hover read as the same
     interaction. Mirrors the BOX-225 dashboard rail-action
     vocabulary on a primitive every set-detail / per-set
     worklist / intake-hub page already consumes. */
  transition: color 120ms ease;
}
.set-detail-breadcrumb a:hover { color: var(--accent); }
/* UIRECON-INTAKEHUB (BOX-226) — keyboard-accessible focus ring
   on every breadcrumb anchor. The intake hub uses the shipped
   ``.set-detail-breadcrumb`` as its primary back-anchor, and
   the same primitive is reused by the per-set + per-worklist
   surfaces shipped under BOX-209 → BOX-215, so this single
   rule keyboard-anchors the breadcrumb across every operator-
   facing page that mounts it. Token-driven; no palette change. */
.set-detail-breadcrumb a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
  color: var(--accent);
}
.set-detail-breadcrumb-sep {
  color: var(--ink-faint, var(--text-muted));
  user-select: none;
}
.set-detail-breadcrumb-current {
  color: var(--ink, var(--text-primary));
  font-weight: 500;
}
.set-detail-header {
  padding: 22px 24px;
  margin-bottom: 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.set-detail-eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
}
.set-detail-title {
  font-size: 26px;
  font-weight: 600;
  color: var(--ink, var(--text-primary));
  margin: 0;
  letter-spacing: -0.005em;
  line-height: 1.15;
}
.set-detail-subtitle {
  font-size: 13px;
  color: var(--ink-dim, var(--text-secondary));
}
.set-detail-kpi-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  margin-top: 4px;
}
@media (max-width: 760px) {
  .set-detail-kpi-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.set-detail-kpi {
  background: var(--surface-2, var(--bg-secondary));
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 5px);
  padding: 10px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.set-detail-kpi-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
}
.set-detail-kpi-value {
  font-size: 18px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink, var(--text-primary));
  line-height: 1.1;
}
.set-detail-kpi-value-empty {
  color: var(--ink-faint, var(--text-muted));
  font-size: 14px;
  font-weight: 500;
}
.set-detail-kpi-sub {
  font-size: 11px;
  color: var(--ink-dim, var(--text-secondary));
}
.set-detail-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* UIRECON-SETDETAIL (BOX-228) — narrow mode-tab visual polish on
   the single mode-control surface (the
   ``set-detail-taxonomy-mode-summary`` <nav> after
   ``SET-DETAIL-UX-V2-RETIRE-LEGACY-TABS-AND-EXTEND-DIAGNOSTICS-1``
   retired the legacy duplicate strip). The mode-tab anchor is
   styled inline by the template (background / border-color /
   color flip on ``data-active="1"``); CSS only animates the
   properties that are NOT set inline so inline-style precedence
   never fights the new rules. Adds a smooth transform-on-hover
   lift + token-driven focus-visible outline that keyboard-anchors
   the tab strip. */
[data-testid="set-detail-taxonomy-mode-cell"] {
  transition:
    transform 120ms ease,
    box-shadow 120ms ease;
}
[data-testid="set-detail-taxonomy-mode-cell"]:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 6px color-mix(in srgb, var(--accent) 12%, transparent);
}
[data-testid="set-detail-taxonomy-mode-cell"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
[data-testid="set-detail-taxonomy-mode-cell"][data-active="1"]:hover {
  /* Active tab gets a slightly stronger lift cue so the active
     state continues to read as "selected" even when the
     non-active tab is being hovered next to it. */
  box-shadow: var(--shadow-lg);
}

/* ── Set tracking cards ─────────────────────────────────────── */
.set-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 20px 24px;
  margin-bottom: 16px;
  /* SETS-SCREEN-DESIGN-ALIGNMENT-2A — make the card a
     clickable surface via the stretched-link pattern (no JS).
     `position: relative` is the anchor for the .set-card-cta-
     stretched ::after pseudo that covers the entire card.
     `cursor: pointer` signals interactivity even when the
     pointer is over inert text inside the card. */
  position: relative;
  cursor: pointer;
  transition:
    border-color 120ms ease,
    transform 120ms ease,
    box-shadow 120ms ease;
}
.set-card:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
  box-shadow: var(--shadow);
}
.set-card:focus-within {
  border-color: var(--accent);
  outline: 2px solid color-mix(in srgb, var(--accent) 32%, transparent);
  outline-offset: 2px;
}
/* Stretched-link affordance: a CSS pseudo on the primary CTA
   anchor expands to fill the entire .set-card so any click on
   the card navigates to the set detail. Other interactive
   elements (Find Missing link, badges) sit on a higher z-index
   so they remain individually clickable. */
.set-card-cta-stretched::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
}
.set-card-cta-stretched:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
/* Inner interactive elements stay above the stretched-link
   pseudo so they remain clickable. */
.set-card .set-card-find-missing {
  position: relative;
  z-index: 2;
}
.set-card-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 12px;
}
.set-card-name { font-size: 16px; font-weight: 600; }
.set-card-meta { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.set-card-value { font-size: 22px; font-weight: 600; }
.set-card-stats {
  display: flex;
  gap: 24px;
  margin-bottom: 4px;
}
.set-stat {}
.set-stat-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.3px; }
.set-stat-value { font-size: 16px; font-weight: 600; margin-top: 1px; }
.set-card-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.set-card-cta {
  font-size: 13px;
  font-weight: 500;
}

/* SETS-2D — dense multi-column tracking grid. Placed AFTER the
   `.set-card {` rule so legacy substring-search tests
   (`css.find(".set-card {")`) match the original rule first.
   Operators with many tracked sets can scan more sets per
   viewport without scrolling endlessly; operators with few sets
   see the same one-tall-card-per-row layout because `auto-fill`
   with `minmax(360px, 1fr)` collapses to a single column at
   narrow widths. The grid's `gap` is the single source of truth
   for inter-card spacing — the legacy `.set-card { margin-bottom:
   16px }` is reset to 0 inside the grid so cards don't
   double-space. */
.sets-tracking-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
  gap: 16px;
  margin-bottom: 16px;
}
.sets-tracking-grid > .set-card {
  margin-bottom: 0;
}

/* SETS-SCREEN-DESIGN-ALIGNMENT-2E — chip-based operator-control
   surface above the tracking grid. Search input + chip-grouped
   filters (checklist state, sport theme) + sort field/direction
   toggle. All controls scoped to `.sets-filter-*` so Collection /
   Item Detail / Set Detail selectors are not affected. Hover/focus
   parallels the shipped `.collection-view-toggle` vocabulary;
   active-state painting via `data-active="true"` mirrors that
   pattern verbatim. */
.sets-filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 24px;
  align-items: center;
  padding: 12px 14px;
  margin-bottom: 16px;
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
}
.sets-filter-search {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 220px;
  margin: 0;
}
.sets-filter-search-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint, var(--text-muted));
  margin: 0;
}
.sets-filter-search-input {
  flex: 1 1 180px;
  min-width: 140px;
  padding: 6px 10px;
  font-size: 13px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 5px);
  color: var(--ink, var(--text-primary));
}
.sets-filter-search-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}
.sets-filter-search-submit { flex: 0 0 auto; }
.sets-filter-reset {
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
  text-decoration: none;
  flex: 0 0 auto;
}
.sets-filter-reset:hover { color: var(--accent); }

.sets-filter-group {
  display: flex;
  align-items: center;
  gap: 8px;
}
.sets-filter-group-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint, var(--text-muted));
}
.sets-filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 5px);
  padding: 2px;
  background: var(--bg-card);
}
.sets-filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  font-size: 12px;
  text-decoration: none;
  color: var(--ink-dim, var(--text-secondary));
  background: transparent;
  border-radius: var(--radius-sm, 5px);
  transition: background 120ms, color 120ms, box-shadow 120ms;
}
.sets-filter-chip:hover {
  background: var(--surface-2, var(--bg-secondary));
  color: var(--ink, var(--text-primary));
}
.sets-filter-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.sets-filter-chip[data-active="true"] {
  background: var(--accent);
  color: var(--bg-card);
  font-weight: 500;
}
.sets-filter-chip[data-active="true"]:hover {
  background: var(--accent);
  color: var(--bg-card);
}
.sets-filter-sort-arrow {
  font-size: 10px;
  line-height: 1;
}
.sets-filter-sort-clear {
  font-size: 11px;
  color: var(--ink-faint, var(--text-muted));
}

/* Empty-state surface used by both "no sets tracked yet" and "no
   sets match the active filters" branches. */
.sets-tracking-empty {
  text-align: center;
  padding: 32px 20px;
}
.sets-tracking-empty-title {
  font-size: 14px;
  color: var(--ink-dim, var(--text-secondary));
  margin-bottom: 4px;
}
.sets-tracking-empty-body {
  font-size: 13px;
  color: var(--ink-faint, var(--text-muted));
  margin-bottom: 12px;
}

/* Visually-hidden helper — used by the sort chip's asc/desc state
   announcement so screen readers hear the direction without
   relying on the &uarr;/&darr; glyph. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* SET-DETAIL-COMPLETION-MAP-1 — heat-grid on the Set Detail page.
   One cell per unique card_number in the shipped checklist,
   color-coded by ownership state derived in
   shared.db.services.set_completion. Dense by design (operators
   need to scan 200+ cells in one view); cells display the card
   number itself and a native `title` tooltip. No FMV / popover /
   sparkline — all deferred to a follow-up batch. The shell wrapper
   reuses .lb-surface from the upper-panel; the title/subtitle
   primitives parallel .item-detail-section-title /
   .item-detail-section-subtitle so the section reads with the
   shipped Design vocabulary. */
.set-detail-completion-map {
  /* Shell padding — `.lb-surface` already supplies the surface +
     border + radius; the section gets its own internal padding so
     header / grid / legend breathe consistently. */
  padding: 20px 24px;
}
.set-detail-completion-map-header {
  margin-bottom: 12px;
}
.set-detail-section-title {
  font-size: 16px;
  font-weight: 600;
  margin: 0 0 4px;
  color: var(--ink, var(--text-primary));
}
.set-detail-section-subtitle {
  font-size: 12px;
  margin: 0;
  color: var(--ink-faint, var(--text-muted));
}
/* F-14 — keep the active filter context pinned so it doesn't scroll off above a
   long completion grid; reuses existing surface/border tokens only. */
.set-detail-section-subtitle[data-grid-filter-active="1"] {
  position: sticky;
  top: 0;
  z-index: 4;
  padding: 6px 0;
  background: var(--surface, var(--bg-card));
  border-bottom: 1px solid var(--border);
}
.set-detail-completion-map-empty {
  padding: 16px 0;
  font-size: 13px;
}

/* The dense grid itself. `auto-fill` + `minmax` keeps cells
   uniform across viewports while letting the grid wrap to fit
   the available width. Cells are square-ish at 36–44px so a
   300-card set fits ~6-8 cells per row on a typical desktop. */
.completion-map-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
  gap: 4px;
  margin-bottom: 16px;
}

/* Each cell is a small square showing the card number + carrying
   the state via `data-completion-state` + an `is-{state}` class.
   The base shape is shared; the four state variants below paint
   the swatch color. Cells are non-interactive `<span>` elements
   in this batch (no href / tabindex) — title-tooltip + aria-label
   carry every screen-reader and pointer affordance the operator
   needs. */
.completion-map-cell {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 10px;
  font-weight: 500;
  color: var(--ink, var(--text-primary));
  background: var(--surface-2, var(--bg-secondary));
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: help;
  transition:
    transform var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    box-shadow var(--dur-fast) var(--ease);
}
/* Visible-hover delta — same vocabulary as .set-card:hover /
   .dash-stat-tile:hover / .item-detail-rail-card:hover,
   scaled down for the smaller cell size (translateY(-1px) +
   soft accent shadow + accent border). */
.completion-map-cell:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
  z-index: 1;
}
.completion-map-cell:focus-visible {
  border-color: var(--accent);
  outline: 2px solid color-mix(in srgb, var(--accent) 32%, transparent);
  outline-offset: 1px;
}

/* Four state variants. Color values borrow from the existing FMV
   palette tokens (var(--success) / var(--warning) / var(--accent))
   plus a neutral surface-2 for "missing" so the scheme reads under
   both light and dark themes without new tokens. The text color
   on each variant stays on the high-contrast side of the swatch. */
.completion-map-cell.is-owned {
  background: color-mix(in srgb, var(--success) 32%, var(--surface, var(--bg-card)));
  border-color: color-mix(in srgb, var(--success) 50%, var(--border));
  color: var(--ink, var(--text-primary));
}
.completion-map-cell.is-graded {
  background: color-mix(in srgb, var(--success) 60%, var(--surface, var(--bg-card)));
  border-color: color-mix(in srgb, var(--success) 70%, var(--border));
  color: var(--ink, var(--text-primary));
  font-weight: 600;
}
.completion-map-cell.is-parallel {
  background: color-mix(in srgb, var(--accent) 30%, var(--surface, var(--bg-card)));
  border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
  color: var(--ink, var(--text-primary));
}
.completion-map-cell.is-missing {
  background: var(--surface-2, var(--bg-secondary));
  border-color: var(--border);
  color: var(--ink-faint, var(--text-muted));
}
/* BOX-2037 — the completion map consumes the shared unbound-slot token
   instead of painting this state as an ordinary missing card. */
.completion-map-cell.is-unresolved {
  background: var(--slot-unbound-surface);
  border-color: var(--slot-unbound-border);
  border-style: dashed;
  color: var(--slot-unbound-ink);
  opacity: var(--slot-unbound-opacity);
}

/* Compact legend — only renders states actually present in the
   grid (the template guards each chip with
   `{% if s in completion_grid.states_present %}`). The legend
   never includes Wishlist; it's not a production state and this
   batch must not fake it. */
.completion-map-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  font-size: 11px;
  color: var(--ink-dim, var(--text-secondary));
}
.completion-map-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.completion-map-legend-swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  border: 1px solid var(--border);
}
.completion-map-legend-swatch.is-owned {
  background: color-mix(in srgb, var(--success) 32%, var(--surface, var(--bg-card)));
}
.completion-map-legend-swatch.is-graded {
  background: color-mix(in srgb, var(--success) 60%, var(--surface, var(--bg-card)));
}
.completion-map-legend-swatch.is-parallel {
  background: color-mix(in srgb, var(--accent) 30%, var(--surface, var(--bg-card)));
}
.completion-map-legend-swatch.is-missing {
  background: var(--surface-2, var(--bg-secondary));
}
.completion-map-legend-swatch.is-unresolved {
  background: var(--slot-unbound-surface);
  border-color: var(--slot-unbound-border);
  border-style: dashed;
  opacity: var(--slot-unbound-opacity);
}
/* F-11 — controls row above the completion grid: legend (left) + a
   "Missing only" density toggle (right). View-only; the toggle hides
   non-missing cells via the data-missing-only attribute set by inline JS. */
.completion-map-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  margin: 4px 0 10px;
}
.completion-map-missing-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  color: var(--ink-dim, var(--text-secondary));
  user-select: none;
}
.completion-map-grid[data-missing-only="1"]
  .completion-map-cell:not([data-completion-state="missing"]) {
  display: none;
}

/* SET-DETAIL-COMPLETION-MAP-PEEK-1 — hover/focus popover. Pinned
   to absolute coordinates relative to <body> via inline JS; no
   global stacking-context surprises. Width-bounded so wide
   valuation strings wrap cleanly. Kept minimalist on purpose —
   no actions, no editable fields, no sparkline. */
.completion-map-peek {
  position: absolute;
  z-index: 50;
  min-width: 180px;
  max-width: 220px;
  padding: 10px 12px;
  border-radius: 6px;
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--accent);
  box-shadow:
    0 4px 12px color-mix(in srgb, var(--accent) 18%, transparent),
    0 1px 3px rgba(0, 0, 0, 0.12);
  font-size: 12px;
  line-height: 1.4;
  color: var(--ink, var(--text-primary));
  pointer-events: none;  /* mouseleave on the cell still fires */
}
.completion-map-peek[hidden] { display: none; }
.completion-map-peek .peek-card-num {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-faint, var(--text-muted));
  margin-bottom: 4px;
}
.completion-map-peek .peek-mid {
  font-size: 18px;
  font-weight: 600;
  color: var(--ink, var(--text-primary));
  font-variant-numeric: tabular-nums;
}
.completion-map-peek .peek-range {
  font-size: 11px;
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}
.completion-map-peek .peek-meta {
  font-size: 10px;
  margin-top: 4px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.completion-map-peek .peek-comps {
  font-size: 11px;
  margin-top: 2px;
}
.completion-map-peek .peek-review-needed {
  margin-top: 6px;
  font-size: 10px;
  font-weight: 600;
  color: var(--warning, #d97706);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.completion-map-peek .peek-status,
.completion-map-peek .peek-loading {
  font-size: 12px;
}

/* SETS-P1-IDENTITY-1 — hero identity line spacing only. The
   inline-flex layout is on the element itself; this rule just
   keeps the eyebrow labels visually subordinate to the values
   when rendered next to the existing subtitle. No new design
   tokens. */
.set-detail-identity-line {
  margin-top: 6px;
}

/* ── Progress bar ────────────────────────────────────────────── */
.progress-bar {
  height: 6px;
  background: var(--bg-secondary);
  border-radius: 3px;
  overflow: hidden;
}
.progress-bar-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
  min-width: 2px;
}

/* ── Set summary (collection totals) ─────────────────────────── */
.set-summary {
  display: flex;
  gap: 32px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 20px 24px;
  margin-top: 8px;
}
.set-summary-stat { flex: 1; }

/* ── Missing cards grid ─────────────────────────────────────── */
.missing-cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}
.missing-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 12px;
}

/* ── SC-1A: Checklist icons + availability ─────────────────── */
.ci-icon { display: inline-block; vertical-align: middle; flex-shrink: 0; }
.ci-badge-icon { display: inline-block; vertical-align: middle; }

.checklist-summary {
  font-size: 12px;
  color: var(--text-muted);
  margin-bottom: 10px;
}
.constraint-summary {
  font-size: 12px;
  color: var(--text-secondary);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 6px 10px;
  margin-bottom: 8px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.badge-tracked {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 3px;
  background: var(--bg-secondary);
  color: var(--text-secondary);
  border: 1px solid var(--border);
}
.badge-weak-match {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 3px;
  background: var(--bg-secondary);
  color: var(--warning);
  border: 1px solid var(--warning);
}

.avail-area {
  margin-top: 6px;
  padding: 6px 8px;
  background: var(--bg-secondary);
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}
.avail-price { font-weight: 600; font-variant-numeric: tabular-nums; }
.avail-condition { color: var(--text-muted); font-size: 11px; }
.avail-link { font-size: 11px; color: var(--accent); white-space: nowrap; }
.avail-more { font-size: 10px; color: var(--text-muted); }

/* ── Compact acquisition rows (shared across dashboard + wantlist) */
.acq-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 14px;
  font-size: 13px;
}

/* ── Dashboard Buy Next rows ────────────────────────────────── */
.dash-buynext-list { display: flex; flex-direction: column; gap: 6px; }
.dash-buynext-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 14px;
  font-size: 13px;
}

/* ── Complete set view (numeric grid) ────────────────────────── */
.set-grid {
  display: grid;
  grid-template-columns: repeat(20, 1fr);
  gap: 4px;
  margin-bottom: 8px;
}
.set-grid-cell {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 500;
  cursor: default;
  /* UIRECON-COMPLETIONMAP (BOX-229) — animate any future state
     change (re-render, programmatic focus) so the legacy grid
     reads as part of the modern UIRECON vocabulary. Token-driven;
     no static visual delta. */
  transition:
    background-color 120ms ease,
    border-color 120ms ease,
    box-shadow 120ms ease;
}
/* UIRECON-COMPLETIONMAP (BOX-229) — defensive keyboard-
   accessible focus ring on the legacy ``.set-grid-cell``.
   Cells are non-interactive today (``cursor: default``, no
   tabindex), so the rule is dormant; if any future slice
   adds a tabindex / interactive role to the cell, the
   outline is already in place and matches the modern
   ``.completion-map-cell:focus-visible`` recipe. */
.set-grid-cell:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 32%, transparent);
  outline-offset: 1px;
}
.set-grid-owned {
  background: #1b5e20;
  color: #a5d6a7;
}
.set-grid-missing {
  background: var(--bg-secondary);
  color: var(--text-muted);
}
.set-grid-unresolved {
  background: var(--slot-unbound-surface);
  border: 1px dashed var(--slot-unbound-border);
  color: var(--slot-unbound-ink);
  opacity: var(--slot-unbound-opacity);
}

/* Shared hook used by Maintenance, both Definition renderers, and the
   completion map.  Surface selectors may own geometry, but never the
   unbound-slot palette or emphasis. */
.lb-unbound-slot {
  background: var(--slot-unbound-surface);
  border-color: var(--slot-unbound-border);
  border-width: 1px;
  border-style: dashed;
  color: var(--slot-unbound-ink);
  opacity: var(--slot-unbound-opacity);
}

/* UNMATCHED-ENTRY-RESOLUTION (P1) — operator closeout status pills. */
.tag {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}
.tag-acknowledged {
  background: var(--bg-secondary);
  color: var(--text-secondary);
  border: 1px solid var(--border);
}
.tag-deferred {
  background: rgba(243, 156, 18, 0.15);
  color: var(--warning);
  border: 1px solid var(--warning);
}
.tag-resolved {
  background: rgba(76, 175, 80, 0.15);
  color: var(--success);
  border: 1px solid var(--success);
}

/* INTAKE-FMV-ON-RECEIPT — truthful FMV envelope-state pills. */
.fmv-tag {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  /* UIRECON-INTAKE-FMV (BOX-230) — animate any future state change
     (e.g., tag swapping after a re-run lands) so the chip swaps
     smoothly. Only animate properties intrinsic to the chip;
     palette colors are NOT modified by BOX-230 — the FMV palette
     semantics shipped under FMV-ATTENTION-SEMANTICS-AND-DASHBOARD-1
     are a contract. */
  transition:
    background 120ms ease,
    border-color 120ms ease,
    color 120ms ease;
}
/* UIRECON-INTAKE-FMV (BOX-230) — defensive keyboard-accessible
   focus ring on FMV status chips. Today's chips render as
   non-interactive ``<span>`` labels so the rule is dormant; if a
   future slice promotes a chip to a link / button (e.g., a chip
   that filters the queue by status), the outline + offset are
   already in place and match the BOX-225 / BOX-227 / BOX-228 /
   BOX-229 ``:focus-visible`` recipe. */
.fmv-tag:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 10px;
}
.fmv-tag-ok {
  background: rgba(76, 175, 80, 0.15);
  color: var(--success);
  border-color: var(--success);
}
.fmv-tag-review_needed {
  background: rgba(243, 156, 18, 0.15);
  color: var(--warning);
  border-color: var(--warning);
}
.fmv-tag-stale {
  background: rgba(243, 156, 18, 0.15);
  color: var(--warning);
  border-color: var(--warning);
}
.fmv-tag-override {
  background: rgba(74, 144, 217, 0.15);
  color: var(--accent);
  border-color: var(--accent);
}
.fmv-tag-lookup_error {
  background: rgba(231, 76, 60, 0.15);
  color: var(--error);
  border-color: var(--error);
}

/* UIRECON-INTAKE-FMV (BOX-230) — keyboard-focus row anchor for
   the FMV queue. When focus lands on a control inside a queue row
   (checkbox, action link, etc.), give the row a subtle accent
   tint so the operator visibly anchors which row is active. The
   `data-table-hover-strong` opt-in already handles the mouse-hover
   path; this rule covers the keyboard equivalent. Token-driven;
   no palette change. */
.fmv-queue-row:focus-within > td {
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.fmv-queue-row-checkbox:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* DESIGN-ALIGN-DASHBOARD-KPI-STRIP-1 — 4-up KPI stat strip on
   /ui/intake-workflow above the existing 11 dashboard cards.
   Adapts the dashboard mockup's stat-strip pattern (mockup
   provenance unverified — see
   docs/CLAUDE_DESIGN_PRODUCTION_ALIGNMENT_AUDIT.md Provenance
   note). Reuses existing [data-theme] tokens; introduces no new
   theme variables. Tiles render as anchor elements so the entire
   tile is the click target into the linked operator surface. */
.dash-stat-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  margin: 0 0 16px;
}
.dash-stat-tile {
  display: block;
  padding: 14px 16px;
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--ink, var(--text-primary));
  text-decoration: none;
  /* INTAKE-2 hover repair: mirror the shipped .set-card:hover
     pattern (lift + accent shadow) so the hover delta is visible
     in normal use, not just in devtools. Operator validation on
     the prior batch confirmed border-color-only deltas read as
     "static" against the dashboard background. */
  transition:
    border-color 120ms ease,
    background 120ms ease,
    transform 120ms ease,
    box-shadow 120ms ease;
}
.dash-stat-tile:hover {
  border-color: var(--accent);
  color: var(--ink, var(--text-primary));
  transform: translateY(-1px);
  box-shadow: var(--shadow);
}
.dash-stat-tile:focus-visible {
  border-color: var(--accent);
  outline: 2px solid color-mix(in srgb, var(--accent) 32%, transparent);
  outline-offset: 2px;
}
/* DASHBOARD-VISUAL-MIGRATION-CROSS-PAGE-5A — kpi-strip tile
   typography aligned with the migrated dashboard's .dash-kpi
   shell. Mono small-caps label + tabular-nums value + ink-faint
   sub-text, all consuming the fc86963 alias chain with the
   legacy --text-* / --bg-card token as inline fallback. */
.dash-stat-tile-label {
  font-size: 11px;
  color: var(--ink-faint, var(--text-muted));
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}
.dash-stat-tile-value {
  font-size: 28px;
  font-weight: 600;
  margin-top: 6px;
  color: var(--ink, var(--text-primary));
  line-height: 1.1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.dash-stat-tile-sub {
  font-size: 12px;
  color: var(--ink-dim, var(--text-secondary));
  margin-top: 4px;
}

/* ════════════════════════════════════════════════════════════════
   DASHBOARD-VISUAL-MIGRATION-COMPONENT-PRIMITIVES-6
   Foundation component layer for the dashboard visual migration.

   Mirrors the Claude Design prototype's component primitives
   (handoff: docs/lunchbox-memorabilia/project/src/theme.jsx +
   src/components.jsx + src/dashboard.jsx). Pure additive CSS:
   no existing class renamed, no template touched, no existing
   selector modified. Future per-page migration slices opt in
   by replacing legacy markup with these primitives.

   Namespace discipline: every primitive is prefixed `.lb-` so
   it cannot collide with the legacy operator-app vocabulary
   (.btn alone has 10 production rules + heavy template usage;
   .field has a sibling `.field-hint` rule). Templates that
   want the new primitive use `.lb-btn`, `.lb-chip`, etc.;
   templates that don't, stay on the legacy classes.

   Token discipline: every color/spacing reference uses the
   fc86963 alias chain (--ink, --ink-dim, --ink-faint,
   --surface) + the COMPONENT-PRIMITIVES-6 spacing tokens
   (--card-p, --gap, --row-h, --cell-px, --radius, --radius-
   sm) with the legacy token as inline fallback so the layer
   remains readable if any alias is later removed.

   Coverage:
     §1 .lb-surface — flat card primitive
     §2 .lb-chip + 6 color variants
     §3 .lb-btn + 4 variants (primary, ghost, sm, lg)
     §4 .lb-dtable — sticky-header data table primitive
     §5 .lb-field — form input shell with confidence routing
     §6 .lb-dot + 5 color variants
     §7 .lb-hover-peek-anchor + .lb-hover-peek — JS-driven
        detail-card popover (lifts the prior no-JS-interaction
        constraint per operator decision; positioning + dismiss
        in app/api/static/hover_peek.js)

   None of these primitives are wired into any production
   template by this slice. Activation is per-page (next
   batches). Tests assert declarations exist + behavior is
   sound; no template render assertions because no templates
   consume yet.
   ════════════════════════════════════════════════════════════════ */

/* §1 — .lb-surface: flat card primitive
   Replaces the legacy .card / .section-panel / .bg-card
   inline patterns with a single primitive. Three tiers via
   the --surface, --surface-2, --surface-3 tokens. */
.lb-surface {
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  padding: var(--card-p, 20px);
}
.lb-surface-2 {
  background: var(--surface-2, var(--bg-secondary));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  padding: var(--card-p, 20px);
}
.lb-surface-flat {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  padding: var(--card-p, 20px);
}
/* RE-REVIEW-V6 §3 C1 — .lb-surface-legacy: bounded-interior
   boundary marker. Wraps an intentionally legacy interior on
   an otherwise-migrated page so design review + the next
   migration agent read the bound as deliberate scope rather
   than a regression. Same surface tokens as .lb-surface, plus
   a 2px dashed --ink-faint inset on the top edge as the
   visible "intentional scope boundary" cue. Pair with
   .lb-surface-legacy-label for the mono small-caps top label. */
.lb-surface-legacy {
  position: relative;
  border-top: 2px dashed var(--ink-faint, var(--text-muted));
  padding-top: calc(var(--card-p, 20px) + 4px);
  margin-top: 16px;
}
.lb-surface-legacy-label {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint, var(--text-muted));
  margin-bottom: 12px;
}

/* §2 — .lb-chip: color-routed pill chip
   For status / event-family / count chips. 999px radius +
   tabular-nums + mono-uppercase variant. */
.lb-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  font-family: var(--font-sans);
  background: var(--surface-2, var(--bg-secondary));
  color: var(--ink-dim, var(--text-secondary));
  border: 1px solid var(--border);
  white-space: nowrap;
  vertical-align: middle;
}
.lb-chip-mono {
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 10px;
}
.lb-chip-num {
  font-variant-numeric: tabular-nums;
}
.lb-chip-ok {
  color: var(--success);
  border-color: var(--success);
  background: color-mix(in srgb, var(--success) 8%, transparent);
}
.lb-chip-warn {
  color: var(--warning);
  border-color: var(--warning);
  background: color-mix(in srgb, var(--warning) 8%, transparent);
}
.lb-chip-danger {
  color: var(--error);
  border-color: var(--error);
  background: color-mix(in srgb, var(--error) 8%, transparent);
}
.lb-chip-info {
  color: var(--accent);
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.lb-chip-accent {
  color: var(--accent);
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.lb-chip-muted {
  color: var(--ink-faint, var(--text-muted));
  border-color: var(--border);
  background: var(--surface-2, var(--bg-secondary));
}
/* RE-REVIEW-V6 §3 C2 — named-token chip vocabulary aliases.
   The existing `-ok / -warn / -danger / -info` modifiers are
   role-named; v6 wants the named-token contract
   `-default / -success / -warning / -error` to be authoritative
   across collection + the next route-families. Aliases are
   additive — existing `-ok / -warn / -danger / -info` continue
   to work for prior templates and tests. */
.lb-chip-default {
  color: var(--ink-dim, var(--text-secondary));
  border-color: var(--border);
  background: var(--surface-2, var(--bg-secondary));
}
.lb-chip-success {
  color: var(--success);
  border-color: var(--success);
  background: color-mix(in srgb, var(--success) 8%, transparent);
}
.lb-chip-warning {
  color: var(--warning);
  border-color: var(--warning);
  background: color-mix(in srgb, var(--warning) 8%, transparent);
}
.lb-chip-error {
  color: var(--error);
  border-color: var(--error);
  background: color-mix(in srgb, var(--error) 8%, transparent);
}

/* §2c — .lb-flash* / .lb-badge / .lb-chip active-state: status + label
   primitives (BOX-1531 slice 1). These lb-* classes render across the FMV
   evidence + BYO-AI surfaces (+ sets/set_health) but were undefined
   no-ops, so flash notices, badges, and the active filter chip rendered
   unstyled. Aligned to the design-v2 token vocabulary — role tints via
   color-mix + semantic surface/ink/border tokens; no raw --bg-*/--text-*
   primary, so off the ADR-039 raw-token ratchet.

   ACCESSIBILITY: the .lb-flash-* role modifiers carry the role hue ONLY on
   the border + the 8% background tint — flash TEXT stays --ink (primary).
   Do NOT add `color: var(--role)` to a flash: it inherits into the
   multi-line flash body (the byoai_import schema-error <ul>, the
   evidence_queue "Replaces existing FMV…" warning) where role hue on the
   near-page tint fails WCAG AA for normal-size text (light warning ~2.9:1).
   Unlike the 11px .lb-chip LABELS this mirrors, flash bodies are readable
   body copy, so the 4.5:1 normal-text bar (test_material_muted_contrast_a11y)
   applies. --ink on the 8% tint clears it.

   Definitions only (no markup change); the button convergence
   (lb-button* -> the canonical .lb-btn*) is a separate slice. */
.lb-flash {
  padding: 8px 12px;
  border-radius: var(--radius, 8px);
  border: 1px solid var(--border);
  background: var(--surface-2, var(--bg-secondary));
  color: var(--ink, var(--text-primary));
  font-size: 13px;
}
.lb-flash-success {
  border-color: var(--success);
  background: color-mix(in srgb, var(--success) 8%, transparent);
}
.lb-flash-error {
  border-color: var(--error);
  background: color-mix(in srgb, var(--error) 8%, transparent);
}
.lb-flash-warning {
  border-color: var(--warning);
  background: color-mix(in srgb, var(--warning) 8%, transparent);
}
.lb-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 7px;
  border-radius: var(--radius-sm, 5px);
  font-size: 11px;
  font-weight: 500;
  font-family: var(--font-sans);
  background: var(--surface-2, var(--bg-secondary));
  color: var(--ink-dim, var(--text-secondary));
  border: 1px solid var(--border);
  white-space: nowrap;
  vertical-align: middle;
}
/* Grouped so both the filter-bar spelling and evidence_ops's BEM
   `.lb-chip--active` get the active highlight. Keep `.lb-chip-active` the
   brace-adjacent (last) selector — the BOX-1227 structural guard's
   extract_rule_body matches a selector immediately before its opening
   brace at line start. */
.lb-chip--active,
.lb-chip-active {
  color: var(--accent);
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  font-weight: 500;
}

/* §2b — .lb-chip-row / .lb-section-title / .lb-text-small: filter + section
   primitives (BOX-1528). All three were referenced across the FMV evidence
   + BYO-AI surfaces but never defined — silent no-ops (the class-level
   analogue of the BOX-1150 `.muted` restore), so `<ul class="lb-chip-row">`
   fell back to default list chrome (marker + 40px indent, no global ul
   reset), section titles rendered as unstyled block text, and `lb-text-small`
   helper/meta spans rendered at body size. None sets a color token, so they
   stay off the ADR-039 raw-token ratchet and each inherits its context text
   color (primary ink; the `.lb-flash*` wrappers — defined in §2c above — set
   no text color either, only a role border + tint). `.lb-text-small` also pins font-weight:400
   so it does NOT inherit the 600 of a parent `.lb-section-title` — the
   filter-group labels nest a `<span class="muted lb-text-small">` helper that
   must stay de-emphasized. `.lb-chip-row` works on both its `<ul>` callers
   (queue / intake-activity) and its `<div>` caller (evidence-ops). */
.lb-chip-row {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.lb-section-title {
  margin: 0 0 6px;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
}
.lb-text-small {
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
}

/* §3 — .lb-btn: button primitive + 4 variants
   Namespaced to avoid collision with the legacy .btn family
   (10 existing rules + heavy template usage). Templates that
   want the prototype's button system use `.lb-btn`. */
.lb-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: var(--radius-sm, 5px);
  background: var(--surface-2, var(--bg-secondary));
  color: var(--ink, var(--text-primary));
  border: 1px solid var(--border);
  font-size: 13px;
  font-family: var(--font-sans);
  font-weight: 500;
  cursor: pointer;
  transition: background 120ms, border-color 120ms, color 120ms;
  text-decoration: none;
}
.lb-btn:hover {
  background: var(--surface-3, var(--bg-input));
  border-color: var(--border-strong, var(--text-secondary));
}
.lb-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.lb-btn-primary {
  /* BOX-1158: darkened accent fill + white text (was --accent fill with
     --bg-card text = 3.65:1). White on --accent-fill clears AA. */
  background: var(--accent-fill);
  color: #fff;
  border-color: var(--accent-fill);
}
.lb-btn-primary:hover {
  filter: brightness(1.08);
  background: var(--accent-fill);
  border-color: var(--accent-fill);
}
.lb-btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--ink-dim, var(--text-secondary));
}
.lb-btn-ghost:hover {
  color: var(--ink, var(--text-primary));
  background: var(--surface-2, var(--bg-secondary));
  border-color: transparent;
}
/* BOX-1155: .lb-btn-outline — referenced 11x in templates
   (class="lb-btn lb-btn-sm lb-btn-outline") but never defined (a no-op
   that fell back to the base .lb-btn neutral fill). Defines the bordered,
   transparent-fill variant the markup intends. */
.lb-btn-outline {
  background: transparent;
  border-color: var(--border-strong, var(--text-secondary));
  color: var(--ink, var(--text-primary));
}
.lb-btn-outline:hover {
  background: var(--surface-2, var(--bg-secondary));
  border-color: var(--accent);
}
.lb-btn-sm {
  padding: 4px 8px;
  font-size: 12px;
}
.lb-btn-lg {
  padding: 10px 16px;
  font-size: 14px;
}
/* X-02 — destructive action tier (Remove/Delete). Outline-by-default
   using the --error token; fills on hover; visible focus ring. Distinct
   from the neutral .lb-btn and the affirmative .lb-btn-primary. */
.lb-btn-danger {
  background: transparent;
  border-color: var(--error);
  color: var(--error);
}
.lb-btn-danger:hover {
  background: var(--error);
  color: var(--bg-card);
  border-color: var(--error);
}
.lb-btn-danger:focus-visible {
  outline: 2px solid var(--error);
  outline-offset: 2px;
}
/* BOX-1532 — warning action tier (e.g. the FMV "Reject" button), the one
   .lb-btn* variant the templates referenced but style.css never defined.
   Implements the design pinned by BOX-1158's test_button_fill_contrast_a11y
   (test_warning_button_dark_text_clears_aa_every_theme): a filled --warning
   (amber) button with DARK #1a1a1a text. `--warning` fails AA as white-on-fill
   (2.19:1) and as text-on-surface (~3.2:1); dark #1a1a1a on the amber fill
   clears AA (~5.9:1) in every theme. Mirrors .lb-btn-primary's filled +
   brightness-hover structure. #1a1a1a is a fixed on-fill ink (like
   .lb-btn-primary's #fff) — amber is light enough that dark text works in
   both light and dark themes, so it is NOT theme-varying. */
.lb-btn-warning {
  background: var(--warning);
  color: #1a1a1a;
  border-color: var(--warning);
}
.lb-btn-warning:hover {
  filter: brightness(1.06);
  background: var(--warning);
  border-color: var(--warning);
}
.lb-btn-warning:focus-visible {
  outline: 2px solid var(--warning);
  outline-offset: 2px;
}
.lb-btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

/* §3b — .lb-alert: inline status-message primitive (BOX-1153). First shared
   alert primitive (the audit found per-island/per-template alerts reinvented).
   A bordered box with a severity-tinted left rule; the MARKUP owns the a11y
   semantics (role="alert" + aria-live for dynamic messages). Variants tint only
   the left rule and keep --ink body text for readability (colored body text on
   the surface is often sub-AA). Spacing/margins stay on the call site. */
.lb-alert {
  padding: 8px 14px;
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-strong, var(--text-secondary));
  border-radius: var(--radius-sm, 5px);
  font-size: 13px;
  color: var(--ink, var(--text-primary));
}
.lb-alert-info    { border-left-color: var(--accent); }
.lb-alert-success { border-left-color: var(--success); }
.lb-alert-warning { border-left-color: var(--warning); }
.lb-alert-error   { border-left-color: var(--error); }

/* §4 — .lb-dtable: data-table primitive
   Sticky mono-uppercase headers, hover-row, tabular-nums
   cells. Opt-in via class on the <table> element. */
.lb-dtable {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  font-family: var(--font-sans);
}
.lb-dtable th {
  text-align: left;
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
  padding: 10px var(--cell-px, 14px);
  border-bottom: 1px solid var(--border);
  background: var(--surface-2, var(--bg-secondary));
  font-family: var(--font-mono);
  position: sticky;
  top: 0;
  z-index: 1;
}
.lb-dtable td {
  padding: 0 var(--cell-px, 14px);
  height: var(--row-h, 40px);
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
  color: var(--ink, var(--text-primary));
}
.lb-dtable td.num,
.lb-dtable td[data-num] {
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.lb-dtable tbody tr {
  transition: background var(--dur-fast) var(--ease);
}
.lb-dtable tbody tr:hover {
  background: var(--surface-2, var(--bg-secondary));
  cursor: pointer;
}
.lb-dtable tbody tr[data-active="true"] {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
/* RE-REVIEW-V6 §3 C3 — .lb-dtable-empty: empty-state primitive.
   Replaces per-template prose drift on no-rows. Slots:
   `.lb-dtable-empty-icon` (optional emoji/glyph),
   `.lb-dtable-empty-primary` (--ink heading line),
   `.lb-dtable-empty-secondary` (--ink-faint detail line),
   `.lb-dtable-empty-cta` (optional action). Renders inside a
   single full-width <td colspan> on a tbody row, OR as a
   stand-alone block on a non-tabular surface (e.g. dashboard
   "all clear" message). */
.lb-dtable-empty {
  text-align: center;
  padding: 32px 20px;
  color: var(--ink-dim, var(--text-secondary));
}
.lb-dtable-empty-icon {
  font-size: 24px;
  line-height: 1;
  margin-bottom: 8px;
  color: var(--ink-faint, var(--text-muted));
}
.lb-dtable-empty-primary {
  font-size: 14px;
  color: var(--ink, var(--text-primary));
  margin-bottom: 4px;
}
.lb-dtable-empty-secondary {
  font-size: 13px;
  color: var(--ink-faint, var(--text-muted));
  margin-bottom: 12px;
}
.lb-dtable-empty-cta {
  margin-top: 6px;
}

/* §4b — .lb-table: flat read-only data-table primitive (BOX-1531 slice 3).
   The most-referenced still-undefined lb-* class — 21 `<table class="lb-table">`
   uses across 10 FMV-evidence / intake-workbench / eBay-import surfaces. These
   tables were NOT unstyled: the un-namespaced global `table`/`th`/`td`/`tr:hover
   td` block (§ Tables, ~L2572) already bordered + padded them with raw-token
   values (`--text-muted` header, `--bg-secondary` hover, 2px header rule, 0.5px
   tracking). `.lb-table` is the design-v2-token-aligned, guard-protected
   namespaced primitive those surfaces opt into (test_box1542 / test_box1227):
   same layout, but header color routed through the semantic --ink-faint (byte-
   identical to the global's --text-muted, AA-guarded per
   test_material_muted_contrast_a11y), a flatter 1px header rule, and a subtler
   accent row-hover. Distinct from the heavier §4 .lb-dtable (sticky mono headers
   + cursor:pointer hover for CLICKABLE worklists): .lb-table is the flat,
   informational read table (accepted comps, orchestration telemetry cells,
   media-review lists) — no cursor change because the rows are not clickable.
   Body stays --ink. No role text color, so off the ADR-039 raw-token ratchet
   (raw appears only in var(--semantic, var(--raw)) fallback slots) and it adds
   no new text-contrast surface. The hover targets `td` (not `tr`) so it
   overrides the higher-in-the-cell global `tr:hover td` fill; mirrors the
   shipped `.worklist-table` 5%-accent read-table hover. */
.lb-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  font-family: var(--font-sans);
  color: var(--ink, var(--text-primary));
}
.lb-table th {
  text-align: left;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
  padding: 8px var(--cell-px, 12px);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  vertical-align: bottom;
}
.lb-table td {
  padding: 8px var(--cell-px, 12px);
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  color: var(--ink, var(--text-primary));
}
.lb-table tbody tr:last-child td {
  border-bottom: none;
}
.lb-table tbody tr:hover td {
  background: color-mix(in srgb, var(--accent) 5%, transparent);
}
.lb-table td.num,
.lb-table td[data-num] {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* §5 — .lb-field: form input shell with confidence routing
   Wraps a label + input pair. Confidence routing via
   `data-conf="{medium,low}"` tints the input border for
   evidence-based form validation. */
.lb-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.lb-field > label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
  display: flex;
  align-items: center;
  gap: 6px;
}
.lb-field input,
.lb-field select,
.lb-field textarea {
  width: 100%;
  padding: 8px 10px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 5px);
  font-size: 13px;
  font-family: var(--font-sans);
  color: var(--ink, var(--text-primary));
  outline: none;
  transition: border-color var(--dur), background var(--dur);
}
/* BOX-1152: keyboard focus ring for .lb-field controls (the :focus rule
   below intentionally keeps the borderless pointer look). */
.lb-field input:focus-visible,
.lb-field select:focus-visible,
.lb-field textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.lb-field input:focus,
.lb-field select:focus,
.lb-field textarea:focus {
  border-color: var(--accent);
  background: var(--surface, var(--bg-card));
}
.lb-field[data-conf="medium"] input,
.lb-field[data-conf="medium"] select,
.lb-field[data-conf="medium"] textarea {
  border-color: color-mix(in srgb, var(--warning) 50%, var(--border));
}
.lb-field[data-conf="low"] input,
.lb-field[data-conf="low"] select,
.lb-field[data-conf="low"] textarea {
  border-color: color-mix(in srgb, var(--error) 50%, var(--border));
  background: color-mix(in srgb, var(--error) 5%, var(--bg-input));
}

/* §5b — .lb-input / .lb-input-sm / .lb-inline-form / .lb-field-label /
   .lb-checkbox: standalone form primitives (BOX-1531 slice 4). The §5 .lb-field
   shell styles inputs via the descendant `.lb-field input` selector, but the FMV
   / intake surfaces also use these classes DIRECTLY on controls OUTSIDE a
   .lb-field wrapper (evidence_queue handoff/transition forms, orchestration
   canonical + commit forms) where they were undefined no-ops — bare browser
   inputs, an unstyled inline form row, block labels, and a plain checkbox label.
   Matched to the shipped `.lb-field input` / `.lb-field > label` treatment so a
   control styled by BOTH (a .lb-input inside a .lb-field) renders identically.
   No role text color -> off the ADR-039 raw-token ratchet (raw only in
   var(--semantic, var(--raw)) fallback slots). */
.lb-input {
  width: 100%;
  padding: 8px 10px;
  background: var(--surface-3, var(--bg-input));
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 5px);
  font-size: 13px;
  font-family: var(--font-sans);
  color: var(--ink, var(--text-primary));
  outline: none;
  transition: border-color var(--dur), background var(--dur);
}
.lb-input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.lb-input:focus {
  border-color: var(--accent);
  background: var(--surface, var(--bg-card));
}
.lb-input[readonly] {
  color: var(--ink-dim, var(--text-secondary));
  cursor: default;
}
.lb-input-sm {
  padding: 4px 8px;
  font-size: 12px;
}
/* Inline form row: input + adjacent action button (copy field, accept/reject
   transitions). The input flexes to fill; the base .lb-input width:100% becomes
   the flex-basis override so the button stays on the row instead of wrapping. */
.lb-inline-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.lb-inline-form .lb-input {
  flex: 1 1 12rem;
  width: auto;
  min-width: 0;
}
/* BOX-1550 — filter-scoped inline form (evidence-ops filter row): several compact
   controls + a submit share the row, so they must NOT flex-grow to the 12rem
   basis the single copy-field/transition input above uses. Compound selector so
   it beats `.lb-inline-form .lb-input` regardless of source order. */
.lb-inline-form--filter.lb-inline-form .lb-input {
  flex: 0 1 auto;
  width: auto;
  min-width: 10ch;
}
/* Standalone field label (mirrors the §5 `.lb-field > label` mono eyebrow so a
   label used with or without the .lb-field wrapper matches). --ink-faint is
   AA-guarded (test_material_muted_contrast_a11y). */
.lb-field-label {
  display: block;
  margin-bottom: 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint, var(--text-muted));
}
/* Checkbox row: a <label> wrapping a native checkbox + its text. Body text stays
   --ink; the native control keeps its default focus ring. */
.lb-checkbox {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink, var(--text-primary));
  cursor: pointer;
}
.lb-checkbox input[type="checkbox"] {
  flex-shrink: 0;
  cursor: pointer;
}

/* §6 — .lb-dot: micro-status indicator
   Small color-coded circle. Two sizes (default 6px, lg 8px).
   For status routing in dense tables, audit-trail rows, and
   row-level freshness indicators. */
.lb-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
  vertical-align: middle;
  background: var(--ink-faint, var(--text-muted));
}
.lb-dot-lg {
  width: 8px;
  height: 8px;
}
.lb-dot-ok { background: var(--success); }
.lb-dot-warn { background: var(--warning); }
.lb-dot-danger { background: var(--error); }
.lb-dot-info { background: var(--accent); }
.lb-dot-muted { background: var(--ink-faint, var(--text-muted)); }

/* §7 — .lb-hover-peek-anchor + .lb-hover-peek: detail-card
   popover on hover/focus. Lifts the prior no-JS-interaction
   constraint per operator decision. CSS handles the visual
   reveal via `[data-visible="true"]`; positioning logic lives
   in app/api/static/hover_peek.js so the popover survives
   viewport edges and supports keyboard dismiss. */
.lb-hover-peek-anchor {
  position: relative;
  display: inline-block;
}
.lb-hover-peek {
  display: none;
  position: absolute;
  z-index: 50;
  min-width: 220px;
  max-width: 360px;
  padding: 12px 14px;
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18),
              0 1px 0 rgba(255, 255, 255, 0.03) inset;
  font-size: 13px;
  font-family: var(--font-sans);
  color: var(--ink, var(--text-primary));
  pointer-events: auto;
}
/* Visibility flipped via JS by setting `data-visible="true"`
   on the .lb-hover-peek element. JS also manages position via
   inline `top`/`left` styles that account for viewport edges
   and the configured side preference (data-side="left" /
   "right" / "above" / "below"). */
.lb-hover-peek[data-visible="true"] {
  display: block;
}
.lb-hover-peek-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink, var(--text-primary));
  margin-bottom: 4px;
}
.lb-hover-peek-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-faint, var(--text-muted));
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 6px;
}
.lb-hover-peek-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 2px 0;
  font-size: 12px;
  color: var(--ink-dim, var(--text-secondary));
}
.lb-hover-peek-row > .num {
  font-variant-numeric: tabular-nums;
  color: var(--ink, var(--text-primary));
}

/* §8 — I-a foundation utilities (operator-UI design-review remediation).
   Source: design/handoff/design_handoff_operator_ui_review/PLANNING_SUMMARY.md
   (EPIC I-a). A small, additive utility layer that the later remediation
   epics consume — a type scale with a 12px practical floor, a muted-metadata
   text class, and a shared horizontal-overflow container for dense tables /
   wide grids (the X-05 containment thread). Reuses the existing token
   vocabulary only (--ink-faint / --text-muted); introduces NO new tokens,
   NO new palette, and NO new token system. Pure additive: NO template
   references these yet — the consuming epics opt in per surface
   (D wraps .lb-dtable; F wraps the completion-map grid; E/F-06 floor the
   gain/loss text). Broad inline-style migration is deferred to I-b. Names
   follow the planning doc; the type/meta helpers are an atomic utility layer
   (distinct from the §1–§7 `.lb-` component primitives). */

/* Type scale — 12px is the practical floor (replaces ad-hoc inline
   font-size:10px/11px). .txt-sm is the value-bearing-delta size (>=13px),
   e.g. the gain/loss legibility work in EPIC E / finding F-06. */
.txt-xs {
  font-size: 12px;
  line-height: 1.4;
}
.txt-sm {
  font-size: 13px;
  line-height: 1.4;
}

/* Muted metadata text — consolidates the recurring inline
   `font-size:11px;color:var(--ink-faint, var(--text-muted))` meta rows
   onto one class at the 12px floor. */
.meta-muted {
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
}

/* Generic muted-text utility (BOX-1150, design-system audit 2026-06-18).
   The bare `.muted` class is referenced ~1,771x across templates (plus the
   JS layer) but was never defined anywhere — a silent no-op that collapsed
   text hierarchy. Color-only by intent: `.muted` is applied to spans, table
   cells, and block elements alike, so it must NOT impose a font-size (that
   is what .meta-muted is for). Resolves per theme via --text-muted, which
   is now AA-compliant in dark mode (BOX-1149). */
.muted {
  color: var(--text-muted);
}

/* Shared horizontal-overflow container (X-05 containment thread). Wrap a
   dense table or wide auto-fill grid so it scrolls within its column on
   tablet/phone widths instead of overflowing the layout. EPIC D wraps
   .lb-dtable; EPIC F wraps the completion-map grid. */
.lb-scroll-x {
  overflow-x: auto;
  max-width: 100%;
  -webkit-overflow-scrolling: touch;
}

/* .lb-disclosure-link — accessible inline disclosure trigger (EPIC B / X-03).
   A real <button> reset to an inline dotted-underline link so keyboard +
   screen-reader users get a native control (Enter/Space activation, a focus
   ring, aria-expanded state) instead of a click-only <span>. Pairs with
   aria-controls on a collapsible target toggled by the [data-comp-toggle]
   handler in collection/detail.html. */
.lb-disclosure-link {
  display: inline;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--ink, var(--text-primary));
  cursor: pointer;
  text-decoration: underline dotted;
}
.lb-disclosure-link:hover {
  color: var(--accent);
}
.lb-disclosure-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* F-02 / EPIC A — Card Detail in-page anchor row. A sticky tier that separates
   the open valuation/identity read (Zone A) from the collapsed forensic
   disclosures (Zone B: Evidence / History). Reuses existing tokens only. */
.item-detail-anchor-nav {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  gap: 16px;
  padding: 8px 0;
  margin-bottom: 8px;
  background: var(--surface, var(--bg-card));
  border-bottom: 1px solid var(--border);
  font-size: 12px;
}
.item-detail-anchor-nav a {
  color: var(--ink-dim, var(--text-secondary));
  text-decoration: none;
  font-weight: 500;
}
.item-detail-anchor-nav a:hover {
  color: var(--accent);
}

/* UIRECON-TOKENS (BOX-224) — narrow token-backed table primitive
   for the legacy admin worklists (set_backfill, fmv_evidence)
   that pre-date the .data-table / .lb-dtable conventions. Captures
   the inline `style="width:100%;font-size:12px;border-collapse:collapse"`
   + per-row `style="border-bottom:1px solid var(--border)"` shape
   without changing visual output. Anything more ambitious (sticky
   headers, hover-row, monospace cells) belongs to a future
   migration to .lb-dtable; this class is the surgical cleanup
   that lets us drop the inline-style overrides today.
   Reuses existing tokens; no palette / semantic-token change. */
.worklist-table {
  width: 100%;
  font-size: 12px;
  border-collapse: collapse;
}
.worklist-table thead tr {
  text-align: left;
  border-bottom: 1px solid var(--border);
}
.worklist-table tbody tr {
  border-bottom: 1px solid var(--border);
}
.worklist-table th,
.worklist-table td {
  padding: 6px 8px;
}
.worklist-table td.num {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-variant-numeric: tabular-nums;
}
/* UIRECON-WORKLISTS (BOX-232) — keyboard-focus + mouse-hover row
   anchor for the legacy admin worklists migrated to
   ``.worklist-table`` under BOX-224. The mouse path uses a
   subtle accent tint that matches the ``.lb-dtable tbody
   tr:hover`` vocabulary; the keyboard equivalent fires when any
   control inside a row gains focus (link, button, checkbox).
   Token-driven; no palette change. */
.worklist-table tbody tr:hover td,
.worklist-table tbody tr:focus-within td {
  background: color-mix(in srgb, var(--accent) 5%, transparent);
}
.worklist-table a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* §9 — BOX-1531 slice 5 layout / list / text utilities. The structural tranche
   of the design-v2 `lb-*` reconciliation: page + workbench + breadcrumb headers,
   stat / key-value lists, pagination + empty-state, and the mono / muted / link
   text helpers — all referenced across the FMV-evidence + intake surfaces but
   undefined no-ops (block text, default list chrome, unstyled nav). Structural /
   text only; every color routes through a semantic, AA-guarded token (--ink /
   --ink-dim / --ink-faint / --accent), so this stays off the ADR-039 raw-token
   ratchet (raw appears only in var(--semantic, var(--raw)) fallback slots). */

/* Breadcrumb — a <nav> of links + aria-hidden separators + the current page. */
.lb-breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 12px;
  font-size: 12px;
  color: var(--ink-faint, var(--text-muted));
}
.lb-breadcrumb a {
  color: var(--ink-dim, var(--text-secondary));
  text-decoration: none;
}
.lb-breadcrumb a:hover {
  color: var(--accent);
}

/* Page header — <header> wrapping an <h1> + muted subtitle paragraphs. Section
   rhythm + tightens the reset-zeroed child margins. */
.lb-page-header {
  margin-bottom: 20px;
}
.lb-page-header > h1 {
  margin: 0 0 8px;
}
.lb-page-header > p {
  margin: 0 0 6px;
  max-width: 720px;
}

/* Workbench header — semantic hooks on the intake-workbench identity header,
   which is ALREADY styled by .set-detail-header (+ .lb-surface). The inner
   codifies the flex layout the markup carries inline (so the class is
   load-bearing and the inline style becomes a future cleanup); the outer is a
   positioning anchor. No spacing override — .set-detail-header owns the margin. */
.lb-workbench-header {
  position: relative;
}
.lb-workbench-header-inner {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  flex-wrap: wrap;
}

/* Stat list — <ul> of "Label: <strong>value</strong>" rows read as inline
   sentences; no list chrome, muted label, emphasized tabular value. Kept a
   simple vertical stack (not a left/right split) because several rows carry a
   trailing "(note)" span that a space-between layout would strand. */
.lb-stat-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-dim, var(--text-secondary));
}
.lb-stat-list strong {
  color: var(--ink, var(--text-primary));
  font-variant-numeric: tabular-nums;
}

/* Key-value list — <ul> of "<strong>Key:</strong> value" rows read inline. */
.lb-key-value-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-dim, var(--text-secondary));
}
.lb-key-value-list strong {
  color: var(--ink, var(--text-primary));
  font-weight: 600;
  margin-right: 4px;
}

/* Pagination — a <nav> of prev/next .lb-btn links; layout only (the buttons
   carry their own .lb-btn styling). */
.lb-pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
}

/* Empty state — pairs with .lb-surface (the card chrome); centers + dims the
   no-rows message, mirroring the shipped .lb-dtable-empty house style. */
.lb-empty-state {
  text-align: center;
  color: var(--ink-dim, var(--text-secondary));
}

/* Mono cell/inline text (IDs, hashes) — tabular monospace, inherits color. */
.lb-mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* Namespaced muted text — the lb-* sibling of the global .muted; resolves through
   the AA-guarded --ink-faint (=--text-muted). Color-only (no size) so it can sit
   on spans / cells / blocks alike. */
.lb-muted {
  color: var(--ink-faint, var(--text-muted));
}

/* Accent link — matches the global `a` treatment (AA-safe --link tone, BOX-1549)
   with an explicit hover underline affordance. */
.lb-link {
  color: var(--link, var(--accent));
  text-decoration: none;
}
.lb-link:hover {
  color: var(--link-hover, var(--accent-hover));
  text-decoration: underline;
}

/* §10 — BOX-1531 slice 6 role-colored status vocabulary + dynamic-stem variants
   (the final reconciliation tranche): evidence-state / intake-outcome /
   source-freshness badges, message surfaces, and inline error text across the
   FMV + eBay-import surfaces.

   ACCESSIBILITY: role hues appear ONLY on the border + a faint tint, NEVER as
   text, because every role hue fails WCAG-AA as normal-size text in at least one
   theme (measured on the card surface: --error 3.73:1 dark, --warning ~3.2:1 /
   --success ~3.3:1 light, --accent 4.27:1 dark). Body text stays --ink —
   var(--ink) on an 8% role tint clears AA 9:1+ in every theme — mirroring the
   shipped §2c .lb-flash / §3b .lb-alert pattern. Semantic tokens only, so this
   stays off the ADR-039 raw-token ratchet (raw only in var(--semantic,
   var(--raw)) fallback slots).

   Dynamic-suffix keys are the persisted enums, product/set-AGNOSTIC (workflow
   states, not product names): evidence state
   (candidate/accepted/rejected/context_only/quarantined/superseded —
   evidence_records.py ALL_STATES),
   intake outcome (the full evidence_intake_* markers — fmv_evidence_intake_api.py),
   source freshness (active/quiet/stale/never — admission_telemetry.py), and the
   media-review msg_type (success/error/warning/info). Any value without a role
   variant degrades gracefully to the neutral base .lb-badge / .lb-surface. */

/* Inline/block error text — role hue on a left rule + faint tint, text --ink
   (var(--error) as text is 3.73:1 in dark = sub-AA). */
.lb-error {
  color: var(--ink, var(--text-primary));
  border-left: 3px solid var(--error);
  padding-left: 8px;
  background: color-mix(in srgb, var(--error) 6%, transparent);
}

/* Message surfaces — .lb-surface variants keyed on msg_type; role border + a
   faint role tint over the opaque surface. .lb-surface-error is the literal
   spelling of the error variant. */
.lb-surface--success {
  border-color: var(--success);
  background: color-mix(in srgb, var(--success) 6%, var(--surface, var(--bg-card)));
}
.lb-surface--warning {
  border-color: var(--warning);
  background: color-mix(in srgb, var(--warning) 6%, var(--surface, var(--bg-card)));
}
.lb-surface--info {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, var(--surface, var(--bg-card)));
}
.lb-surface--error,
.lb-surface-error {
  border-color: var(--error);
  background: color-mix(in srgb, var(--error) 6%, var(--surface, var(--bg-card)));
}

/* Role badges — border + 8% tint; text darkens to --ink for extra margin on the
   tint (base .lb-badge is --ink-dim). Shared role recipe across the three badge
   families (state / intake-outcome / freshness). */
.lb-badge-state-accepted,
.lb-badge-intake-outcome-evidence_intake_inserted,
.lb-freshness-active {
  color: var(--ink, var(--text-primary));
  border-color: var(--success);
  background: color-mix(in srgb, var(--success) 8%, transparent);
}
.lb-badge-state-quarantined,
.lb-badge-intake-outcome-evidence_intake_duplicate,
.lb-badge-intake-outcome-evidence_intake_conflict,
.lb-freshness-quiet,
.lb-freshness-stale {
  color: var(--ink, var(--text-primary));
  border-color: var(--warning);
  background: color-mix(in srgb, var(--warning) 8%, transparent);
}
.lb-badge-state-rejected,
.lb-badge-intake-outcome-evidence_intake_validation_rejected,
.lb-badge-intake-outcome-evidence_intake_service_rejected,
.lb-freshness-never {
  color: var(--ink, var(--text-primary));
  border-color: var(--error);
  background: color-mix(in srgb, var(--error) 8%, transparent);
}
.lb-badge-state-candidate {
  color: var(--ink, var(--text-primary));
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
/* context_only + superseded are terminal / non-actionable states — an
   INTENTIONAL neutral (no role hue), distinct from an unmapped-value accident. */
.lb-badge-state-context_only,
.lb-badge-state-superseded {
  color: var(--ink-dim, var(--text-secondary));
  border-color: var(--border);
  background: var(--surface-2, var(--bg-secondary));
}

/* ============================================================ */
/* Design v2 — port from `260517-1651` handoff                  */
/* ============================================================ */
/*
   Layered dark surfaces — material variant. Activated by
   `data-dark-variant="material"` on <html> (set in base.html).
   Base #121212 · Cards #1E1E1E · Elevated #242424. Desaturated
   accents keep contrast under control. The shipped Navy variant
   tokens remain available; design's `material` is now the
   default dark theme.

   Spec source: `Dashboard v2.html` + `Intake Workbench.html`
   inline <style> blocks in the canonical Claude Design handoff
   (`design/handoff/Lunchbox Memorabilia — Design (v2)-handoff
   260517-1651/project/`).
*/
[data-theme="dark"][data-dark-variant="material"] {
  --bg-primary: #121212;
  --bg-secondary: #1a1a1a;
  --bg-card: #1e1e1e;
  --bg-input: #242424;
  --text-primary: #ECECEC;
  --text-secondary: #A8A8A8;
  /* WCAG-AA contrast fix: the design handoff value (#6E6E6E) is only
     ~3.3:1 on cards (#1E1E1E) — it fails AA 4.5:1 for the small
     secondary/meta text it drives across the app. #949494 clears 4.5:1
     on every material surface (card 5.5:1 / input #242424 5.1:1 /
     base #121212 6.2:1) while staying the most-recessive text tier
     (below --text-secondary #A8A8A8). Intentional deviation from the
     handoff hex for accessibility. */
  --text-muted: #949494;
  --border: #2C2C2C;
  --accent: #6FA8DC;
  --accent-hover: #8BBBE2;
  /* BOX-1549: material --accent #6FA8DC already clears AA as link text (6.60:1 on
     the #1e1e1e card), so --link mirrors it. */
  --link: #6FA8DC;
  --link-hover: #8BBBE2;
  --success: #7BB37F;
  --error: #D08080;
  --warning: #D4A574;
  /* BOX-1158: darkened accent for filled buttons (plain --accent #6FA8DC
     = 2.53:1 with white). White on #45739c = 5.02:1. */
  --accent-fill: #45739c;
  --surface: var(--bg-card);
  --surface-2: var(--bg-secondary);
  --surface-3: var(--bg-input);
  --ink: var(--text-primary);
  --ink-dim: var(--text-secondary);
  --ink-faint: var(--text-muted);

  /* CARD-VAULT (BOX-1159) — yellow desaturated to match material's
     muted accents; dark ink on fills. See dark-block note. */
  --accent-2: #e0c16a;
  --accent-2-ink: #1a1a1a;
  --accent-2-soft: color-mix(in srgb, var(--accent-2) 14%, transparent);
  --accent-2-line: color-mix(in srgb, var(--accent-2) 55%, var(--border));
  --vault-bg-warm: color-mix(in srgb, var(--accent-2) 4%, var(--surface));
}

/* Sidebar brand container — Design v2 keeps the logo link and theme
   toggle in one relative positioning block. The controls are siblings
   so the button can sit at the logo's top-right without invalid nested
   interactivity. */
.sidebar-brand {
  position: relative;
  flex-shrink: 0;
}

/* Inline theme toggle — Design v2 moves the toggle from the
   sidebar footer to the top-right of the brand block. Same JS hook,
   same DOM contract (`class="theme-toggle"` + both icon spans
   + `onclick="toggleTheme()"`); only its DOM relationship to the
   logo link changes.
   The bare `.theme-toggle` rule above still applies to any
   non-inline toggle elsewhere in the app (none today, but
   the rule is preserved for backwards compatibility). */
.theme-toggle-inline {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 30px;
  height: 30px;
  padding: 0;
  font-size: 14px;
  line-height: 1;
  display: grid;
  place-items: center;
  border-radius: 6px;
  z-index: 2;
}

/* Sidebar nav entries — Design v2 puts icons on every entry.
   `.sidebar-nav a` becomes a flex row of icon + label so the
   icon stays vertically centered and the label flexes naturally.
   Existing active/hover/focus styles still apply. */
.sidebar-nav a {
  display: flex;
  align-items: center;
  gap: 10px;
}
/* SIDEBAR SHARED-ELEMENT PASS (2026-07-16 ruling) — icons are uniform
   brand gold at full opacity, INCLUDING active (the hover/active
   recolor overrides are retired): the rail + chip + text tier carry
   the active state, and blue stays the interactive vocabulary. */
.sidebar-nav a .nav-icon {
  flex-shrink: 0;
  opacity: 1;
  color: var(--accent-2);
}
.sidebar-nav a .nav-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* BOX-889 (sidebar pass, turn-3 ruling) — cached attention badge.
   Brewers-blue pill: blue tint fill inside a blue outline; the
   COUNT is readable --ink (the tint/outline is decorative), so the
   text-based signal clears AA in all themes. Never --accent-2 —
   identity is not state. Static at rest: the count is cached
   (short-TTL), not live. Display cap 99+ (template-side).
   BOX-1900 (legibility ruling) — the original 16% fill / 60% outline
   was faint enough that two identical pills read as different
   treatments; deepened to 30% fill / 85% outline so the single ruled
   pill is unmistakable at a glance while staying a tint (not a solid
   state fill). --ink count still carries the AA signal. */
.nav-badge {
  margin-left: auto;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--ink, var(--text-primary));
  background: color-mix(in srgb, var(--link) 30%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 85%, var(--border));
}
/* Zero state — ruled: explicit all-clear check, --success green so
   clear-vs-work stays two-color (SR text carries the meaning; the
   light-theme glyph contrast is accepted in the ruling). */
.nav-badge-clear {
  background: transparent;
  border-color: transparent;
  color: var(--success);
  font-size: 11px;
  font-weight: 700;
}

/* Generic Design v2 icon class — applies to inline SVGs emitted
   by the `icon()` Jinja macro. Keeps a baseline alignment so
   icons used inside text (e.g. dashboard headings) sit at the
   text baseline rather than the line-box top. */
.lb-icon {
  display: inline-block;
  vertical-align: -2px;
  flex-shrink: 0;
}

/* ── Design v2 — Intake Workbench stage progress stepper ─── */
/*
   7-step linear stepper used on the Intake Workbench landing
   (and reused across stage pages when active). Ported visually
   from `intake-workbench-atoms.jsx::StageProgress` in the
   canonical handoff. Per-step states: `done` (success dot),
   `current` (accent dot), `issue` (warning dot), `todo`
   (border-only dot).
*/
.lb-stage-progress {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 8px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface, var(--bg-card));
  margin-bottom: 20px;
}
.lb-stage-step {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-left: 0;
  min-width: 0;
}
/* Connector line between adjacent dots. Anchored to the bottom-
   right of the dot, runs into the next step's dot. */
.lb-stage-step:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 11px;
  left: 26px;
  right: -8px;
  height: 1.5px;
  background: var(--border);
  opacity: 0.6;
}
.lb-stage-step.is-done:not(:last-child)::after {
  background: var(--success);
}
.lb-stage-step-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.lb-stage-dot {
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: transparent;
  border: 1.5px solid var(--border);
  color: var(--text-muted);
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 10px;
  font-weight: 700;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  position: relative;
  z-index: 1;
}
.lb-stage-step.is-done   .lb-stage-dot { background: var(--success); border-color: var(--success); color: #fff; }
.lb-stage-step.is-current .lb-stage-dot { background: var(--accent);  border-color: var(--accent);  color: #fff; }
.lb-stage-step.is-issue   .lb-stage-dot { background: var(--warning); border-color: var(--warning); color: #fff; }
.lb-stage-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lb-stage-step.is-current .lb-stage-label { color: var(--text-primary); }
.lb-stage-step.is-done    .lb-stage-label { color: var(--text-secondary); }
.lb-stage-step.is-issue   .lb-stage-label { color: var(--warning); }
.lb-stage-sub {
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.35;
  padding-left: 30px;
}

/* ── Design v2 — Dashboard greeting header + quick-reach pills ─ */
/*
   Dashboard greeting block: mono small-caps eyebrow + portfolio
   metric headline + green delta chip. Ported from
   `dashboard-v2-app.jsx::DashboardFrame` header in the handoff.
   Used as an additive replacement for the existing dash-page-
   header eyebrow/h1/subtitle pattern.
*/
.lb-dash-greeting {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 18px;
}
.lb-dash-greeting-eyebrow {
  font-size: 11px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  margin-bottom: 4px;
}
.lb-dash-greeting-headline {
  margin: 0;
  font-size: 30px;
  font-weight: 600;
  letter-spacing: -0.01em;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.lb-dash-greeting-headline .lb-icon { color: var(--accent); }
.lb-dash-delta-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 13px;
  font-weight: 500;
  padding: 3px 10px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--success) 14%, transparent);
  color: var(--success);
}
.lb-dash-delta-chip.is-down {
  background: color-mix(in srgb, var(--error) 14%, transparent);
  color: var(--error);
}
.lb-dash-subtitle {
  margin: 6px 0 0;
  color: var(--text-secondary);
  font-size: 14px;
}

/* Quick-reach pill row — 5 link pills above the operational
   dashboard sections. Every pill is a real route; design-only
   pills with no destination are omitted. */
.lb-quick-reach {
  display: flex;
  gap: 6px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.lb-quick-reach a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  padding: 6px 12px;
  border-radius: 16px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  text-decoration: none;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.lb-quick-reach a:hover {
  background: var(--bg-input);
  color: var(--text-primary);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
}

/* ============================================================ */
/* Design v2 — second-pass parity refinements (2026-05-18)      */
/* ============================================================ */
/*
   Bring `.dash-summary-card`, `.dash-rail-card`, `.dash-section-*`
   closer to the canonical handoff's widget chrome
   (`dashboard-v2-widgets.jsx::Widget` — 12px header, 16px radius,
   14px padding, 22–26px body metric, accent-rail inset shadow).

   Refinement scope:
     - bigger card corners (12px summary, 14px rail)
     - mono small-caps section labels (new `.lb-section-label`
       primitive shared across dashboard + workbench)
     - rail-card titles align to design's mono small-caps idiom
     - dash-summary-card carries an accent-rail inset for the
       portfolio hero only — every other tile stays neutral.
*/

/* Shared mono small-caps section label per
   `intake-workbench-atoms.jsx::SectionLabel` + the design's
   `.dash-eyebrow` typography. Available outside the dashboard
   so the Workbench landing can use the same idiom. */
.lb-section-label {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
}

/* Dashboard KPI card refinement — match the design's widget
   chrome (`dashboard-v2-widgets.jsx::Widget`). 12px radius +
   accent-rail inset for the portfolio hero ⇒ rail uses the
   shipped `--accent` token. Non-portfolio summary cards stay
   neutral. */
.dash-summary-card {
  border-radius: 12px;
}
.dash-summary-card.dash-kpi-portfolio {
  box-shadow: inset 3px 0 0 var(--accent);
}

/* Right-rail card chrome — design uses 10px radius + 16px
   padding + mono small-caps title. The existing
   `.dash-rail-card-title` rule stays for back-compat; this
   new selector pin layers the new typography on top. */
.dash-rail-card {
  border-radius: 12px;
}
.dash-rail-card .dash-rail-card-title {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Dashboard section title — design uses 16px section h2 in the
   primary text color but with the new mono small-caps eyebrow
   `.lb-section-label` *above* it where applicable. Slightly
   tightens the prior 16px / 600 / -0.005em rule so the section
   reads as the design's standard h2. No change to back-compat
   classes (test pin `class="dash-section-title"` still
   matches). */
.dash-section-title {
  letter-spacing: -0.01em;
}

/* Operational queue card — 12px radius parity. */
.dash-queue-card {
  border-radius: 12px;
}

/* ── Design v2 — Workbench KPI tile row (landing) ─────────── */
/*
   Used by the Intake Workbench landing to surface real session
   + exception counts in the design's `KpiTile` chrome
   (`intake-workbench-atoms.jsx::KpiTile`). Each tile is a
   surface-bordered card with an icon + uppercase label +
   large numeric value + optional sub-line. Tone-based accent
   color routes via `data-tone` ⇒ accent / warning / success
   / neutral.
*/
.lb-kpi-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}
.lb-kpi-tile {
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.lb-kpi-tile-header {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--text-muted);
}
.lb-kpi-tile-icon {
  color: var(--text-muted);
}
.lb-kpi-tile[data-tone="accent"]  .lb-kpi-tile-icon { color: var(--accent); }
.lb-kpi-tile[data-tone="warning"] .lb-kpi-tile-icon { color: var(--warning); }
.lb-kpi-tile[data-tone="success"] .lb-kpi-tile-icon { color: var(--success); }
.lb-kpi-tile[data-tone="error"]   .lb-kpi-tile-icon { color: var(--error); }
.lb-kpi-tile[data-tone="accent"]  { box-shadow: inset 3px 0 0 var(--accent); }
.lb-kpi-tile[data-tone="warning"] { box-shadow: inset 3px 0 0 var(--warning); }
.lb-kpi-tile[data-tone="success"] { box-shadow: inset 3px 0 0 var(--success); }
.lb-kpi-tile[data-tone="error"]   { box-shadow: inset 3px 0 0 var(--error); }
.lb-kpi-tile-label {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.lb-kpi-tile-value {
  font-size: 26px;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  margin-top: 2px;
}
.lb-kpi-tile[data-tone="warning"] .lb-kpi-tile-value { color: var(--warning); }
.lb-kpi-tile[data-tone="success"] .lb-kpi-tile-value { color: var(--success); }
.lb-kpi-tile[data-tone="error"]   .lb-kpi-tile-value { color: var(--error); }
.lb-kpi-tile-sub {
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.4;
  margin-top: 2px;
}

/* ── Design v2 — Severity badge ───────────────────────────── */
/*
   Uniform shape across the consolidated exception model per
   `intake-workbench-atoms.jsx::SeverityBadge`. Used inside
   the workbench landing KPI sub-line + future per-card
   adoption.
*/
.lb-severity-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 999px;
  line-height: 1.3;
  color: var(--text-secondary);
  background: var(--bg-input);
}
.lb-severity-badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: currentColor;
  flex-shrink: 0;
}
.lb-severity-badge[data-level="blocker"] {
  color: var(--error);
  background: color-mix(in srgb, var(--error) 16%, transparent);
}
.lb-severity-badge[data-level="warning"] {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 18%, transparent);
}
.lb-severity-badge[data-level="info"] {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.lb-severity-badge[data-level="ok"] {
  color: var(--success);
  background: color-mix(in srgb, var(--success) 16%, transparent);
}

/* ── Design v2 — Workbench session card refinement ───────── */
/*
   Production session rows (`.intake-workbench-session-row`) are
   already rendered as `.lb-surface` cards; the design wants
   them slightly more compact + with a stronger hierarchy.
*/
.intake-workbench-session-row {
  border-radius: 12px;
}

/* PARALLEL-OVERLAY (Phase 7) — flag-gated, display-only parallel family
   chip for the set-detail registry + collection surfaces. Rendered only
   when ?parallel_overlay=1; supplements (never replaces) existing
   parallel text. A small accent swatch + the resolved family label,
   readable on the dark UI without relying on color alone. --pc-accent /
   --pc-border are sanitized inline vars set by the route (hex/rgba
   only) and fall back to neutral tokens when absent (unknown family).
   It is intentionally NOT used anywhere in the rip-sheet editable grid
   cells — the rip-sheet header swatch is .rse-ph-swatch in
   rip_sheet_entry.css. */
.parallel-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 1px 8px 1px 6px;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.03em;
  line-height: 1.6;
  color: var(--text-secondary);
  background: color-mix(in srgb, var(--pc-accent, var(--text-muted)) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--pc-accent, var(--border)) 45%, var(--border));
  white-space: nowrap;
  vertical-align: middle;
}
.parallel-chip__swatch {
  width: 9px;
  height: 9px;
  border-radius: 2px;
  flex-shrink: 0;
  background: var(--pc-accent, var(--text-muted));
  border: 1px solid color-mix(in srgb, var(--pc-accent, #888) 55%, #000);
}
.parallel-chip__label {
  white-space: nowrap;
}
.parallel-chip--neutral {
  --pc-accent: var(--text-muted);
  color: var(--text-muted);
}

/* BOX-870 (B1) — FMV value chips (item-detail hero full set; the grid
   tile renders its single chip inline in the React island). Text label
   + toned border — never color-only; tones ride the theme tokens. */
.item-detail-fmv-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
}
.fmv-chip {
  display: inline-flex;
  align-items: center;
  padding: 1px 8px;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.03em;
  line-height: 1.6;
  white-space: nowrap;
  vertical-align: middle;
  color: var(--text-secondary);
  background: var(--bg-input);
  border: 1px solid var(--border);
}
.fmv-chip--blocker {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 12%, var(--bg-input));
  border-color: color-mix(in srgb, var(--warning) 40%, var(--border));
}
.fmv-chip--big_move {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-input));
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
}
.fmv-chip--confidence {
  color: var(--text-secondary);
}
.fmv-chip--caveat {
  color: var(--text-muted);
}
a.fmv-chip--why {
  color: var(--accent);
  text-decoration: none;
}
a.fmv-chip--why:hover,
a.fmv-chip--why:focus-visible {
  text-decoration: underline;
}

/* PARALLEL-OVERLAY (BOX-817 S2 / BOX-822) — Mojo overlay treatment.
   Faithful CSS port of the Claude Design MojoOverlay
   (parallel-visual-effects.jsx §9): a 5×5 beaded grid (circle r≈1.2 at
   opacity 0.6, soft-light) + a diagonal white sheen (135°, stops
   0.30/0/0.25, screen) over the CHIP_BG.mojo ground (linear-gradient
   155°, color-mix accent 50%→22% on #0a0a0a). Display-only; applies ONLY
   to the resolved 'mojo' family on the flag-gated overlay chip (the chip
   itself renders only under ?parallel_overlay=1). Beads + ground track the
   sanitized --pc-accent so the tint matches the resolved color.

   OPTION A (ratified — Erik, BOX-822): this CSS IS the accepted Mojo
   treatment. The two divergences vs the design SVG — the fixed 135° sheen
   angle and the stronger background-blend bead/sheen — are INTENDED, not
   defects. The design SVG (MojoOverlay) is REFERENCE ONLY; do NOT regress
   this treatment toward the SVG (no sheen-angle "fix", no blend dial-back).
   For Mojo's rendering the shipped CSS is source-of-truth. Render registry:
   shared/parallel_taxonomy/render_registry.py → mojo = css/f1/decided. */
.parallel-overlay-chip[data-parallel-family="mojo"] {
  color: #f4f4f4;
  border-color: color-mix(in srgb, var(--pc-accent, #c8d3df) 55%, #000);
  background-image:
    radial-gradient(circle at 50% 50%,
      color-mix(in srgb, var(--pc-accent, #c8d3df) 60%, transparent) 1.2px,
      transparent 1.35px),
    linear-gradient(135deg, rgba(255, 255, 255, 0.30) 0%,
      rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0.25) 100%),
    linear-gradient(155deg,
      color-mix(in srgb, var(--pc-accent, #c8d3df) 50%, #0a0a0a) 0%,
      color-mix(in srgb, var(--pc-accent, #c8d3df) 22%, #0a0a0a) 100%);
  background-size: 5px 5px, auto, auto;
  background-blend-mode: soft-light, screen, normal;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);  /* keep label legible over the ground */
}
.parallel-overlay-chip[data-parallel-family="mojo"] .parallel-chip__swatch {
  background: transparent;  /* the beaded ground supersedes the flat swatch */
  border-color: color-mix(in srgb, var(--pc-accent, #c8d3df) 50%, #000);
}
@media (prefers-reduced-motion: reduce) {
  /* static treatment only — no hover shimmer animation is introduced here. */
  .parallel-overlay-chip[data-parallel-family="mojo"] { transition: none; }
}

/* PARALLEL-OVERLAY (BOX-817 / BOX-824) — Wave Prizm overlay treatment (F1 chip).
   Tool DECIDED in S3 (BOX-823): SVG, NOT CSS — WavePrizmOverlay is 10 stroked SINE
   paths (no CSS-gradient sine). Built on the F1 set-detail chip (same path as Mojo,
   for program coherence — see render_registry.py). The verbatim sine geometry lives
   in the static asset app/api/static/parallel_overlays/waveprizm.svg; here it is a
   CSS MASK so the chip's sanitized --pc-accent FILLS the bands (an external SVG can't
   read the CSS var). Ground = CHIP_BG.waveprizm; bands = accent, masked + screen. */
.parallel-overlay-chip[data-parallel-family="waveprizm"] {
  position: relative;
  overflow: hidden;
  color: #f4f4f4;
  border-color: color-mix(in srgb, var(--pc-accent, #c43a28) 55%, #000);
  background-image:
    linear-gradient(180deg,
      color-mix(in srgb, var(--pc-accent, #c43a28) 55%, #0a0a0a) 0%,
      color-mix(in srgb, var(--pc-accent, #c43a28) 22%, #050505) 100%);  /* CHIP_BG.waveprizm */
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
}
.parallel-overlay-chip[data-parallel-family="waveprizm"]::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--pc-accent, #c43a28);
  -webkit-mask: url("/static/parallel_overlays/waveprizm.svg") 0 0 / 100% 100% no-repeat;
          mask: url("/static/parallel_overlays/waveprizm.svg") 0 0 / 100% 100% no-repeat;
  mix-blend-mode: screen;   /* matches WavePrizmOverlay's mixBlendMode */
  pointer-events: none;
}
.parallel-overlay-chip[data-parallel-family="waveprizm"] .parallel-chip__swatch,
.parallel-overlay-chip[data-parallel-family="waveprizm"] .parallel-chip__label {
  position: relative;
  z-index: 1;   /* keep swatch + label above the masked band layer */
}
.parallel-overlay-chip[data-parallel-family="waveprizm"] .parallel-chip__swatch {
  background: transparent;
  border-color: color-mix(in srgb, var(--pc-accent, #c43a28) 50%, #000);
}
@media (prefers-reduced-motion: reduce) {
  .parallel-overlay-chip[data-parallel-family="waveprizm"]::after { transition: none; }
}

/* PARALLEL-OVERLAY (BOX-817 / BOX-825) — Negative overlay treatment (F1 chip).
   Tool = CSS (validated, NOT SVG): the design "Negative Refractor" is three layers
   (parallel-visual-effects.jsx) — (1) NegativeImageFilter "grayscale(1) invert(0.88)
   brightness(1.05) contrast(1.15)" applies ONLY to a card photo (realImage, jsx:583);
   (2) NegativeShimmerOverlay, a COLORLESS white vertical-ribbon shimmer (plain
   linear-gradient + screen, jsx:143); (3) CHIP_BG.negative, a FIXED light/silver ground
   linear-gradient(180deg,#f0f0f0,#c8c8c8) taking NO color arg (jsx:538). Layers (2)+(3)
   are plain gradients → a clean lossless CSS reduction (no sine/polygon geometry → no
   SVG, unlike Wave Prizm). Stacked here as background-image + background-blend-mode:screen
   (mirrors the design's mixBlendMode), exactly as Mojo stacks its layers.
   IMAGE-INVERT (layer 1) SHIPPED in BOX-1919 — see the EffectChip photo-layer block
   below. BOX-825 deferred it because the F1 chip carries no photo and faking an
   inverted photograph on a photoless chip was rejected; the deferral is resolved by
   giving the chip a REAL photo layer to invert, not by simulating one. A chip with no
   photo still renders exactly as it did before (ground + shimmer only).
   DIVERGENCE (intended): Negative is ACCENT-INDEPENDENT (colorless by design — ground +
   shimmer ignore --pc-accent, unlike Mojo/Wave Prizm), and it is the FIRST light-ground
   family, so the label flips to DARK text (#1a1a1a) with no dark text-shadow — the only
   legible choice on the light silver ground; this is a faithful consequence of the design,
   not a deviation from it. The design's 0.6 overlay-opacity is dropped: it tempered the
   shimmer over a DARK inverted photo; the chip's ground is light, so the unscaled design
   alphas (0.12/0.10) reproduce the intended "faint sheen" weight here.
   Render registry: shared/parallel_taxonomy/render_registry.py → negative = css/f1/built. */
.parallel-overlay-chip[data-parallel-family="negative"] {
  color: #1a1a1a;                 /* dark label — the negative ground is LIGHT */
  border-color: #b0b0b0;          /* fixed silver border (accent-independent, per design) */
  background-image:
    linear-gradient(180deg,
      transparent 0%, rgba(255, 255, 255, 0.12) 40%, transparent 55%,
      rgba(255, 255, 255, 0.10) 75%, transparent 100%),   /* NegativeShimmerOverlay */
    linear-gradient(180deg, #f0f0f0 0%, #c8c8c8 100%);     /* CHIP_BG.negative */
  background-blend-mode: screen, normal;
  text-shadow: none;              /* dark text on a light ground — no dark shadow */
}
.parallel-overlay-chip[data-parallel-family="negative"] .parallel-chip__swatch {
  /* keep the small accent dot as a color cue; darken its border for the light ground.
     When no tint resolves (Negative is usually colorless) it falls back to a neutral grey. */
  border-color: color-mix(in srgb, var(--pc-accent, #888) 55%, #000);
}
@media (prefers-reduced-motion: reduce) {
  .parallel-overlay-chip[data-parallel-family="negative"] { transition: none; }
}

/* PARALLEL-OVERLAY (BOX-817 S4 / BOX-1919) — EffectChip PHOTO LAYER + the Negative
   image-invert treatment.

   The design's two-layer model (handoff Parallel_Library_Handoff): BASE = the card
   (photo/substrate/nameplate), PARALLEL = the base-agnostic overlay. Every overlay
   family shipped so far rendered the PARALLEL half only, because the F1 chip had no
   base photograph. This block supplies the missing base half.

   The layer is FAMILY-AGNOSTIC: any tile whose server VM carries an image gets a
   .parallel-overlay-chip__photo child, and the per-family tone-mapping is selected by
   the data-parallel-family attribute below. Effect selection therefore stays driven by
   the resolved parallel FAMILY (schema/taxonomy metadata) — never by a set or product
   name. A tile with no photo renders no element at all, so all seven shipped families
   keep their current photoless appearance byte-for-byte.

   Orientation is a sibling axis, derived server-side from the face's own dimensions
   (parallel_overlay_helpers._orientation_from_dims, mirroring the collection grid's
   rule) and emitted as .parallel-overlay-chip--landscape. That modifier is what finally
   drives the landscape Raywave foil scan shipped in BOX-827 — see the Raywave block. */
.parallel-overlay-chip__photo {
  position: absolute;
  inset: 0;
  z-index: 1;                     /* above the family ground, below the label */
  background-position: center;
  background-size: cover;         /* card photo fills the face; crop over letterbox */
  background-repeat: no-repeat;
  pointer-events: none;
}

/* NegativeImageFilter, VERBATIM from the design (parallel-visual-effects.jsx:135):
   the whole point of the Negative family is what it does to a PHOTOGRAPH, so the
   filter is scoped to the photo layer and never touches the label, the swatch, or the
   family ground. */
.parallel-overlay-chip[data-parallel-family="negative"] .parallel-overlay-chip__photo {
  filter: grayscale(1) invert(0.88) brightness(1.05) contrast(1.15);
}

/* Design layer order is ground → inverted photo → shimmer. With a photo present the
   shimmer must therefore ride ABOVE it, and it cannot simply be a child of the photo
   element: `filter` applies to a filtered element's descendants, so a nested shimmer
   would be inverted along with the photograph. It moves to the chip's own ::after
   instead. Photoless chips are untouched — their shimmer stays in the background-image
   stack exactly as BOX-825 shipped it. */
.parallel-overlay-chip[data-parallel-family="negative"].parallel-overlay-chip--photo::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image:
    linear-gradient(180deg,
      transparent 0%, rgba(255, 255, 255, 0.12) 40%, transparent 55%,
      rgba(255, 255, 255, 0.10) 75%, transparent 100%);   /* NegativeShimmerOverlay */
  mix-blend-mode: screen;
}

/* PARALLEL-OVERLAY (BOX-817 / BOX-826) — Dazzle overlay treatment (F1 chip).
   Tool = static SVG bead-tile asset + CSS gradient layers (validated). The design
   DazzleOverlay (parallel-visual-effects.jsx:156) is a DENSE BEADED HOLOGRAPHIC
   DOT-SCREEN — confirmed by the design's own rendered output (uploads/dazzle_design_effect.png)
   and the real Panini Threads Dazzle foil. (The "110 sparkles + swirl" in the prose docs
   PARALLEL_SCHEMA/CLEANUP_SPEC is a STALE earlier spec the code superseded; operator
   confirmed 2026-06-08 to build the code/rendered output.) Verbatim, blend "overlay"
   (DazzleOverlay mixBlendMode), stacked top to bottom:
     (1) bead PATTERN cell -> static asset parallel_overlays/dazzle-beads.svg, tiled at
         background-size 3.6px so bead DENSITY is fixed regardless of chip size (the Dazzle
         signature). SVG not CSS: a stroked annulus + 2 discs per bead is crisp in SVG, only
         approximate as a radial-gradient (per-family discipline: Mojo/Negative=CSS, but a
         3-ring bead and a sine path are not faithful CSS reductions -> asset).
     (2) dz-ir2: radial glow wash (cx72 cy22 r85, verbatim stops).
     (3) dz-ir : 6-stop rainbow holo linear wash (verbatim stops, each stopOpacity 0.5).
     (4) DAZZLE_FIELD: silvery-blue ground (verbatim).
   ACCENT-INDEPENDENT: Dazzle's canonical color is the FIXED rainbow holographic palette
   (familyTileBg passes color||"rainbow"); iris/beads/ground are fixed -> the accent-mask
   technique (waveprizm) does NOT apply (multi-color, not a single mask-able accent). Second
   light-ground family (after Negative) -> DARK label. TILE-BACKGROUND family: it grounds the
   whole chip, not a faint texture.
   Render registry: shared/parallel_taxonomy/render_registry.py -> dazzle = svg/f1/built. */
.parallel-overlay-chip[data-parallel-family="dazzle"] {
  color: #14181f;                 /* dark label — the holo ground is LIGHT (silvery-blue) */
  border-color: color-mix(in srgb, #8ea0c0 60%, #000);
  background-image:
    url("/static/parallel_overlays/dazzle-beads.svg"),                            /* (1) beads */
    radial-gradient(85% 85% at 72% 22%,
      rgba(127, 227, 255, 0.55) 0%, rgba(201, 182, 255, 0.22) 50%,
      rgba(255, 240, 200, 0) 100%),                                               /* (2) dz-ir2 glow */
    linear-gradient(135deg,
      rgba(127, 227, 255, 0.5) 0%, rgba(255, 255, 255, 0.5) 20%,
      rgba(201, 182, 255, 0.5) 40%, rgba(255, 240, 200, 0.5) 60%,
      rgba(154, 240, 207, 0.5) 80%, rgba(255, 198, 230, 0.5) 100%),               /* (3) dz-ir rainbow */
    linear-gradient(158deg, #c4cee0 0%, #9fb1ca 46%, #b7c1d4 70%, #94a7c2 100%);  /* (4) DAZZLE_FIELD */
  /* bead tile 5px: the verbatim 3-ring bead GEOMETRY (the SVG viewBox is 3.6, a vector,
     so this scales the same bead) at a legible size on the small F1 chip — the verbatim
     3.6px renders sub-perceptibly at chip scale, losing the "beaded" read; 5px keeps the
     dense bead-grid signature visible (same legibility scale as Mojo's grid on this chip,
     ~42x30 beads on a card-aspect chip — dense, not a handful). */
  background-size: 5px 5px, 100% 100%, 100% 100%, 100% 100%;
  background-repeat: repeat, no-repeat, no-repeat, no-repeat;
  /* beads composite NORMAL (crisp dots — they are white/dark, not holo-tinted; overlay
     washes them out on the light ground); the holo washes overlay-blend onto the ground.
     Mirrors the design: the dz-dot/ir rects are normal within the svg, the group blends
     onto the ground. */
  background-blend-mode: normal, overlay, overlay, normal;
  text-shadow: none;              /* dark label on a light holo ground — no dark shadow */
}
.parallel-overlay-chip[data-parallel-family="dazzle"] .parallel-chip__swatch {
  background: transparent;        /* the holo beaded ground supersedes the flat swatch */
  border-color: color-mix(in srgb, #8ea0c0 55%, #000);
}
@media (prefers-reduced-motion: reduce) {
  /* static treatment only — no animated shimmer is introduced here. The design's
     "no shimmer on S tiles" is an S4 EffectChip size-tier concern, N/A on the single-size
     F1 chip. */
  .parallel-overlay-chip[data-parallel-family="dazzle"] { transition: none; }
}

/* PARALLEL-OVERLAY (BOX-817 / BOX-827) — Raywave overlay treatment (F1 chip).
   Tool = PHOTOGRAPHIC FOIL PNG asset (the design is a real scan, NOT geometry — no CSS/SVG
   reduction). RaywaveOverlay (parallel-visual-effects.jsx:71) paints a scanned foil PNG at
   background cover/center, mix-blend-mode screen, over the base.
   PROVENANCE: the real scanned foils (Jacob Wilson Green Raywave is the canonical reference)
   committed verbatim from the design uploads/ to app/api/static/parallel_overlays/
   raywave-foil.png (portrait 1054x1492) + raywave-foil-h.png (landscape 1492x1054).

   ACCENT MODEL (confirmed from source, jsx:62-65): the FOIL is accent-INDEPENDENT (the SAME
   PNG on every SKU). The SKU color ("Blue Raywave" not "Green Raywave") lives in the BASE
   showing THROUGH the screen blend, so the base is CHIP_BG.raywave (jsx:535), an accent-tinted
   dark gradient. The chip's BASE tracks --pc-accent; the foil layer never recolors. (A fully
   accent-independent chip would lose the Blue-vs-Green distinction the design calls out.)

   ORIENTATION-AWARE (jsx:67-72, RAYWAVE_FOIL.portrait/landscape): the foil URL is the
   --rw-foil variable. DEFAULT = portrait. The .parallel-overlay-chip--landscape modifier
   flips --rw-foil to the landscape scan. The set-detail chip still exposes NO orientation
   signal (the route emits none; the chip is a single portrait pill) so it renders PORTRAIT
   there. As of BOX-1919 the landscape path IS exercised by a live surface: the /ui/parallels
   EffectChip tiles derive orientation from each face's own dimensions and emit the modifier,
   so the landscape scan renders for real rather than sitting behind a test-only hook.
   Render registry: shared/parallel_taxonomy/render_registry.py -> raywave = png/f1/built. */
.parallel-overlay-chip[data-parallel-family="raywave"] {
  --rw-foil: url("/static/parallel_overlays/raywave-foil.png");    /* portrait (default) */
  color: #f4f4f4;                 /* light label — the accent-tinted base is dark */
  border-color: color-mix(in srgb, var(--pc-accent, #5a6e9e) 55%, #000);
  background-image:
    var(--rw-foil),                                                /* screen-blended foil */
    linear-gradient(150deg,
      color-mix(in srgb, var(--pc-accent, #5a6e9e) 70%, #0a0a0a) 0%,
      color-mix(in srgb, var(--pc-accent, #5a6e9e) 30%, #0a0a0a) 60%,
      #0a0a0a 100%);                                               /* CHIP_BG.raywave base */
  background-size: cover, auto;
  background-position: center, center;
  background-repeat: no-repeat, no-repeat;
  background-blend-mode: screen, normal;   /* foil screen-blends onto the accent-tinted base */
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);  /* keep the label legible over the foil */
}
.parallel-overlay-chip[data-parallel-family="raywave"].parallel-overlay-chip--landscape {
  --rw-foil: url("/static/parallel_overlays/raywave-foil-h.png");  /* landscape variant */
}
.parallel-overlay-chip[data-parallel-family="raywave"] .parallel-chip__swatch {
  background: transparent;        /* the foil ground supersedes the flat swatch */
  border-color: color-mix(in srgb, var(--pc-accent, #5a6e9e) 50%, #000);
}
@media (prefers-reduced-motion: reduce) {
  /* static treatment only — the foil is a still scan, no animation introduced. */
  .parallel-overlay-chip[data-parallel-family="raywave"] { transition: none; }
}

/* PARALLEL-OVERLAY (BOX-817 / BOX-829) — Pandora overlay treatment (F1 chip).
   Tool = static SVG asset PER PALETTE (validated, §4b·2). Pandora is PALETTE-DRIVEN, not
   --pc-accent-driven: PandoraOverlay (parallel-visual-effects.jsx:454) is a 6x8 / U=10 grid
   of concentric nested squares whose 9 colors come from PANDORA_PALETTES[palette]. Two real
   SKUs ship as ONE family — "Pandora" (holo) + "Pandora Yellow" (yellow). Because each carries
   MULTIPLE baked colors, the Wave-Prizm single-accent mask CANNOT reproduce it (§4b·2) -> the
   faithful path is a pre-baked SVG asset per palette (colors baked, no mask):
   parallel_overlays/pandora-holo.svg + pandora-yellow.svg (verbatim geometry: glow rects +
   concentric rings + center pip + mortar grid + blur 0.45). The squares stretch to fill
   (preserveAspectRatio=none) over PANDORA_FIELD[palette] (a metallic/gold ground), squares
   overlay-blended onto the ground (PandoraOverlay mixBlendMode).
   PALETTE SELECTION: the route emits data-parallel-palette (holo default, yellow when the
   resolved tint is 'yellow') -> the base rule is holo, the [data-parallel-palette="yellow"]
   modifier flips both the SVG and the field. ACCENT-INDEPENDENT (palette-driven) + light
   metallic ground -> DARK label. The Pandora tile-BACKGROUND-behind-a-real-image (familyTileBg)
   stays deferred to S4.
   Render registry: shared/parallel_taxonomy/render_registry.py -> pandora = svg/f1/built. */
.parallel-overlay-chip[data-parallel-family="pandora"] {
  --pd-overlay: url("/static/parallel_overlays/pandora-holo.svg");   /* holo (default) */
  --pd-field: linear-gradient(155deg, #e4e7ee 0%, #b7bdc9 42%,
              #d2d6df 66%, #a9afbd 100%);                            /* PANDORA_FIELD.holo */
  color: #1a1a1a;                 /* dark label — the metallic Pandora field is LIGHT */
  border-color: #9aa0ac;
  background-image: var(--pd-overlay), var(--pd-field);
  background-size: 100% 100%, 100% 100%;   /* the 6x8 grid stretches to fill (preserveAspectRatio none) */
  background-repeat: no-repeat, no-repeat;
  background-blend-mode: overlay, normal;   /* squares overlay-blend onto the metallic ground */
  text-shadow: none;
}
.parallel-overlay-chip[data-parallel-family="pandora"][data-parallel-palette="yellow"] {
  --pd-overlay: url("/static/parallel_overlays/pandora-yellow.svg");  /* yellow SKU */
  --pd-field: linear-gradient(155deg, #f4d268 0%, #d9a833 44%,
              #edc24c 68%, #cf9f2b 100%);                             /* PANDORA_FIELD.yellow */
}
.parallel-overlay-chip[data-parallel-family="pandora"] .parallel-chip__swatch {
  background: transparent;        /* the nested-square ground supersedes the flat swatch */
  border-color: #9aa0ac;
}
@media (prefers-reduced-motion: reduce) {
  /* static treatment only — no animation introduced. */
  .parallel-overlay-chip[data-parallel-family="pandora"] { transition: none; }
}

/* PARALLEL-OVERLAY (BOX-817 / BOX-832) — Stained Glass overlay treatment (F1 chip).
   Tool = a single self-contained static SVG asset (validated). TOOL-DECISION CORRECTION:
   the prose ("39-polygon SVG") and the BOX-832 prompt ("canvas-rendered") are BOTH wrong vs
   the code — StainedGlassOverlay (parallel-visual-effects.jsx:274) returns an <svg> (the useRef
   /useLayoutEffect only MEASURE the tile for responsive sizing, not a canvas), and the panes
   come from buildSGCells, a SEEDED (20260601) jittered tessellation — DETERMINISTIC, no SG_CELLS
   constant, count varies with the lattice. So the faithful path is a deterministic static SVG
   (a Python port of the seeded algorithm), NOT a canvas pre-render. Asset:
   parallel_overlays/stainedglass-rainbow.svg (self-contained: dark stainedglass field
   #14141a->#060608 + per-pane spatial-hash RAINBOW gradients + diagonal sheen + dark leading).
   RAINBOW ONLY ships (the catalog SKU); cool/warm/dusk are design-demo only, not built.
   PHOTO-BLEND ADAPTATION: the design pane fills use mix-blend-mode multiply (to tint a card
   PHOTO through the glass); the photoless chip has no photo, so the panes alpha-composite on the
   dark leaded field directly (multiply over near-black would kill the color) — same backlit
   stained-glass intent. ACCENT-INDEPENDENT (palette baked) + dark field -> light label.
   RESPONSIVE SQUARE PANES — SHIPPED in BOX-1920 (was: "the S4 EffectChip's JS concern").
   A single portrait asset stretched under preserveAspectRatio=none ballooned every pane
   horizontally on a landscape tile. The design solves this by MEASURING the tile and
   rebuilding the lattice (useRef/useLayoutEffect/ResizeObserver), which this island cannot
   host — it is hook-free by contract. But the measurement only ever feeds ASPECT RATIO:
   the design normalises the viewBox so the short side is 100 and targets ~15-unit panes
   (jsx:299-308), so pane geometry depends on aspect alone, never on pixel size. Two
   per-orientation assets therefore reproduce the responsive behaviour exactly, and S/M/L of
   one orientation share an asset — the SAME two-asset pattern raywave uses above for its
   foil scan. Portrait = 7x9 on a 100x140 box; landscape = the exact transpose, 9x7 on
   140x100. BOTH assets are generated by scripts/generate_stainedglass_overlay.py (a
   verified port of buildSGCells; one provenance since BOX-1971 regenerated the portrait —
   the original BOX-832 hand bake did not replay from its documented seed/lattice).
   Render registry: shared/parallel_taxonomy/render_registry.py -> stainedglass = svg/f1/built. */
.parallel-overlay-chip[data-parallel-family="stainedglass"] {
  --sg-panes: url("/static/parallel_overlays/stainedglass-rainbow.svg");  /* portrait (default) */
  color: #f4f4f4;                 /* light label — the leaded-glass field is dark */
  border-color: #2a2c34;
  background-image: var(--sg-panes);
  background-size: 100% 100%;     /* the SVG (preserveAspectRatio none) stretches to fill */
  background-repeat: no-repeat;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);  /* keep the label legible over the glass */
}
.parallel-overlay-chip[data-parallel-family="stainedglass"].parallel-overlay-chip--landscape {
  /* 9x7 lattice on a 140x100 viewBox — panes stay square instead of stretching wide. */
  --sg-panes: url("/static/parallel_overlays/stainedglass-rainbow-h.svg");
}
.parallel-overlay-chip[data-parallel-family="stainedglass"] .parallel-chip__swatch {
  background: transparent;        /* the leaded-glass ground supersedes the flat swatch */
  border-color: #2a2c34;
}
@media (prefers-reduced-motion: reduce) {
  /* static treatment only — no animation introduced. */
  .parallel-overlay-chip[data-parallel-family="stainedglass"] { transition: none; }
}

/* PARALLEL-OVERLAY (BOX-1938) — Superfractor overlay treatment (F1 chip).
   The apex (1/1) parallel. NO design-source counterpart exists (superfractor is a
   BOX-1278 prod vocabulary extension; the design's FAMILY_PATTERNS and overlay
   components never mention it) — this treatment is designed within the shipped F1
   vocabulary, provenance recorded here and in render_registry.py, not hidden.
   Tool = colorless curved-band SVG texture + CSS gold ground (curves are not
   CSS-faithful — the BOX-823 Wave Prizm ruling — so the sweeping bands live in
   parallel_overlays/superfractor-swirl.svg, generated deterministically by
   scripts/generate_superfractor_overlay.py, --check-guarded like stainedglass).
   Layering (dazzle split): texture OVERLAY-blended above a diagonal sheen (screen)
   above the fixed gold ground ramp. ACCENT-INDEPENDENT: the 1/1 is definitionally
   the gold apex, carries no color axis, ignores --pc-accent (negative/dazzle accent
   model) → light gold ground → DARK label, no text-shadow. ONE asset, both
   orientations: stroked bands stretch acceptably under preserveAspectRatio=none
   (waveprizm precedent; the per-orientation pair is reserved for square-pane
   geometry like stainedglass). Render registry: superfractor = svg/f1/built. */
.parallel-overlay-chip[data-parallel-family="superfractor"] {
  color: #1a1a1a;                 /* dark label — the gold ground is light */
  border-color: #8a6a1c;
  background-image:
    url("/static/parallel_overlays/superfractor-swirl.svg"),
    linear-gradient(120deg, rgba(255, 255, 255, 0) 38%,
      rgba(255, 255, 255, 0.45) 50%, rgba(255, 255, 255, 0) 62%),
    linear-gradient(160deg, #f2d377 0%, #d9a83f 45%, #a87718 100%);
  background-size: 100% 100%, auto, auto;
  background-repeat: no-repeat;
  background-blend-mode: overlay, screen, normal;
}
.parallel-overlay-chip[data-parallel-family="superfractor"] .parallel-chip__swatch {
  background: transparent;        /* the gold ground supersedes the flat swatch */
  border-color: #8a6a1c;
}
@media (prefers-reduced-motion: reduce) {
  /* static treatment only — no animation introduced. */
  .parallel-overlay-chip[data-parallel-family="superfractor"] { transition: none; }
}

/* PARALLEL-OVERLAY (BOX-817 S4 / BOX-1920) — FAMILY TILE BACKGROUND (familyTileBg).
   Verbatim port of familyTileBg (parallel-visual-effects.jsx:800-833), used at
   RealVsChip (jsx:1108).

   WHAT THIS IS, because it is easy to confuse with a chip treatment: this is the ROW
   background sitting BEHIND a real-image chip and its meta text — the "design behind the
   chip". It is NOT the chip ground. (The registry's dazzle note "Tile-bg family (grounds
   the chip)" describes the chip ground, a different thing that shipped in BOX-826; BOX-1920
   comment 25030 misread the two as the same and was retracted by 25031.) Some families
   carry a distinctive foil ground that should read as the tile background in the in-app
   representation: the family pattern fills behind, and a left-to-right scrim fades it to a
   near-solid card surface so the meta text stays legible.

   Only pandora and dazzle have one — familyTileBg returns null for every other family, so
   a row without these hooks simply renders a plain surface. Selection is by FAMILY (and
   pandora's palette), never by product or set name.

   LAYERS, outermost last (jsx:822-831): the family field at opacity 0.14, the family
   overlay asset, then a 92deg scrim ramping var(--bg-card) 8% -> 32% at 14% -> 74% at 26%
   -> solid at 40%. The scrim is why the meta column is readable over a busy foil. */
.parallel-family-row {
  position: relative;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px;
  overflow: hidden;
}
/* The pattern layers live in a child so the row's own content stacks above them.
   THREE SIBLING LAYERS, not pseudo-elements: an element's own background paints BELOW its
   ::before, so putting the field on ::before and the overlay on the element background
   would invert the stack and hide the overlay behind the field. Siblings paint in DOM
   order — field, overlay, scrim — which is exactly the design's three divs (jsx:822-831),
   and it keeps the field's opacity from cascading onto the layers above it. */
.parallel-family-row__bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
.parallel-family-row__field,
.parallel-family-row__overlay,
.parallel-family-row__scrim {
  position: absolute;
  inset: 0;
}
/* layer 1 (bottom) — the family field, held at the design's 0.14 */
.parallel-family-row__field {
  background-image: var(--ptb-field);
  opacity: 0.14;
}
/* layer 2 — the family overlay asset, stretched over the field */
.parallel-family-row__overlay {
  background-image: var(--ptb-overlay);
  background-size: 100% 100%;
  background-repeat: no-repeat;
}
/* layer 3 (top) — the scrim, so the meta column fades to a near-solid card surface.

   THE ONE DELIBERATE DEVIATION FROM THE DESIGN, and why. The design writes these stops as
   PERCENTAGES of the row (8% at 0, 32% at 14%, 74% at 26%, solid at 40%). That works
   because its RealVsChip row lives in a narrow grid cell where 40% of the row lands
   exactly at the end of the 180px chip column — the scrim reaches solid precisely where
   the meta text begins. Percentages were a proxy for "solid by the end of the chip".

   This row is full page width, so those same percentages stretch: measured live at a
   1122px row, the meta text starts at 159px while the scrim would not go solid until
   449px — ~290px of meta text sitting over an unfaded foil, which is the exact failure
   the scrim exists to prevent.

   So the ramp is anchored to the chip column in ABSOLUTE units, preserving the design's
   stop RATIOS (14/40 = 0.35, 26/40 = 0.65). Same curve, same intent, landing where the
   design lands it at any row width. --ptb-scrim-end = row padding + chip + gap. */
.parallel-family-row {
  --ptb-scrim-end: 158px;   /* 12px padding + 132px chip + 14px gap */
}
.parallel-family-row__scrim {
  background-image: linear-gradient(92deg,
    color-mix(in srgb, var(--bg-card) 8%, transparent) 0,
    color-mix(in srgb, var(--bg-card) 32%, transparent) calc(var(--ptb-scrim-end) * 0.35),
    color-mix(in srgb, var(--bg-card) 74%, transparent) calc(var(--ptb-scrim-end) * 0.65),
    var(--bg-card) var(--ptb-scrim-end));
}
.parallel-family-row__content { position: relative; z-index: 1; }

/* Per-family tileBg + field + overlay. Values verbatim from familyTileBg; every gradient
   color-mixes against var(--bg-card), so all three follow the active theme. */
.parallel-family-row[data-parallel-family="dazzle"] {
  --ptb-field: linear-gradient(158deg, #c4cee0 0%, #9fb1ca 46%, #b7c1d4 70%, #94a7c2 100%);
  --ptb-overlay: url("/static/parallel_overlays/dazzle-beads.svg");
  background-image: linear-gradient(135deg,
    color-mix(in srgb, #8fb6d6 24%, var(--bg-card)) 0%,
    color-mix(in srgb, #9fb0c8 9%, var(--bg-card)) 62%,
    var(--bg-card) 100%);
}
.parallel-family-row[data-parallel-family="pandora"] {
  /* holo is the default palette (the route resolves silver -> holo, yellow -> yellow). */
  --ptb-field: linear-gradient(155deg, #e4e7ee 0%, #b7bdc9 42%, #d2d6df 66%, #a9afbd 100%);
  --ptb-overlay: url("/static/parallel_overlays/pandora-holo.svg");
  background-image: linear-gradient(135deg,
    color-mix(in srgb, #8ea0d8 26%, var(--bg-card)) 0%,
    color-mix(in srgb, #c4c9d4 10%, var(--bg-card)) 62%,
    var(--bg-card) 100%);
}
.parallel-family-row[data-parallel-family="pandora"][data-parallel-palette="yellow"] {
  --ptb-field: linear-gradient(155deg, #f4d268 0%, #d9a833 44%, #edc24c 68%, #cf9f2b 100%);
  --ptb-overlay: url("/static/parallel_overlays/pandora-yellow.svg");
  background-image: linear-gradient(135deg,
    color-mix(in srgb, #d9a833 32%, var(--bg-card)) 0%,
    color-mix(in srgb, #d9a833 11%, var(--bg-card)) 62%,
    var(--bg-card) 100%);
}
@media (prefers-reduced-motion: reduce) {
  /* static treatment only — no animation introduced. */
  .parallel-family-row { transition: none; }
}

/* ── MFA enforcement gate (BOX-421 follow-up) ───────────────────────────
   The COURTESY visual layer over the server route/API enforcement. The card
   is the only interactive surface; the sidebar (.mfa-gate-blur, set in
   base.html under `mfa_gate`) and the page body behind the scrim are made
   non-interactive. Token-backed (no new design tokens). */
.mfa-gate-blur {
  filter: blur(3px) grayscale(0.25);
  pointer-events: none;   /* belt-and-suspenders with the `inert` attribute */
  user-select: none;
}
.mfa-gate {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  /* Scrim over the page body — dims the blurred shell behind the card. Dark
     scrim works in both themes (modal convention). */
  background: rgba(10, 14, 22, 0.72);
  backdrop-filter: blur(2px);
}
.mfa-gate-card {
  width: 100%;
  max-width: 440px;
  background: var(--surface, var(--bg-card));
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 28px 28px 24px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
}
.mfa-gate-eyebrow {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.mfa-gate-title {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 6px 0 0;
  color: var(--text-primary);
}
.mfa-gate-body {
  color: var(--text-secondary);
  font-size: 13.5px;
  line-height: 1.5;
  margin: 8px 0 20px;
}
/* BOX-911 — verify-first gate: the primary CTA is the existing-
   authenticator path (an anchor), enrollment demoted to btn-outline. */
.mfa-gate .mfa-gate-verify-cta,
.mfa-gate .mfa-gate-enroll {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 44px;       /* a11y: 44px min hit target */
  font-size: 14px;
  cursor: pointer;
  text-decoration: none;  /* verify CTA is an <a> */
}
.mfa-gate .mfa-gate-form { margin-top: 8px; }
.mfa-gate-secondary {
  margin: 16px 0 0;
  font-size: 13px;
  color: var(--text-muted);
  text-align: center;
}
.mfa-gate-link {
  color: var(--accent);
  text-decoration: none;
  font-weight: 500;
}
.mfa-gate-link:hover { text-decoration: underline; }
.mfa-gate-signout {
  margin: 18px 0 0;
  text-align: center;
}
.mfa-gate-signout-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 12px;
  min-height: 44px;       /* a11y: 44px min hit target */
  padding: 0 14px;
  cursor: pointer;
}
/* a11y: visible focus ring (3px accent), per the handoff. */
.mfa-gate a:focus-visible,
.mfa-gate button:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--accent) 55%, transparent);
  outline-offset: 2px;
}

/* ============================================================ */
/* CARD-VAULT — dashboard visual identity (BOX-1159)            */
/* Handoff: design/handoff/design_handoff_dashboard_visual_     */
/* identity_260618/TOKEN_AND_COMPONENT_SPEC.md                  */
/*                                                              */
/* Additive re-skin of the shipped dashboard. Three levers:     */
/* Permanent Marker display type, brand yellow (--accent-2) as  */
/* a real second accent, and depth + one motion moment on the   */
/* shipped --shadow-* / --dur-* / --ease tokens. Semantic-token */
/* layer only (ADR-039 ratchet). No IA / data / governance      */
/* change. Everything is scoped under the dashboard shell so it */
/* never leaks to other surfaces. */
/* ============================================================ */

/* Centred shell (D1) — the main column is no longer a full-bleed
   ribbon on wide monitors. */
[data-testid="dashboard-shell"] {
  max-width: 1440px;
  margin-inline: auto;
}

/* ── Lever 1: display type ─────────────────────────────────── */
/* Greeting h1 + section titles take the marker display voice. */
[data-testid="dashboard-shell"] .lb-dash-greeting-headline,
[data-testid="dashboard-shell"] .dash-section-title {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
}
[data-testid="dashboard-shell"] .lb-dash-greeting-headline {
  font-size: var(--fs-h1);
}
/* the accent word in the greeting ("vault") */
[data-testid="dashboard-shell"] .lb-dash-greeting-headline .cv-accent {
  color: var(--accent-2);
}
/* The figure layer — hero figure, the four summary KPI values, and
   the queue counts — carries the display face. Dense sub-data
   (valuation rows, set $/%, rail figures) stays Inter tabular-nums. */
[data-testid="dashboard-shell"] .dash-summary-value,
[data-testid="dashboard-shell"] .dash-summary-card .dash-kpi-value,
[data-testid="dashboard-shell"] .dash-queue-card-value {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.01em;
}
/* Portfolio hero figure — the signature display moment. */
[data-testid="dashboard-shell"] .dash-kpi-portfolio .dash-summary-value-currency,
[data-testid="dashboard-shell"] .dash-kpi-portfolio .dash-kpi-value {
  font-size: var(--fs-hero);
  line-height: 1.05;
}
/* Shrunk siblings (D2): values a touch smaller so they don't
   compete with the hero figure. */
[data-testid="dashboard-shell"] .dash-summary-card:not(.dash-kpi-portfolio) .dash-summary-value {
  font-size: 24px;
}

/* ── Lever 2: depth — elevated hero + shrunk siblings (D2) ──── */
/* Hero = the featured vault card: yellow spine, lifted shadow, a
   warm top wash. Overrides the shipped blue inset rail (L5174). */
[data-testid="dashboard-shell"] .dash-summary-card.dash-kpi-portfolio {
  box-shadow: inset 3px 0 0 var(--accent-2), var(--shadow-lg);
  background:
    linear-gradient(180deg, var(--accent-2-soft) 0, transparent 60px),
    var(--surface);
  border-color: var(--accent-2-line);
}
/* Siblings shrink: lighter elevation, tighter padding, and they
   no longer stretch to the hero's height (the ~half-empty fix). */
[data-testid="dashboard-shell"] .dash-summary-grid > .dash-summary-card:not(.dash-kpi-portfolio) {
  align-self: start;
  box-shadow: var(--shadow-sm);
  padding: 14px 16px;
  gap: 4px;
}

/* ── Lever 2: color — warm hover edges + blue→yellow progress ── */
[data-testid="dashboard-shell"] .lb-quick-reach a:hover,
[data-testid="dashboard-shell"] .dash-queue-card:hover {
  border-color: var(--accent-2-line);
}
/* Set-progress fill goes blue→yellow (identity gradient). Scoped to
   the set-progress section so generic progress bars are untouched. */
[data-testid="dashboard-set-progress-section"] .progress-bar-fill {
  background: linear-gradient(90deg, var(--accent) 0, var(--accent-2) 100%);
}

/* ── D1: sticky rail (kills the dead right gutter ≥1101px) ──── */
@media (min-width: 1101px) {
  [data-testid="dashboard-shell"] .dash-rail {
    position: sticky;
    top: 24px;
    align-self: start;
    max-height: calc(100vh - 48px);
    overflow: auto;
  }
}

/* ── Depth + one motion moment ─────────────────────────────── */
/* A single orchestrated KPI-row reveal on load. The visible
   end-state IS the base style; this only runs while the
   [data-cv-reveal] hook attr is present AND motion is allowed, so
   print / PDF / reduced-motion show the final state immediately. */
@media (prefers-reduced-motion: no-preference) {
  [data-cv-reveal] .dash-summary-grid > .dash-summary-card {
    animation: cv-rise var(--dur-slow) var(--ease) backwards;
  }
  [data-cv-reveal] .dash-summary-grid > .dash-summary-card:nth-child(2) { animation-delay: 45ms; }
  [data-cv-reveal] .dash-summary-grid > .dash-summary-card:nth-child(3) { animation-delay: 90ms; }
  [data-cv-reveal] .dash-summary-grid > .dash-summary-card:nth-child(4) { animation-delay: 135ms; }
}
@keyframes cv-rise {
  from { opacity: 0; transform: translateY(8px); }
}

/* ── D3: warm "getting started" empty hero ─────────────────── */
/* When the portfolio has no value yet, the hero card carries the
   warm vault wash + a marker title + a real-route CTA. */
[data-testid="dashboard-shell"] .cv-empty-hero {
  background: var(--vault-bg-warm);
  border-color: var(--accent-2-line);
}
[data-testid="dashboard-shell"] .cv-empty-hero-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 22px;
  margin-bottom: 4px;
}

/* ============================================================ */
/* INTAKE WORKBENCH — Card Vault visual identity (BOX-1230)      */
/* Rollout surface #4. Scoped under the shared `.intake-workbench`*/
/* class added to all 12 workbench page roots, so the shared      */
/* header / card / KPI vocabulary gets the identity in one place  */
/* (cascades to the landing + all 7 stages). Per-stage inline-    */
/* style cleanup is a later slice. Semantic tokens only (ADR-039);*/
/* the stage-progress stepper keeps blue --accent (progress =     */
/* interactive); yellow --accent-2 is identity (header rail +     */
/* warm hover) only.                                              */
/* ============================================================ */

/* Type — marker display voice on the workbench page headline. */
.intake-workbench .dash-h1 {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
}

/* Color — yellow --accent-2 identity rail on the header. */
.intake-workbench .set-detail-header {
  border-left: 3px solid var(--accent-2);
}

/* Depth — --shadow-sm elevation + a one-step warm hover lift on the
   workbench cards + KPI tiles (was flat 1px borders). */
.intake-workbench .lb-surface,
.intake-workbench .lb-kpi-tile {
  box-shadow: var(--shadow-sm);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.intake-workbench .lb-surface:hover,
.intake-workbench .lb-kpi-tile:hover {
  border-color: var(--accent-2-line);
  box-shadow: var(--shadow);
}

/* Motion — one orchestrated reveal on the landing only ([data-cv-reveal]);
   end-state IS the base style, so reduced-motion / print / no-JS render the
   final state immediately. */
@keyframes iwbRise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: no-preference) {
  .intake-workbench[data-cv-reveal] > header,
  .intake-workbench[data-cv-reveal] > section {
    animation: iwbRise var(--dur-slow, 200ms) var(--ease) both;
  }
  .intake-workbench[data-cv-reveal] > header { animation-delay: 0ms; }
  .intake-workbench[data-cv-reveal] > section:nth-of-type(1) { animation-delay: 45ms; }
  .intake-workbench[data-cv-reveal] > section:nth-of-type(2) { animation-delay: 90ms; }
  .intake-workbench[data-cv-reveal] > section:nth-of-type(3) { animation-delay: 135ms; }
  .intake-workbench[data-cv-reveal] > section:nth-of-type(4) { animation-delay: 180ms; }
}

/* Buttons: the intake-workbench markup now uses the global .lb-btn / .lb-btn-sm
   / .lb-btn-primary etc. (BOX-1532 converged lb-button* -> .lb-btn*), so the
   former scoped `.intake-workbench .lb-button*` block (BOX-1231 Slice 3) was
   deleted as dead CSS — it was byte-identical to the global .lb-btn rules it
   deferred to (.lb-button == .lb-btn; .lb-button-active == .lb-btn-primary). */

/* Pills (BOX-1249) — `.lb-pill` is used across the capture/source/match/
   resolve stages but was never defined (the pills carried their full
   styling inline). Define the base pill on semantic tokens so the class is
   meaningful (parallels the Slice-3 `.lb-button` fix); the filled status
   pills keep their `background: var(--accent-fill); color: #fff` inline
   (AA-safe, the .lb-btn-primary contract). `.lb-pill-inactive` is the
   AA-safe not-configured / not-set-up variant — the prior inline pill
   painted white text (#fff) on a `--text-muted` grey fill, which fails AA. */
.intake-workbench .lb-pill {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  line-height: 1.7;
}
.intake-workbench .lb-pill-inactive {
  background: transparent;
  color: var(--ink-dim, var(--text-secondary));
  border: 1px solid var(--border);
}

/* Done stage — featured "Launch" launchpad (BOX-1249). The done page's
   positive terminal moment wears the identity per the standard's featured-
   element guidance: warm vault wash + a yellow `--accent-2-line` edge +
   marker section title. The marker page H1 ("Done"), header rail, and
   `--shadow-sm` depth already come from Slice 1; this lifts the launchpad
   to the page's featured element. The nested per-destination launch cards
   stay plain `.lb-surface`. */
.intake-workbench .intake-done-launch {
  background: var(--vault-bg-warm);
  border-color: var(--accent-2-line);
}
.intake-workbench .intake-done-launch > h2 {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
}

/* ============================================================ */
/* SET DETAIL PAGE — Card Vault visual identity (BOX-1244)       */
/* Rollout surface #7. Scoped under [data-testid="set-detail-    */
/* page"] because the .set-detail-page CLASS is shared with the  */
/* workbench / rip-sheet / ebay-import / admin surfaces. Semantic */
/* tokens only (ADR-039); shadow-only hover so any per-card      */
/* status / scope borders survive. The completion grid + KPI     */
/* semantics are untouched.                                      */
/* ============================================================ */
[data-testid="set-detail-page"] .set-detail-title {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
}
[data-testid="set-detail-page"] .set-detail-header {
  border-left: 3px solid var(--accent-2);
}
[data-testid="set-detail-page"] .lb-surface {
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--dur) var(--ease);
}
[data-testid="set-detail-page"] .lb-surface:hover {
  box-shadow: var(--shadow);
}
/* One reduced-motion-gated reveal of the identity header (the dense
   data sections below render immediately — no per-section stagger). */
@keyframes sdpRise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: no-preference) {
  [data-testid="set-detail-page"][data-cv-reveal] .set-detail-header {
    animation: sdpRise var(--dur-slow, 200ms) var(--ease) both;
  }
}

/* ============================================================ */
/* MARKETPLACE — Card Vault visual identity (BOX-1245)          */
/* Rollout surface #8. Scoped under [data-testid="marketplace-  */
/* page"] (the page wraps its content in that hook; .page-title */
/* / .section-panel are shared classes so can't be the scope).  */
/* Semantic tokens only (ADR-039). The .mp-card already carries  */
/* a hover shadow + transition; this adds resting depth.        */
/* ============================================================ */
[data-testid="marketplace-page"] .page-title {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
  border-left: 3px solid var(--accent-2);
  padding-left: 12px;
}
[data-testid="marketplace-page"] .section-panel,
[data-testid="marketplace-page"] .mp-card {
  box-shadow: var(--shadow-sm);
}
/* One reduced-motion-gated reveal of the page's top-level blocks. */
@keyframes mpRise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: no-preference) {
  [data-testid="marketplace-page"][data-cv-reveal] > * {
    animation: mpRise var(--dur-slow, 200ms) var(--ease) both;
  }
  [data-testid="marketplace-page"][data-cv-reveal] > *:nth-child(1) { animation-delay: 0ms; }
  [data-testid="marketplace-page"][data-cv-reveal] > *:nth-child(2) { animation-delay: 45ms; }
  [data-testid="marketplace-page"][data-cv-reveal] > *:nth-child(3) { animation-delay: 90ms; }
  [data-testid="marketplace-page"][data-cv-reveal] > *:nth-child(4) { animation-delay: 135ms; }
  [data-testid="marketplace-page"][data-cv-reveal] > *:nth-child(n+5) { animation-delay: 180ms; }
}

/* ============================================================ */
/* FMV QUEUE + REVIEW/REPORT SURFACES — Card Vault identity      */
/* (BOX-1243). Rollout surface #6, Slice 2+. Extends Slice 1     */
/* (BOX-1241, the .fmv-worklist-shell levers) to the FMV sibling */
/* surfaces: the cross-commit queue + the read-only review-      */
/* detail / review-session / attention-coverage surfaces.        */
/* Semantic tokens only (ADR-039); no new tokens, no [data-theme]*/
/* block edits; additive + surface-scoped so nothing leaks. The  */
/* conformance sweep found no bare hardcoded colors on these     */
/* surfaces — every hex is a var(--token,#fallback) (token wins).*/
/* ============================================================ */

/* FMV queue — the queue header reuses the .set-detail-header
   lb-surface identity component (same component as the set-detail
   page), so it mirrors the BOX-1244 treatment: marker .page-title,
   a yellow identity rail on the header surface edge, and resting
   --shadow-sm card depth with a shadow-only hover lift. */
.fmv-queue-shell .page-title {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
}
.fmv-queue-shell .set-detail-header {
  border-left: 3px solid var(--accent-2);
}
.fmv-queue-shell .card {
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--dur) var(--ease);
}
.fmv-queue-shell .card:hover {
  box-shadow: var(--shadow);
}
@keyframes fmvCvRise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: no-preference) {
  .fmv-queue-shell[data-cv-reveal] > * {
    animation: fmvCvRise var(--dur-slow, 200ms) var(--ease) both;
  }
  .fmv-queue-shell[data-cv-reveal] > *:nth-child(1) { animation-delay: 0ms; }
  .fmv-queue-shell[data-cv-reveal] > *:nth-child(2) { animation-delay: 45ms; }
  .fmv-queue-shell[data-cv-reveal] > *:nth-child(3) { animation-delay: 90ms; }
  .fmv-queue-shell[data-cv-reveal] > *:nth-child(4) { animation-delay: 135ms; }
  .fmv-queue-shell[data-cv-reveal] > *:nth-child(n+5) { animation-delay: 180ms; }
}

/* FMV review / report surfaces — shared scoped wrapper for the
   read-only review-detail, review-session, and attention-coverage
   surfaces. Each template wraps its body in
   <div class="fmv-cv-surface" data-cv-reveal>. Marker on the page
   H1 + section/card titles, a yellow identity rail on the
   .page-header (the surfaces that carry one), and resting card
   depth with a shadow-only hover lift (any status/scope borders
   are not recolored — depth is shadow only). */
.fmv-cv-surface .page-header h1,
.fmv-cv-surface .page-title,
.fmv-cv-surface > .card > h2,
.fmv-cv-surface > .card > .card-title {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
}
.fmv-cv-surface > .page-header {
  border-left: 3px solid var(--accent-2);
  padding-left: 14px;
}
.fmv-cv-surface > .card {
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--dur) var(--ease);
}
.fmv-cv-surface > .card:hover {
  box-shadow: var(--shadow);
}
@media (prefers-reduced-motion: no-preference) {
  .fmv-cv-surface[data-cv-reveal] > * {
    animation: fmvCvRise var(--dur-slow, 200ms) var(--ease) both;
  }
  .fmv-cv-surface[data-cv-reveal] > *:nth-child(1) { animation-delay: 0ms; }
  .fmv-cv-surface[data-cv-reveal] > *:nth-child(2) { animation-delay: 45ms; }
  .fmv-cv-surface[data-cv-reveal] > *:nth-child(3) { animation-delay: 90ms; }
  .fmv-cv-surface[data-cv-reveal] > *:nth-child(4) { animation-delay: 135ms; }
  .fmv-cv-surface[data-cv-reveal] > *:nth-child(n+5) { animation-delay: 180ms; }
}

/* ── BOX-1517 A1 (ADR-084) — "eBay orders" converged door identity ──
   Card Vault pass scoped to the door shell (the BOX-1244/1245
   pattern): marker H1, --accent-2 identity rail on the header
   anchor, --shadow-sm resting cards. Semantic tokens only; all
   three themes resolve via var(). */
[data-testid="ebay-orders-door"] .page-title {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
}
[data-testid="ebay-orders-door"] .set-detail-header {
  border-left: 3px solid var(--accent-2);
  box-shadow: var(--shadow-sm);
}
[data-testid="ebay-orders-door"] .lb-surface,
[data-testid="ebay-orders-door"] .card {
  box-shadow: var(--shadow-sm);
}

/* ── BOX-1901 A2r.2 (PART_A2 #4) — Card Vault identity on the eBay
   intake surfaces. The headers already ship `.set-detail-header
   .lb-surface` + a `.dash-h1`; this activates the marker display
   voice on the headline and the --accent-2 identity rail, matching
   the FMV-worklist (L2794) / intake-workbench (L6583) precedent. The
   door already carries the rail (A2.1 block above) — it only needs
   the marker H1. Semantic tokens only (ADR-039); yellow --accent-2 is
   identity (rail), never state. ── */
[data-testid="ebay-api-intake-page"] .set-detail-header {
  border-left: 3px solid var(--accent-2);
  box-shadow: var(--shadow-sm);
}
[data-testid="ebay-api-intake-page"] .dash-h1,
[data-testid="ebay-orders-door"] .dash-h1 {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
}

/* ── BOX-1517 A2.1 (ADR-084) — converged review commit bar + Ready?
   column, scoped to the paste-review commit form. Sticky once the
   order outgrows the viewport (build-flag ruling); readiness uses the
   .lb-dot state vocabulary — never identity yellow. */
[data-testid="ebay-order-import-commit-form"] .review-commit-bar,
[data-testid="ebay-api-confirm-form"] .review-commit-bar {
  position: sticky;
  bottom: 0;
  z-index: 5;
  box-shadow: var(--shadow);
}
[data-testid="ebay-order-import-commit-form"] .review-commit-mode label,
[data-testid="ebay-api-confirm-form"] .review-commit-mode label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-right: 14px;
}
[data-testid="ebay-order-import-commit-form"] .review-ready-cell,
[data-testid="ebay-api-confirm-form"] .review-ready-cell {
  white-space: nowrap;
}

/* ── BOX-1517 A2.2 (ADR-084) — tabbed per-card line editor. Tabs are
   buttons (role=tab); the active one carries aria-selected="true" and
   the gold identity accent (sidebar-rail precedent) — panels toggle
   the hidden ATTRIBUTE only, so every input keeps POSTing with the
   form. Scoped to the paste-review commit form like the A2.1 block;
   A2.3 extends the scope when pipeline B adopts the family. */
[data-testid="ebay-order-import-commit-form"] .review-line-editor,
[data-testid="ebay-api-confirm-form"] .review-line-editor {
  min-width: 320px;
}
[data-testid="ebay-order-import-commit-form"] .review-editor-tabs,
[data-testid="ebay-api-confirm-form"] .review-editor-tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 6px;
}
[data-testid="ebay-order-import-commit-form"] .review-editor-tabs [role="tab"],
[data-testid="ebay-api-confirm-form"] .review-editor-tabs [role="tab"] {
  appearance: none;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 3px 8px;
  font-size: 11px;
  color: var(--ink-faint);
  cursor: pointer;
}
[data-testid="ebay-order-import-commit-form"] .review-editor-tabs [role="tab"][aria-selected="true"],
[data-testid="ebay-api-confirm-form"] .review-editor-tabs [role="tab"][aria-selected="true"] {
  color: var(--ink);
  border-bottom-color: var(--accent-2);
  font-weight: 600;
}
[data-testid="ebay-order-import-commit-form"] .review-editor-panel,
[data-testid="ebay-api-confirm-form"] .review-editor-panel {
  padding: 2px 0;
}
[data-testid="ebay-order-import-commit-form"] .review-display-grid,
[data-testid="ebay-api-confirm-form"] .review-display-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px 10px;
  margin: 6px 0 0 0;
  font-size: 11px;
}
/* BOX-1906 — the display grids ship `hidden` (A2r.3 / PART_A2 #6: no
   empty "Player —" before a card is picked) and the review JS reveals
   them on pick. This author `display: grid` outranks the UA
   `[hidden] { display: none }`, so the attribute alone did NOT hide
   them in the browser — same trap already guarded for the collection
   views at L2054. Re-assert display:none at equal scope + the extra
   [hidden] attribute (higher specificity — no !important needed). */
[data-testid="ebay-order-import-commit-form"] .review-display-grid[hidden],
[data-testid="ebay-api-confirm-form"] .review-display-grid[hidden] {
  display: none;
}

/* BOX-1951 — advisory divergence chip: the listing title claims an
   autograph/relic the picked card type lacks. Status messaging: the
   amber attention cue rides the BORDER (the warning-note idiom, cf.
   the border-left pattern at L1375) while the text inherits default
   ink — --warning as 11px TEXT is ~3.19:1 on the light theme's card
   and fails AA (adversarial-review blocker). Message carried in text,
   never color alone. Advisory only: a <p> the review JS fills; it
   gates nothing. */
.review-divergence-chip {
  margin: 2px 0 4px 0;
  padding: 2px 0 2px 8px;
  border-left: 3px solid var(--warning);
  font-size: 11px;
  font-weight: 600;
}
/* Same [hidden] trap as the display grids directly above (BOX-1906):
   any author display rule would outrank the UA [hidden] — pin the
   guard at equal scope so hidden ALWAYS means hidden. */
[data-testid="ebay-order-import-commit-form"] .review-divergence-chip[hidden],
[data-testid="ebay-api-confirm-form"] .review-divergence-chip[hidden] {
  display: none;
}
[data-testid="ebay-order-import-commit-form"] .review-display-grid > div,
[data-testid="ebay-api-confirm-form"] .review-display-grid > div {
  display: flex;
  gap: 4px;
  min-width: 0;
}
[data-testid="ebay-order-import-commit-form"] .review-display-grid dt,
[data-testid="ebay-api-confirm-form"] .review-display-grid dt {
  color: var(--ink-faint);
}
[data-testid="ebay-order-import-commit-form"] .review-display-grid dd,
[data-testid="ebay-api-confirm-form"] .review-display-grid dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* ── BOX-1517 A2.6 — the door's single load reveal. Same contract
   as the dashboard's cv-rise moment: runs only under the
   [data-cv-reveal] hook AND motion allowance; the visible end-state
   IS the base style. One moment per surface (identity checklist). */
@media (prefers-reduced-motion: no-preference) {
  [data-testid="ebay-orders-door"][data-cv-reveal] > .lb-surface,
  [data-testid="ebay-orders-door"][data-cv-reveal] > div > .lb-surface,
  [data-testid="ebay-orders-door"][data-cv-reveal] > .card {
    animation: cv-rise var(--dur-slow) var(--ease) backwards;
  }
  [data-testid="ebay-orders-door"][data-cv-reveal] > div > .lb-surface {
    animation-delay: 45ms;
  }
  [data-testid="ebay-orders-door"][data-cv-reveal] > .card {
    animation-delay: 90ms;
  }
}
