/* ─── CardFinder — Dark Glassmorphic Theme ────────────────────────────────── */
/* Design tokens are direct from game-manager so the two apps feel cohesive. */

:root {
  --bg-primary: #0a0a0f;
  --bg-secondary: #12121a;
  --bg-card: rgba(255, 255, 255, 0.05);
  --bg-card-hover: rgba(255, 255, 255, 0.08);
  --bg-input: rgba(255, 255, 255, 0.08);
  --border-glass: rgba(255, 255, 255, 0.1);
  --border-glass-strong: rgba(255, 255, 255, 0.2);
  --text-primary: #ffffff;
  /* Brightened from .7 → .86 and .5 → .72 in the contrast pass — the
     prior values read as "thin" across muted UI chrome (eyebrows,
     metadata, captions, labels).  These tokens are referenced by
     hundreds of component selectors, so bumping them is the highest-
     leverage move toward making the whole app legible. */
  --text-secondary: rgba(255, 255, 255, 0.86);
  --text-muted: rgba(255, 255, 255, 0.72);
  --text-strong:    rgba(255, 255, 255, 0.96);
  --text-faint:     rgba(255, 255, 255, 0.55);
  /* Trading Floor accent — gold leaf against charcoal/ivory.  Reserved for
     the *single* moment per surface where the meaning is "act on this" or
     "this is hot": active tab, primary CTA, hot-tier rail + multiplier,
     focus ring.  Everywhere else uses ivory or muted ivory.  Gold has real
     heritage in card collecting (Topps Gold, gold-label slabs, premium
     parallels) so it carries category meaning, not just a UI choice. */
  --accent: #c8a85a;
  --accent-glow: rgba(200, 168, 90, 0.28);
  --accent-hover: #b89846;
  --accent-ink: #0a0a0f;
  --success: #22c55e;
  --success-glow: rgba(34, 197, 94, 0.3);
  --warning: #f59e0b;
  --warning-glow: rgba(245, 158, 11, 0.3);
  --error: #ef4444;
  --error-glow: rgba(239, 68, 68, 0.3);
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --shadow-glow: 0 0 20px var(--accent-glow);
  --transition: all 0.2s ease;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
/* iOS PWA viewport ladder.  The historical bug: `height: 100%` on html/body
   resolves against the *layout* viewport, but iOS standalone PWAs reserve a
   strip at the bottom for the (now-absent) address bar / home-indicator
   region.  When the body is shorter than the visual viewport, you get a
   persistent black band at the bottom.  The fix is the -webkit-fill-available
   cascade — older iOS reads it, newer iOS falls through to 100dvh — combined
   with extending the body background under the safe-area inset so even if the
   reservation IS still there, it's the same color as the page chrome and
   reads as intentional. */
html { height: -webkit-fill-available; }
html, body, #root {
  width: 100%;
  min-height: 100vh;            /* legacy fallback */
  min-height: -webkit-fill-available;
  min-height: 100dvh;            /* modern dynamic viewport */
  overflow-x: hidden;
}
body {
  /* Trading Floor display family.  Inter Tight (loaded via Google Fonts in
     index.html) gives us editorial-financial body type; system stack is the
     fallback while the web font is in flight.  JetBrains Mono is used for
     numeric strips via the .num utility class and the Browse row mono cells.
     Default weight is 500 (not 400) to match the contrast pass — the prior
     400 default rendered too thin against this dark background. */
  font-family: 'Inter Tight', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif;
  font-feature-settings: 'ss01' on, 'cv11' on;
  font-weight: 500;
  letter-spacing: -.003em;
  background: var(--bg-primary);
  color: var(--text-primary);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
/* Default mono-numeric weight up too — JetBrains Mono at weight 400 reads
   particularly thin in our small numeric strips. */
.num, .num *, code, pre { font-weight: 500; }

/* Tabular numerics utility — opt-in for prices, counts, timers. */
.num, .num * { font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace; font-variant-numeric: tabular-nums; }

button, input, select, textarea {
  font-family: inherit;
  -webkit-tap-highlight-color: transparent;
}
a { color: var(--accent); text-decoration: none; }
a:active { opacity: 0.8; }

/* ─── App shell ────────────────────────────────────────────────────────────── */
/* Same viewport ladder as html/body — `100vh` is the safety net for
   ancient WebKit, `-webkit-fill-available` covers iOS 13–15, `100dvh`
   covers everything modern.  The later declarations win where supported. */
.app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: -webkit-fill-available;
  min-height: 100dvh;
  /* Paint the body color UNDER the bottom safe-area inset region so any
     residual viewport-reservation strip the OS keeps reads as the page
     itself, not as a black band underneath the page. */
  background: var(--bg-primary);
}
/* Standalone iOS PWA only — pin the shell to the visualViewport height
   measured by app.js.  This is the ONLY thing that cures the bottom
   black band on the iPhone home-screen install where `100dvh` alone
   doesn't cover the reserved address-bar strip. */
@media all and (display-mode: standalone) {
  .app { min-height: var(--app-vh, 100dvh); }
  body  { min-height: var(--app-vh, 100dvh); }
}

.app-version {
  position: fixed; bottom: 8px; right: 12px;
  font-size: 11px; font-weight: 600; letter-spacing: .5px;
  color: rgba(255,255,255,.3); pointer-events: none; z-index: 9999;
}

/* ─── Page layout ──────────────────────────────────────────────────────────── */
.page { flex: 1; display: flex; flex-direction: column; min-height: 0; }

/* The tabs ARE the page identity — no separate "Targets / Searches / …"
   header above them.  This bar is the only sticky element at the top, with
   the iOS safe-area inset baked into its top padding. */
/* ─── Tabbar — app-level masthead + ticker-style nav ─────────────────────
   Replaces the prior rounded-capsule chrome with an editorial publication
   header: small wordmark with a tagline at the top, a hairline rule, then
   a row of underlined tabs.  Sticky so navigation stays available while
   you scroll, but visually it disappears into the page. */
.tabbar {
  position: sticky; top: 0; z-index: 100;
  padding: calc(10px + env(safe-area-inset-top, 0px)) 14px 0;
  background: rgba(10,10,15,.92);
  backdrop-filter: saturate(140%) blur(18px);
  -webkit-backdrop-filter: saturate(140%) blur(18px);
  border-bottom: 1px solid var(--b-rule);
}

/* Wordmark line: a tiny gold square, the app name in editorial Inter
   Tight, and a categorical tagline tucked to the right.  Acts like the
   sub-nameplate on a financial paper. */
.masthead {
  display: flex; align-items: baseline;
  gap: 12px;
  padding: 2px 0 12px;
  border-bottom: 1px solid var(--b-rule);
}
.masthead__wordmark {
  display: flex; align-items: baseline; gap: 10px;
  flex: 1; min-width: 0;
}
.masthead__mark {
  align-self: center;
  width: 8px; height: 8px;
  background: var(--b-accent);
  border-radius: 1px;
  flex-shrink: 0;
}
.masthead__name {
  font-family: 'Inter Tight', sans-serif;
  font-size: 16px; font-weight: 800;
  letter-spacing: -.014em;
  color: var(--b-ivory);
  white-space: nowrap;
}
.masthead__tag {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 9.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .42);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-width: 0;
}
@media (max-width: 480px) {
  .masthead { padding: 0 0 10px; gap: 10px; }
  .masthead__name { font-size: 15px; }
  .masthead__tag { font-size: 9px; letter-spacing: .1em; }
}
@media (max-width: 360px) {
  /* On the smallest phones drop the tagline so the wordmark stays clean. */
  .masthead__tag { display: none; }
}

/* User chip — small "ap · sign out" cluster on the right of the masthead. */
.masthead__user {
  display: flex; align-items: center; gap: 8px;
  flex-shrink: 0;
}
.masthead__user-name {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--b-accent);
  padding: 3px 7px;
  border: 1px solid var(--b-accent-edge);
  border-radius: 2px;
}
.masthead__logout {
  font-family: 'Inter Tight', sans-serif;
  font-size: 9.5px; font-weight: 700;
  letter-spacing: .22em; text-transform: uppercase;
  color: rgba(244, 241, 234, .55);
  background: transparent;
  border: 1px solid var(--b-rule-strong);
  border-radius: 2px;
  padding: 4px 8px;
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
}
.masthead__logout:hover {
  color: var(--b-accent);
  border-color: var(--b-accent-edge);
}
@media (max-width: 480px) {
  .masthead__logout { font-size: 9px; padding: 4px 6px; letter-spacing: .14em; }
}
@media (max-width: 360px) {
  .masthead__logout { display: none; }
}
.page-content {
  flex: 1; padding: 16px 14px 24px;
  /* Reserve the iOS home-indicator inset INSIDE this scroll region. */
  padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px));
  overflow-y: auto;
  /* Match the page background so when the OS reserves any strip beyond
     our flex column (iOS PWA quirk), it visually disappears. */
  background: var(--bg-primary);
}
@media (min-width: 640px) { .page-content { padding: 20px; } }

/* ─── Glass card ──────────────────────────────────────────────────────────── */
.glass-card {
  background: var(--bg-card);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius-lg);
  box-shadow: 0 1px 0 rgba(255,255,255,0.04) inset, 0 8px 24px -16px rgba(0,0,0,0.5);
  transition: var(--transition);
  padding: 16px;
}
@media (min-width: 640px) { .glass-card { padding: 20px; } }
.glass-card.clickable:active { transform: scale(.98); }
.glass-card + .glass-card { margin-top: 12px; }

/* ─── Target card (compact, mobile-first, collapsible) ──────────────────────
   Default state shows verdict, multiple, all-in→net, set/player.  Tap the
   card to expand for full comp breakdown, sources, and edit/delete actions. */
.tcard { padding: 14px; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.tcard:active { transform: scale(.99); }
.tcard__head { display: flex; align-items: center; gap: 12px; min-height: 44px; }
.tcard__thumb {
  width: 48px; height: 64px; flex-shrink: 0;
  background: var(--bg-input); border-radius: 6px;
  background-size: cover; background-position: center;
  border: 1px solid var(--border-glass);
}
.tcard.is-open .tcard__thumb-large {
  display: block; margin-top: 12px;
  width: 100%; max-width: 320px; aspect-ratio: 3/4;
  background: var(--bg-input); border-radius: 8px;
  background-size: contain; background-position: center; background-repeat: no-repeat;
  border: 1px solid var(--border-glass);
  margin-left: auto; margin-right: auto;
}
.tcard__thumb-large { display: none; }
.tcard__id { flex: 1; min-width: 0; }
.tcard__title { font-size: 15px; font-weight: 600; line-height: 1.25; letter-spacing: .1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tcard__sub { font-size: 12px; color: var(--text-secondary); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tcard__verdict { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex-shrink: 0; }
.tcard__mult { font-size: 16px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -.3px; line-height: 1; }
.tcard__mult.go      { color: var(--success); }
.tcard__mult.marginal{ color: var(--warning); }
.tcard__mult.avoid   { color: var(--error); }
.tcard__mult.muted   { color: var(--text-muted); }
.tcard__money {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 10px; padding: 8px 12px;
  background: var(--bg-input); border-radius: var(--radius-sm);
  font-size: 13px; font-variant-numeric: tabular-nums;
}
.tcard__money .arrow { color: var(--text-muted); font-size: 12px; }
.tcard__money b      { font-weight: 700; color: var(--text-primary); }
.tcard__attrib {
  margin-top: 8px; font-size: 11px; color: var(--text-muted);
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.tcard__attrib .chev { transition: transform .2s ease; opacity: .6; }
.tcard.is-open .tcard__attrib .chev { transform: rotate(180deg); }

.tcard__detail { display: none; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border-glass); }
.tcard.is-open .tcard__detail { display: block; }

.tcard__comps {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 14px;
  font-variant-numeric: tabular-nums; font-size: 13px;
}
.tcard__comps .row { display: flex; justify-content: space-between; gap: 8px; }
.tcard__comps .row .label { color: var(--text-muted); font-size: 12px; }

.tcard__notes { margin-top: 10px; padding: 10px 12px; background: rgba(255,255,255,0.03); border-radius: var(--radius-sm); font-size: 12px; line-height: 1.45; color: var(--text-secondary); }

.tcard__actions { display: flex; gap: 6px; margin-top: 12px; flex-wrap: wrap; }
.tcard__actions .btn { flex: 1 1 auto; min-width: 0; min-height: 40px; padding: 10px 8px; font-size: 12px; }
.tcard__actions .btn.icon { flex: 0 0 auto; padding: 10px 12px; }

/* Stale source attribution (TOS staleness disclosure). */
.tcard__attrib.is-stale { color: var(--warning); }
.tcard__attrib.is-stale::before { content: '⚠ '; }

/* ─── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 8px;
  padding: 12px 18px;
  font-size: 15px; font-weight: 500; letter-spacing: .1px;
  border: none; border-radius: var(--radius-md);
  min-height: 44px; min-width: 44px;
  transition: var(--transition);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.btn-primary { background: var(--accent); color: var(--accent-ink); box-shadow: 0 0 20px var(--accent-glow); font-weight: 700; }
.btn-primary:active { transform: scale(.98); background: var(--accent-hover); }
.btn-secondary { background: var(--bg-card); color: var(--text-primary); border: 1px solid var(--border-glass); }
.btn-secondary:active { background: var(--bg-card-hover); border-color: var(--border-glass-strong); }
.btn-ghost { background: transparent; color: var(--text-secondary); }
.btn-ghost:active { background: var(--bg-card); color: var(--text-primary); }
.btn-danger { background: var(--error); color: #fff; box-shadow: 0 0 20px var(--error-glow); }
.btn-icon { padding: 10px; min-width: 44px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-sm { padding: 9px 14px; font-size: 13px; min-height: 40px; }
.btn-block { width: 100%; }
.btn-primary-cta {
  width: 100%; padding: 14px 20px; min-height: 48px;
  background: linear-gradient(180deg, var(--accent) 0%, var(--accent-hover) 100%);
  color: #fff; font-weight: 600; font-size: 15px;
  border-radius: var(--radius-md);
  box-shadow: 0 0 24px var(--accent-glow), 0 4px 12px rgba(0,0,0,0.25);
  border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  -webkit-tap-highlight-color: transparent;
}
.btn-primary-cta:active { transform: scale(.985); }

/* ─── Toolbar (page-content top action area) ──────────────────────────────── */
.toolbar { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; }
.toolbar-secondary {
  display: flex; gap: 6px; justify-content: center; flex-wrap: wrap;
  font-size: 13px;
}
.toolbar-secondary button {
  background: none; border: none; color: var(--accent); font-size: 13px;
  padding: 8px 12px; min-height: 36px; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  font-weight: 500;
}
.toolbar-secondary .sep { color: var(--text-muted); padding: 8px 0; }

/* ─── Inputs ──────────────────────────────────────────────────────────────── */
.input, textarea.input, select.input {
  width: 100%;
  padding: 12px 16px;
  font-size: 16px;
  color: var(--text-primary);
  background: var(--bg-input);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius-md);
  outline: none;
  transition: var(--transition);
  min-height: 44px;
  -webkit-appearance: none;
}
.input:focus, textarea.input:focus, select.input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
}
.input::placeholder { color: var(--text-muted); }
textarea.input { min-height: 80px; resize: vertical; }
.input-group { margin-bottom: 16px; }
.input-label { display: block; margin-bottom: 8px; font-size: 14px; font-weight: 500; color: var(--text-secondary); }
.input-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.input-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }

/* ─── Nav tabs (segmented control) ────────────────────────────────────────── */
/* Ticker-style nav — flat row of labels divided by hairlines.  Active
   tab gets a gold underline, no fill, no chip.  Reads as "section
   headers in a paper" rather than "buttons in an app." */
.nav-tabs {
  display: flex; gap: 0;
  margin: 0; padding: 0;
  background: transparent;
  border: none;
  border-radius: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.nav-tab {
  flex: 1;
  position: relative;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 14px 10px 12px;       /* 44px+ tap height */
  min-height: 46px;
  font-family: 'Inter Tight', sans-serif;
  font-size: 11px; font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .42);
  background: transparent;
  border: none;
  border-radius: 0;
  white-space: nowrap;
  cursor: pointer;
  transition: color .15s ease;
  -webkit-tap-highlight-color: transparent;
}
.nav-tab + .nav-tab {
  /* Tiny vertical hairline between tabs — barely there, but it gives
     the row the ticker-divider feel without shouting. */
  box-shadow: inset 1px 0 0 var(--b-rule);
}
.nav-tab:hover,
.nav-tab:focus-visible {
  color: rgba(244, 241, 234, .75);
  outline: none;
}
@media (max-width: 480px) {
  .nav-tab { font-size: 10px; letter-spacing: .18em; padding: 14px 4px 12px; gap: 4px; }
}
@media (max-width: 360px) {
  .nav-tab { font-size: 9.5px; letter-spacing: .14em; }
}

/* Count chip — outlined hairline, mono numerics.  Drops the filled-pill
   look so it sits inside the editorial tab strip without competing. */
.nav-tab .tab-count {
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: 4px;
  min-width: 18px; height: 18px; padding: 0 5px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 9.5px; font-weight: 600; letter-spacing: 0;
  color: rgba(244, 241, 234, .55);
  background: transparent;
  border: 1px solid var(--b-rule-strong);
  border-radius: 2px;
  font-variant-numeric: tabular-nums;
}
.nav-tab .tab-count.is-warning {
  color: var(--b-warm);
  background: transparent;
  border-color: rgba(251, 191, 36, .35);
}
.nav-tab.active .tab-count.is-warning {
  color: var(--b-warm);
  background: transparent;
  border-color: rgba(251, 191, 36, .5);
}
@media (max-width: 380px) {
  .nav-tab .tab-count { display: none; }
}
/* Active tab — gold underline only, no fill.  The underline sits flush
   with the tabbar's bottom border so it reads as a continuation of the
   hairline rule rather than a separate decoration. */
.nav-tab.active {
  color: var(--b-ivory);
  font-weight: 800;
  background: transparent;
  box-shadow: inset 1px 0 0 var(--b-rule);   /* preserve the divider */
}
.nav-tab.active::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;            /* sit on the tabbar rule */
  height: 2px;
  background: var(--b-accent);
}
.nav-tab.active .tab-count {
  color: var(--b-accent);
  background: transparent;
  border: 1px solid var(--b-accent-edge);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-weight: 600;
}

/* ─── Badges / pills ──────────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 10px;
  font-size: 11px; font-weight: 700; letter-spacing: .5px;
  text-transform: uppercase;
  border-radius: 999px;
}
.badge-go      { background: var(--success-glow); color: var(--success); }
.badge-marginal{ background: var(--warning-glow); color: var(--warning); }
.badge-avoid   { background: var(--error-glow);   color: var(--error); }
.badge-info    { background: var(--accent-glow);  color: var(--accent); }
.badge-muted   { background: var(--bg-input);     color: var(--text-secondary); }

.pill { padding: 1px 8px; font-size: 11px; font-weight: 500; color: var(--text-secondary); background: var(--bg-input); border-radius: 999px; }

/* ─── Empty state ─────────────────────────────────────────────────────────── */
.empty-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 40px 20px; gap: 10px; text-align: center;
  color: var(--text-secondary);
}
.empty-state-icon {
  width: 64px; height: 64px;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-card); border: 1px solid var(--border-glass); border-radius: 50%;
  color: var(--accent); box-shadow: 0 0 30px var(--accent-glow);
  margin-bottom: 4px;
}
.empty-state h3 { font-size: 18px; color: var(--text-primary); }
.empty-state p { font-size: 14px; max-width: 280px; }

/* ─── Card list rows (targets / watchlist / sellers / searches) ───────────── */
.row-card {
  display: flex; flex-direction: column; gap: 8px;
}
.row-card-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
}
.row-card-title { font-size: 16px; font-weight: 600; line-height: 1.3; }
.row-card-sub { font-size: 13px; color: var(--text-secondary); }
.row-card-meta {
  display: flex; flex-wrap: wrap; gap: 8px 16px;
  font-size: 13px; color: var(--text-secondary);
}
.row-card-actions {
  display: flex; gap: 8px; flex-wrap: wrap;
}
.row-card-actions .btn { flex: 1 1 auto; }

.kvp { display: flex; align-items: baseline; gap: 6px; font-size: 13px; }
.kvp b { font-weight: 600; color: var(--text-primary); }
.kvp .label { color: var(--text-muted); }

/* ─── Margin block (target card) ──────────────────────────────────────────── */
.margin-block {
  margin-top: 12px; padding: 12px 14px;
  background: var(--bg-input); border-radius: var(--radius-md);
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
}
.margin-block .stat { display: flex; flex-direction: column; gap: 2px; }
.margin-block .stat .label { font-size: 11px; text-transform: uppercase; letter-spacing: .5px; color: var(--text-muted); }
.margin-block .stat .val { font-size: 16px; font-weight: 700; }

/* ─── Vetting checklist ───────────────────────────────────────────────────── */
.vet-list {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  padding: 12px; background: var(--bg-input); border-radius: var(--radius-md);
  margin-top: 8px;
}
@media (max-width: 480px) { .vet-list { grid-template-columns: 1fr; } }
.vet-item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px; border-radius: var(--radius-sm);
  font-size: 13px; color: var(--text-secondary);
  cursor: pointer;
}
.vet-item input[type="checkbox"] {
  width: 18px; height: 18px;
  accent-color: var(--accent);
}
.vet-item.checked { color: var(--success); }

/* ─── Search builder ──────────────────────────────────────────────────────── */
.chip-input { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px; background: var(--bg-input); border: 1px solid var(--border-glass); border-radius: var(--radius-md); min-height: 44px; }
.chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; background: var(--accent-glow); color: var(--accent); border-radius: 999px; font-size: 13px; font-weight: 500; }
.chip button { background: none; border: none; color: var(--accent); font-size: 14px; cursor: pointer; padding: 0; line-height: 1; }
.chip-input input { flex: 1; min-width: 80px; background: none; border: none; outline: none; color: var(--text-primary); font-size: 14px; }

.preview-block { margin-top: 12px; padding: 12px 14px; background: var(--bg-input); border-radius: var(--radius-md); overflow: hidden; }
.preview-block .label { font-size: 11px; text-transform: uppercase; letter-spacing: .5px; color: var(--text-muted); margin-bottom: 6px; display: flex; justify-content: space-between; align-items: center; }
.preview-block code { font-family: 'SF Mono', Menlo, Consolas, monospace; font-size: 12px; color: var(--text-primary); word-break: break-all; overflow-wrap: anywhere; line-height: 1.45; display: block; }
.preview-block.url code { font-size: 11px; color: var(--text-secondary); }
.preview-block.url code.truncate { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.preview-block .copy-btn { background: none; border: none; color: var(--accent); font-size: 11px; cursor: pointer; padding: 2px 6px; border-radius: 4px; -webkit-tap-highlight-color: transparent; }

/* ─── Look-up result (Targets → "Look up card" modal) ────────────────────── */
/* Stacked vertically.  Hides empty sources rather than rendering blank
   columns at squeezed mobile widths. */
.lookup-result { display: flex; flex-direction: column; gap: 12px; }

.lookup-head {
  padding: 4px 0 12px;
  border-bottom: 1px solid var(--border-glass);
}
.lookup-head__title { font-size: 17px; font-weight: 600; line-height: 1.2; }
.lookup-head__sub   { font-size: 12px; color: var(--text-secondary); margin-top: 3px; }

.lookup-section {
  background: var(--bg-input);
  border-radius: var(--radius-md);
  padding: 11px 14px;
}
.lookup-section__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-bottom: 8px;
  font-size: 10px; font-weight: 700; letter-spacing: 1.5px;
  text-transform: uppercase; color: var(--text-muted);
}
.lookup-section__meta {
  font-size: 11px; font-weight: 500; letter-spacing: .3px;
  text-transform: none; color: var(--text-secondary);
}
.lookup-section__body { display: flex; flex-direction: column; gap: 4px; }
.lookup-section__body .kvp { padding: 2px 0; font-size: 13px; }

.lookup-empty {
  display: flex; align-items: baseline; gap: 8px;
  padding: 6px 14px;
  font-size: 11px;
  color: var(--text-muted);
}
.lookup-empty b { font-weight: 700; letter-spacing: 1.4px; text-transform: uppercase; color: var(--text-muted); font-size: 10px; }

.lookup-item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0;
  font-size: 13px; text-decoration: none;
  border-top: 1px solid rgba(255,255,255,0.05);
  color: var(--text-primary);
  -webkit-tap-highlight-color: transparent;
}
.lookup-item:first-child { border-top: none; padding-top: 4px; }
.lookup-item:active { opacity: .7; }
.lookup-item__title {
  flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--accent); font-size: 12px;
}
.lookup-item__price {
  font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--text-primary); white-space: nowrap;
}
.lookup-item__ends {
  font-size: 11px; color: var(--text-muted); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ─── Discover row — captured eBay listing inside a search group ──────────
   6-zone layout: thumb · title · price+ends · [Track] [✕].  Track is the
   primary CTA (filled accent on tap); dismiss is a ghost icon button that
   warms red on hover.  Tabular numerics on price/time. */
.disco-row {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  padding: 9px 4px;
  border-top: 1px solid rgba(255,255,255,0.05);
  font-size: 13px;
}
.disco-row:first-child { border-top: none; padding-top: 4px; }

.disco-row__thumb {
  width: 36px; height: 48px;
  border-radius: 6px;
  background-color: rgba(255,255,255,0.03);
  background-size: cover; background-position: center;
  flex-shrink: 0;
}
.disco-row__thumb--empty {
  background-image: linear-gradient(135deg,
    rgba(255,255,255,.04) 0%, rgba(255,255,255,.01) 100%);
  border: 1px dashed rgba(255,255,255,.08);
}
.disco-row__thumb { position: relative; cursor: zoom-in; }
.disco-row__thumb--empty { cursor: default; }
.disco-row__thumb:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.disco-row__thumb-count {
  position: absolute;
  bottom: 2px; right: 2px;
  padding: 1px 5px;
  font-size: 9.5px; font-weight: 700; letter-spacing: .3px;
  color: #fff;
  background: rgba(0, 0, 0, .75);
  border-radius: 4px;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

/* ─── Lightbox: full-screen image carousel ───────────────────────────────
   Triggered by clicking a row thumb. Esc closes; ArrowLeft/Right cycle.
   Black backdrop covers the app; image displayed full-fit with caption +
   counter at bottom. */
.lightbox {
  position: fixed; inset: 0;
  z-index: 2000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, .92);
  animation: lightbox-fade .14s ease both;
}
@keyframes lightbox-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.lightbox__panel {
  position: relative;
  width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 40px 60px 80px;
}
.lightbox__img {
  max-width: 100%; max-height: 100%;
  object-fit: contain;
  border-radius: 6px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .65);
}
.lightbox__close,
.lightbox__nav {
  position: absolute;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, .08);
  border: 1px solid rgba(255, 255, 255, .15);
  color: #fff;
  cursor: pointer;
  border-radius: 50%;
  transition: background .15s ease, transform .15s ease;
}
.lightbox__close:hover, .lightbox__nav:hover { background: rgba(255, 255, 255, .15); }
.lightbox__close:active, .lightbox__nav:active { transform: scale(.94); }
.lightbox__close {
  top: 16px; right: 16px;
  width: 36px; height: 36px;
  font-size: 14px;
}
.lightbox__nav {
  top: 50%; transform: translateY(-50%);
  width: 48px; height: 48px;
  font-size: 28px; line-height: 1; font-weight: 600;
}
.lightbox__nav--prev { left: 12px; }
.lightbox__nav--next { right: 12px; }
.lightbox__nav:active { transform: translateY(-50%) scale(.94); }
.lightbox__footer {
  position: absolute;
  bottom: 16px; left: 50%; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  max-width: 80%;
  pointer-events: none;
}
.lightbox__counter {
  font-size: 11px; font-weight: 700; letter-spacing: 1.4px;
  text-transform: uppercase; color: rgba(255, 255, 255, .7);
  font-variant-numeric: tabular-nums;
}
.lightbox__loading {
  font-size: 11px; font-weight: 600; letter-spacing: .8px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .7);
  background: rgba(255, 255, 255, .08);
  padding: 4px 10px;
  border-radius: 999px;
  animation: lightbox-loading-pulse 1.4s ease-in-out infinite;
}
@keyframes lightbox-loading-pulse {
  0%, 100% { opacity: .55; }
  50%      { opacity: 1; }
}
.lightbox__caption {
  font-size: 12.5px; color: rgba(255, 255, 255, .85);
  text-align: center;
  text-overflow: ellipsis; overflow: hidden;
  white-space: nowrap; max-width: 100%;
}
@media (max-width: 480px) {
  .lightbox__panel { padding: 32px 8px 80px; }
  .lightbox__nav { width: 40px; height: 40px; font-size: 22px; }
  .lightbox__nav--prev { left: 6px; }
  .lightbox__nav--next { right: 6px; }
}

.disco-row__title {
  min-width: 0;
  font-size: 13px; font-weight: 500;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.disco-row__title:hover { text-decoration: underline; text-underline-offset: 3px; }

.disco-row__meta {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 2px;
  font-variant-numeric: tabular-nums;
}
.disco-row__price {
  font-size: 13px; font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.005em;
}
.disco-row__ends {
  font-size: 10.5px; font-weight: 500;
  color: var(--text-muted);
  letter-spacing: .2px;
}

.disco-row__actions {
  display: flex; align-items: center; gap: 6px;
  flex-shrink: 0;
}

.disco-action {
  display: inline-flex; align-items: center; justify-content: center;
  height: 30px;
  font-family: inherit; font-size: 12px; font-weight: 600;
  letter-spacing: .2px;
  background: transparent;
  border: 1px solid var(--border-glass);
  border-radius: 999px;
  color: var(--text-primary);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: var(--transition);
}
.disco-action--track {
  padding: 0 14px;
  color: var(--accent);
  border-color: rgba(59, 130, 246, .35);
  background: rgba(59, 130, 246, .08);
}
.disco-action--track:hover {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 14px var(--accent-glow);
}
.disco-action--track:active { transform: scale(.96); }

.disco-action--dismiss {
  width: 30px; padding: 0;
  font-size: 12px; line-height: 1;
  color: var(--text-muted);
  border-color: transparent;
  background: transparent;
}
.disco-action--dismiss:hover {
  color: var(--error);
  border-color: rgba(239, 68, 68, .25);
  background: rgba(239, 68, 68, .08);
}
.disco-action--dismiss:active { transform: scale(.92); }
.disco-action:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* On very tight widths (≤380px) the time-left can feel crowded; let the
   meta column collapse to price-only by hiding the time-left line. */
@media (max-width: 380px) {
  .disco-row { grid-template-columns: 32px minmax(0, 1fr) auto auto; gap: 8px; }
  .disco-row__thumb { width: 32px; height: 42px; }
  .disco-action--track { padding: 0 12px; }
}

/* ─── Triage rows — heuristic-ranked Discover view ────────────────────────
   Verdict-led layout: badge | thumb | title+reason | bid+ends | actions.
   The badge color tells you in one glance whether to look at the row at
   all; reason tells you *why* the scorer landed there (spread, ROI,
   reject pattern). Tabular numerics on bids, no decoration drift. */
.triage-card { padding: 4px 6px !important; }

.triage-row {
  display: grid;
  grid-template-columns: auto 36px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  padding: 10px 8px;
  border-top: 1px solid rgba(255,255,255,0.05);
}
.triage-row:first-child { border-top: none; }
.triage-row[data-verdict="reject"] { opacity: .55; }
.triage-row[data-verdict="pass"]   { opacity: .7; }

.triage-row__verdict {
  font-size: 9.5px; font-weight: 700; letter-spacing: .8px;
  padding: 4px 7px;
  text-transform: uppercase;
  white-space: nowrap;
}

.triage-row__main { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.triage-row__title {
  font-size: 13px; font-weight: 500;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.triage-row__title:hover { text-decoration: underline; text-underline-offset: 3px; }
.triage-row__reason {
  font-size: 11px; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.triage-row[data-verdict="chase"]    .triage-row__reason { color: var(--success); }
.triage-row[data-verdict="marginal"] .triage-row__reason { color: var(--warning); }

.triage-row__money {
  display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.triage-row__bid {
  font-size: 13px; font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.005em;
}
.triage-row__ends {
  font-size: 10.5px; color: var(--text-muted); letter-spacing: .2px;
}

/* Disclosure groups (unknown / filtered-out). */
.triage-details {
  margin-top: 10px;
  padding: 10px 12px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius-md);
}
.triage-details > summary {
  cursor: pointer;
  font-size: 11px; font-weight: 700; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--text-muted);
  list-style: none;
  -webkit-tap-highlight-color: transparent;
}
.triage-details > summary::-webkit-details-marker { display: none; }
.triage-details > summary::before {
  content: '▸'; display: inline-block;
  margin-right: 8px; transition: transform .15s ease;
  font-size: 10px; color: var(--text-muted);
}
.triage-details[open] > summary::before { transform: rotate(90deg); }
.triage-details > summary:hover { color: var(--text-secondary); }

.triage-empty {
  margin: 8px 0 16px;
  padding: 18px 16px;
  text-align: center;
  background: var(--bg-card);
  border: 1px dashed var(--border-glass);
  border-radius: var(--radius-md);
}
.triage-empty__hd {
  font-size: 11px; font-weight: 700; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--text-muted);
  margin-bottom: 6px;
}
.triage-empty__body {
  font-size: 13px; color: var(--text-secondary); line-height: 1.5;
  max-width: 36ch; margin: 0 auto;
}

@media (max-width: 480px) {
  .triage-row {
    grid-template-columns: auto 32px minmax(0, 1fr) auto;
    gap: 8px;
    padding: 9px 6px;
  }
  .triage-row__money { display: none; }
  .triage-row__reason { white-space: normal; }
  .triage-row__verdict { font-size: 9px; padding: 3px 6px; }
}

/* ─── Browse tab — Hot Cards from the local PriceCharting catalog ────────
   Reuses the .pc-row scanner primitive shipped on Targets, with a few
   Browse-specific surfaces for filters and the empty/onboarding state. */
.b-search {
  position: relative;
  display: flex; align-items: center;
  margin: 0 0 10px;
}
.b-search__icon {
  position: absolute; left: 14px; top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  pointer-events: none;
}
.b-search__input {
  flex: 1; min-width: 0;
  width: 100%;
  padding: 12px 40px 12px 42px;
  font-size: 14px; color: var(--text-primary);
  background: var(--bg-input);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius-md);
  outline: none;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.b-search__input::placeholder { color: var(--text-muted); }
.b-search__input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 14px var(--accent-glow);
}
.b-search__clear {
  position: absolute; right: 8px; top: 50%;
  transform: translateY(-50%);
  width: 28px; height: 28px;
  display: none;
  align-items: center; justify-content: center;
  font-size: 14px; line-height: 1;
  color: var(--text-muted);
  background: transparent; border: none;
  cursor: pointer; border-radius: 6px;
  transition: color .15s ease, background .15s ease;
}
.b-search__clear.is-shown { display: inline-flex; }
.b-search__clear:hover { color: var(--text-primary); background: var(--bg-card-hover); }

/* Sort pill row — sits between the search input and the filters
   disclosure. Six chips, gold underline + ivory text on the active one,
   muted otherwise. Horizontally scrolls on narrow viewports rather than
   wrapping, so a single sweep of the thumb covers all six. */
.b-sort {
  display: flex;
  gap: 6px;
  margin: 0 2px 10px;
  padding: 6px 0 8px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  border-bottom: 1px solid var(--b-rule);
  -webkit-overflow-scrolling: touch;
}
.b-sort::-webkit-scrollbar { display: none; }
.b-sort__pill {
  flex: 0 0 auto;
  appearance: none;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 5px 12px;
  color: var(--text-muted);
  font: 600 11.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .35px;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .12s ease, background .12s ease, border-color .12s ease, box-shadow .12s ease;
}
.b-sort__pill:hover {
  color: var(--text-primary);
  background: var(--bg-card-hover);
}
.b-sort__pill.is-active {
  color: var(--bg-base);
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 1px 0 rgba(0,0,0,.25);
}
.b-sort__pill:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent-glow);
}
/* When chrome collapses during search, hide the sort row too — search
   results don't need a sort toggle, the relevance ordering is implicit. */
body.is-search-active .b-sort { display: none; }

/* Genre filter — sits beneath the sort chips.  Quieter than sort
   (smaller, hairline-bordered) so the two rows read as a hierarchy:
   sort = primary, genre = secondary.  Each pill carries its own
   count so the user knows the size of the slice. */
.b-genre {
  display: flex;
  gap: 6px;
  margin: 0 2px 12px;
  padding: 4px 0 6px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.b-genre::-webkit-scrollbar { display: none; }
.b-genre__pill {
  flex: 0 0 auto;
  appearance: none;
  background: transparent;
  border: 1px solid var(--b-rule);
  border-radius: 999px;
  padding: 4px 10px;
  display: inline-flex; align-items: baseline; gap: 6px;
  color: rgba(244, 241, 234, .72);
  font: 600 11px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .25px;
  cursor: pointer;
  transition: color .12s ease, background .12s ease, border-color .12s ease;
}
.b-genre__pill:hover {
  color: var(--b-ivory);
  border-color: var(--b-rule-strong);
  background: rgba(255, 255, 255, .03);
}
.b-genre__pill.is-active {
  color: var(--b-accent);
  border-color: var(--b-accent-edge);
  background: var(--b-accent-soft);
}
.b-genre__count {
  font: 700 9.5px/1 'JetBrains Mono', ui-monospace, monospace;
  color: rgba(244, 241, 234, .55);
  font-variant-numeric: tabular-nums;
}
.b-genre__pill.is-active .b-genre__count { color: var(--b-accent); }
body.is-search-active .b-genre { display: none; }

/* PriceCharting remote-search fallback — appears below the local
   "Not in your local catalog" empty state.  Visually distinct from
   local rows so the user understands these are imports-on-demand. */
.b-remote {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--b-rule);
}
.b-remote__hed {
  display: flex; align-items: baseline; gap: 10px;
  margin-bottom: 12px;
}
.b-remote__tag {
  font: 800 10px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: 1.6px; text-transform: uppercase;
  background: var(--b-accent);
  color: #14110a;
  padding: 4px 8px 3px;
  border-radius: 3px;
}
.b-remote__lead {
  font: 700 12.5px/1.3 'Inter Tight', system-ui, sans-serif;
  color: var(--b-ivory);
  letter-spacing: -.005em;
}
.b-remote__list { display: flex; flex-direction: column; gap: 0; }
.b-remote__row {
  border-top: 1px dashed var(--b-rule-strong);
  border-radius: 0;
}
.b-remote__row:first-child { border-top: 1px solid var(--b-rule-strong); }
.b-remote__chip {
  font: 800 8.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--b-accent);
  border: 1px solid var(--b-accent-edge);
  padding: 2px 5px 1px;
  border-radius: 3px;
  background: var(--b-accent-soft);
  margin-right: 6px;
}
.b-remote__actions { display: flex; align-items: center; }
.b-remote__add {
  white-space: nowrap;
  padding: 8px 14px;
  font-size: 12px;
}

.b-results { transition: opacity .12s ease; }
.b-results.is-loading { opacity: .55; }

/* Row-level save feedback. The "saving" state pulses the accent rail to
   show the click landed; "saved" replaces row content with a centered
   confirmation banner before the tab switches to Targets. */
@keyframes b-row-saving-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--accent-glow); }
  50%      { box-shadow: 0 0 16px 2px var(--accent-glow); }
}
.b-row.is-saving {
  cursor: progress;
  animation: b-row-saving-pulse 1.1s ease-in-out infinite;
  border-color: var(--accent) !important;
}
.b-row.is-saved {
  position: relative;
  pointer-events: none;
}
.b-row.is-saved > *:not(.b-row__saved-overlay) { opacity: .15; transition: opacity .15s ease; }
.b-row__saved-overlay {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-size: 13px; font-weight: 700; letter-spacing: .3px;
  color: var(--success);
  background: rgba(34, 197, 94, .08);
  border: 1px solid rgba(34, 197, 94, .35);
  border-radius: var(--radius-md);
  animation: b-row-saved-in .18s ease both;
}
.b-row__saved-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  font-size: 13px; font-weight: 700;
  color: var(--success);
  background: var(--success-glow);
  border-radius: 50%;
}
@keyframes b-row-saved-in {
  from { opacity: 0; transform: scale(.97); }
  to   { opacity: 1; transform: scale(1); }
}

/* Filter disclosure — flush hairline strip, no glass.  Matches the legend
   above and the eyebrow below. */
.b-filters-disclosure.is-hidden { display: none !important; }
.b-filters-disclosure {
  margin: 0 2px 14px;
  padding: 0;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--b-rule);
  border-radius: 0;
}
.b-filters-disclosure > summary {
  cursor: pointer;
  list-style: none;
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  padding: 12px 0;
  font-size: 10.5px; font-weight: 800; letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .55);
}
.b-filters-disclosure > summary::-webkit-details-marker { display: none; }
.b-filters-disclosure > summary::before {
  content: '+'; display: inline-block;
  width: 16px; height: 16px;
  margin-right: 8px;
  font-size: 14px; font-weight: 400; line-height: 14px;
  text-align: center;
  color: var(--b-accent);
  border: 1px solid var(--b-rule-strong);
  border-radius: 999px;
  transition: transform .2s ease, border-color .2s ease, background .2s ease;
}
.b-filters-disclosure[open] > summary::before {
  content: '−';
  transform: rotate(180deg);
  border-color: var(--b-accent-edge);
  background: var(--b-accent-soft);
}
.b-filters-disclosure__hint {
  font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  font-weight: 500; letter-spacing: .04em;
  text-transform: none; font-size: 10.5px;
  color: rgba(244, 241, 234, .42);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.b-filters {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 16px 20px;
  margin: 0;
  padding: 14px 0 18px;
}
@media (max-width: 480px) { .b-filters { grid-template-columns: 1fr; gap: 12px; } }

.b-filter { display: flex; flex-direction: column; gap: 6px; }
.b-filter__head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 11.5px;
}
.b-filter__label {
  font-size: 9.5px; font-weight: 800;
  letter-spacing: .22em; text-transform: uppercase;
  color: rgba(244, 241, 234, .55);
}
.b-filter__val {
  font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 13px; font-weight: 500;
  color: var(--b-ivory);
  font-variant-numeric: tabular-nums;
}
.b-filter input[type="range"] { accent-color: var(--b-accent); }

.b-empty {
  padding: 24px 18px;
  text-align: center;
  background: var(--bg-card);
  border: 1px dashed var(--border-glass);
  border-radius: var(--radius-md);
}
.b-empty--bootstrap { text-align: left; padding: 20px; }
.b-empty__hd {
  font-size: 11px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--text-muted);
  margin-bottom: 8px;
}
.b-empty__body {
  font-size: 13.5px; color: var(--text-secondary); line-height: 1.55;
  max-width: 56ch; margin: 0 auto;
}
.b-empty--bootstrap .b-empty__body { margin: 0 0 14px 0; max-width: none; }
.b-empty__steps {
  margin: 0 0 0 22px;
  padding: 0;
  font-size: 13px; color: var(--text-primary);
  line-height: 1.7;
}
.b-empty__steps li { padding: 2px 0; }

/* ─── Discover status banner — human-readable refresh state ──────────────
   Replaces the leaky "APIFY · push off" admin string. Top line answers
   "is what I'm looking at fresh?", sub line answers "what's the cadence?".
   Action button is the dominant CTA. */
.discover-status {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px;
  padding: 12px 14px;
  margin-bottom: 14px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius-md);
}
.discover-status__lines { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.discover-status__primary {
  font-size: 13px; font-weight: 600;
  color: var(--text-primary);
  letter-spacing: -0.005em;
}
.discover-status__sub {
  font-size: 11px; color: var(--text-muted);
  letter-spacing: .2px;
}
.discover-status__btn { flex-shrink: 0; padding: 9px 16px; }

/* Quota line — hidden under 50% of daily eBay budget; muted/amber/red as
   usage climbs.  Leading indicator so users see the headroom shrinking
   before a 429 actually lands. */
.discover-status__quota {
  margin-top: 4px;
  font-size: 10.5px; font-weight: 500; letter-spacing: .2px;
  font-variant-numeric: tabular-nums;
}
.discover-status__quota--muted   { color: var(--text-muted); }
.discover-status__quota--warning { color: var(--warning); }
.discover-status__quota--danger  { color: var(--error); font-weight: 600; }

@media (max-width: 480px) {
  .discover-status { padding: 11px 12px; gap: 10px; }
  .discover-status__btn { padding: 8px 12px; font-size: 12.5px; }
}

/* ─── Inline Match flow on Triage rows ────────────────────────────────────
   "Match" action variant + the inline picker that drops below the row when
   tapped. Reuses the .pc-row primitive shipped on Targets so the picker
   visually matches what the user already knows. */
.disco-action--lookup {
  padding: 0 13px;
  color: var(--accent);
  border-color: rgba(59, 130, 246, .35);
  background: rgba(59, 130, 246, .12);
}
.disco-action--lookup:hover {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 14px var(--accent-glow);
}
.disco-action--lookup:active { transform: scale(.96); }

@keyframes triage-match-pulse {
  0%, 100% { box-shadow: 0 0 0 var(--accent-glow); }
  50%      { box-shadow: 0 0 22px var(--accent-glow); }
}
.triage-row.is-matching {
  position: relative;
}
.triage-row.is-matching::after {
  content: ''; position: absolute; inset: 0;
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
  animation: triage-match-pulse 1s ease-in-out infinite;
  pointer-events: none;
}

.triage-row__picker {
  margin: -2px 8px 10px 56px;
  padding: 10px 12px 8px;
  background: var(--bg-input);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius-md);
  display: flex; flex-direction: column; gap: 6px;
  animation: triage-picker-in .18s ease both;
}
@keyframes triage-picker-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.triage-row__picker-header {
  font-size: 10.5px; font-weight: 700; letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 0 2px 4px;
}
.triage-row__picker-error {
  font-size: 12px;
  color: var(--error);
  padding: 6px 4px 0;
}
@media (max-width: 480px) {
  .triage-row__picker { margin-left: 12px; margin-right: 4px; padding: 8px; }
}

/* Bulk auto-match bar inside the unknown disclosure. */
.triage-bulk-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  margin-top: 10px;
  padding: 10px 12px;
  background: var(--bg-input);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-glass);
}
.triage-bulk-bar__hint {
  font-size: 12px; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  flex: 1; min-width: 0;
}
.triage-bulk-bar .btn { white-space: nowrap; flex-shrink: 0; }

@media (max-width: 480px) {
  .triage-bulk-bar { flex-direction: column; align-items: stretch; gap: 8px; }
  .triage-bulk-bar__hint { text-align: center; }
}

/* Lightweight in-app toast.  Used when an action result needs to surface
   but isn't worth disrupting the page (e.g. bulk auto-match summary). */
.app-toast {
  position: fixed;
  left: 50%; bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%) translateY(20px);
  z-index: 1100;
  max-width: min(560px, calc(100vw - 32px));
  padding: 12px 18px;
  font-size: 13px; font-weight: 500;
  color: var(--text-primary);
  background: rgba(18, 18, 26, .96);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius-md);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .5);
  opacity: 0;
  transition: opacity .18s ease, transform .18s ease;
}
.app-toast.is-shown {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.app-toast--error {
  border-color: rgba(239, 68, 68, .35);
  color: var(--error);
}

/* ─── PriceCharting result picker — trader-scanner row ─────────────────────
   Used in the "Look up card" modal. Each row is a tappable card-comp result;
   left zone = set/parallel/card#, right zone = PSA10 headline + raw→10 spread.
   Stacked tight; tabular numerics; a single accent rail on the left edge that
   appears on hover/focus to mark the active row without a heavy fill. */
.pc-pick {
  display: flex; flex-direction: column; gap: 2px;
  margin-top: 4px;
}
/* Legacy intro — kept for any other surface that uses it. The picker now
   uses `.pc-pick__header` instead, which actually answers the user's
   "did it find my player?" question. */
.pc-pick__intro {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; padding: 0 4px 6px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--text-muted);
}

/* Search-result confirmation header. Tells the user up front: "this many
   matches, for this player" — so they never wonder whether the algorithm
   understood them. The hint underneath is the call to action. */
.pc-pick__header {
  padding: 4px 4px 12px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--border-glass);
}
.pc-pick__header-line {
  display: flex; align-items: baseline; gap: 10px;
  flex-wrap: wrap;
  font-size: 14px;
}
.pc-pick__count-badge {
  display: inline-flex; align-items: center;
  padding: 3px 9px;
  font-size: 11px; font-weight: 700; letter-spacing: .6px;
  color: var(--accent);
  background: rgba(59, 130, 246, .12);
  border: 1px solid rgba(59, 130, 246, .25);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}
.pc-pick__for {
  display: inline-flex; align-items: baseline; gap: 6px;
  color: var(--text-primary);
}
.pc-pick__for-prefix {
  font-size: 12px; color: var(--text-muted);
  text-transform: lowercase;
}
.pc-pick__for-player {
  font-size: 14.5px; font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.005em;
}
.pc-pick__for--multi {
  font-size: 12px; color: var(--text-muted);
  font-style: italic;
}
.pc-pick__hint {
  margin-top: 6px;
  font-size: 11px; font-weight: 600; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--text-muted);
}

/* Unmatched-token banner. Quiet amber tone — disclosure, not error.
   The diagnostic that tells you "you typed '1st auto' but PriceCharting
   doesn't have a row matching that"; lets you reformulate or accept. */
.pc-pick__unmatched {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 0 0 12px;
  padding: 10px 12px;
  background: rgba(245, 158, 11, .07);
  border: 1px solid rgba(245, 158, 11, .25);
  border-left: 3px solid var(--warning);
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  color: var(--text-secondary);
  line-height: 1.45;
}
.pc-pick__unmatched-label {
  font-size: 9.5px; font-weight: 700; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--warning);
  flex-shrink: 0;
  padding-top: 2px;
}
.pc-pick__unmatched-token {
  display: inline-block;
  padding: 1px 6px;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 11px; font-weight: 600;
  color: var(--warning);
  background: rgba(245, 158, 11, .12);
  border-radius: 4px;
}
.pc-pick__unmatched-sep { color: var(--text-muted); }

/* Product-family section header. Used when results span multiple kinds
   of cards (Prospects vs. Autograph vs. Auto Relic) — a thin labeled
   divider tells the user the list isn't homogeneous. */
.pc-family {
  display: flex; align-items: baseline; gap: 10px;
  padding: 16px 4px 6px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--text-muted);
}
.pc-family:first-of-type { padding-top: 6px; }
.pc-family::after {
  content: ''; flex: 1 1 auto; height: 1px;
  background: var(--border-glass);
  margin-left: 4px;
}
.pc-family__name { color: var(--text-secondary); }
.pc-family__count {
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  letter-spacing: .4px;
}

/* Legacy player group selector — kept for compatibility but unused now
   that the picker groups by product family instead. */
.pc-group {
  display: flex; align-items: baseline; gap: 10px;
  padding: 14px 4px 6px;
  font-size: 12px; font-weight: 600;
  color: var(--text-primary);
}
.pc-group::before {
  content: ''; flex: 0 0 8px; height: 1px;
  background: var(--border-glass);
}
.pc-group::after {
  content: ''; flex: 1 1 auto; height: 1px;
  background: var(--border-glass);
}
.pc-group:first-child { padding-top: 4px; }

.pc-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 14px;
  padding: 11px 12px 11px 14px;
  width: 100%;
  text-align: left;
  background: var(--bg-input);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: var(--text-primary);
  cursor: pointer;
  position: relative;
  transition: var(--transition);
  -webkit-tap-highlight-color: transparent;
}
.pc-row + .pc-row { margin-top: 6px; }
.pc-row::before {
  content: ''; position: absolute; left: 0; top: 10px; bottom: 10px;
  width: 2px; border-radius: 2px; background: transparent;
  transition: background .15s ease, transform .15s ease;
  transform: scaleY(0.6); transform-origin: center;
}
.pc-row:hover, .pc-row:focus-visible {
  background: var(--bg-card-hover);
  border-color: var(--border-glass);
  outline: none;
}
.pc-row:hover::before, .pc-row:focus-visible::before {
  background: var(--accent); transform: scaleY(1);
}
.pc-row:active { transform: scale(0.99); }

/* Left zone: set name (primary), parallel chip + card # underneath. */
.pc-row__left { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.pc-row__set {
  font-size: 13.5px; font-weight: 600; line-height: 1.25;
  color: var(--text-primary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pc-row__set .pc-row__year {
  display: inline-block; margin-right: 6px;
  color: var(--text-muted); font-weight: 500;
  font-variant-numeric: tabular-nums; letter-spacing: .2px;
}
.pc-row__sub {
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.pc-row__num { letter-spacing: .3px; }
.pc-row__parallel {
  display: inline-flex; align-items: center;
  padding: 2px 7px;
  font-size: 10px; font-weight: 600; letter-spacing: .4px;
  color: var(--accent);
  background: var(--accent-glow);
  border-radius: 999px;
}
.pc-row__player {
  /* Only shown when multiple players in result set — already sectioned above,
     so this class is hidden by default. JS adds a player line conditionally. */
  font-size: 11px; color: var(--text-muted);
}

/* Right zone: headline price + spread + confidence. */
.pc-row__right {
  display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
  font-variant-numeric: tabular-nums;
}
.pc-row__price {
  display: flex; align-items: baseline; gap: 4px;
  font-size: 16px; font-weight: 700; line-height: 1;
  color: var(--text-primary);
  letter-spacing: -0.01em;
}
.pc-row__price .pc-row__price-tag {
  font-size: 9.5px; font-weight: 700; letter-spacing: 1px;
  color: var(--text-muted); text-transform: uppercase;
  margin-right: 2px;
}
.pc-row__price--missing { color: var(--text-muted); font-weight: 600; }

.pc-row__spread {
  display: flex; align-items: center; gap: 5px;
  font-size: 10.5px; font-weight: 500;
  color: var(--text-muted);
}
.pc-row__spread .pc-row__arrow {
  display: inline-block; opacity: .55; font-size: 9px; letter-spacing: -1px;
}
.pc-row__mult {
  display: inline-flex; align-items: center;
  margin-left: 2px;
  padding: 1px 6px;
  font-size: 10px; font-weight: 700;
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
  letter-spacing: .2px;
}
.pc-row__mult--hot {
  color: var(--success);
  background: var(--success-glow);
}
.pc-row__mult--warm {
  color: var(--warning);
  background: var(--warning-glow);
}
.pc-row__mult--mild {
  color: var(--text-muted);
  background: rgba(255,255,255,.06);
}

/* Confidence indicator for sales-volume signal — lives inline in the meta
   line of the left column. Dot color = tier; trailing number = lifetime
   sales count from PriceCharting. The whole element gets a tooltip
   spelling out the meaning so newcomers don't have to decode the dot. */
.pc-row__conf {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 1px 7px 1px 6px;
  font-size: 10px; font-weight: 600; letter-spacing: .3px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  background: rgba(255, 255, 255, .04);
  border-radius: 999px;
  cursor: help;
}
.pc-row__conf-dot {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--text-muted); opacity: .6;
  flex-shrink: 0;
}
.pc-row__conf-num { line-height: 1; }
.pc-row__conf--high .pc-row__conf-dot { background: var(--success); opacity: 1; }
.pc-row__conf--mid  .pc-row__conf-dot { background: var(--warning); opacity: 1; }
.pc-row__conf--low  .pc-row__conf-dot { background: var(--text-muted); opacity: .6; }

@media (max-width: 380px) {
  .pc-row { padding-right: 14px; }
}

/* Labeled legs for the raw → PSA 10 spread.  The tag is a small uppercase
   eyebrow above the number so a first-time user reads "Raw $11.50" instead
   of an unlabeled price. */
.pc-row__spread-leg {
  display: inline-flex; align-items: baseline; gap: 4px;
}
.pc-row__spread-tag {
  font-size: 8.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .6px;
  color: var(--text-muted); opacity: .75;
}

/* "low confidence" pill — sample size below 30.  Quiet amber so it warns
   without dominating the row. */
.pc-row__lowconf {
  display: inline-flex; align-items: center;
  padding: 1px 7px;
  font-size: 9.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .4px;
  color: var(--warning);
  background: var(--warning-glow);
  border-radius: 999px;
  cursor: help;
}

/* ─── Browse masthead ──────────────────────────────────────────────────
   Editorial header above the search bar.  Two large numerical headlines
   with their categorical labels underneath, separated by a vertical rule.
   Dateline strip at the bottom reads like a price-guide edition stamp. */
.b-masthead {
  margin: 4px 2px 14px;
  padding: 0;
}
.b-masthead__row {
  display: grid;
  grid-template-columns: 1fr 1px 1fr;
  align-items: center;
  gap: 16px;
  padding: 8px 0 14px;
}
.b-masthead__metric { min-width: 0; }
.b-masthead__num {
  font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 30px;
  font-weight: 500;
  letter-spacing: -.02em;
  line-height: 1;
  color: var(--b-ivory);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'zero' on;
}
/* Both masthead numbers stay ivory now — the accent is reserved for action,
   not informational metrics.  The "hot candidates" emphasis comes from the
   label underneath, not from coloring the digits. */
.b-masthead__num--accent { color: var(--b-ivory); }
.b-masthead__lbl {
  margin-top: 6px;
  font-size: 9.5px; font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .42);
}
.b-masthead__rule {
  align-self: stretch;
  background: var(--b-rule-strong);
  width: 1px;
}
.b-masthead__dateline {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 0;
  border-top: 1px solid var(--b-rule);
  border-bottom: 1px solid var(--b-rule);
  font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 10px;
  letter-spacing: .08em;
  color: rgba(244, 241, 234, .42);
}
.b-masthead__edition {
  padding: 2px 6px;
  font-weight: 700;
  letter-spacing: .26em;
  color: rgba(244, 241, 234, .72);
  background: transparent;
  border: 1px solid var(--b-rule-strong);
  border-radius: 2px;
}
.b-masthead__when { font-variant-numeric: tabular-nums; }
.b-masthead--empty { padding: 18px 0 8px; }
.b-masthead--empty .b-masthead__title {
  font-size: 22px; font-weight: 700; letter-spacing: -.015em;
  color: var(--b-ivory);
}
.b-masthead--empty .b-masthead__sub {
  margin-top: 6px;
  font-size: 13px; color: rgba(244, 241, 234, .55);
}

/* ─── Footnote-style legend strip ──────────────────────────────────────
   Replaces the prior blue glass card.  Reads like a price-guide footnote
   key: hairlines top and bottom, definition list inline, tiny × dismiss
   anchored right.  Dismissal persists in localStorage. */
.b-legend {
  display: flex; align-items: flex-start;
  gap: 14px;
  margin: 4px 2px 14px;
  padding: 10px 0;
  border-top: 1px solid var(--b-rule);
  border-bottom: 1px solid var(--b-rule);
  background: transparent;
  font-size: 12px; line-height: 1.5;
  color: rgba(244, 241, 234, .55);
}
.b-legend__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.b-legend__line {
  display: flex; gap: 10px;
  align-items: baseline;
}
.b-legend__term {
  flex-shrink: 0;
  min-width: 86px;
  font-size: 9.5px; font-weight: 800;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .85);
}
.b-legend__def { color: rgba(244, 241, 234, .65); }
.b-legend__dismiss {
  flex-shrink: 0;
  width: 26px; height: 26px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 16px; line-height: 1; font-weight: 400;
  color: rgba(244, 241, 234, .55);
  background: transparent;
  border: 1px solid var(--b-rule-strong);
  border-radius: 999px;
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
}
.b-legend__dismiss:hover,
.b-legend__dismiss:active {
  color: var(--b-accent);
  border-color: var(--b-accent-edge);
}
@media (max-width: 480px) {
  .b-legend__line { flex-direction: column; gap: 2px; }
  .b-legend__term { min-width: 0; }
}

/* ─── "About this card" detail sheet ──────────────────────────────────
   Trading Floor edition.  Eyebrow / heroic title / hairline numeric
   strip / quiet warning rule / outlined-vs-filled CTA pair.  Same
   vocabulary as the Browse rows so the modal reads as a magnified
   version of the row you tapped. */
.b-sheet { display: flex; flex-direction: column; gap: 18px; }

/* Hero image at the top of the About-this-card sheet. Centered,
   fixed-ratio, hairline border, dropped shadow.  Falls back to the
   SVG card-back placeholder when the resolver hasn't landed an
   image yet. */
.b-sheet__hero {
  display: flex; align-items: center; justify-content: center;
  align-self: center;
  width: 144px; aspect-ratio: 3 / 4;
  border: 1px solid var(--b-rule, rgba(255,255,255,.12));
  border-radius: 6px;
  overflow: hidden;
  background: rgba(0,0,0,.35);
  box-shadow: 0 6px 20px rgba(0,0,0,.45);
}
.b-sheet__hero--placeholder { background: rgba(255,255,255,.025); }
.b-sheet__hero-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.b-sheet__hero-ph { display: block; width: 100%; height: 100%; }
.b-sheet__hero-ph svg { width: 100%; height: 100%; display: block; }
@media (max-width: 480px) {
  .b-sheet__hero { width: 124px; }
}

/* Identity stack — small-caps eyebrow above a heroic editorial title. */
.b-sheet__id {
  padding-bottom: 14px;
  border-bottom: 1px solid var(--b-rule);
}
.b-sheet__id .b-sheet__set {
  font-size: 9.5px; font-weight: 800;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .42);
  margin-bottom: 8px;
}
.b-sheet__id .b-sheet__name {
  font-family: 'Inter Tight', -apple-system, sans-serif;
  font-size: 22px; font-weight: 700;
  letter-spacing: -.014em;
  color: var(--b-ivory);
  line-height: 1.2;
}

/* Math block — no card chrome, hairline rules, mono numerics. */
.b-sheet__math {
  padding: 0;
  background: transparent;
  border-radius: 0;
}
.b-sheet__math-line {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 14px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  font-size: 17px; font-weight: 500;
  letter-spacing: -.005em;
  color: var(--b-ivory);
}
.b-sheet__leg {
  display: inline-flex; flex-direction: column; gap: 4px;
  align-items: flex-start;
}
.b-sheet__leg-tag {
  font-family: 'Inter Tight', sans-serif;
  font-size: 9px; font-weight: 800;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .42);
}
.b-sheet__arrow {
  font-family: 'Inter Tight', sans-serif;
  color: rgba(244, 241, 234, .35);
  font-size: 14px;
  align-self: flex-end;
  padding-bottom: 2px;
}
/* Multiplier pill — solid gold, dark ink.  Matches .b-row__mult--hot. */
.b-sheet__mult {
  margin-left: auto;
  padding: 8px 12px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 13px; font-weight: 700;
  letter-spacing: -.005em;
  color: var(--accent-ink);
  background: var(--b-accent);
  border-radius: 4px;
  white-space: nowrap;
}
.b-sheet__sales {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--b-rule-strong);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: .02em;
  color: rgba(244, 241, 234, .5);
  font-variant-numeric: tabular-nums;
}

/* Low-confidence warning — quiet hairline rule, no fill, warm accent. */
.b-sheet__warn {
  position: relative;
  padding: 12px 0 12px 14px;
  border: none;
  border-top: 1px solid var(--b-rule);
  border-bottom: 1px solid var(--b-rule);
  border-radius: 0;
  background: transparent;
  font-size: 12.5px; line-height: 1.5;
  color: var(--b-warm);
}
.b-sheet__warn::before {
  content: '';
  position: absolute; left: 0; top: 12px; bottom: 12px;
  width: 2px;
  background: var(--b-warm);
}

/* ─── PSA Pop & Gem Rate research tile ─────────────────────────────────
   Lives in the Browse-tab card detail sheet.  Three states: empty
   (paste affordance), loading (waiting on the API), resolved (full
   metric grid + EV ratio + expandable grade histogram).  Editorial
   gold-leaf vocabulary — same chrome as the rest of Browse.        */
.b-poprep {
  border-top: 1px solid var(--b-rule);
  border-bottom: 1px solid var(--b-rule);
  padding: 14px 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.b-poprep__head {
  display: flex; align-items: center; gap: 8px;
}
.b-poprep__head-tag {
  font: 800 10px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .26em;
  color: var(--b-accent);
  text-transform: uppercase;
}

/* Empty state — paste CTA */
.b-poprep__empty {
  display: flex; flex-direction: column; gap: 10px;
}
.b-poprep__empty-msg {
  font-size: 13px;
  color: rgba(244,241,234,.62);
}
.b-poprep__empty-hint {
  font-size: 12px; line-height: 1.5;
  color: rgba(244,241,234,.55);
  margin-top: -4px;
}

/* Inline graded-eBay-listings list — appears in the empty state when
   auto-resolve found graded copies but couldn't extract the cert.  The
   user clicks one, eyeballs PSA's panel on the eBay page, pastes the
   cert back here.  Tight ledger-style rows. */
.b-poprep__graded {
  display: flex; flex-direction: column; gap: 4px;
  margin-top: 4px;
}
.b-poprep__graded-head {
  font: 800 9.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .26em;
  color: rgba(244,241,234,.55);
  text-transform: uppercase;
  margin-bottom: 4px;
}
.b-poprep__graded-row {
  display: grid;
  grid-template-columns: 1fr auto 16px;
  gap: 8px;
  align-items: center;
  padding: 8px 10px;
  border: 1px solid var(--b-rule);
  border-radius: 3px;
  background: rgba(255,255,255,.02);
  font-size: 12px;
  color: var(--b-ivory);
  text-decoration: none;
  transition: background-color .15s ease, border-color .15s ease;
}
.b-poprep__graded-row:hover {
  background: rgba(200,168,90,.06);
  border-color: var(--b-accent-edge);
}
.b-poprep__graded-title {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: rgba(244,241,234,.85);
}
.b-poprep__graded-price {
  font: 700 12px/1 'JetBrains Mono', ui-monospace, monospace;
  color: var(--b-accent);
}
.b-poprep__graded-chev {
  color: var(--b-accent);
  font-size: 13px;
}
.b-poprep__graded-tip {
  font-size: 11.5px;
  color: rgba(244,241,234,.62);
  line-height: 1.4;
  margin-top: 4px;
  padding: 4px 0;
}
.b-poprep__empty-actions {
  display: flex; gap: 8px; flex-wrap: wrap;
}

.b-poprep__btn {
  font: 700 12px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .04em;
  padding: 8px 14px;
  border-radius: 3px;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex; align-items: center;
}
.b-poprep__btn--primary {
  background: var(--b-accent);
  color: #14110a;
  border: 1px solid var(--b-accent);
}
.b-poprep__btn--primary:hover {
  background: #d8b86a;
}
.b-poprep__btn--ghost {
  background: transparent;
  color: var(--b-accent);
  border: 1px solid var(--b-accent-edge);
}
.b-poprep__btn--ghost:hover {
  background: rgba(200,168,90,.08);
}

/* Paste form */
.b-poprep__paste {
  display: flex; flex-direction: column; gap: 8px;
}
.b-poprep__paste-hint {
  font-size: 12px;
  color: rgba(244,241,234,.6);
}
.b-poprep__input {
  font: 600 14px/1 'JetBrains Mono', ui-monospace, monospace;
  padding: 10px 12px;
  background: rgba(255,255,255,.04);
  border: 1px solid var(--b-rule);
  border-radius: 3px;
  color: var(--b-ivory);
  outline: none;
}
.b-poprep__input:focus {
  border-color: var(--b-accent);
}
.b-poprep__input.is-invalid {
  border-color: #f6a464;
  animation: b-poprep-shake .3s ease;
}
@keyframes b-poprep-shake {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-4px); }
  75%      { transform: translateX(4px); }
}
.b-poprep__paste-actions {
  display: flex; gap: 8px;
}

/* Loading / warn */
.b-poprep__loading,
.b-poprep__warn {
  font-size: 13px;
  color: rgba(244,241,234,.62);
  padding: 6px 0;
}
.b-poprep__warn { color: var(--b-warm); }

/* Resolved — three-metric grid */
.b-poprep__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border: 1px solid var(--b-rule);
  border-radius: 3px;
}
.b-poprep__metric {
  padding: 12px;
  text-align: center;
  border-right: 1px solid var(--b-rule);
}
.b-poprep__metric:last-child { border-right: none; }
.b-poprep__metric-lbl {
  font: 700 9.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .22em;
  color: rgba(244,241,234,.55);
  margin-bottom: 6px;
}
.b-poprep__metric-val {
  font: 700 20px/1 'JetBrains Mono', ui-monospace, monospace;
  color: var(--b-ivory);
}

/* EV ratio — the headline */
.b-poprep__ev {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 14px;
  border-radius: 3px;
}
.b-poprep__ev--hot {
  background: rgba(34,197,94,.08);
  border: 1px solid rgba(34,197,94,.32);
}
.b-poprep__ev--warm {
  background: rgba(246,164,100,.06);
  border: 1px solid rgba(246,164,100,.28);
}
.b-poprep__ev--mute {
  background: rgba(255,255,255,.02);
  border: 1px solid var(--b-rule);
}
.b-poprep__ev-lbl {
  font: 700 10px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: rgba(244,241,234,.62);
}
.b-poprep__ev-val {
  font: 800 22px/1 'JetBrains Mono', ui-monospace, monospace;
}
.b-poprep__ev--hot  .b-poprep__ev-val { color: #4ade80; }
.b-poprep__ev--warm .b-poprep__ev-val { color: #f6a464; }
.b-poprep__ev--mute .b-poprep__ev-val { color: var(--b-ivory); }
.b-poprep__ev-formula {
  font: 500 11px/1 'JetBrains Mono', ui-monospace, monospace;
  color: rgba(244,241,234,.5);
  margin-left: auto;
}

/* Grade-distribution histogram (collapsed by default) */
.b-poprep__hist {
  font-size: 12px;
}
.b-poprep__hist > summary {
  cursor: pointer;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--b-accent);
  list-style: none;
  padding: 4px 0;
}
.b-poprep__hist > summary::-webkit-details-marker { display: none; }
.b-poprep__hist > summary::before {
  content: '▸ ';
  display: inline-block;
  transition: transform .15s ease;
}
.b-poprep__hist[open] > summary::before {
  transform: rotate(90deg);
}
.b-poprep__hist-rows {
  display: grid;
  gap: 4px;
  padding: 8px 0 4px;
}
.b-poprep__hist-row {
  display: grid;
  grid-template-columns: 64px 1fr 64px;
  align-items: center;
  gap: 8px;
  font-size: 11px;
}
.b-poprep__hist-lbl {
  color: rgba(244,241,234,.65);
  font-weight: 600;
  letter-spacing: .04em;
}
.b-poprep__hist-bar {
  background: rgba(255,255,255,.05);
  height: 8px;
  border-radius: 1px;
  overflow: hidden;
}
.b-poprep__hist-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--b-accent), rgba(200,168,90,.5));
}
.b-poprep__hist-count {
  text-align: right;
  color: var(--b-ivory);
}

/* PSA baseline calibration line in the AI pre-grade modal.
   Quiet gold tag + neutral body text — adds context to the verdict
   without competing with the predicted-grade hero. */
.w-pre__poprate {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  padding: 10px 12px;
  margin: 8px 0 0;
  border-left: 2px solid var(--b-accent);
  background: rgba(200,168,90,.04);
  font-size: 13px;
  line-height: 1.5;
  color: rgba(244,241,234,.78);
  border-radius: 0 3px 3px 0;
}
.w-pre__poprate-tag {
  font: 800 9.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .26em;
  color: var(--b-accent);
  text-transform: uppercase;
  margin-right: 4px;
}
.w-pre__poprate strong {
  color: var(--b-ivory);
  font-weight: 700;
}

/* Dev-only PSA quota pill (?dev=1).  Bottom-left so it doesn't collide
   with the existing app-version pill in the bottom-right. */
.psa-quota-pill {
  position: fixed;
  bottom: 8px; left: 12px;
  font: 700 11px/1 'JetBrains Mono', ui-monospace, monospace;
  letter-spacing: .04em;
  color: var(--b-accent);
  background: rgba(10,10,15,.85);
  border: 1px solid var(--b-accent-edge);
  padding: 5px 9px;
  border-radius: 3px;
  z-index: 9999;
  pointer-events: none;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.psa-quota-pill--warn  { color: #f6a464; border-color: rgba(246,164,100,.5); }
.psa-quota-pill--block { color: #ef4444; border-color: rgba(239,68,68,.5); }

.b-sheet__hint {
  font-size: 12px; line-height: 1.55;
  color: rgba(244, 241, 234, .55);
}

/* CTAs — outlined "Save" + filled gold "Find listings".  Order on mobile
   puts the primary action on top so the thumb-to-button distance is
   shorter; on >=480 they sit side-by-side, primary on the right. */
.b-sheet__actions {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  margin-top: 6px;
}
.b-sheet__cta {
  width: 100%; justify-content: center;
  border-radius: 4px;
  font-family: 'Inter Tight', sans-serif;
  font-size: 12px; font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: 14px 16px;
  min-height: 48px;
}
.b-sheet .btn-secondary.b-sheet__cta {
  background: transparent;
  border: 1px solid var(--b-rule-strong);
  color: var(--b-ivory);
}
.b-sheet .btn-secondary.b-sheet__cta:hover,
.b-sheet .btn-secondary.b-sheet__cta:active {
  border-color: var(--b-accent-edge);
  color: var(--b-accent);
  background: var(--b-accent-soft);
}
.b-sheet .btn-primary-cta.b-sheet__cta {
  background: var(--b-accent);
  color: var(--accent-ink);
  border: none;
  box-shadow: none;
}
.b-sheet .btn-primary-cta.b-sheet__cta:hover,
.b-sheet .btn-primary-cta.b-sheet__cta:active {
  background: var(--accent-hover);
}
.b-sheet .btn-primary-cta.b-sheet__cta:disabled,
.b-sheet .btn-secondary.b-sheet__cta:disabled {
  opacity: .55;
}
@media (max-width: 480px) {
  .b-sheet__actions { grid-template-columns: 1fr; }
  .b-sheet__cta:first-child { order: 2; }
}

/* ─── Watchlist tab — card-centric collapsed view ──────────────────────── */
.w-newpill {
  margin-left: auto; margin-right: 6px;
  padding: 1px 8px;
  font-size: 9.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .6px;
  color: var(--warning);
  background: var(--warning-glow);
  border-radius: 999px;
}

.w-listings {
  margin-top: 12px; padding-top: 10px;
  border-top: 1px solid rgba(255,255,255,.06);
}
.w-listings__head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 6px;
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .5px;
  color: var(--text-muted);
}
.w-listings__meta { font-weight: 500; text-transform: none; letter-spacing: 0; opacity: .7; }
.w-listings__list { display: flex; flex-direction: column; gap: 8px; }
.w-listings__empty { padding: 8px 0; font-size: 12px; color: var(--text-muted); }

.w-listing {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.06);
  border-radius: 8px;
}
.w-listing--new {
  background: rgba(60, 130, 246, .07);
  border-color: rgba(60, 130, 246, .25);
}
.w-listing__thumb {
  flex-shrink: 0;
  width: 40px; height: 40px;
  background-size: cover; background-position: center;
  background-color: rgba(255,255,255,.04);
  border-radius: 6px;
}
.w-listing__thumb--empty {
  background-image: linear-gradient(135deg, rgba(255,255,255,.05) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.05) 50%, rgba(255,255,255,.05) 75%, transparent 75%);
  background-size: 8px 8px;
}
.w-listing__body { flex: 1; min-width: 0; }
.w-listing__title {
  font-size: 12.5px; font-weight: 500;
  color: var(--text-default);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.w-listing__meta {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-top: 2px;
  font-size: 11px; color: var(--text-muted);
}
.w-listing__price { font-weight: 700; color: var(--text-strong); }
.w-listing__ends { color: var(--warning); }
.w-listing__new {
  padding: 0 6px;
  font-size: 9px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .5px;
  color: var(--success); background: var(--success-glow);
  border-radius: 999px;
}
.w-listing__actions {
  flex-shrink: 0;
  display: flex; gap: 4px;
}
@media (max-width: 480px) {
  .w-listing__title { font-size: 12px; white-space: normal; }
}

/* Focused listing — already moved to watchlist.  Left-edge stripe and
   slightly elevated background so users see "this is what I'm acting
   on" at a glance. */
.w-listing--focused {
  position: relative;
  padding-left: 14px;
  background: rgba(60, 130, 246, .08);
  border-color: rgba(60, 130, 246, .35);
}
.w-listing--focused::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--accent, #3c82f6);
  border-radius: 2px 0 0 2px;
}
.w-listing__status {
  font-weight: 700;
  text-transform: uppercase; letter-spacing: .5px;
  color: var(--text-strong);
  font-size: 10px;
}
.w-listing__maxbid { color: var(--accent, #3c82f6); font-weight: 600; }
.w-listing__vet { color: var(--text-muted); font-style: italic; }

.w-edit__title {
  padding: 10px 12px;
  background: rgba(255,255,255,.04);
  border-radius: 8px;
  font-size: 13px; color: var(--text-default);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Listing wrapper — holds the row + the inline-expanded detail panel */
.w-listing-wrap { display: flex; flex-direction: column; gap: 6px; }

/* End-of-feed capstone — newspaper-style "—30—" sign-off below the
   last watchlist row.  Provides visual finality so the iOS PWA's
   bottom safe-area inset doesn't read as a stray dead band.  The
   capstone itself sits just above the inset; the inset shows the
   page bg, which the capstone visually owns as an intentional margin. */
.w-endmark {
  display: flex; align-items: center; gap: 12px;
  padding: 32px 0 8px;
  margin-top: 8px;
  color: rgba(244, 241, 234, .35);
}
.w-endmark__rule {
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--b-rule-strong), transparent);
}
.w-endmark__text {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  font: 800 9.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  white-space: nowrap;
}
.w-endmark__sub {
  font: 500 9px/1 'JetBrains Mono', ui-monospace, monospace;
  letter-spacing: .8px;
  text-transform: none;
  color: rgba(244, 241, 234, .42);
}

/* ─── Watchlist stat pills (top of page) ──────────────────────────────
   Three pills replacing the prior masthead+eyebrow stack.  Big number
   + small label, high contrast.  Accent variant (gold-filled) for the
   NEW count when there is one.  Reads like a Bloomberg ticker
   summary — at-a-glance state, no decorative copy. */
.w-stats {
  display: flex; gap: 10px; flex-wrap: wrap;
  margin: 4px 0 14px;
}
.w-stats__pill {
  display: inline-flex; align-items: baseline; gap: 8px;
  padding: 10px 16px;
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--b-rule-strong);
  border-radius: 6px;
}
.w-stats__pill--accent {
  background: var(--b-accent);
  border-color: var(--b-accent);
  color: #14110a;
}
.w-stats__num {
  font: 800 22px/1 'JetBrains Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.5px;
  color: var(--b-ivory);
}
.w-stats__pill--accent .w-stats__num { color: #14110a; }
.w-stats__lbl {
  font: 800 10px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .85);
}
.w-stats__pill--accent .w-stats__lbl { color: rgba(20, 17, 10, .82); }
@media (min-width: 640px) {
  .w-stats__pill { padding: 12px 20px; }
  .w-stats__num  { font-size: 26px; }
  .w-stats__lbl  { font-size: 11px; }
}

/* ─── AI pre-grade button ─────────────────────────────────────────────
   Lives in the listing action bar (left of eBay/Focus/Acquired).  Two
   visual states drawn on the same .btn-secondary shape so the row
   reads as a coherent button cluster:
     • ungraded → "Grade" — neutral secondary button
     • graded   → "[AI] 9.5" — same shape, gold-tinted, opens reasoning modal
   The grade is a *suggestion* — modal copy + small size reinforce that. */
.w-pregrade-btn { gap: 6px; }
.w-pregrade-btn.is-loading {
  color: var(--b-accent);
  border-color: var(--b-accent-edge);
  background: var(--b-accent-soft);
  cursor: wait;
  animation: w-pregrade-pulse 1.2s ease-in-out infinite;
}
@keyframes w-pregrade-pulse {
  0%,100% { opacity: .65; }
  50%     { opacity: 1; }
}

/* Graded state — same button shell, gold tint, two-part content. */
.w-pregrade-btn--graded {
  display: inline-flex !important;
  align-items: center;
  gap: 6px;
  padding: 6px 10px 6px 6px;
  background: var(--b-accent-soft);
  border-color: var(--b-accent-edge);
  color: var(--b-accent);
}
.w-pregrade-btn--graded:hover {
  background: rgba(200,168,90,.20);
  border-color: var(--b-accent);
  color: var(--b-accent);
}
.w-pregrade-btn__tag {
  font: 800 9px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .9px;
  text-transform: uppercase;
  background: var(--b-accent);
  color: #0a0a0f;
  padding: 3px 6px 2px;
  border-radius: 3px;
}
.w-pregrade-btn__grade {
  font: 700 12px/1 'JetBrains Mono', ui-monospace, monospace;
  letter-spacing: .2px;
}

/* Tier ramping for graded state. */
.w-pregrade-btn--gem  { background: rgba(200,168,90,.24); color: #f0d590; border-color: rgba(200,168,90,.60); }
.w-pregrade-btn--gem  .w-pregrade-btn__tag  { background: #e8c878; }
.w-pregrade-btn--mint { /* default gold — already styled */ }
.w-pregrade-btn--near { background: rgba(255,255,255,.05); color: var(--b-ivory); border-color: rgba(255,255,255,.22); }
.w-pregrade-btn--near .w-pregrade-btn__tag { background: var(--b-ivory); color: #0a0a0f; }
.w-pregrade-btn--mid,
.w-pregrade-btn--low,
.w-pregrade-btn--unknown {
  background: transparent; color: var(--text-muted); border-color: var(--b-rule-strong);
}
.w-pregrade-btn--mid .w-pregrade-btn__tag,
.w-pregrade-btn--low .w-pregrade-btn__tag,
.w-pregrade-btn--unknown .w-pregrade-btn__tag {
  background: var(--text-muted); color: #0a0a0f;
}

/* ════════════════════════════════════════════════════════════════════
   AI ASSESSMENT MODAL
   ════════════════════════════════════════════════════════════════════
   Single-column readable prose.  No clever grids — they fought the
   model's variable-length output.  Anatomy:
     hero    ← compact: small photo, eyebrow, title, grade
     verdict ← italic pull-quote, the model's one-line take
     caveat  ← restrained "suggestion only" note
     body    ← parsed-markdown prose: 01/02/03 numbered headings,
               <strong> bullets, real list markers
     foot    ← generation timestamp + model name
*/

/* Wide variant — used for content-rich modals (AI dossier, etc.).
   Strips the default modal padding so the inner surface (.w-pre)
   can supply its own.  Width scales fluidly: hugs the viewport with
   a breathing margin until it caps at 720px on larger screens.

   Specificity: doubled-up selector (`.modal.modal--wide`) so this
   block beats the base `.modal { max-width: 520px }` rule that's
   declared later in the file. */
.modal.modal--wide {
  max-width: min(720px, calc(100vw - 32px));
  padding: 0;
}
@media (min-width: 1100px) {
  .modal.modal--wide { max-width: 760px; }
}
@media (max-width: 639px) {
  /* Mobile bottom-sheet — eat the side margin so it goes full-bleed.
     The .modal already handles top-radius + safe-area inset bottom. */
  .modal.modal--wide { max-width: 100%; }
}
.modal.modal--titleless { padding-top: 0; }
.modal.modal--titleless .modal-head__close--floating {
  position: absolute; top: 10px; right: 10px;
  z-index: 2;
  background: rgba(0,0,0,.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,.08);
}
@media (min-width: 640px) {
  .modal.modal--titleless .modal-head__close--floating { top: 14px; right: 14px; }
}

/* AI assessment surface.  Padding shrinks on smaller screens; the gold
   1px top edge anchors the page across all sizes.  Scrolling is owned
   by the parent .modal — don't double-scope it here. */
.w-pre {
  position: relative;
  display: flex; flex-direction: column;
  background: linear-gradient(180deg, var(--b-accent) 0 2px, transparent 2px);
  padding: 22px 18px 18px;
  /* Honor iOS bottom safe-area when the modal is a full-height sheet. */
  padding-bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  gap: 14px;
}
@media (min-width: 480px) {
  .w-pre { padding: 24px 22px 20px; gap: 16px; }
}
@media (min-width: 640px) {
  .w-pre { padding: 28px 30px 24px; gap: 18px; }
}
@media (min-width: 900px) {
  .w-pre { padding: 30px 36px 26px; gap: 20px; }
}

/* ─── Hero ─── */
.w-pre__hero {
  display: grid;
  /* Mobile-first: small thumb, single ratio.  Photo grows with screen. */
  grid-template-columns: 56px 1fr;
  gap: 12px;
  align-items: start;
  padding-right: 40px; /* leave room for floating × */
}
@media (min-width: 480px) {
  .w-pre__hero { grid-template-columns: 72px 1fr; gap: 16px; padding-right: 44px; }
}
@media (min-width: 640px) {
  .w-pre__hero { grid-template-columns: 88px 1fr; gap: 20px; }
}
.w-pre__photo {
  width: 56px; height: 78px;
  border: 1px solid var(--b-rule-strong);
  border-radius: 3px;
  background-size: cover; background-position: center;
  background-color: rgba(255,255,255,.025);
}
@media (min-width: 480px) { .w-pre__photo { width: 72px;  height: 100px; } }
@media (min-width: 640px) { .w-pre__photo { width: 88px;  height: 124px; border-radius: 4px; } }

.w-pre__hero-text { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.w-pre__eyebrow {
  font: 800 9.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--b-accent);
}
@media (min-width: 640px) { .w-pre__eyebrow { font-size: 10px; letter-spacing: 2px; } }
.w-pre__title {
  margin: 0;
  font: 700 16px/1.25 'Inter Tight', system-ui, sans-serif;
  letter-spacing: -0.012em;
  color: var(--b-ivory);
  /* Wrap long titles cleanly even at narrow widths. */
  overflow-wrap: anywhere;
}
@media (min-width: 480px) { .w-pre__title { font-size: 17px; } }
@media (min-width: 640px) { .w-pre__title { font-size: 19px; line-height: 1.22; } }
@media (min-width: 900px) { .w-pre__title { font-size: 21px; } }

/* Grade chip — inline below title.  Wraps to next line on narrow screens
   when label + number + confidence pip can't fit. */
.w-pre__grade {
  margin-top: 4px;
  display: inline-flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 6px 10px 7px;
  background: var(--b-accent-soft);
  border: 1px solid var(--b-accent-edge);
  border-radius: 4px;
  align-self: flex-start;
  max-width: 100%;
}
@media (min-width: 480px) { .w-pre__grade { gap: 10px; padding: 6px 12px 7px; } }
.w-pre__grade-label {
  font: 700 8.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--b-accent);
}
@media (min-width: 480px) { .w-pre__grade-label { font-size: 9px; letter-spacing: 1.4px; } }
.w-pre__grade-num {
  font: 700 16px/1 'JetBrains Mono', ui-monospace, monospace;
  color: var(--b-accent);
}
@media (min-width: 480px) { .w-pre__grade-num { font-size: 18px; } }
@media (min-width: 640px) { .w-pre__grade-num { font-size: 20px; } }
.w-pre__conf {
  font: 600 9.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 3px 7px 2px;
  border: 1px solid var(--b-rule-strong);
  border-radius: 999px;
}
.w-pre__conf--high { color: #aaffb4; border-color: rgba(170,255,180,.40); }
.w-pre__conf--medium { color: var(--b-ivory); border-color: rgba(255,255,255,.25); }
.w-pre__conf--low { color: #ffaa6a; border-color: rgba(255,170,106,.40); }

.w-pre__grade--gem  { background: rgba(200,168,90,.18); border-color: rgba(200,168,90,.55); }
.w-pre__grade--gem  .w-pre__grade-num,
.w-pre__grade--gem  .w-pre__grade-label { color: #f0d590; }
.w-pre__grade--near { background: rgba(255,255,255,.04); border-color: rgba(255,255,255,.20); }
.w-pre__grade--near .w-pre__grade-num,
.w-pre__grade--near .w-pre__grade-label { color: var(--b-ivory); }
.w-pre__grade--mid,
.w-pre__grade--low,
.w-pre__grade--unknown { background: transparent; border-color: var(--b-rule-strong); }
.w-pre__grade--mid .w-pre__grade-num,
.w-pre__grade--low .w-pre__grade-num,
.w-pre__grade--unknown .w-pre__grade-num,
.w-pre__grade--mid .w-pre__grade-label,
.w-pre__grade--low .w-pre__grade-label,
.w-pre__grade--unknown .w-pre__grade-label { color: var(--text-muted); }

/* ─── Verdict ─── */
.w-pre__verdict {
  margin: 0;
  padding: 11px 14px;
  background: rgba(255,255,255,.018);
  border-left: 2px solid var(--b-accent);
  border-radius: 0 4px 4px 0;
  font: 500 13px/1.5 Georgia, 'Inter Tight', serif;
  color: var(--b-ivory);
  font-style: italic;
}
@media (min-width: 480px) { .w-pre__verdict { padding: 12px 16px; font-size: 13.5px; } }
@media (min-width: 640px) { .w-pre__verdict { font-size: 14px; line-height: 1.55; } }

/* ─── Caveat ─── */
.w-pre__caveat {
  margin: 0;
  font: 500 11px/1.5 'Inter Tight', system-ui, sans-serif;
  color: var(--text-muted);
  font-style: italic;
}
@media (min-width: 480px) { .w-pre__caveat { font-size: 11.5px; } }

/* ─── Body prose ─── */
.w-pre__body {
  font: 400 13px/1.6 'Inter Tight', system-ui, sans-serif;
  color: var(--b-ivory);
  /* Use the full modal width.  Earlier max-width: 64ch capped lines
     too aggressively at desktop and left half the modal blank. */
  max-width: none;
  width: 100%;
}
@media (min-width: 480px) { .w-pre__body { font-size: 13.5px; } }
@media (min-width: 900px) { .w-pre__body { font-size: 14px; line-height: 1.65; } }
.w-pre__h {
  display: flex; align-items: baseline; gap: 10px;
  margin: 16px 0 8px;
  font: 800 11px/1.2 'Inter Tight', system-ui, sans-serif;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--b-ivory);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--b-rule);
  /* Allow long heading text to wrap nicely on narrow screens. */
  flex-wrap: wrap;
}
@media (min-width: 480px) { .w-pre__h { font-size: 12px; letter-spacing: 1.6px; margin-top: 18px; } }
.w-pre__h:first-child { margin-top: 4px; }
.w-pre__h-num {
  font: 700 11px/1 'JetBrains Mono', ui-monospace, monospace;
  letter-spacing: 1px;
  color: var(--b-accent);
}
.w-pre__p {
  margin: 0 0 8px;
  color: var(--b-ivory);
}
.w-pre__body strong {
  color: var(--b-ivory);
  font-weight: 700;
}
.w-pre__ul {
  list-style: none;
  padding: 0;
  margin: 0 0 10px;
  display: flex; flex-direction: column; gap: 6px;
}
.w-pre__ul li {
  position: relative;
  padding-left: 16px;
  color: var(--text-muted);
}
.w-pre__ul li::before {
  content: '';
  position: absolute; left: 0; top: 9px;
  width: 6px; height: 1px;
  background: var(--b-accent);
}
.w-pre__ul li strong { color: var(--b-ivory); }

/* ─── Footer ─── */
.w-pre__foot {
  font: 500 10px/1 'JetBrains Mono', ui-monospace, monospace;
  color: var(--text-muted);
  letter-spacing: 1.2px;
  text-transform: uppercase;
  padding-top: 14px;
  border-top: 1px solid var(--b-rule);
  margin-top: 4px;
}
.w-listing--clickable { cursor: pointer; user-select: none; }
.w-listing--clickable:hover { background: rgba(255,255,255,.05); }
.w-listing__thumb--btn {
  cursor: zoom-in;
  border: 0; padding: 0;
  background-color: rgba(255,255,255,.04);
  background-size: cover; background-position: center;
}
/* Inline detail panel under a listing row */
.w-detail {
  display: grid; gap: 12px;
  padding: 12px 14px;
  margin-left: 6px;
  background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: 8px;
}
@media (min-width: 720px) {
  .w-detail { grid-template-columns: minmax(160px, 240px) 1fr; align-items: start; }
}
.w-detail__photos {
  display: flex; flex-wrap: wrap; gap: 6px;
  /* Reserve room for two rows of 64px thumbs + 6px gap so the panel
     doesn't grow when async-fetched photos arrive. */
  min-height: 134px;
  align-content: flex-start;
}
.w-detail__thumb {
  width: 64px; height: 64px;
  border: 1px solid rgba(255,255,255,.1);
  border-radius: 6px;
  background-size: cover; background-position: center;
  background-color: rgba(255,255,255,.04);
  cursor: zoom-in;
  padding: 0;
}
.w-detail__thumb:hover { border-color: var(--accent, #3c82f6); }
/* Skeleton placeholder — keeps the strip's footprint stable while the
   eBay item-detail call is in flight. */
.w-detail__thumb--skeleton {
  cursor: default;
  background-color: rgba(255,255,255,.025);
  background-image: linear-gradient(
    90deg,
    rgba(255,255,255,.025) 0%,
    rgba(255,255,255,.06) 50%,
    rgba(255,255,255,.025) 100%
  );
  background-size: 200% 100%;
  animation: w-detail-shimmer 1.4s ease-in-out infinite;
}
.w-detail__thumb--ghost {
  /* No shimmer — these are the trailing skeletons after real thumbs.
     Quiet so the user doesn't keep tracking them as 'still loading'. */
  animation: none;
  opacity: .35;
  background: rgba(255,255,255,.025);
}
@keyframes w-detail-shimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}
.w-detail__meta { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.w-detail__row { display: grid; grid-template-columns: 110px 1fr; gap: 10px; font-size: 12.5px; }
.w-detail__label {
  text-transform: uppercase; letter-spacing: .4px;
  font-size: 10.5px; font-weight: 700;
  color: var(--text-muted); padding-top: 2px;
}
.w-detail__value {
  color: var(--text-default);
  word-break: break-word; min-width: 0;
}
.w-detail__open { align-self: flex-start; margin-top: 4px; }

/* Lightbox — full-screen image viewer */
.lightbox {
  position: fixed; inset: 0;
  z-index: 1000;
  background: rgba(0, 0, 0, .92);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  animation: lightbox-in .12s ease;
}
.lightbox.is-leaving { animation: lightbox-out .12s ease forwards; }
@keyframes lightbox-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes lightbox-out { to { opacity: 0; } }
.lightbox__stage {
  position: relative;
  max-width: 96vw; max-height: 88vh;
  display: flex; align-items: center; justify-content: center;
}
.lightbox__img {
  max-width: 96vw; max-height: 88vh;
  object-fit: contain;
  background: #111;
  border-radius: 6px;
  user-select: none;
}
.lightbox__nav {
  position: absolute;
  top: 50%; transform: translateY(-50%);
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  font-size: 28px; line-height: 1;
  color: #fff;
  background: rgba(0, 0, 0, .55);
  border: 1px solid rgba(255,255,255,.18);
  border-radius: 50%;
  cursor: pointer;
}
.lightbox__nav:hover { background: rgba(0, 0, 0, .8); }
.lightbox__nav:disabled { opacity: .35; cursor: not-allowed; }
.lightbox__nav--prev { left: 12px; }
.lightbox__nav--next { right: 12px; }
.lightbox__close {
  position: absolute; top: 14px; right: 16px;
  width: 36px; height: 36px;
  font-size: 18px; color: #fff;
  background: rgba(0, 0, 0, .55);
  border: 1px solid rgba(255,255,255,.18);
  border-radius: 50%;
  cursor: pointer;
}
.lightbox__counter {
  margin-top: 12px;
  padding: 4px 10px;
  font-size: 12px; color: rgba(255,255,255,.7);
  background: rgba(0, 0, 0, .5);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}

/* ─── Chosen card surface (post-pick view) ───────────────────────────────
   Replaces the old flat price table.  Leads with the buy-case math —
   raw → PSA 10 spread + grading-fee EV — because that's the actual
   "why am I saving this" answer.  Reference grade table is demoted to
   a collapsible disclosure. */
.pc-chosen { display: flex; flex-direction: column; gap: 14px; }

.pc-back {
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px 6px 8px;
  font-size: 12px; font-weight: 600;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: var(--transition);
}
.pc-back:hover { color: var(--accent); border-color: var(--border-glass); }
.pc-back__arrow { font-size: 14px; line-height: 1; }

/* 1. Identity card — what you picked. Strong, but not louder than the buy case.
   Two-column layout: card photo (when available) | text identity. */
.pc-chosen__identity {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  padding: 12px 14px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-md);
}
.pc-chosen__identity-text { min-width: 0; }

/* Card photo — sits left of the identity text. eBay listing aspect ratio
   (roughly 3:4 for a vertical card) so the image doesn't squash. */
.pc-chosen__photo {
  width: 64px; height: 86px;
  flex-shrink: 0;
  border-radius: 6px;
  overflow: hidden;
  background: rgba(255,255,255,.04);
  border: 1px solid var(--border-glass);
}
.pc-chosen__photo-img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
/* Empty placeholder — quiet, not broken-looking. The icon is generic
   "image", and the hint copy explains the next step the user can take. */
.pc-chosen__photo--empty,
.pc-chosen__photo--broken {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px;
  background: linear-gradient(135deg,
    rgba(255,255,255,.04) 0%,
    rgba(255,255,255,.01) 100%);
  border: 1px dashed rgba(255,255,255,.12);
  color: var(--text-muted);
  cursor: help;
}
.pc-chosen__photo-placeholder { opacity: .55; }
.pc-chosen__photo-empty-hint {
  font-size: 9px; font-weight: 600; letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--text-muted);
  opacity: .7;
}

@media (max-width: 380px) {
  .pc-chosen__photo { width: 56px; height: 76px; }
}
.pc-chosen__eyebrow {
  font-size: 9.5px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--accent);
  margin-bottom: 6px;
}
.pc-chosen__title {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  font-size: 16px; font-weight: 600;
  color: var(--text-primary);
  letter-spacing: -0.005em;
}
.pc-chosen__parallel {
  display: inline-flex; align-items: center;
  padding: 2px 8px;
  font-size: 11px; font-weight: 700; letter-spacing: .4px;
  color: var(--accent);
  background: var(--accent-glow);
  border-radius: 999px;
}
.pc-chosen__sub {
  display: flex; align-items: baseline; gap: 10px;
  margin-top: 4px;
  font-size: 12.5px; color: var(--text-secondary);
}
.pc-chosen__num {
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

/* 2. Buy case — the headline math. This is the visual centerpiece. */
.pc-chosen__buycase {
  padding: 16px;
  background: linear-gradient(135deg,
    rgba(34, 197, 94, .04) 0%,
    rgba(255, 255, 255, .03) 60%,
    rgba(255, 255, 255, .02) 100%);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius-md);
}
.pc-chosen__buycase-head {
  font-size: 9.5px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--text-muted);
  margin-bottom: 12px;
}
.pc-chosen__spread {
  display: flex; align-items: center; gap: 12px;
  flex-wrap: wrap;
  font-variant-numeric: tabular-nums;
}
.pc-chosen__spread-leg { display: flex; flex-direction: column; gap: 2px; }
.pc-chosen__spread-tag {
  font-size: 9.5px; font-weight: 700; letter-spacing: 1.2px;
  text-transform: uppercase; color: var(--text-muted);
}
.pc-chosen__spread-num {
  font-size: 20px; font-weight: 700; line-height: 1.1;
  color: var(--text-primary);
  letter-spacing: -0.01em;
}
.pc-chosen__spread-num--big {
  font-size: 26px;
  background: linear-gradient(135deg, var(--success) 0%, #4ade80 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.pc-chosen__spread-arrow {
  font-size: 22px; color: var(--text-muted);
  line-height: 1;
}
.pc-chosen__mult {
  margin-left: auto;
  display: inline-flex; align-items: center;
  padding: 4px 10px;
  font-size: 13px; font-weight: 700; letter-spacing: .2px;
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}
.pc-chosen__mult--hot  { color: var(--success); background: var(--success-glow); }
.pc-chosen__mult--warm { color: var(--warning); background: var(--warning-glow); }
.pc-chosen__mult--mild { color: var(--text-muted); background: rgba(255,255,255,.05); }

/* Math breakdown — explicit grading-fee + net calculation. */
.pc-chosen__math {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border-glass);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.pc-chosen__math-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px;
  padding: 4px 0;
}
.pc-chosen__math-label { color: var(--text-secondary); }
.pc-chosen__math-value {
  color: var(--text-primary);
  font-weight: 600;
}
.pc-chosen__math-value--win  { color: var(--success); font-weight: 700; }
.pc-chosen__math-value--lose { color: var(--error);   font-weight: 700; }
.pc-chosen__math-caveat {
  margin-top: 10px;
  padding: 8px 10px;
  font-size: 11.5px; line-height: 1.45;
  color: var(--text-muted);
  background: rgba(255,255,255,.03);
  border-radius: var(--radius-sm);
  border-left: 2px solid rgba(255, 255, 255, .12);
  font-style: italic;
}

/* 3. Reference grade table — collapsed disclosure, demoted from headline. */
.pc-chosen__grades {
  background: var(--bg-input);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.pc-chosen__grades > summary {
  display: flex; align-items: center; justify-content: space-between;
  cursor: pointer;
  padding: 10px 14px;
  font-size: 11.5px; font-weight: 700; letter-spacing: 1.1px;
  text-transform: uppercase; color: var(--text-muted);
  list-style: none;
}
.pc-chosen__grades > summary::-webkit-details-marker { display: none; }
.pc-chosen__grades > summary::before {
  content: '▸'; display: inline-block;
  margin-right: 10px;
  font-size: 10px;
  transition: transform .15s ease;
  color: var(--text-muted);
}
.pc-chosen__grades[open] > summary::before { transform: rotate(90deg); }
.pc-chosen__grades-count {
  font-weight: 600; letter-spacing: .4px;
  font-variant-numeric: tabular-nums;
}
.pc-chosen__grade-table {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 4px 16px;
  padding: 4px 14px 12px;
  border-top: 1px solid var(--border-glass);
}
.pc-chosen__grade-table .kvp {
  display: flex; align-items: baseline; justify-content: space-between;
  padding: 4px 0;
  font-size: 12.5px;
}
@media (max-width: 480px) {
  .pc-chosen__grade-table { grid-template-columns: 1fr; }
}

/* 4. Save CTA — full-width, dominant. */
.pc-chosen__save { width: 100%; padding: 14px 16px; font-size: 14px; }

/* Saved state — replaces the panel content with a clear confirmation. */
.pc-chosen__saved {
  display: flex; flex-direction: column; align-items: center;
  gap: 6px;
  padding: 28px 16px 24px;
  text-align: center;
}
.pc-chosen__saved-mark {
  width: 48px; height: 48px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 24px; font-weight: 700;
  color: var(--success);
  background: var(--success-glow);
  border-radius: 50%;
  margin-bottom: 4px;
}
.pc-chosen__saved-title {
  font-size: 16px; font-weight: 700;
  color: var(--text-primary);
}
.pc-chosen__saved-sub {
  font-size: 13px; color: var(--text-secondary);
  max-width: 38ch;
}

/* Result-picker empty state. */
.pc-empty {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 36px 12px 28px;
  text-align: center;
  color: var(--text-muted);
}
.pc-empty__hd {
  font-size: 11px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--text-muted);
}
.pc-empty__body { font-size: 13px; color: var(--text-secondary); max-width: 28ch; }

/* ─── Section eyebrow (tiny all-caps section header, used on every tab) ──── */
.section-eyebrow {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin: 18px 4px 10px;
  font-size: 11px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--text-muted);
}
.section-eyebrow:first-child { margin-top: 4px; }
.section-eyebrow .lead { color: var(--text-secondary); }
.section-eyebrow .meta {
  font-weight: 500; letter-spacing: .4px; text-transform: none;
  font-size: 11px; color: var(--text-muted);
}
.section-eyebrow .accent { color: var(--accent); letter-spacing: 1.6px; }

/* ─── Empty state (shared across every tab) ───────────────────────────────── */
/* (already defined above; just ensure all tabs follow the same DOM shape)    */

/* ─── Disclosure (collapsible section header) ─────────────────────────────── */
.disclosure { background: var(--bg-card); border: 1px solid var(--border-glass); border-radius: var(--radius-lg); overflow: hidden; }
.disclosure + .disclosure { margin-top: 12px; }
.disclosure__head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px; min-height: 48px;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  background: none; border: none; width: 100%;
  color: var(--text-primary); text-align: left;
}
.disclosure__head:active { background: var(--bg-card-hover); }
.disclosure__title { flex: 1; font-size: 15px; font-weight: 600; }
.disclosure__chev { transition: transform .2s ease; opacity: .6; }
.disclosure.is-open .disclosure__chev { transform: rotate(180deg); }
.disclosure__body { display: none; padding: 0 16px 16px; }
.disclosure.is-open .disclosure__body { display: block; }

/* ─── Snipe bar (compact stats + actions) ─────────────────────────────────── */
.snipe-bar { /* override the existing definition lower in the file */ }

/* ─── Modal ───────────────────────────────────────────────────────────────── */
@keyframes modal-fade-in   { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-rise-in   { from { opacity: 0; transform: translateY(16px) scale(.98); }
                             to   { opacity: 1; transform: translateY(0)   scale(1); } }
@keyframes modal-fade-out  { from { opacity: 1; } to { opacity: 0; } }
@keyframes modal-fall-out  { from { opacity: 1; transform: translateY(0) scale(1); }
                             to   { opacity: 0; transform: translateY(8px) scale(.985); } }

.modal-backdrop {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(0,0,0,.6); backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  display: flex; align-items: flex-end; justify-content: center;
  animation: modal-fade-in .18s ease both;
}
.modal-backdrop.is-leaving { animation: modal-fade-out .14s ease both; }

.modal {
  position: relative;
  width: 100%; max-width: 520px;
  /* Slightly lifted off pure black so the rounded top edge reads.  No
     glass blur — this is editorial, not iOS Notification Center. */
  background: #14141a;
  border-top: 1px solid var(--b-rule-strong);
  border-radius: 14px 14px 0 0;
  padding: 22px 20px;
  padding-bottom: calc(22px + env(safe-area-inset-bottom, 0px));
  max-height: 90dvh; overflow-y: auto;
  animation: modal-rise-in .22s cubic-bezier(.2,.7,.2,1) both;
  /* Hairline gold cap across the very top — restrained signature, not a
     glow.  Replaces the prior radius-pill chrome. */
  box-shadow: inset 0 1px 0 var(--b-accent-edge);
}
.is-leaving .modal { animation: modal-fall-out .14s ease both; }

@media (min-width: 640px) {
  .modal-backdrop { align-items: center; }
  .modal { border-radius: 8px; border: 1px solid var(--b-rule-strong); }
}

/* Compact size — used for confirms.  Tighter padding, shorter max width. */
.modal--compact { max-width: 400px; padding: 18px 20px 16px; }
.modal--compact .modal-actions { margin-top: 18px; }

/* Danger tone — destructive confirmations.  A red glow rail across the top
   edge replaces the usual chrome.  Eyebrow above the title sets the stakes. */
.modal--danger { padding-top: 24px; }
.modal__rail {
  position: absolute; left: 0; right: 0; top: 0;
  height: 2px;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--error) 30%,
    var(--error) 70%,
    transparent 100%);
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  box-shadow: 0 0 18px var(--error-glow), 0 0 6px var(--error-glow);
}

.modal-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  margin: -2px 0 18px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--b-rule);
}
.modal-head__titles { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.modal-head__eyebrow {
  font-family: 'Inter Tight', sans-serif;
  font-size: 9.5px; font-weight: 800;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .55);
  text-shadow: none;
}
.modal-head h2 {
  font-family: 'Inter Tight', sans-serif;
  font-size: 11px; font-weight: 800;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .65);
  line-height: 1.25;
}
.modal--danger .modal-head__eyebrow { color: var(--error); text-shadow: none; }
.modal--danger .modal-head h2 {
  font-size: 19px; letter-spacing: -0.005em;
  text-transform: none;
  font-weight: 700;
  color: var(--b-ivory);
}
.modal-head__close {
  flex: 0 0 auto;
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 16px; line-height: 1; font-weight: 400;
  color: rgba(244, 241, 234, .55);
  background: transparent;
  border: 1px solid var(--b-rule-strong);
  border-radius: 999px;
  transition: color .15s ease, border-color .15s ease;
}
.modal-head__close:hover,
.modal-head__close:active {
  color: var(--b-accent);
  border-color: var(--b-accent-edge);
  background: transparent;
}

.modal__body-text {
  font-size: 14px; line-height: 1.5;
  color: var(--text-secondary);
  margin-bottom: 4px;
}

/* Structured lists inside a modal — used by Snipe failure summary and
   "Seller items" overlay. Replaces what used to be alert() walls of text. */
.modal__failure-list,
.modal__seller-list {
  list-style: none; padding: 0; margin: 8px 0 0;
  display: flex; flex-direction: column; gap: 8px;
  max-height: 50vh; overflow-y: auto;
}
.modal__failure-list li {
  padding: 10px 12px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-left: 3px solid var(--error);
  border-radius: var(--radius-sm);
}
.modal__failure-title { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.modal__failure-reason { font-size: 12px; color: var(--text-muted); margin-top: 2px; }

.modal__seller-list li {
  display: flex; align-items: baseline; gap: 12px;
  padding: 8px 12px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius-sm);
}
.modal__seller-price {
  font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--text-primary);
  min-width: 60px;
}
.modal__seller-title {
  font-size: 12.5px; color: var(--text-secondary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  flex: 1; min-width: 0;
}

/* Inline error banner inside a modal — replaces native alert() for failed
   primary actions. Rendered above the action row so it's contextually clear
   the buttons can still be retried. */
.modal__error {
  margin-top: 12px;
  padding: 10px 12px;
  font-size: 13px; line-height: 1.4;
  color: var(--error);
  background: rgba(239, 68, 68, 0.08);
  border: 1px solid rgba(239, 68, 68, 0.32);
  border-left: 3px solid var(--error);
  border-radius: var(--radius-sm);
  font-weight: 500;
}
.modal__error[hidden] { display: none; }

.modal-actions { display: flex; gap: 8px; margin-top: 16px; }
.modal-actions .btn { flex: 1; }
.modal--compact .modal-actions { gap: 10px; }
.modal--compact .modal-actions .btn { padding: 11px 14px; font-size: 14px; font-weight: 600; }

/* Destructive primary button — used for the confirmation primary action. */
.btn-danger {
  background: var(--error);
  color: #fff;
  border: 1px solid transparent;
  box-shadow: 0 0 22px var(--error-glow), inset 0 1px 0 rgba(255,255,255,.12);
  font-weight: 600;
  letter-spacing: .1px;
  transition: var(--transition);
}
.btn-danger:hover {
  background: #dc2626;
  box-shadow: 0 0 28px var(--error-glow), inset 0 1px 0 rgba(255,255,255,.16);
}
.btn-danger:active { transform: scale(.98); background: #b91c1c; }
.btn-danger:focus-visible {
  outline: 2px solid var(--error);
  outline-offset: 2px;
}

/* ─── Snipe table ─────────────────────────────────────────────────────────── */
.snipe-bar {
  display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
  padding: 10px 12px; background: var(--bg-input);
  border-radius: var(--radius-md); margin-bottom: 14px;
  font-size: 13px; color: var(--text-secondary);
}
.snipe-bar b { color: var(--text-primary); }
.snipe-bar .btn-sm { flex: 1 1 auto; min-width: 0; }
.snipe-bar .stat { padding: 4px 10px 4px 4px; flex: 1 1 100%; }
@media (min-width: 640px) { .snipe-bar .stat { flex: 0 1 auto; } }

/* ─── Utilities ───────────────────────────────────────────────────────────── */
.row { display: flex; align-items: center; gap: 8px; }
.row.between { justify-content: space-between; }
.col { display: flex; flex-direction: column; gap: 8px; }
.muted { color: var(--text-muted); }
.danger { color: var(--error); }
.warning { color: var(--warning); }
.success { color: var(--success); }
.mt-8 { margin-top: 8px; } .mt-12 { margin-top: 12px; } .mt-16 { margin-top: 16px; }
.hidden { display: none !important; }
.spacer { flex: 1; }

/* ════════════════════════════════════════════════════════════════════════
   Browse — Trading Floor redesign (mobile-first, iOS Safari primary target)
   ────────────────────────────────────────────────────────────────────────
   Aesthetic: editorial-financial.  Bloomberg-terminal density meets
   Beckett-price-guide typography.  One bright accent (chartreuse) for hot
   multipliers; everything else lives in charcoal/ivory.  Numbers are set
   in JetBrains Mono on a tabular baseline so prices align column-wise.
   The display family is Inter Tight — humanist enough for a player name
   to feel like a name, technical enough for the numeric strip.
   ════════════════════════════════════════════════════════════════════════ */
:root {
  --b-accent: #c8a85a;             /* gold leaf — "hot" signal, refined */
  --b-accent-soft: rgba(200, 168, 90, .12);
  --b-accent-edge: rgba(200, 168, 90, .32);
  --b-warm: #fbbf24;
  --b-warm-soft: rgba(251, 191, 36, .14);
  --b-ivory: #f4f1ea;
  --b-rule: rgba(255, 255, 255, .06);
  --b-rule-strong: rgba(255, 255, 255, .12);
  --b-display: 'Inter Tight', -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif;
  --b-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
}

/* Body already inherits --b-display via the global rule.  Mono numerics
   are opt-in per element below. */
.b-row__strip,
.b-row__mult,
.b-row__leg-num {
  font-family: var(--b-mono);
  font-variant-numeric: tabular-nums;
}

/* ─── Sticky search header ─────────────────────────────────────────────
   Stays fixed at the top of the scroll region while typing — primary fix
   for iOS Safari where losing the input mid-scroll was the #1 frustration.
   Backdrop blur keeps the result list readable behind it.  Input is 17px
   so iOS Safari does not zoom on focus (the 16px threshold is unreliable
   on certain iPhone models, 17px is the safe floor). */
.b-search {
  position: sticky;
  top: 0;
  z-index: 5;
  margin: -16px -14px 0;     /* full-bleed against page-content padding */
  padding: 14px 14px 12px;
  background: rgba(10, 10, 15, .82);
  backdrop-filter: saturate(140%) blur(18px);
  -webkit-backdrop-filter: saturate(140%) blur(18px);
  border-bottom: 1px solid var(--b-rule);
}
.b-search__icon {
  left: 26px;
  color: var(--b-ivory);
  opacity: .55;
}
.b-search__input {
  height: 48px;                              /* meets WCAG tap target */
  padding: 0 44px 0 50px;
  font-size: 17px;                           /* iOS no-zoom floor */
  font-family: var(--b-display);
  font-weight: 500;
  letter-spacing: -.005em;
  color: var(--b-ivory);
  background: rgba(255, 255, 255, .045);
  border: 1px solid var(--b-rule-strong);
  border-radius: 14px;
  transition: border-color .18s ease, background .18s ease, box-shadow .18s ease;
}
.b-search__input::placeholder {
  color: rgba(244, 241, 234, .35);
  font-weight: 400;
}
.b-search__input:focus {
  background: rgba(255, 255, 255, .07);
  border-color: var(--b-accent-edge);
  box-shadow: 0 0 0 4px rgba(202, 255, 51, .08);
}
.b-search__clear {
  right: 22px;
  width: 32px; height: 32px;
  font-size: 13px;
  color: var(--b-ivory); opacity: .6;
  background: rgba(255, 255, 255, .08);
  border-radius: 999px;
}
.b-search__clear:hover,
.b-search__clear:active { opacity: 1; background: rgba(255, 255, 255, .14); }

/* ─── Results eyebrow ─────────────────────────────────────────────────
   Newspaper-style section label.  Lead is small-caps display, meta is mono
   so the count aligns visually with the numbers in the rows below. */
.b-eyebrow {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px;
  margin: 18px 0 10px;
  padding: 0 2px;
}
.b-eyebrow__lead {
  font-family: var(--b-display);
  font-size: 11px; font-weight: 800;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--b-ivory);
}
.b-eyebrow__lead::before {
  content: '';
  display: inline-block;
  width: 8px; height: 8px;
  margin-right: 9px;
  background: var(--b-accent);
  border-radius: 1px;
  vertical-align: 0;
  /* No glow — single small mark, not a beacon. */
}
.b-eyebrow__meta {
  font-family: var(--b-mono);
  font-size: 11px; font-weight: 500;
  letter-spacing: .04em;
  color: rgba(244, 241, 234, .5);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* ─── Result list (the big change) ─────────────────────────────────────
   Replaces the old card-grid look with a hairline-divided full-bleed list.
   Recovers ~28px of horizontal space per row vs. the previous padded card
   chrome, which is exactly what was getting eaten on iPhone widths. */
.b-list {
  margin: 0 -14px;                /* full-bleed on mobile */
  border-top: 1px solid var(--b-rule);
}
@media (min-width: 640px) {
  .b-list { margin: 0; border-top: none; }
}

.b-row {
  position: relative;
  display: flex; align-items: stretch;
  width: 100%;
  padding: 0;
  text-align: left;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--b-rule);
  border-radius: 0;
  color: var(--b-ivory);
  cursor: pointer;
  transition: background .15s ease, transform .12s ease;
  -webkit-tap-highlight-color: transparent;
}
@media (min-width: 640px) {
  .b-row {
    border-radius: 12px;
    border: 1px solid var(--b-rule);
    margin-bottom: 4px;
  }
}
.b-row:active {
  background: rgba(255, 255, 255, .045);
  transform: scale(.997);
}
.b-row:focus-visible {
  outline: none;
  background: rgba(255, 255, 255, .04);
  box-shadow: inset 0 0 0 2px var(--b-accent-edge);
}

/* Left rail — color encodes spread tier.  Hot rows light up chartreuse. */
.b-row__rail {
  flex-shrink: 0;
  width: 3px;
  background: transparent;
  transition: background .18s ease, box-shadow .18s ease;
}
.b-row--hot   .b-row__rail {
  background: var(--b-accent);
}
.b-row--warm  .b-row__rail { background: var(--b-warm); }
.b-row--mild  .b-row__rail { background: rgba(255,255,255,.08); }
.b-row--untrusted .b-row__rail { background: rgba(255,255,255,.04); }

/* ─── Thumbnail slot ──────────────────────────────────────────────────
   Lives between the tier rail and the body.  Real eBay images get
   surfaced once the user has hunted that card; everything else gets
   the SVG card-back placeholder. */
.b-row__thumb {
  flex-shrink: 0;
  width: 48px; height: 64px;
  margin: 10px 0 10px 10px;
  border: 1px solid var(--b-rule-strong);
  border-radius: 4px;
  overflow: hidden;
  background: rgba(255, 255, 255, .025);
  display: flex; align-items: stretch; justify-content: stretch;
}
@media (min-width: 640px) {
  .b-row__thumb { width: 56px; height: 80px; margin-left: 12px; }
}
.b-row__thumb-img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.b-row__thumb-ph,
.b-row__thumb-ph svg {
  width: 100%; height: 100%; display: block;
}
.b-row__thumb--placeholder { background: transparent; }
.b-row__thumb--broken { background: rgba(255,255,255,.025); }

.b-row__body {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
  gap: 4px;
  padding: 10px 14px 10px 12px;
}

/* Eyebrow strip — confidence dot + set name + sales count.
   Single line, never wraps; the dot is what was the ●●● glyph. */
.b-row__eyebrow {
  display: flex; align-items: center;
  gap: 8px;
  font-size: 10.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  min-height: 14px;
}
.b-row__conf-dot {
  flex-shrink: 0;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: rgba(244, 241, 234, .25);
  /* Use a tooltip so the hover/long-press still surfaces the sales count. */
  cursor: help;
}
.b-row__conf-dot--high { background: var(--b-accent); }
.b-row__conf-dot--mid  { background: rgba(244, 241, 234, .55); }
.b-row__conf-dot--low  { background: rgba(244, 241, 234, .22); }
.b-row__set {
  flex: 1; min-width: 0;
  font-weight: 700;
  color: rgba(244, 241, 234, .55);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.b-row__sales {
  flex-shrink: 0;
  font-family: var(--b-mono);
  font-size: 9.5px;
  letter-spacing: .04em;
  text-transform: lowercase;
  color: rgba(244, 241, 234, .35);
  font-variant-numeric: tabular-nums;
}

/* Title row — heroic player name on the left, gold multiplier pill on the
   right.  Both sit at the same eye-stop so the verdict is always within
   thumb-reach next to the name. */
.b-row__head {
  display: flex; align-items: center; gap: 10px;
  min-width: 0;
}
.b-row__hero {
  flex: 1; min-width: 0;
  font-family: var(--b-display);
  font-size: 17.5px;
  font-weight: 700;
  letter-spacing: -.014em;
  line-height: 1.2;
  color: var(--b-ivory);
  /* clamp to one line on mobile; expands at >=640 if it doesn't fit */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
@media (min-width: 640px) {
  .b-row__hero { font-size: 21px; }
}

/* Variant chip — sits between the title and multiplier pill, calls
   out whether the row is the BASE card or a specific parallel.  The
   key product-clarity affordance: prices and gem rates can vary
   100× between variants, so the user needs to see at a glance which
   variant they're scanning. */
.b-row__variant {
  flex-shrink: 0;
  font: 800 9.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .22em;
  text-transform: uppercase;
  padding: 3px 7px 2px;
  border-radius: 2px;
  white-space: nowrap;
}
.b-row__variant--base {
  color: rgba(244, 241, 234, .55);
  background: transparent;
  border: 1px solid var(--b-rule);
}
.b-row__variant--parallel {
  color: var(--b-accent);
  background: rgba(200, 168, 90, .08);
  border: 1px solid var(--b-accent-edge);
}
@media (max-width: 480px) {
  .b-row__variant { letter-spacing: .14em; padding: 2px 5px 1px; font-size: 9px; }
}

/* Variant chip on the Browse detail sheet — same vocabulary as the
   row chip but a touch larger, sits below the card name as its own
   line for clarity. */
.b-sheet__variant {
  margin-top: 6px;
}
.b-sheet__variant-chip {
  display: inline-block;
  font: 800 10.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: .24em;
  text-transform: uppercase;
  padding: 4px 9px 3px;
  border-radius: 2px;
}
.b-sheet__variant-chip--base {
  color: rgba(244, 241, 234, .58);
  background: transparent;
  border: 1px solid var(--b-rule);
}
.b-sheet__variant-chip--parallel {
  color: var(--b-accent);
  background: rgba(200, 168, 90, .08);
  border: 1px solid var(--b-accent-edge);
}

/* Compact numeric strip — single line, mono, mid-dot separated. */
.b-row__strip {
  display: flex; align-items: baseline;
  gap: 8px;
  margin-top: 2px;
  font-family: var(--b-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12.5px;
  color: var(--b-ivory);
  white-space: nowrap;
  overflow: hidden;
}
.b-row__leg {
  display: inline-flex; align-items: baseline; gap: 5px;
  min-width: 0;
}
.b-row__leg-tag {
  font-family: var(--b-display);
  font-size: 9px; font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .42);
}
.b-row__leg-num {
  font-weight: 500;
  letter-spacing: -.01em;
}
.b-row__sep {
  color: rgba(244, 241, 234, .25);
  font-family: var(--b-display);
}

/* Multiplier pill — moves into .b-row__head, anchored right, smaller
   than the prior end-of-strip placement so it doesn't dominate the row. */
.b-row__mult {
  flex-shrink: 0;
  padding: 4px 8px 3px;
  font-family: var(--b-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12.5px; font-weight: 700;
  letter-spacing: -.01em;
  border-radius: 4px;
  white-space: nowrap;
}
.b-row__mult--hot {
  color: var(--accent-ink);
  background: var(--b-accent);
}
.b-row__mult--warm {
  color: var(--b-warm);
  background: var(--b-warm-soft);
  box-shadow: inset 0 0 0 1px rgba(251, 191, 36, .35);
}
.b-row__mult--mild,
.b-row__mult--muted {
  color: rgba(244, 241, 234, .5);
  background: rgba(255, 255, 255, .04);
}

/* Low-confidence footer.  Quiet amber strip, full-width under the strip. */
.b-row__warn {
  margin-top: 6px;
  padding: 6px 9px;
  font-family: var(--b-mono);
  font-size: 10.5px; font-weight: 500;
  letter-spacing: .02em;
  color: var(--b-warm);
  background: var(--b-warm-soft);
  border-radius: 4px;
}

/* ─── Skeleton rows during fetch ─────────────────────────────────────── */
@keyframes b-shimmer {
  0%   { background-position: -160% 0; }
  100% { background-position:  260% 0; }
}
.b-row--skeleton { pointer-events: none; }
.b-row--skeleton .b-row__rail { background: var(--b-rule); }
.sk {
  display: inline-block;
  height: 12px;
  border-radius: 4px;
  background:
    linear-gradient(90deg,
      rgba(255,255,255,.04) 0%,
      rgba(255,255,255,.10) 50%,
      rgba(255,255,255,.04) 100%);
  background-size: 200% 100%;
  animation: b-shimmer 1.4s ease-in-out infinite;
}
.sk--eyebrow { width: 60%; height: 9px; }
.sk--glyph   { width: 32px; height: 9px; }
.sk--hero    { flex: 1; height: 16px; max-width: 70%; }
.sk--leg     { width: 30%; height: 12px; }
.sk--mult    { width: 38px; height: 18px; border-radius: 4px; }
.sk--thumb   { width: 100%; height: 100%; border-radius: 0; }
.sk--lead    { width: 110px; height: 11px; }
.sk--meta    { width: 90px;  height: 11px; }
.b-eyebrow--skel { opacity: .8; }

/* ─── Saved-state overlay (preserve existing behavior, restyled) ──────── */
.b-row.is-saved > *:not(.b-row__saved-overlay) { opacity: .12; }
.b-row__saved-overlay {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  font-family: var(--b-display);
  font-size: 12px; font-weight: 800; letter-spacing: .18em; text-transform: uppercase;
  color: var(--b-accent);
  background: rgba(202, 255, 51, .06);
  border: 1px solid var(--b-accent-edge);
  border-radius: inherit;
}
.b-row__saved-mark {
  width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px;
  color: #0a0a0f;
  background: var(--b-accent);
  border-radius: 50%;
}

/* ─── Tighten the existing chrome to match ─────────────────────────────── */
.discover-status {
  background: transparent;
  border: none;
  padding: 8px 2px 2px;
}
.discover-status__primary {
  font-family: var(--b-display);
  font-size: 13px; font-weight: 600; color: var(--b-ivory);
}
.discover-status__sub {
  font-family: var(--b-mono);
  font-size: 10.5px; letter-spacing: .04em;
  color: rgba(244, 241, 234, .42);
}
.b-filters-disclosure {
  background: transparent;
  border: 1px solid var(--b-rule);
  border-radius: 10px;
}
.b-filters-disclosure > summary {
  font-family: var(--b-display);
  font-size: 10.5px; letter-spacing: .22em;
  color: rgba(244, 241, 234, .55);
}

/* ════════════════════════════════════════════════════════════════════════
   Page — generic design-system primitives
   ────────────────────────────────────────────────────────────────────────
   These class names are emitted by /js/page.js composers (Page.masthead,
   Page.eyebrow, Page.toolbar, Page.search, Page.empty, Page.list, etc).
   Most are aliases for the existing .b-* selectors so the same CSS
   already drives them; the ones below add the primitives that didn't
   exist before (page-level identity stack, toolbar wrapper, action
   cluster, empty-state icon).

   Future pages should never declare bespoke chrome — call the composers,
   the styles below take care of the look. */

/* Masthead identity stack — eyebrow + heroic title + kicker.  Sits above
   any optional metric grid the masthead may also include. */
.page__masthead-id {
  padding: 8px 0 14px;
}
.page__masthead-eyebrow {
  font-family: 'Inter Tight', sans-serif;
  font-size: 9.5px; font-weight: 800;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .42);
  margin-bottom: 8px;
}
.page__masthead-title {
  font-family: 'Inter Tight', sans-serif;
  font-size: 26px; font-weight: 700;
  letter-spacing: -.018em;
  line-height: 1.05;
  color: var(--b-ivory);
}
@media (max-width: 480px) {
  .page__masthead-title { font-size: 22px; }
}
.page__masthead-kicker {
  margin-top: 6px;
  font-size: 12.5px;
  color: rgba(244, 241, 234, .55);
  line-height: 1.5;
}
.page__masthead-id + .b-masthead__row,
.page__masthead-id + .page__masthead-metrics {
  border-top: 1px solid var(--b-rule);
  padding-top: 14px;
}

/* Page-level toolbar — sticky action row that survives scroll.  Uses the
   same blur language as the search bar so the two stack cleanly. */
.page__toolbar {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 8px;
  margin: 0 2px 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--b-rule);
  background: transparent;
}
.page__toolbar--sticky {
  position: sticky;
  top: 0;     /* tabbar is its own sticky context above the panel scroll */
  z-index: 4;
  margin: -16px -14px 12px;
  padding: 12px 14px;
  background: rgba(10, 10, 15, .82);
  backdrop-filter: saturate(140%) blur(18px);
  -webkit-backdrop-filter: saturate(140%) blur(18px);
}
.page__toolbar > .btn,
.page__toolbar > .btn-sm,
.page__toolbar > button:not(.b-search__clear) {
  border-radius: 4px;
  font-family: 'Inter Tight', sans-serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: 10px 14px;
  min-height: 40px;
}

/* Action button cluster — bottom-of-card row of equal-width buttons. */
.page__actions {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding-top: 4px;
}
.page__actions > .btn,
.page__actions > .btn-sm,
.page__actions > a.btn,
.page__actions > button {
  flex: 1 1 auto; min-width: 0;
  font-family: 'Inter Tight', sans-serif;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  font-weight: 700;
  border-radius: 4px;
  min-height: 40px;
}

/* Empty-state icon slot — sits above the title. */
.page__empty-icon {
  display: flex; justify-content: center;
  margin-bottom: 10px;
  color: rgba(244, 241, 234, .35);
}
.page__empty-icon svg { width: 32px; height: 32px; }

/* Disclosure body wrapper — gives any composer-rendered children
   consistent inner padding regardless of what they are. */
.page__disclosure-body {
  /* No padding here — children own their own spacing.  This wrapper
     exists purely so composers don't have to know about <details>'s
     direct-child quirks. */
}

/* Empty-list shell — keeps vertical rhythm when a list resolves to zero
   items but no empty-state is supplied.  Reserves a tiny strip so the
   layout doesn't collapse to nothing. */
.page__list--empty {
  min-height: 1px;
}

/* ─── Reduced motion: kill shimmers and transforms ────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .sk { animation: none; }
  .b-row { transition: none; }
  .b-row:active { transform: none; }
}

/* ════════════════════════════════════════════════════════════════════════
   Watchlist — Trading Floor overlay
   ────────────────────────────────────────────────────────────────────────
   Re-skins .tcard.w-card, .w-listing, .w-detail, the verdict badges and
   the focus stripe through the Trading Floor token system so Watchlist
   speaks the same visual language as Browse.  No JS surgery — these are
   pure overrides keyed off classes already emitted by watchlist.js.
   The shape is the same as Browse rows: small-caps eyebrow, heroic
   title, mono numeric strip, hairline dividers, single gold accent for
   actionable signals (verdict pill, focus stripe, max-bid value).
   ════════════════════════════════════════════════════════════════════════ */

/* Watchlist panel — slightly darker substrate so the gold-edged
   tickets read as floating slabs above a "void" rather than fighting
   the page background. */
.tab-panel[data-panel="watchlist"] {
  background:
    radial-gradient(140% 90% at 50% 0%, rgba(0,0,0,.20), transparent 60%);
}

/* ─── Card row (the trading ticket) ───────────────────────────────────
   Each card is treated as a distinct "trading ticket": tonal slab over
   the page bg, stamped with a thin gold top edge (the same dateline
   vocabulary as the Browse masthead's EDITION rule), drop-shadowed off
   the surface, separated by generous void.
   Open state warms the slab and thickens the top edge to solid gold —
   the active ticket reads as elevated and "marked." */
.w-card.tcard {
  position: relative;
  background:
    /* gold dateline at the top edge */
    linear-gradient(180deg, var(--b-accent-edge) 0 1.5px, transparent 1.5px),
    /* tonal slab — subtle lift off page bg */
    linear-gradient(180deg, rgba(255,255,255,.022), rgba(255,255,255,.012));
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid var(--b-rule-strong);
  border-radius: 8px;
  margin: 0 -14px 10px;       /* full-bleed against page-content padding */
  padding: 18px 14px 16px;
  box-shadow:
    0 1px 0 rgba(255,255,255,.02) inset,
    0 1px 0 rgba(0,0,0,.35),
    0 8px 22px rgba(0,0,0,.22);
  transition: background .14s ease, box-shadow .14s ease, border-color .14s ease, transform .14s ease;
}
.w-card.tcard:hover {
  border-color: var(--b-accent-edge);
  background:
    linear-gradient(180deg, var(--b-accent-edge) 0 1.5px, transparent 1.5px),
    linear-gradient(180deg, rgba(255,255,255,.030), rgba(255,255,255,.016));
}
.w-card.tcard:active { transform: translateY(1px); }
.w-card.tcard + .w-card.tcard { margin-top: 0; }

@media (min-width: 640px) {
  .w-card.tcard {
    margin: 0 0 14px;
    border-radius: 10px;
    padding: 20px 18px 18px;
    box-shadow:
      0 1px 0 rgba(255,255,255,.025) inset,
      0 2px 0 rgba(0,0,0,.30),
      0 14px 36px rgba(0,0,0,.30);
  }
}

/* Active / open ticket — gold rule thickens to solid, slab warms,
   shadow gets deeper to sell the elevation. */
.w-card.tcard.is-open {
  background:
    linear-gradient(180deg, var(--b-accent) 0 2.5px, transparent 2.5px),
    linear-gradient(180deg, rgba(255,255,255,.045), rgba(255,255,255,.020));
  border-color: var(--b-accent-edge);
  box-shadow:
    0 1px 0 rgba(255,255,255,.04) inset,
    0 2px 0 rgba(0,0,0,.40),
    0 18px 44px rgba(0,0,0,.38),
    0 0 0 1px var(--b-accent-edge);
}

/* Header row inside the card — thumbnail | identity | verdict.  The
   identity stack rebuilds the eyebrow + heroic-title rhythm without
   changing the JS markup. */
.w-card .tcard__head { gap: 14px; align-items: flex-start; min-height: 0; }
.w-card .tcard__thumb {
  width: 44px; height: 60px;
  border-radius: 4px;
  border: 1px solid var(--b-rule-strong);
  background-color: rgba(255,255,255,.025);
}
.w-card .tcard__title {
  font-family: 'Inter Tight', -apple-system, sans-serif;
  font-size: 19px; font-weight: 700;
  letter-spacing: -.014em;
  line-height: 1.2;
  color: var(--b-ivory);
  white-space: normal;
}
@media (min-width: 640px) {
  .w-card .tcard__title { font-size: 21px; }
}
/* Promote .tcard__sub to a small-caps eyebrow — same vocabulary as
   .b-row__set on the Browse rows. */
.w-card .tcard__sub {
  margin-top: 6px;
  font-size: 10.5px; font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .42);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* place it visually above the title via flex-direction reverse on parent */
}
.w-card .tcard__id {
  display: flex; flex-direction: column-reverse;
  /* eyebrow rendered first via reverse order, hero (title) below it */
}

/* Verdict cluster — multiplier + badge stack.  Multiplier becomes the
   gold "hot pill" treatment; badges become outlined chips, no glow. */
.w-card .tcard__verdict { gap: 6px; align-items: flex-end; }
.w-card .tcard__mult {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 18px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
  padding: 4px 10px;
  border-radius: 4px;
  line-height: 1;
}
.w-card .tcard__mult.go {
  color: var(--accent-ink);
  background: var(--b-accent);
}
.w-card .tcard__mult.marginal {
  color: var(--b-warm);
  background: var(--b-warm-soft);
  box-shadow: inset 0 0 0 1px rgba(251, 191, 36, .3);
}
.w-card .tcard__mult.avoid {
  color: rgba(244, 241, 234, .5);
  background: rgba(255, 255, 255, .04);
}
.w-card .tcard__mult.muted {
  color: rgba(244, 241, 234, .35);
  background: transparent;
}
/* Verdict text badge — outlined chip, no fill */
.w-card .badge {
  font-family: 'Inter Tight', sans-serif;
  font-size: 9px; font-weight: 800;
  letter-spacing: .22em;
  text-transform: uppercase;
  padding: 3px 7px;
  border-radius: 2px;
  background: transparent;
  border: 1px solid var(--b-rule-strong);
  color: rgba(244, 241, 234, .55);
}
.w-card .badge-go       { color: var(--b-accent); border-color: var(--b-accent-edge); }
.w-card .badge-marginal { color: var(--b-warm);   border-color: rgba(251, 191, 36, .3); }
.w-card .badge-avoid    { color: rgba(244, 241, 234, .35); }
.w-card .badge-muted    { color: rgba(244, 241, 234, .72); font-weight: 600; }

/* Money / spread strip — convert to mono tabular numerics like the
   Browse numeric strip.  Same baseline so the two lists feel related. */
.w-card .tcard__money {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 14.5px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.005em;
  margin-top: 12px; padding-top: 10px;
  border-top: 1px dashed var(--b-rule-strong);
  color: var(--b-ivory);
}
.w-card .tcard__money b { font-weight: 700; color: var(--b-ivory); }
.w-card .tcard__money .arrow { color: rgba(244, 241, 234, .55); }

/* Attribution / chevron line beneath the strip — readable teletype. */
.w-card .tcard__attrib {
  margin-top: 8px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px; font-weight: 500; letter-spacing: .04em;
  color: rgba(244, 241, 234, .72);
}
.w-card .tcard__attrib .chev { color: rgba(244, 241, 234, .82); }

/* "NEW" pill above the listings group — outlined gold chip, no fill. */
.w-newpill {
  background: rgba(200, 168, 90, .08);
  border: 1px solid var(--b-accent);
  color: #f0d590;
  letter-spacing: .22em;
  font-size: 10px; font-weight: 800;
  padding: 3px 8px;
  border-radius: 3px;
}
/* Button variant — same chip, but clickable as "Mark all as read."
   Hover bumps the fill so the affordance reads.  Reset native button
   chrome since we're styling it ourselves. */
.w-newpill--btn {
  font: inherit;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease, transform .1s ease;
}
.w-newpill--btn:hover {
  background: rgba(200, 168, 90, .18);
  color: #ffe6a0;
}
.w-newpill--btn:active { transform: scale(.96); }

/* ─── Expanded detail body ──────────────────────────────────────────── */
.w-card .tcard__detail {
  margin-top: 16px; padding-top: 14px;
  border-top: 1px solid var(--b-rule);
}
.w-card .tcard__comps {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 12px 18px;
  padding-bottom: 12px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
}
.w-card .tcard__comps .row .label {
  font-family: 'Inter Tight', sans-serif;
  font-size: 10px; font-weight: 800;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .72);
}
.w-card .tcard__comps .row b {
  color: var(--b-ivory);
  font-size: 14.5px; font-weight: 700;
}
/* BGS 10 reads as bright as PSA 10 — both are headline-tier comps. */
.w-card .tcard__comps .row[data-grade="bgs10"]    b { color: #f0d590; }
.w-card .tcard__comps .row[data-grade="psa10"]    b { color: #f0d590; }
/* Buy / sell zone — green for buy, soft amber for sell, since these
   are live trade-decision signals not pure reference data. */
.w-card .tcard__comps .row[data-grade="buyzone"]  b { color: #4ade80; }
.w-card .tcard__comps .row[data-grade="sellzone"] b { color: var(--b-warm); }
.w-card .tcard__comps .row[data-grade="buyzone"]  .label,
.w-card .tcard__comps .row[data-grade="sellzone"] .label { color: rgba(244, 241, 234, .82); }
/* PSA pop signals — same chrome as the price rows, label slightly
   muted so eye groups them as research metadata next to prices. */
.w-card .tcard__comps .row[data-grade="pop-total"] b,
.w-card .tcard__comps .row[data-grade="gem-rate"] b,
.w-card .tcard__comps .row[data-grade="psa10-pop"] b {
  color: var(--b-ivory);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
}
/* EV ratio is the headline hunting signal — color-coded by tier with
   a slightly heavier presentation than the surrounding rows. */
.w-card .tcard__comps .row.tcard__ev {
  margin-top: 2px;
  padding-top: 8px;
  border-top: 1px dashed var(--b-rule);
}
.w-card .tcard__comps .row.tcard__ev .label {
  color: rgba(244, 241, 234, .82);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  font-size: 11px;
}
.w-card .tcard__comps .row.tcard__ev b {
  font: 800 16px/1 'JetBrains Mono', ui-monospace, monospace;
}
.w-card .tcard__comps .row.tcard__ev--hot  b { color: #4ade80; }
.w-card .tcard__comps .row.tcard__ev--warm b { color: var(--b-warm); }
.w-card .tcard__comps .row.tcard__ev--mute b { color: rgba(244, 241, 234, .55); }
.w-card .tcard__notes {
  background: transparent;
  border: 1px solid var(--b-rule);
  border-radius: 6px;
  font-size: 12.5px; line-height: 1.55; font-weight: 500;
  color: rgba(244, 241, 234, .82);
}

/* ─── Listings group inside an expanded card ─────────────────────────── */
.w-listings {
  margin-top: 16px; padding-top: 12px;
  border-top: 1px solid var(--b-rule);
}
.w-listings__head {
  font-family: 'Inter Tight', sans-serif;
  font-size: 10.5px; font-weight: 800;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .82);
  margin-bottom: 10px;
}
.w-listings__meta {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10.5px; font-weight: 500; letter-spacing: .04em;
  color: rgba(244, 241, 234, .68);
  text-transform: none; opacity: 1;
}
.w-listings__list { gap: 0; }
.w-listings__empty {
  padding: 14px 0;
  font-size: 12.5px; font-weight: 500;
  color: rgba(244, 241, 234, .68);
  font-style: normal;
  border-top: 1px solid var(--b-rule);
  border-bottom: 1px solid var(--b-rule);
}

/* ─── Listing row — full-bleed hairline list (same as .b-row anatomy) ─
   Mobile-first grid: thumbnail on the left spanning two rows, title/
   meta on the right of row 1, action cluster filling row 2.  This
   gives the title the full row width on phones (~280px) instead of
   the ~100px it had when actions were inline.  Desktop collapses
   back to a single row via the breakpoint below. */
.w-listing {
  position: relative;
  display: grid;
  grid-template-columns: 44px 1fr;
  grid-template-areas:
    "thumb body"
    "thumb actions";
  column-gap: 12px;
  row-gap: 8px;
  padding: 12px 0;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--b-rule);
  border-radius: 0;
  transition: background .15s ease;
}
.w-listing > .w-listing__thumb,
.w-listing > .w-listing__thumb--empty,
.w-listing > .w-listing__thumb--btn { grid-area: thumb; align-self: start; }
.w-listing > .w-listing__body    { grid-area: body; min-width: 0; }
.w-listing > .w-listing__actions { grid-area: actions; }
@media (min-width: 640px) {
  /* Single-row layout on tablet+ where there's room for everything. */
  .w-listing {
    display: flex;
    align-items: center;
    grid-template-columns: none;
    grid-template-areas: none;
  }
}
.w-listing--clickable:hover,
.w-listing--clickable:active {
  background: rgba(255, 255, 255, .025);
}
.w-listing__thumb {
  width: 44px; height: 44px;
  border: 1px solid var(--b-rule-strong);
  border-radius: 4px;
  background-color: rgba(255,255,255,.025);
}
.w-listing__thumb--btn:hover { border-color: var(--b-accent-edge); }
.w-listing__title {
  font-family: 'Inter Tight', sans-serif;
  font-size: 13.5px; font-weight: 600;
  letter-spacing: -.005em;
  color: var(--b-ivory);
  white-space: normal;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.w-listing__meta {
  margin-top: 4px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11.5px; font-weight: 500;
  letter-spacing: .02em;
  color: rgba(244, 241, 234, .78);
  font-variant-numeric: tabular-nums;
  gap: 10px;
}
.w-listing__price {
  color: var(--b-ivory);
  font-weight: 700;
}
.w-listing__ends { color: var(--b-warm); font-weight: 600; }
/* Buy-It-Now indicator — same slot as "ends in Xd" but for fixed-price
   listings that have no auction clock.  Quiet ivory tone so it reads
   as informational rather than urgent (auctions ARE urgent; BINs are
   not — they're available until pulled). */
.w-listing__bin {
  color: rgba(244, 241, 234, .58);
  font-weight: 600;
  letter-spacing: .14em;
  font-size: 10px;
  text-transform: uppercase;
}
.w-listing__seller { color: rgba(244, 241, 234, .65); font-weight: 500; }
.w-listing__new {
  color: var(--b-accent);
  background: transparent;
  border: 1px solid var(--b-accent-edge);
  letter-spacing: .22em;
  padding: 1px 6px;
  font-size: 9.5px; font-weight: 800;
}
.w-listing__status {
  color: var(--b-ivory);
  letter-spacing: .22em;
  font-weight: 700;
}
.w-listing__maxbid {
  color: var(--b-accent);
  font-weight: 700;
}
.w-listing__vet {
  color: rgba(244, 241, 234, .68);
  font-weight: 500;
  font-style: normal;
}

/* ─── Buy-zone signal pill ───────────────────────────────────────────
   Surfaced inline in a listing's meta row when the current bid is
   below PriceCharting's dealer-buy guidance.  Two tiers:
     STEAL    — bright green; bid is ≤80% of dealer buy price
     BUY ZONE — soft green; bid is ≤100% of dealer buy price
   Both pop against the row's quiet gold-tone palette without
   competing for the gold accent reserved for the gold-leaf brand. */
.w-buyzone {
  display: inline-block;
  font: 800 9.5px/1 'Inter Tight', system-ui, sans-serif;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  padding: 3px 7px 2px;
  border-radius: 3px;
  white-space: nowrap;
}
.w-buyzone--buy {
  color: #a7f0b3;
  background: rgba(34, 197, 94, .12);
  border: 1px solid rgba(34, 197, 94, .42);
}
.w-buyzone--steal {
  color: #14110a;
  background: #4ade80;
  border: 1px solid #22c55e;
  box-shadow: 0 0 14px -4px rgba(74, 222, 128, .55);
  animation: w-buyzone-pulse 2.6s ease-in-out infinite;
}
@keyframes w-buyzone-pulse {
  0%, 100% { box-shadow: 0 0 14px -4px rgba(74, 222, 128, .55); }
  50%      { box-shadow: 0 0 22px -2px rgba(74, 222, 128, .85); }
}

/* "NEW" listing — quiet gold-tinted background, gold left edge stripe.
   Legacy class — kept for any consumer still using it. */
.w-listing--new {
  background: rgba(200, 168, 90, .04);
  border-color: var(--b-rule);
}
.w-listing--new::after {
  content: '';
  position: absolute; left: -14px; top: 6px; bottom: 6px;
  width: 2px;
  background: var(--b-accent-edge);
}
@media (min-width: 640px) {
  .w-listing--new::after { left: 0; }
}

/* ─── Read / Unread treatment (inverse-contrast model) ────────────────
   The email-inbox visual: UNREAD is the loud, full-saturation default;
   READ items VISUALLY RECEDE.  This is the inverse of "highlight the
   new things" — instead, the eye scans a list and instantly registers
   the things that haven't been touched yet because everything else has
   been dimmed back.  Mirrors Gmail / Mail.app / Reddit visited-link.
*/
.w-listing {
  transition: opacity .35s ease, filter .35s ease, background-color .25s ease, border-color .25s ease;
}

/* UNREAD = the baseline.  Bold ivory title, full-saturation thumbnail,
   3px gold left rail, and a small gold notification dot pinned to the
   thumbnail's top-left corner — the same vocabulary used by every
   modern inbox to mean "there's something here for you." */
.w-listing--unread .w-listing__title {
  font-weight: 700;
  color: var(--b-ivory);
}
.w-listing--unread::before {
  content: '';
  position: absolute; left: -14px; top: 8px; bottom: 8px;
  width: 3px;
  background: var(--b-accent);
  border-radius: 1px;
  box-shadow: 0 0 8px -1px rgba(200, 168, 90, .55);
}
@media (min-width: 640px) {
  .w-listing--unread::before { left: 0; }
}
/* Pulsing gold dot on the thumbnail.  Position is relative to the row,
   anchored to the thumbnail corner.  Subtle — this is a notification
   tell, not a UI button. */
.w-listing--unread .w-listing__thumb {
  position: relative;
  box-shadow: 0 0 0 1px rgba(200, 168, 90, .35), 0 0 12px -2px rgba(200, 168, 90, .35);
}
.w-listing--unread .w-listing__thumb::after {
  content: '';
  position: absolute; top: -3px; right: -3px;
  width: 9px; height: 9px;
  background: var(--b-accent);
  border: 2px solid var(--bg-primary);
  border-radius: 50%;
  box-shadow: 0 0 8px rgba(200, 168, 90, .8);
  animation: w-unread-pulse 2.4s ease-in-out infinite;
}
@keyframes w-unread-pulse {
  0%, 100% { box-shadow: 0 0 6px rgba(200, 168, 90, .55); }
  50%      { box-shadow: 0 0 14px rgba(200, 168, 90, .95); }
}

/* READ = recedes.  Lower opacity + slight desaturation on the row
   itself; muted title weight + ivory→muted color on the title.  The
   row stays clickable, but the eye walks past it.  The contrast is
   intentionally strong — this is what makes scanning 20 listings work. */
.w-listing:not(.w-listing--unread) {
  opacity: .62;
  filter: saturate(.85);
}
.w-listing:not(.w-listing--unread) .w-listing__title {
  font-weight: 500;
  color: rgba(244, 241, 234, .58);
}
.w-listing:not(.w-listing--unread):hover {
  opacity: .85;
  filter: none;
}

/* "UNREAD" chip — kept available but no longer needed as the primary
   tell; the thumbnail dot + recession do the heavy lifting.  Hidden
   for now to keep the meta row tight; flip `display: inline-block`
   to bring it back if you want belt-and-suspenders signaling. */
.w-listing__unread {
  display: none;
  color: var(--b-accent);
  background: rgba(200, 168, 90, .10);
  border: 1px solid var(--b-accent-edge);
  letter-spacing: .22em;
  padding: 1px 6px;
  font-size: 9.5px; font-weight: 800;
  text-transform: uppercase;
  border-radius: 2px;
}

/* Focused listing — was blue.  Now gold left rail + slightly tinted bg. */
.w-listing--focused {
  padding-left: 12px;
  background: rgba(200, 168, 90, .045);
  border-color: var(--b-rule);
}
.w-listing--focused::before {
  content: '';
  position: absolute; left: 0; top: 6px; bottom: 6px;
  width: 3px;
  background: var(--b-accent);
  border-radius: 0;
}

/* Action button cluster — tighten and tone down to fit the language.
   On mobile the cluster sits on its own row beneath the title/meta
   and gets a hairline divider above it for visual separation. */
.w-listing__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.w-listing__actions .btn-sm {
  padding: 7px 10px;
  font-size: 11px;
  letter-spacing: .04em;
  min-height: 34px;
  border-radius: 4px;
}
@media (max-width: 639px) {
  .w-listing__actions {
    padding-top: 6px;
    border-top: 1px dashed rgba(255, 255, 255, .04);
    width: 100%;
  }
  .w-listing__actions .btn-sm,
  .w-listing__actions .w-pregrade-btn { flex: 1 1 auto; min-height: 36px; }
  /* Dismiss × stays compact — no need to flex it. */
  .w-listing__actions > button:last-child:not(.w-pregrade-btn) { flex: 0 0 auto; }
}

@media (max-width: 480px) {
  .w-listing { column-gap: 10px; }
  .w-listing__thumb { width: 44px; height: 44px; }
  .w-listing__title { font-size: 13px; }
}

/* ─── Inline detail panel (when a listing is expanded) ───────────────── */
.w-detail {
  margin: 0 0 8px;
  padding: 14px 14px 16px;
  background: rgba(255, 255, 255, .015);
  border: none;
  border-top: 1px solid var(--b-rule);
  border-bottom: 1px solid var(--b-rule);
  border-radius: 0;
}
.w-detail__row { font-family: 'Inter Tight', sans-serif; font-size: 13px; }
.w-detail__label {
  font-size: 10px; font-weight: 800;
  letter-spacing: .22em;
  color: rgba(244, 241, 234, .82);
}
.w-detail__value {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 13px; font-weight: 600;
  color: var(--b-ivory);
  font-variant-numeric: tabular-nums;
}
.w-detail__thumb { border-radius: 4px; border-color: var(--b-rule-strong); }
.w-detail__thumb:hover { border-color: var(--b-accent-edge); }

/* "Tighten query" / "Refresh listings" / "Open on eBay" action row at
   the bottom of an expanded card — outlined chips that read consistent. */
.w-card .tcard__actions { gap: 6px; padding-top: 4px; }
.w-card .tcard__actions .btn-secondary {
  background: transparent;
  border: 1px solid var(--b-rule-strong);
  color: rgba(244, 241, 234, .85);
  font-size: 11px;
  letter-spacing: .04em;
  border-radius: 4px;
}
.w-card .tcard__actions .btn-secondary:hover,
.w-card .tcard__actions .btn-secondary:active {
  border-color: var(--b-accent-edge);
  color: var(--b-accent);
  background: var(--b-accent-soft);
}
.w-card .tcard__actions .btn-primary {
  border-radius: 4px;
  font-size: 11px;
  letter-spacing: .04em;
}


/* ════════════════════════════════════════════════════════════════════════
   Search mode — chrome collapse for mobile PWA usability.
   ────────────────────────────────────────────────────────────────────────
   When body.is-search-active is set (search input has a non-empty query),
   we hide everything that's not search itself: masthead, dateline,
   legend, filters disclosure, and the section eyebrow.  This recovers
   ~290px of vertical space — on iPhone with the keyboard up, that's
   the difference between "1 row visible" and "5–6 rows visible."

   Triggered ON: input focus + non-empty trimmed value, or value typed.
   Triggered OFF: input cleared, or a row tapped (modal opens).
   ════════════════════════════════════════════════════════════════════════ */
body.is-search-active .masthead,
body.is-search-active .b-masthead,
body.is-search-active .b-legend,
body.is-search-active .b-filters-disclosure,
body.is-search-active .b-eyebrow {
  display: none !important;
}
/* When chrome collapses, give the sticky search bar a quiet gold rule
   underneath so the disappearance of dividers above doesn't read as a
   broken-looking floating bar. */
body.is-search-active .b-search {
  border-bottom: 1px solid var(--b-accent-edge);
  margin-bottom: 0;
}
/* Tighten the result list spacing in search mode — the surrounding
   chrome is gone so we can pull the rows up against the search bar. */
body.is-search-active .b-results { margin-top: 8px; }

/* ════════════════════════════════════════════════════════════════════════
   Watchlist — keyboard focus rings.
   Subtle gold inset on the focused card / listing so keyboard users see
   their selection.  :focus-visible (not :focus) so mouse clicks don't
   leave a ring on the row after the click lands.
   ════════════════════════════════════════════════════════════════════════ */
.w-card.tcard:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--b-accent-edge),
              inset 3px 0 0 var(--b-accent);
}
.w-card.tcard.is-open:focus-visible {
  /* When a card is expanded and still keyboard-focused, dim the ring so
     the user knows the focus has logically moved past the header. */
  box-shadow: inset 0 0 0 1px var(--b-rule),
              inset 3px 0 0 var(--b-accent-edge);
}
.w-listing:focus-visible {
  outline: none;
  background: rgba(200, 168, 90, .06);
  box-shadow: inset 2px 0 0 var(--b-accent);
}

/* ════════════════════════════════════════════════════════════════════════
   Lightbox — magnifier loupe + bottom info banner + boundary bump.
   Layered over the existing lightbox styles (defined earlier).
   ════════════════════════════════════════════════════════════════════════ */

/* ─── Bottom info banner ──────────────────────────────────────────────
   Slick semi-opaque strip pinned to the lightbox's bottom edge.
   Backdrop-blurred so the photo behind it stays visible.  Title +
   meta on the left, action chips on the right.  On narrow viewports
   the actions wrap below.  Counter (top-right of the stage) keeps the
   image position; this banner is for *listing* identity. */
.lightbox__banner {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  width: min(86vw, 880px);
  display: flex; align-items: center; gap: 14px;
  padding: 12px 16px;
  background: rgba(10, 10, 15, .68);
  backdrop-filter: saturate(140%) blur(16px);
  -webkit-backdrop-filter: saturate(140%) blur(16px);
  border: 1px solid var(--b-rule-strong);
  border-radius: 8px;
  box-shadow: 0 12px 36px -16px rgba(0, 0, 0, .6),
              inset 0 1px 0 rgba(255, 255, 255, .04);
  font-family: 'Inter Tight', sans-serif;
  color: var(--b-ivory);
  pointer-events: auto;
  z-index: 2;
}
.lightbox__banner-text {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 4px;
}
.lightbox__banner-title {
  font-size: 13.5px; font-weight: 600;
  letter-spacing: -.005em;
  line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--b-ivory);
}
.lightbox__banner-meta {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: .02em;
  color: rgba(244, 241, 234, .65);
  font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ─── Three-cell price strip in the lightbox banner ───────────────────
   CURRENT BID / RAW / PSA 10.  All three carry the same scale so the
   eye flicks across them on a single horizontal line.  Color carries
   the role:
     • Bid is GOLD — the actionable number you're deciding on
     • PSA 10 is IVORY-bold — the upside you'd realize after grading
     • Raw is muted ivory — the floor / sanity-check
   Vertical hairlines separate them from the title cell on the left
   and the action chip on the right. */
.lightbox__banner-bid {
  flex-shrink: 0;
  display: flex; flex-direction: column; align-items: flex-end; gap: 4px;
  padding: 0 14px;
  border-left: 1px solid var(--b-rule-strong);
  min-width: 0;
}
.lightbox__banner-actions {
  border-left: 1px solid var(--b-rule-strong);
  padding-left: 14px;
}
.lightbox__banner-bid-lbl {
  font-family: 'Inter Tight', sans-serif;
  font-size: 9px; font-weight: 800;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: rgba(244, 241, 234, .42);
  white-space: nowrap;
}
.lightbox__banner-bid-val {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 22px; font-weight: 700;
  letter-spacing: -.015em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  white-space: nowrap;
}
.lightbox__banner-bid--current .lightbox__banner-bid-val { color: var(--b-accent); }
.lightbox__banner-bid--raw     .lightbox__banner-bid-val { color: rgba(244, 241, 234, .55); font-weight: 500; }
.lightbox__banner-bid--psa10   .lightbox__banner-bid-val { color: var(--b-ivory); }
.lightbox__banner-bid--empty   .lightbox__banner-bid-val { color: rgba(244, 241, 234, .25); font-weight: 500; }

/* On narrow viewports the price strip needs to wrap.  Drop the title
   to its own row above and let the three cells sit on a row beneath
   without left-borders (becomes a strip rather than columns). */
@media (max-width: 760px) {
  .lightbox__banner { flex-wrap: wrap; gap: 10px; }
  .lightbox__banner-text { flex: 1 0 100%; }
  .lightbox__banner-bid {
    flex: 1 1 0; min-width: 0;
    align-items: flex-start;
    padding: 0 12px;
    border-left: none;
    border-right: 1px solid var(--b-rule-strong);
  }
  .lightbox__banner-bid:nth-of-type(3) { border-right: 1px solid var(--b-rule-strong); }
  .lightbox__banner-bid:last-of-type   { border-right: none; padding-right: 0; }
  .lightbox__banner-bid-val { font-size: 19px; }
  .lightbox__banner-actions { border-left: none; padding-left: 0; flex: 1 0 100%; justify-content: flex-end; }
}
@media (max-width: 480px) {
  .lightbox__banner-bid-val { font-size: 17px; }
  .lightbox__banner-bid-lbl { font-size: 8.5px; letter-spacing: .22em; }
}

.lightbox__banner-actions {
  flex-shrink: 0;
  display: flex; gap: 8px;
}
.lightbox__banner-btn {
  font-family: 'Inter Tight', sans-serif;
  font-size: 10.5px; font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding: 8px 12px;
  color: var(--b-ivory);
  background: transparent;
  border: 1px solid var(--b-rule-strong);
  border-radius: 4px;
  text-decoration: none;
  white-space: nowrap;
  transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.lightbox__banner-btn:hover,
.lightbox__banner-btn:focus-visible {
  color: var(--b-accent);
  border-color: var(--b-accent-edge);
  background: var(--b-accent-soft);
  outline: none;
}
@media (max-width: 600px) {
  .lightbox__banner {
    width: calc(100vw - 24px);
    bottom: 12px;
    padding: 10px 12px;
    flex-wrap: wrap;
  }
  .lightbox__banner-title { font-size: 12.5px; white-space: normal; }
  .lightbox__banner-meta  { white-space: normal; }
  .lightbox__banner-actions { width: 100%; justify-content: flex-end; }
}

/* ─── Magnifier loupe (eBay-style) ────────────────────────────────────
   A circular div positioned absolutely inside the stage.  JS sets
   background-image to the photo URL, background-size to LOUPE_ZOOM ×
   the displayed image dimensions, and background-position to pan the
   zoomed image so the cursor's hover point lands at the loupe center.
   Hidden by default; .is-active when the pointer is over the image. */
.lightbox__loupe {
  position: absolute;
  /* Compact loupe — was 220px which felt like a porthole; 110px reads
     as a precise jeweler's loupe instead.  Bigger feels like an
     instagram filter, smaller feels professional. */
  width: 110px; height: 110px;
  pointer-events: none;
  border-radius: 50%;
  border: 1.5px solid var(--b-accent-edge);
  background-color: #000;
  background-repeat: no-repeat;
  box-shadow: 0 0 0 2px rgba(0, 0, 0, .5),
              0 8px 22px -6px rgba(0, 0, 0, .8),
              inset 0 0 0 1px rgba(255, 255, 255, .08);
  opacity: 0;
  transition: opacity .12s ease;
  z-index: 3;
}
.lightbox__loupe.is-active { opacity: 1; }
@media (hover: none) {
  .lightbox__loupe { width: 96px; height: 96px; }
}

/* ─── Boundary bump animation ────────────────────────────────────────
   When the user arrows past the very first or very last photo of the
   first/last listing, the entire lightbox stage shakes slightly so the
   user knows they hit a wall.  Subtler than wrapping; clearer than
   silent ignore. */
@keyframes lightbox-bump-prev {
  0% { transform: translateX(0); }
  40% { transform: translateX(12px); }
  100% { transform: translateX(0); }
}
@keyframes lightbox-bump-next {
  0% { transform: translateX(0); }
  40% { transform: translateX(-12px); }
  100% { transform: translateX(0); }
}
.lightbox--bump-prev .lightbox__stage { animation: lightbox-bump-prev .18s ease both; }
.lightbox--bump-next .lightbox__stage { animation: lightbox-bump-next .18s ease both; }

/* The image is interactive (loupe), so hide the system text-cursor on
   hover and use crosshair to signal "you can magnify here." */
.lightbox__img { cursor: crosshair; }

/* The counter sits above the stage now (banner takes the bottom).  Pin
   it with position:absolute so the prior margin-top placement falls away. */
.lightbox__counter {
  position: absolute;
  margin: 0;
  bottom: auto;
  top: 18px;
  left: 50%;
  transform: translateX(-50%);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--b-ivory);
  padding: 6px 12px;
  background: rgba(10, 10, 15, .55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--b-rule-strong);
  border-radius: 999px;
  z-index: 2;
}
