/* app.css — the app's stylesheet, served from 'self' (shared/app.css).
   ➕ Oct 21, 2026 UTC (Oct 20 ET; OI-88, security batch decision H5, Justin
   Bates, Oct 20, 2026): moved byte-for-byte out of index.html's one <style>
   block, so style-src needs neither 'unsafe-inline' nor a style hash. The
   rules below this comment are that block as it stood at 9f50f96, unchanged,
   followed by the "former style attributes" section at the end. */
  :root{
    color-scheme: light dark;

    /* ============ DESIGN TOKENS — Flipwell Visual System ============
       See app/design-spec.md. Light ("Paper") is the :root default; dark
       ("Vault") tokens live in the prefers-color-scheme block below and are
       duplicated under [data-theme="dark"] so a manual override can win
       over system preference. Geometry (radii/shadows/type) is identical
       across themes — only the palette and a few semantic aliases swap. */

    /* ---- Surfaces (light) ---- */
    --bg:#F7F5F0;
    --bg-rgb: 247,245,240;
    --surface:#FFFFFF;
    --surface-sunken:#F7F5F0;
    --surface-raised:#FFFFFF;
    --border:#E8E3D8;
    --border-soft:#F0ECE2;

    /* ---- Ink (light) ---- */
    --ink:#1C1B18;
    --ink-rgb: 28,27,24;
    --cream-rgb: 242,233,216; /* fixed light-alpha family for text/borders on the always-dark header/tab chrome; intentionally NOT theme-relative */
    --ink-secondary:#4A463E;
    --ink-muted:#8C877B;
    --ink-faint:#9A968B;

    /* ---- Profit / forest accent (light) ---- */
    --profit:#2F4A3C;
    --profit-ink-on:#FBFAF7;
    --profit-soft-bg:#EDF2EE;
    --profit-soft-border:#D3E0D7;
    --profit-label:#7C9A88;
    --profit-tint-1:#A9C6B4;
    --profit-tint-2:#CFE0D6;

    /* ---- Loss (light) ---- */
    --loss:#8C3A2E;
    --loss-soft-bg:#F6EBE8;
    --loss-soft-border:#E5CFC9;

    /* ---- Card-image placeholder (light) ---- */
    --grad-thumb: repeating-linear-gradient(135deg, #F2EFE6 0 4px, #E8E4D8 4px 8px);
    --thumb-border:#E8E3D8;

    /* ---- Typography ---- */
    --font-sans: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
    --font-serif: "Newsreader", Georgia, "Times New Roman", serif;
    --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

    /* ---- Border radius scale ---- */
    --r-hero:24px; --r-card:20px; --r-inset:14px; --r-chip:9px;
    --r-button:11px; --r-tab-pill:10px; --r-thumb:8px; --r-pill:999px;

    /* ---- Box shadows (light) ---- */
    --shadow-hero:  0 1px 2px rgba(28,27,24,.05), 0 16px 32px -20px rgba(28,27,24,.30);
    --shadow-card:  0 1px 2px rgba(28,27,24,.05), 0 12px 26px -18px rgba(28,27,24,.30);
    --shadow-tabbar: 0 -8px 24px -18px rgba(28,27,24,.50);
    --shadow-button: 0 1px 2px rgba(28,27,24,.05);
    --shadow-tab-pill: 0 4px 12px -6px rgba(47,74,60,.90);
    --shadow-thumb: 0 2px 6px -3px rgba(28,27,24,.30);

    /* ---- Gradients (light) ---- */
    --grad-card-hero: linear-gradient(180deg, #FFFFFF, #FCFAF6);
    --grad-card-list: #FFFFFF;

    /* ---- Semantic aliases that differ by theme (used by the two rebuilt
       recipe components below) ---- */
    --hero-value-color: var(--ink);
    --hero-cents-color: var(--ink-secondary);
    --hero-value-shadow: none;
    --hero-glow-bg: transparent;
    --live-pill-bg: var(--profit-soft-bg);
    --live-pill-text: var(--profit);
    --live-pill-border: var(--profit-soft-border);
    --link-color: var(--profit);
    --num-weight: 500;
    --value-weight: 500;
    --tab-active-fill: var(--profit);
    --tab-active-ink: var(--profit-ink-on);
    --tab-active-label: var(--profit);

    /* ---- Legacy tokens, remapped to the new system so every existing
       (not-yet-rebuilt) component repaints via the new palette immediately
       without its markup/CSS changing yet ---- */
    --felt: var(--profit);
    --felt-light: var(--profit-tint-2);
    --felt-deep: var(--ink);
    --cream: var(--surface);
    --cream-dark: var(--surface-sunken);
    --gold: #C6971F;
    --gold-light: #E3BE55;
    --slab-white: var(--surface);
    --line: var(--border);
    --line-cream: var(--border-soft);
    --shadow: var(--shadow-card);
    --radius-card: var(--r-card);
    --radius-sm: var(--r-chip);
    --red: #A93226;
    --red-dark: #822720;
  }

  @media (prefers-color-scheme: dark){
    :root:not([data-theme="light"]){
      --bg:#0A0C11;
      --bg-rgb: 10,12,17;
      --surface: var(--surface-flat);
      --surface-flat:#141822;
      --surface-sunken: rgba(255,255,255,0.04);
      --surface-raised: var(--surface-flat);
      --border: rgba(255,255,255,0.07);
      --border-soft: rgba(255,255,255,0.06);
      --hairline-top: rgba(255,255,255,0.06);

      --ink:#F2F0EA;
      --ink-rgb: 242,240,234;
      --ink-strong-num:#EDEBE4;
      --ink-secondary:#C6CBD6;
      --ink-muted:#8E96A6;
      --ink-faint:#656C7C;

      --gold:#D9B968; --gold-bright:#EFD79A; --gold-deep:#C9A85C;
      --gold-text-glow:#F7EBC8; --gold-pale:#F0D896; --gold-ink-on:#141822;
      --gold-soft-bg: rgba(217,185,104,0.12); --gold-soft-border: rgba(217,185,104,0.28);

      --profit:#6ECB99; --profit-soft-bg: rgba(110,203,153,0.12); --profit-soft-border: rgba(110,203,153,0.24);
      --profit-label:#7E9E8B;
      --loss:#E0765F; --loss-soft-bg: rgba(224,118,95,0.12); --loss-soft-border: rgba(224,118,95,0.26);

      --grad-thumb: repeating-linear-gradient(135deg, #222734 0 4px, #1B1F2A 4px 8px);
      --thumb-border: rgba(255,255,255,0.06);

      --shadow-hero: inset 0 1px 0 rgba(255,255,255,.06), 0 18px 40px -22px rgba(0,0,0,.90);
      --shadow-card: inset 0 1px 0 rgba(255,255,255,.05), 0 12px 26px -18px rgba(0,0,0,.95);
      --shadow-tabbar: 0 -8px 24px -18px rgba(0,0,0,.90);
      --shadow-tab-pill: 0 4px 14px -5px rgba(217,185,104,.80);
      --shadow-badge-gold: 0 3px 10px -4px rgba(217,185,104,.70);

      --grad-card-dark: linear-gradient(158deg, #1B2030 0%, #12151E 46%, #0E1118 100%);
      --grad-list-dark: linear-gradient(180deg, #171B26, #12151E);
      --grad-card-hero: var(--grad-card-dark);
      --grad-card-list: var(--grad-list-dark);
      --grad-gold: linear-gradient(180deg, #EFD79A, #D9B968);

      --hero-value-color: var(--gold-text-glow);
      --hero-cents-color: var(--gold-deep);
      --hero-value-shadow: 0 0 28px rgba(217,185,104,.45);
      --hero-glow-bg: rgba(217,185,104,.20);
      --live-pill-bg: var(--gold-soft-bg);
      --live-pill-text: var(--gold);
      --live-pill-border: var(--gold-soft-border);
      --link-color: var(--gold);
      --num-weight: 600;
      --value-weight: 600;
      --tab-active-fill: var(--grad-gold);
      --tab-active-ink: var(--gold-ink-on);
      --tab-active-label: var(--gold-pale);

      --felt: var(--surface-flat);
      --felt-light: #1F4237;
      --felt-deep: var(--ink); /* fixed: felt-deep is used as TEXT color in most legacy rules, paired with --cream as bg — must track --ink, not a bg-toned value, or it collapses onto --cream */
      --cream: var(--surface-flat);
      --cream-dark: rgba(255,255,255,0.04);
      --gold-light: #EFD79A;
      --slab-white: var(--surface-flat);
      --red: #E0765F; --red-dark: #C25C46;
    }
  }
  [data-theme="dark"]{
    --bg:#0A0C11;
    --bg-rgb: 10,12,17;
    --surface: var(--surface-flat);
    --surface-flat:#141822;
    --surface-sunken: rgba(255,255,255,0.04);
    --surface-raised: var(--surface-flat);
    --border: rgba(255,255,255,0.07);
    --border-soft: rgba(255,255,255,0.06);
    --hairline-top: rgba(255,255,255,0.06);

    --ink:#F2F0EA;
    --ink-rgb: 242,240,234;
    --ink-strong-num:#EDEBE4;
    --ink-secondary:#C6CBD6;
    --ink-muted:#8E96A6;
    --ink-faint:#656C7C;

    --gold:#D9B968; --gold-bright:#EFD79A; --gold-deep:#C9A85C;
    --gold-text-glow:#F7EBC8; --gold-pale:#F0D896; --gold-ink-on:#141822;
    --gold-soft-bg: rgba(217,185,104,0.12); --gold-soft-border: rgba(217,185,104,0.28);

    --profit:#6ECB99; --profit-soft-bg: rgba(110,203,153,0.12); --profit-soft-border: rgba(110,203,153,0.24);
    --profit-label:#7E9E8B;
    --loss:#E0765F; --loss-soft-bg: rgba(224,118,95,0.12); --loss-soft-border: rgba(224,118,95,0.26);

    --grad-thumb: repeating-linear-gradient(135deg, #222734 0 4px, #1B1F2A 4px 8px);
    --thumb-border: rgba(255,255,255,0.06);

    --shadow-hero: inset 0 1px 0 rgba(255,255,255,.06), 0 18px 40px -22px rgba(0,0,0,.90);
    --shadow-card: inset 0 1px 0 rgba(255,255,255,.05), 0 12px 26px -18px rgba(0,0,0,.95);
    --shadow-tabbar: 0 -8px 24px -18px rgba(0,0,0,.90);
    --shadow-tab-pill: 0 4px 14px -5px rgba(217,185,104,.80);
    --shadow-badge-gold: 0 3px 10px -4px rgba(217,185,104,.70);

    --grad-card-dark: linear-gradient(158deg, #1B2030 0%, #12151E 46%, #0E1118 100%);
    --grad-list-dark: linear-gradient(180deg, #171B26, #12151E);
    --grad-card-hero: var(--grad-card-dark);
    --grad-card-list: var(--grad-list-dark);
    --grad-gold: linear-gradient(180deg, #EFD79A, #D9B968);

    --hero-value-color: var(--gold-text-glow);
    --hero-cents-color: var(--gold-deep);
    --hero-value-shadow: 0 0 28px rgba(217,185,104,.45);
    --hero-glow-bg: rgba(217,185,104,.20);
    --live-pill-bg: var(--gold-soft-bg);
    --live-pill-text: var(--gold);
    --live-pill-border: var(--gold-soft-border);
    --link-color: var(--gold);
    --num-weight: 600;
    --value-weight: 600;
    --tab-active-fill: var(--grad-gold);
    --tab-active-ink: var(--gold-ink-on);
    --tab-active-label: var(--gold-pale);

    --felt: var(--surface-flat);
    --felt-light: #1F4237;
    --felt-deep: var(--ink); /* see media-query block comment above */
    --cream: var(--surface-flat);
    --cream-dark: rgba(255,255,255,0.04);
    --gold-light: #EFD79A;
    --slab-white: var(--surface-flat);
    --red: #E0765F; --red-dark: #C25C46;
  }

  *{box-sizing:border-box;}
  html,body{margin:0;padding:0;}
  /* Pinch/double-tap zoom disabled app-wide (belt-and-suspenders alongside the
     viewport meta tag — Capacitor's WKWebView doesn't always honor
     user-scalable=no as strictly as mobile Safari). Re-enabled selectively,
     scoped to specific elements, for the camera viewfinder and card images.
     pan-y only, not pan-x: nothing in this app scrolls horizontally, so
     allowing horizontal panning only produced unwanted sideways drift. */
  html{touch-action:pan-y;}
  body{
    background:var(--bg);
    color:var(--ink);
    font-family:var(--font-sans);
    -webkit-font-smoothing:antialiased;
    min-height:100vh;
  }
  .mono{font-family:'Space Mono', monospace;}
  .display{font-family:'Anton', sans-serif; letter-spacing:0.02em; text-transform:uppercase;}

  ::selection{background:var(--gold); color:var(--ink);}

  button{font-family:inherit; cursor:pointer;}
  input,select,textarea{font-family:var(--font-sans); font-size:16px;}

  /* ---------- HEADER (rebuilt to the design-spec's Portfolio header card recipe) ---------- */
  .app-header{
    padding:0 18px 16px;
    background:var(--bg);
    position:relative;
  }
  /* Sticky, not part of the normal scroll flow — the brand-mark/title/settings
     row stays pinned below the status bar at all times, so it can never slide
     up behind the time/signal/battery icons the way non-fixed content does
     while scrolling. env(safe-area-inset-top) clears the status bar/notch —
     viewport-fit=cover lets the page extend edge-to-edge under it, and
     there's no native status-bar plugin inserting this inset natively (same
     reasoning as the bottom tab bar's safe-area-inset-bottom). Everything
     else (the ledger subtitle, the Portfolio Value card) stays regular
     scrolling content in .app-header below. */
  .brand{
    display:flex; align-items:baseline; gap:10px;
    position:sticky; top:0; z-index:10;
    background:var(--bg);
    padding:calc(14px + env(safe-area-inset-top)) 18px 14px;
  }
  .settings-btn{
    margin-left:auto; align-self:center;
    background:var(--surface-raised); border:1px solid var(--border); color:var(--ink);
    width:34px; height:34px; border-radius:var(--r-button); font-size:15px; line-height:1;
    box-shadow:var(--shadow-button);
    display:flex; align-items:center; justify-content:center;
  }
  .settings-btn:active{transform:scale(0.96);}
  /* The OI-74 icon mark (brand/flipwell/oi-74/icon/flipwell-icon-master.svg,
     inlined): the badge's 34px box and corner radius clip the full-bleed
     master. The zero-width ::before keeps the baseline the old "BC" text gave
     the row, so the <h1> sits exactly where it did. */
  .brand-mark{
    display:inline-flex; align-items:center;
    width:34px; height:34px;
    border-radius:var(--r-button);
    overflow:hidden;
    font-family:var(--font-sans);
    font-weight:600;
    font-size:15px;
    flex-shrink:0;
  }
  .brand-mark::before{content:"\200B";}
  .brand-mark svg{display:block; width:100%; height:100%;}
  .brand h1{
    font-family:var(--font-sans); font-weight:600; font-size:21px; letter-spacing:-0.5px;
    margin:0; color:var(--ink);
  }
  .brand-sub{
    margin:2px 0 0 44px; font-family:var(--font-sans); font-size:11px; font-weight:600;
    letter-spacing:1.6px; text-transform:uppercase; color:var(--ink-muted);
  }

  /* ---- Portfolio header card ("hero card") ----
     Recipe (design-spec.md §9): eyebrow row (label + LIVE pill) -> value
     (mono, cents styled smaller/muted) -> divider -> three equal stat
     columns. The spec's delta/gain-chip row is intentionally omitted: this
     app has no stored portfolio-history time series to compute a real 30d
     delta from, and a fabricated number would be worse than none. */
  .hero-card{
    margin-top:16px;
    position:relative; overflow:hidden;
    background:var(--grad-card-hero);
    border-radius:var(--r-hero);
    border:1px solid var(--border);
    box-shadow:var(--shadow-hero);
    padding:22px 20px 18px;
  }
  .hero-card::before{
    content:""; position:absolute; top:-80px; right:-50px;
    width:230px; height:230px; border-radius:50%;
    background:radial-gradient(circle, var(--hero-glow-bg), transparent 68%);
    pointer-events:none;
  }
  .hero-eyebrow-row{display:flex; align-items:center; justify-content:space-between; position:relative;}
  .hero-eyebrow{
    font-family:var(--font-sans); font-size:10.5px; font-weight:600; letter-spacing:1.4px;
    text-transform:uppercase; color:var(--ink-muted);
  }
  .live-pill{
    font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:10.5px; font-weight:500;
    padding:5px 8px; border-radius:var(--r-pill);
    background:var(--live-pill-bg); color:var(--live-pill-text); border:1px solid var(--live-pill-border);
  }
  .hero-value-row{margin-top:14px; position:relative;}
  .hero-value{
    font-family:var(--font-mono); font-variant-numeric:tabular-nums;
    font-size:44px; font-weight:var(--value-weight); letter-spacing:-2px;
    color:var(--hero-value-color); text-shadow:var(--hero-value-shadow);
  }
  .hero-value-cents{font-size:25px; letter-spacing:-0.5px; color:var(--hero-cents-color);}
  .hero-divider{height:1px; background:var(--border-soft); margin:18px 0 16px;}
  .hero-stats{display:flex;}
  .hero-stat{flex:1; display:flex; flex-direction:column; align-items:center; gap:5px;}
  .hero-stat-num{
    font-family:var(--font-mono); font-variant-numeric:tabular-nums;
    font-size:17px; font-weight:var(--num-weight); color:var(--ink);
  }
  .hero-stat-label{
    font-family:var(--font-sans); font-size:9.5px; letter-spacing:0.7px; text-transform:uppercase;
    color:var(--ink-faint);
  }

  /* ---------- TAB BAR (design-spec.md §9 "Tab bar" recipe) ----
     6 equal flex items, blur over a 90%-opaque bg, 1px top border +
     tabbar shadow. Active = filled pill behind the icon (forest in light,
     gold gradient in dark) + weight-600 label in the accent color.
     Fixed to the bottom (the spec's icon/pill sizing only makes sense as
     a bottom bar) with env(safe-area-inset-bottom) as extra padding. */
  .tabs{
    position:fixed; left:0; right:0; bottom:0; z-index:30;
    display:flex;
    padding:10px 6px calc(8px + env(safe-area-inset-bottom));
    background:rgba(var(--bg-rgb), 0.9);
    backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
    border-top:1px solid var(--border);
    box-shadow:var(--shadow-tabbar);
  }
  .tab{
    flex:1; min-height:44px;
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:5px;
    background:none; border:none; padding:2px;
    font-family:var(--font-sans); font-size:9.5px; font-weight:500; color:var(--ink-muted);
    transition:color 0.24s ease;
  }
  .tab-icon-wrap{
    width:34px; height:26px; border-radius:var(--r-tab-pill);
    display:flex; align-items:center; justify-content:center;
    transition:background 0.24s ease;
  }
  .tab-icon{width:21px; height:21px; display:block;}
  .tab.active .tab-icon-wrap{background:var(--tab-active-fill); box-shadow:var(--shadow-tab-pill);}
  .tab.active .tab-icon-wrap .tab-icon{color:var(--tab-active-ink);}
  .tab.active .tab-label{font-weight:600; color:var(--tab-active-label);}
  @media (prefers-reduced-motion: reduce){ .tab, .tab-icon-wrap{transition:none;} }

  main{padding:16px 18px calc(84px + env(safe-area-inset-bottom));}
  .panel{display:none;}
  .panel.active{display:block; animation:fadeIn 0.25s ease;}
  @keyframes fadeIn{from{opacity:0; transform:translateY(4px);} to{opacity:1; transform:translateY(0);}}

  /* ---------- CARDS / SECTIONS ---------- */
  .sheet{
    background:var(--cream);
    color:var(--ink);
    border-radius:var(--radius-card);
    padding:16px;
    box-shadow:var(--shadow);
    border:1px solid rgba(0,0,0,0.06);
  }
  .sheet + .sheet{margin-top:14px;}
  .sheet-title{
    font-family:'Anton', sans-serif; letter-spacing:0.03em; text-transform:uppercase;
    font-size:15px; margin:0 0 12px; color:var(--felt-deep);
    display:flex; align-items:center; gap:8px;
  }

  .field-row{display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-bottom:10px;}
  .field{display:flex; flex-direction:column; gap:4px; margin-bottom:10px; min-width:0;}
  .field label{
    font-size:10px; letter-spacing:0.1em; text-transform:uppercase; color:rgba(var(--ink-rgb),0.55);
  }
  .field input, .field select, .field textarea{
    width:100%;
    border:1px solid rgba(var(--ink-rgb),0.2);
    background:var(--slab-white);
    border-radius:4px;
    padding:9px 10px;
    color:var(--ink);
  }
  .field input:focus, .field select:focus, .field textarea:focus{
    outline:2px solid var(--red); outline-offset:1px;
  }
  .field textarea{resize:vertical; min-height:54px;}
  /* 🔧 Oct 10, 2026 UTC, later (account owner, D3): the 18+ attestation row on
     the Sign Up form and the waitlist screen — one left-aligned row, the
     checkbox at its natural size then the label, both clickable, at phone and
     desktop widths. Outside .field on purpose (see the markup). */
  .attest-row{display:flex; flex-direction:row; align-items:center; gap:10px; margin:2px 0 12px; text-align:left;}
  .attest-row.hidden{display:none;}
  .attest-row input[type="checkbox"]{flex:0 0 auto; width:18px; height:18px; margin:0; padding:0; cursor:pointer;}
  .attest-row label{flex:1 1 auto; font-size:13px; line-height:1.4; color:var(--ink); cursor:pointer; text-align:left;}

  .toggle-row{display:flex; gap:8px; margin-bottom:10px;}
  .toggle-btn{
    flex:1; padding:9px 6px; border:1px solid rgba(var(--ink-rgb),0.25); background:var(--slab-white);
    border-radius:4px; font-size:12px; letter-spacing:0.06em; text-transform:uppercase;
    color:var(--ink); font-family:'Space Mono', monospace;
  }
  .toggle-btn.active{
    background:var(--felt-deep); color:var(--cream); border-color:var(--felt-deep);
  }

  .btn{
    display:inline-flex; align-items:center; justify-content:center; gap:6px;
    padding:12px 16px; border:none; border-radius:5px;
    font-size:13px; letter-spacing:0.08em; text-transform:uppercase; font-weight:700;
    font-family:'Space Mono', monospace;
    width:100%;
  }
  .btn-primary{background:var(--red); color:var(--cream); box-shadow:0 3px 0 var(--red-dark);}
  .btn-primary:active{transform:translateY(2px); box-shadow:0 1px 0 var(--red-dark);}
  .btn-ghost{background:transparent; color:var(--felt-deep); border:1px solid rgba(var(--ink-rgb),0.25);}
  .btn-gold{background:var(--gold); color:var(--felt-deep); box-shadow:0 3px 0 #96721a;}
  .btn-gold:active{transform:translateY(2px); box-shadow:0 1px 0 #96721a;}
  .btn-small{padding:8px 10px; font-size:11px; width:auto;}
  .btn-danger{background:transparent; color:var(--red); border:1px solid var(--red);}

  /* ---------- SLAB LABEL (signature element) ---------- */
  .slab{
    background:var(--slab-white);
    border:1px solid rgba(var(--ink-rgb),0.18);
    border-radius:6px;
    overflow:hidden;
    box-shadow:0 2px 6px rgba(0,0,0,0.12);
  }
  .slab-top{
    display:flex; align-items:stretch; border-bottom:1px solid rgba(var(--ink-rgb),0.15);
  }
  .slab-grade{
    width:64px; flex-shrink:0;
    background:var(--felt-deep); color:var(--cream);
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    font-family:'Anton', sans-serif;
    position:relative;
    overflow:hidden;
  }
  .slab-grade.graded{background:linear-gradient(160deg, var(--felt-deep), var(--felt-light));}
  .slab-grade.graded::after{
    content:""; position:absolute; inset:0;
    background:linear-gradient(115deg, transparent 30%, rgba(230,190,85,0.35) 45%, transparent 60%);
    background-size:220% 220%;
    animation:sheen 4.5s ease-in-out infinite;
  }
  @media (prefers-reduced-motion: reduce){ .slab-grade.graded::after{animation:none;} }
  @keyframes sheen{
    0%{background-position:-40% -40%;}
    50%{background-position:140% 140%;}
    100%{background-position:-40% -40%;}
  }
  .slab-grade .num{font-size:22px; line-height:1; position:relative; z-index:1;}
  .slab-grade .lbl{font-family:'Space Mono', monospace; font-size:8px; letter-spacing:0.1em; margin-top:2px; position:relative; z-index:1;}
  .slab-grade.raw .num{font-size:13px;}

  .slab-id{
    flex:1; padding:8px 10px; display:flex; flex-direction:column; justify-content:center; gap:2px;
  }
  .slab-id .name{font-weight:700; font-size:14px; color:var(--ink); line-height:1.2;}
  .slab-id .meta{font-family:'Space Mono', monospace; font-size:10px; color:rgba(var(--ink-rgb),0.6); letter-spacing:0.03em;}

  .slab-body{padding:12px;}

  .price-dual{display:grid; grid-template-columns:1fr 1fr; gap:8px;}
  .price-block{
    background:var(--slab-white); border:1px solid rgba(var(--ink-rgb),0.14); border-radius:6px;
    padding:9px 10px;
  }
  .price-block .src-label{
    font-family:'Space Mono', monospace; font-size:9px; letter-spacing:0.08em; text-transform:uppercase;
    color:rgba(var(--ink-rgb),0.5); display:block; margin-bottom:3px;
  }
  .price-block .price-main{
    font-family:'Space Mono', monospace; font-size:20px; font-weight:700; color:var(--felt-deep); display:block;
  }
  .price-block .price-conf{
    display:inline-block; margin-top:5px;
    font-family:'Space Mono', monospace; font-size:9px; padding:2px 6px; border-radius:3px;
    background:var(--gold); color:var(--felt-deep); letter-spacing:0.08em;
  }

  .disagreement-flag{
    margin-top:10px; padding:8px 10px; border-radius:5px;
    background:rgba(169,50,38,0.1); border:1px solid rgba(169,50,38,0.35);
    font-size:11.5px; color:var(--red-dark); display:flex; align-items:center; gap:6px;
  }
  .disagreement-flag.ok{
    background:rgba(22,48,42,0.06); border:1px solid rgba(22,48,42,0.18); color:rgba(var(--ink-rgb),0.6);
  }
  .disagreement-flag b{font-family:'Space Mono', monospace;}
  /* Sell View (Sept 18, 2026, OI-45) — same card treatment as
     .disagreement-flag.ok, but its content is several stacked sentences
     rather than the one inline span every other user of this class has, and
     the base rule is `display:flex` in the default `row` direction. Without
     this the four lines lay out as four squeezed columns. */
  .disagreement-flag.stacked{flex-direction:column; align-items:flex-start; gap:0; line-height:1.55;}
  /* 🔧 Oct 21, 2026 UTC (the owner's signed-in phone check, after 4b294c5e): the
     Sell View's listing row overflowed the box's right edge, its price clipped.
     align-items:flex-start above sizes each child to its content, and the row's
     content includes the listing title at its full, unwrapped width, so the row
     was wider than the box at every width (555 px in a 484 px box on desktop).
     The row now fills the box; the title takes the ellipsis, the price keeps
     its width. Held by infra/flipwell-app/test-visual.js's sell-view screen. */
  .disagreement-flag.stacked > .comp-row{align-self:stretch; min-width:0;}
  .ebay-row > .comp-left + div{flex-shrink:0;}

  .price-note{font-size:11px; color:rgba(var(--ink-rgb),0.55); margin-top:4px;}

  .comps-group{margin-top:14px;}
  .comps-group + .comps-group{margin-top:12px; border-top:1px dashed rgba(var(--ink-rgb),0.2); padding-top:10px;}
  .comps-title{font-size:10px; letter-spacing:0.12em; text-transform:uppercase; color:rgba(var(--ink-rgb),0.5); margin-bottom:6px;}
  .comp-row{
    display:flex; justify-content:space-between; align-items:center;
    padding:7px 0; border-bottom:1px solid rgba(var(--ink-rgb),0.08);
    font-size:12.5px;
  }
  .comp-row:last-child{border-bottom:none;}
  .comp-left{display:flex; flex-direction:column;}
  .comp-platform{font-family:'Space Mono', monospace; font-size:9px; color:rgba(var(--ink-rgb),0.5); letter-spacing:0.06em;}
  .comp-right{display:flex; align-items:center; gap:8px;}
  .comp-price{font-family:'Space Mono', monospace; font-weight:700; color:var(--felt-deep);}
  .comp-link{
    font-family:'Space Mono', monospace; font-size:10px; color:var(--red); text-decoration:none;
    border:1px solid rgba(169,50,38,0.4); padding:2px 6px; border-radius:3px;
  }
  .comp-link:active{background:rgba(169,50,38,0.1);}
  /* The eBay block shared by Look Up Price and the Sell View (OI-71). */
  .ebay-row{align-items:flex-start;}
  .ebay-row .comp-left{flex:1; min-width:0; padding-right:8px;}
  .ebay-lead{font-size:10px; letter-spacing:0.1em; text-transform:uppercase; color:rgba(var(--ink-rgb),0.55);}
  .ebay-title{font-size:11px; color:rgba(var(--ink-rgb),0.6); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
  .ebay-cost{font-family:'Space Mono', monospace; font-weight:700; color:var(--felt-deep); text-align:right; white-space:nowrap;}
  .ebay-note{font-size:10.5px; color:rgba(var(--ink-rgb),0.6); line-height:1.5;}
  .link-btn{background:none; border:0; padding:0; font:inherit; color:inherit; text-decoration:underline; cursor:pointer;}
  .value-headline{margin-top:12px;}
  .value-headline .value-amount{font-family:'Space Mono', monospace; font-weight:700; font-size:26px; color:var(--felt-deep);}
  .value-headline .value-label{display:block; font-size:10px; letter-spacing:0.12em; text-transform:uppercase; color:rgba(var(--ink-rgb),0.55);}

  /* ---------- OVERNIGHT DIGEST (price-monitor-spec.md §7.3) ----
     A panel at the top of the Collection tab, not a modal and not an
     interstitial: the spec is explicit that it is something the person
     scrolls past. Same card shell as .gap-card / .ms-card, with the
     movement rows reusing the .gap-inset geometry. */
  .digest-panel{
    background:var(--grad-card-list); border:1px solid var(--border); border-radius:var(--r-card);
    box-shadow:var(--shadow-card); padding:16px; margin-bottom:12px; color:var(--ink);
  }
  .digest-head{display:flex; align-items:flex-start; gap:10px;}
  .digest-summary{
    flex:1; min-width:0;
    font-family:var(--font-sans); font-size:13px; line-height:1.5; color:var(--ink);
  }
  .digest-eyebrow{
    display:block; font-family:var(--font-sans); font-size:9.5px; font-weight:600;
    letter-spacing:0.7px; text-transform:uppercase; color:var(--ink-faint); margin-bottom:4px;
  }
  .digest-dismiss{
    flex-shrink:0; background:none; border:1px solid var(--border); color:var(--ink-muted);
    border-radius:var(--r-button); padding:6px 11px; font-family:var(--font-sans); font-size:11px;
  }
  .digest-dismiss:active{transform:scale(0.97);}
  .digest-movements{display:flex; flex-direction:column; gap:8px; margin-top:13px;}
  .digest-move{
    display:flex; align-items:center; gap:11px; width:100%; text-align:left;
    background:var(--surface-sunken); border:1px solid var(--border-soft);
    border-radius:var(--r-inset); padding:10px 12px; color:var(--ink);
  }
  .digest-move:active{transform:scale(0.99);}
  .digest-move-main{flex:1; min-width:0;}
  .digest-move-name{
    font-family:var(--font-serif); font-weight:500; font-size:15px; line-height:1.15;
    color:var(--ink); display:block;
  }
  .digest-move-kind{font-family:var(--font-sans); font-size:11px; color:var(--ink-muted);}
  .digest-move-delta{
    flex-shrink:0; text-align:right;
    font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-weight:600; font-size:13.5px;
  }
  .digest-move-delta.up{color:var(--profit);}
  .digest-move-delta.down{color:var(--loss);}
  .digest-move-delta small{display:block; font-size:10px; font-weight:400; color:var(--ink-faint);}
  .digest-note{font-family:var(--font-sans); font-size:11.5px; line-height:1.5; color:var(--ink-muted); margin-top:11px;}

  /* ---------- COLLECTION CONTROLS ---------- */
  .controls-row{display:flex; gap:8px; margin-bottom:12px; flex-wrap:wrap;}
  .controls-row select, .controls-row input{
    background:var(--surface-raised); border:1px solid var(--border); color:var(--ink);
    font-family:var(--font-sans);
    border-radius:var(--r-button); padding:9px 10px; font-size:12.5px;
  }
  .controls-row select{flex:1; min-width:130px;}
  .controls-row input{flex:1.4; min-width:140px;}

  .empty-state{
    text-align:center; padding:40px 16px; color:var(--ink-muted); font-family:var(--font-sans);
  }
  .empty-state .stamp{
    display:inline-block; border:1px dashed var(--border); border-radius:var(--r-chip);
    padding:10px 18px; font-family:var(--font-sans); font-weight:600;
    letter-spacing:0.7px; text-transform:uppercase; margin-bottom:10px; font-size:11px; color:var(--ink-faint);
  }

  /* ---------- COLLECTION GRID (extends the design-spec.md visual language:
     thumbnail placeholder texture + r-card radius + r-thumb-style chips,
     same ink/surface/mono tokens as the rebuilt cards elsewhere — the spec
     has no named "collection tile" recipe, so this is a judgment extension,
     not a literal recipe) ---------- */
  .grid{
    display:grid; grid-template-columns:repeat(2, 1fr); gap:12px;
  }
  @media (min-width:520px){ .grid{grid-template-columns:repeat(3, 1fr);} }
  @media (min-width:760px){ .grid{grid-template-columns:repeat(4, 1fr);} }

  .card-tile{
    aspect-ratio:2.5/3.5;
    background:var(--surface);
    border-radius:var(--r-card);
    border:1px solid var(--border);
    box-shadow:var(--shadow-card);
    display:flex; flex-direction:column;
    overflow:hidden;
    transition:transform 0.16s ease-out;
  }
  .card-tile:active{transform:scale(0.98);}
  @media (prefers-reduced-motion: reduce){ .card-tile{transition:none;} .card-tile:active{transform:none;} }
  .card-face{
    flex:1;
    background:var(--grad-thumb);
    display:flex; align-items:center; justify-content:center; flex-direction:column;
    position:relative; padding:8px; text-align:center;
  }
  .card-face .year{
    font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:10px;
    color:var(--ink-faint); letter-spacing:0.08em;
  }
  .card-face .player{
    font-family:var(--font-serif); font-weight:500; font-size:15px; color:var(--ink); line-height:1.15;
    margin-top:4px;
  }
  .card-face .setline{
    font-family:var(--font-sans); font-size:10px; color:var(--ink-muted); margin-top:3px; line-height:1.2;
  }
  .card-face .num-badge{
    position:absolute; top:6px; right:6px;
    font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:9px;
    background:var(--surface-raised); color:var(--ink-muted); border:1px solid var(--border);
    padding:2px 5px; border-radius:var(--r-chip);
  }
  /* Buy/Sell/Hold + grading-opportunity tile badges (Sept 2026) — stacked
     top-left, wrapping if a card carries more than one signal at once
     (e.g. a real grading opportunity plus "add a target to unlock a
     verdict" can both be true for the same raw card). */
  .tile-badge-row{
    position:absolute; top:6px; left:6px; z-index:1;
    display:flex; flex-direction:column; align-items:flex-start; gap:3px;
  }
  .gap-badge.needs-data{
    background:var(--surface-raised); color:var(--ink-muted); border:1px solid var(--border);
  }
  .tile-label{
    padding:8px 9px; border-top:1px solid var(--border-soft);
    display:flex; align-items:center; gap:6px;
  }
  .tile-grade-box{
    width:24px; height:24px; border-radius:var(--r-chip); flex-shrink:0;
    background:var(--ink); color:var(--bg);
    display:flex; align-items:center; justify-content:center;
    font-family:var(--font-mono); font-weight:600; font-size:10px;
  }
  .tile-grade-box.raw{background:transparent; border:1px dashed var(--border); color:var(--ink-faint);}
  .tile-price{
    font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-weight:600; font-size:12.5px;
    color:var(--ink-secondary);
    margin-left:auto;
  }

  /* ---------- FAB ---------- */
  .fab{
    position:fixed; right:18px; bottom:calc(78px + env(safe-area-inset-bottom));
    width:56px; height:56px; border-radius:50%;
    background:var(--red); color:var(--cream); border:none;
    font-size:0; line-height:1;
    display:flex; align-items:center; justify-content:center;
    box-shadow:0 4px 14px rgba(0,0,0,0.4), inset 0 0 0 2px rgba(255,255,255,0.15);
    z-index:20;
  }
  .fab:active{transform:scale(0.94);}
  .fab::before, .fab::after{
    content:""; position:absolute;
    background:var(--cream); border-radius:1px;
  }
  .fab::before{ width:20px; height:2.5px; }
  .fab::after{ height:20px; width:2.5px; }

  /* ---------- MODAL ---------- */
  .modal-overlay{
    position:fixed; inset:0; background:rgba(15,35,30,0.72);
    display:flex; align-items:flex-end; justify-content:center;
    z-index:50; backdrop-filter:blur(2px);
  }
  .modal-overlay.hidden{display:none;}
  .modal{
    background:var(--cream); color:var(--ink);
    width:100%; max-width:520px;
    border-radius:16px 16px 0 0;
    padding:18px 18px 24px;
    max-height:88vh; overflow-y:auto; overflow-x:hidden;
    animation:slideUp 0.2s ease;
  }
  @keyframes slideUp{from{transform:translateY(24px); opacity:0.4;} to{transform:translateY(0); opacity:1;}}
  .modal-header{display:flex; align-items:center; justify-content:space-between; margin-bottom:14px;}
  .modal-header h2{font-family:'Anton', sans-serif; font-size:17px; margin:0; letter-spacing:0.02em; text-transform:uppercase; color:var(--felt-deep);}
  .modal-close{background:none; border:none; font-size:22px; color:rgba(var(--ink-rgb),0.5); line-height:1; padding:4px;}
  .modal-actions{display:flex; gap:8px; margin-top:14px;}
  .modal-actions .btn{flex:1;}

  .inline-lookup-btn{
    background:var(--felt-deep); color:var(--cream);
    border:none; border-radius:4px; padding:9px 10px; font-size:11px;
    font-family:'Space Mono', monospace; letter-spacing:0.06em; text-transform:uppercase;
    width:100%; margin-bottom:10px;
  }

  /* ---------- TOAST ---------- */
  .toast{
    position:fixed; left:50%; bottom:96px; transform:translateX(-50%);
    background:var(--felt-deep); color:var(--cream);
    padding:10px 16px; border-radius:6px; font-size:12.5px;
    font-family:'Space Mono', monospace;
    box-shadow:var(--shadow); z-index:60;
    border:1px solid rgba(230,190,85,0.4);
  }
  .toast.hidden{display:none;}

  .helper-note{
    font-size:11px; color:rgba(var(--cream-rgb),0.5); margin-top:14px; text-align:center; line-height:1.5;
    padding:0 12px;
  }
  .helper-note b{color:rgba(var(--cream-rgb),0.75);}

  /* ---------- SETTINGS: FEE TABLE ---------- */
  .settings-subhead{
    font-family:'Anton', sans-serif; font-size:13px; letter-spacing:0.03em; text-transform:uppercase;
    color:var(--felt-deep); margin:16px 0 6px; border-top:1px dashed rgba(var(--ink-rgb),0.2); padding-top:14px;
  }
  .fee-grid{display:flex; flex-direction:column; gap:8px;}
  .fee-row{
    display:grid; grid-template-columns:52px 1fr 1fr; gap:8px; align-items:center;
    background:var(--slab-white); border:1px solid rgba(var(--ink-rgb),0.14); border-radius:6px; padding:8px 10px;
  }
  .fee-row .fee-label{font-family:'Space Mono', monospace; font-weight:700; font-size:12px; color:var(--felt-deep);}
  /* ➕ Oct 20, 2026 (S1–S6): the table's line under each grader, the sources and the staleness note. */
  .fee-row .fee-table-line{grid-column:1 / -1; font-size:10.5px; line-height:1.4; color:var(--ink-muted);}
  .fee-sources{font-size:10.5px; line-height:1.5; color:var(--ink-muted); margin:8px 0 14px;}
  .fee-stale-note{font-size:11.5px; line-height:1.4; color:var(--red-dark); margin:0 0 10px;}
  .fee-row .fee-input-wrap{display:flex; flex-direction:column; gap:2px; min-width:0;}
  .fee-row .fee-input-wrap label{font-size:9px; letter-spacing:0.06em; text-transform:uppercase; color:rgba(var(--ink-rgb),0.5);}
  .fee-row input{border:1px solid rgba(var(--ink-rgb),0.2); border-radius:4px; padding:6px 7px; font-size:12.5px; background:var(--slab-white); color:var(--ink); width:100%;} /* 🔧 Oct 11, 2026 UTC (OI-104): was background:#fff with no text colour — white on white in the dark theme */

  /* ---------- GRADING GAP (Phase 3) ---------- */
  .grading-gap-panel{
    margin-top:14px; padding-top:14px; border-top:1px dashed rgba(var(--ink-rgb),0.2);
  }
  .gap-badge{
    display:inline-flex; align-items:center; gap:4px;
    background:var(--profit-soft-bg); color:var(--profit); border:1px solid var(--profit-soft-border);
    font-family:var(--font-mono); font-size:9px; letter-spacing:0.05em;
    padding:2px 6px; border-radius:var(--r-chip);
  }
  /* ➕ Oct 19, 2026 UTC (Block B decision 1): "Priced as", the link's status, the picker. */
  .gap-badge.ch-unconfirmed{
    background:var(--surface-raised); color:var(--ink-muted); border:1px dashed var(--border);
  }
  .tile-priced-as{
    display:block; font-size:8.5px; line-height:1.3; opacity:0.7; margin-top:2px;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100%;
  }
  .ch-link-box{
    font-size:12px; line-height:1.5; padding:8px 10px; margin:-4px 0 10px;
    border:1px solid var(--border); border-radius:6px; background:var(--surface-raised); color:var(--ink);
  }
  .ch-link-box .ch-link-status{font-family:var(--font-mono); font-size:9.5px; letter-spacing:0.05em; text-transform:uppercase; color:var(--ink-muted);}
  .ch-link-box .ch-link-actions{display:flex; gap:8px; flex-wrap:wrap; margin-top:6px;}
  .ch-pick-list{display:flex; flex-direction:column; gap:6px; max-height:50vh; overflow-y:auto;}
  .ch-pick-list button{
    text-align:left; font-size:12.5px; line-height:1.4; padding:8px 10px; border-radius:6px;
    border:1px solid var(--border); background:var(--surface-raised); color:var(--ink); cursor:pointer;
  }
  .ch-pick-list button .ch-pick-meta{display:block; font-family:var(--font-mono); font-size:9.5px; color:var(--ink-muted); margin-top:2px;}
  .gap-table td.gap-missing{color:var(--ink-muted); font-family:inherit; font-size:11px;}
  .gap-table{width:100%; border-collapse:collapse; margin-top:8px; font-size:12px;}
  .gap-table th{
    text-align:left; font-family:'Space Mono', monospace; font-size:9px; letter-spacing:0.06em; text-transform:uppercase;
    color:rgba(var(--ink-rgb),0.5); padding:4px 6px; border-bottom:1px solid rgba(var(--ink-rgb),0.15);
  }
  .gap-table td{padding:6px; border-bottom:1px solid rgba(var(--ink-rgb),0.08); font-family:'Space Mono', monospace;}
  .gap-table tr.best-row{background:rgba(198,151,31,0.12);}
  .gap-table tr.best-row td:first-child{font-weight:700;}
  .gap-profit-pos{color:#1e6b3e;}
  .gap-profit-neg{color:var(--red-dark);}
  .gap-summary{
    font-size:12px; padding:8px 10px; border-radius:5px; margin-top:8px;
    background:rgba(22,48,42,0.06); border:1px solid rgba(22,48,42,0.15);
  }
  .gap-summary.positive{background:rgba(198,151,31,0.14); border-color:rgba(198,151,31,0.4);}
  /* ➕ Oct 20, 2026 (G1, G2): the under-threshold note and the per-grade heading. */
  .gap-raw-note{font-size:11px; color:var(--ink-muted); margin:6px 0 0; line-height:1.4;}
  .gap-grade-head{font-family:'Space Mono', monospace; font-size:10.5px; font-weight:700; margin-top:10px; color:var(--ink);}
  /* ➕ Oct 20, 2026 (S4–S6): tier + declared value, the box-size switch, the fees footnote. */
  .gap-table .gap-tier{display:block; font-size:9px; font-weight:400; opacity:0.65; font-family:inherit;}
  .gap-box-switch{display:flex; align-items:center; gap:6px; margin-top:10px; font-size:11px; color:var(--ink-muted); flex-wrap:wrap;}
  .gap-box-switch button{min-width:36px; min-height:32px; padding:4px 8px; border:1px solid rgba(var(--ink-rgb),0.25); border-radius:5px; background:var(--slab-white); color:var(--ink); font-family:'Space Mono', monospace; font-size:12px; cursor:pointer;}
  .gap-box-switch button.on{background:var(--ink); color:var(--slab-white); border-color:var(--ink); font-weight:700;}
  .gap-table td:not(.gap-missing):not(:first-child){white-space:nowrap;} /* S8: "−$54.02" never breaks after the sign */
  .gap-box-note{font-size:11px; color:var(--ink-muted); margin:4px 0 0; line-height:1.4;}
  .gap-fees-note{font-size:10px; line-height:1.45; color:rgba(var(--ink-rgb),0.55); margin:6px 0 0;}
  .gap-fees-note .gap-stale{color:var(--red-dark);}

  /* ---------- AI FEATURES (Claude API) ---------- */
  .ai-btn{
    width:100%; margin-top:10px;
    background:linear-gradient(120deg, #6b3fa0, #a93226);
    color:#fff; border:none; border-radius:5px; padding:11px 12px;
    font-size:12px; font-family:'Space Mono', monospace; letter-spacing:0.03em;
  }
  .ai-btn:disabled{opacity:0.6;}
  .ai-result-box{
    margin-top:10px; padding:12px; border-radius:7px;
    background:rgba(107,63,160,0.08); border:1px solid rgba(107,63,160,0.3);
    font-size:12.5px; line-height:1.55; color:var(--ink); white-space:pre-wrap;
  }
  .ai-result-box .ai-label{
    display:block; font-family:'Space Mono', monospace; font-size:9px; letter-spacing:0.08em; text-transform:uppercase;
    color:#6b3fa0; margin-bottom:6px;
  }
  .ai-error-box{
    margin-top:10px; padding:10px 12px; border-radius:6px;
    background:rgba(169,50,38,0.08); border:1px solid rgba(169,50,38,0.3);
    font-size:12px; color:var(--red-dark);
  }
  .ai-loading{font-size:12px; color:rgba(var(--ink-rgb),0.55); font-family:'Space Mono', monospace; margin-top:8px;}
  .listing-copy-btn{
    margin-top:6px; background:none; border:1px solid rgba(107,63,160,0.4); color:#6b3fa0;
    border-radius:4px; padding:5px 9px; font-size:10.5px; font-family:'Space Mono', monospace;
  }

  /* ---------- ASK AI TAB ----
     No named recipe for chat in design-spec.md — extends the same tokens
     (surface/ink/border for a normal received message, --loss for an
     error, and the same accent used for the active-tab pill for the
     user's own sent message, so "your action" reads consistently across
     the app) rather than reverting to the old purple/gold look. */
  .chat-thread{
    display:flex; flex-direction:column; gap:10px; margin-bottom:12px;
    max-height:calc(100vh - 340px); overflow-y:auto; padding-right:2px;
  }
  .chat-bubble{
    max-width:88%; padding:10px 12px; border-radius:var(--r-chip); font-family:var(--font-sans);
    font-size:13px; line-height:1.5; white-space:pre-wrap;
  }
  .chat-bubble.user{
    align-self:flex-end; background:var(--tab-active-fill); color:var(--tab-active-ink);
    border-bottom-right-radius:3px;
  }
  .chat-bubble.assistant{
    align-self:flex-start; background:var(--surface); color:var(--ink); border-bottom-left-radius:3px;
    border:1px solid var(--border);
  }
  .chat-bubble.error{
    align-self:flex-start; background:var(--loss-soft-bg); color:var(--loss); border:1px solid var(--loss-soft-border);
  }
  .chat-input-row{display:flex; gap:8px;}
  .chat-input-row input{
    flex:1; background:var(--surface-raised); border:1px solid var(--border); color:var(--ink);
    border-radius:var(--r-button); padding:11px 12px; font-size:13px;
  }
  .chat-input-row button{
    background:var(--tab-active-fill); color:var(--tab-active-ink); border:none; border-radius:var(--r-button);
    padding:0 18px; font-size:13px; font-weight:600; font-family:var(--font-sans);
  }
  .chat-empty{color:var(--ink-muted); font-family:var(--font-sans); font-size:12.5px; text-align:center; padding:30px 16px;}
  .chat-suggestions{display:flex; flex-wrap:wrap; gap:6px; margin-top:10px; margin-bottom:14px;}
  .chat-suggestion-chip{
    background:var(--surface-raised); color:var(--ink-muted); border:1px solid var(--border);
    font-family:var(--font-sans);
    border-radius:var(--r-pill); padding:6px 12px; font-size:11.5px;
  }

  /* ---------- WATCHLIST / DISCOVERY — shared "gap-card" component ----
     Same visual language as the Market Scan scan-result card recipe
     (design-spec.md §9: card shell, inset numbers panel, footer divider)
     extended with judgment for content the spec doesn't literally name: a
     tracked watchlist entry or an already-owned collection card has no
     listing or thumbnail — just player identity, plus (once checked) a
     grading-gap result instead of a market listing. Card shell/inset/
     footer geometry matches .ms-card exactly; only the fields differ. */
  .watchlist-list{display:flex; flex-direction:column; gap:10px;}
  .gap-card{
    background:var(--grad-card-list); border:1px solid var(--border); border-radius:var(--r-card);
    padding:16px; box-shadow:var(--shadow-card); color:var(--ink);
  }
  .gap-top{display:flex; justify-content:space-between; align-items:flex-start; gap:10px;}
  .gap-source-tag{
    font-family:var(--font-sans); font-size:9px; font-weight:600; letter-spacing:0.6px; text-transform:uppercase;
    padding:3px 7px; border-radius:var(--r-chip); display:inline-block; margin-bottom:6px;
  }
  .gap-source-tag.collection{background:var(--surface-sunken); color:var(--ink-muted); border:1px solid var(--border-soft);}
  .gap-source-tag.watchlist{background:var(--profit-soft-bg); color:var(--profit); border:1px solid var(--profit-soft-border);}
  .gap-name{
    font-family:var(--font-serif); font-weight:500; font-size:19px; line-height:1.1;
    letter-spacing:-0.2px; color:var(--ink); display:block;
  }
  .gap-meta{font-family:var(--font-sans); font-size:11.5px; line-height:1.4; color:var(--ink-muted); margin-top:5px;}
  /* ➕ Oct 18, 2026 UTC (OI-108): the entry's target is the tap target for
     editing it in place — inherits the meta line's look, underlined. */
  .wl-target-edit{background:none; border:none; padding:0; font:inherit; color:inherit; text-decoration:underline dotted; text-underline-offset:2px; cursor:pointer;}
  .gap-remove{
    background:none; border:none; color:var(--ink-faint); font-size:20px; line-height:1; padding:2px 4px; flex-shrink:0;
  }
  .gap-inset{
    margin-top:14px; background:var(--surface-sunken); border:1px solid var(--border-soft);
    border-radius:var(--r-inset); padding:12px 13px; display:flex; align-items:center; gap:12px;
  }
  .gap-grader{display:flex; flex-direction:column; gap:2px;}
  .gap-grader-name{
    font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-weight:600; font-size:13.5px;
    color:var(--ink-secondary);
  }
  .gap-inset-profit{margin-left:auto; text-align:right; display:flex; flex-direction:column; gap:2px;}
  .gap-confidence-note{font-family:var(--font-sans); font-size:10.5px; color:var(--ink-faint); margin-top:8px;}
  .gap-note{
    font-family:var(--font-sans); font-size:12px; color:var(--ink-muted);
    margin-top:14px; padding-top:12px; border-top:1px solid var(--border-soft);
  }
  .gap-footer{margin-top:13px; padding-top:12px; border-top:1px solid var(--border-soft); display:flex; gap:8px;}
  .gap-footer .btn{flex:1;}
  .gap-empty{text-align:center; padding:24px 12px; color:var(--ink-muted); font-size:13px; font-family:var(--font-sans);}

  /* ---- Market Scan result card (design-spec.md §9 "Scan-result card" recipe) ----
     thumbnail + (name, metadata) top row -> inset numbers panel (Buy / comp
     basis left, NET AFTER FEES + big profit right) -> footer row (EDGE pill,
     comp count, listing link). No status badge is rendered: Targeted/
     Full-Market mode results carry no real status concept (graded/watch/etc)
     to put there, and a placeholder badge would be decorative, not data. */
  .ms-card{
    background:var(--grad-card-list); border:1px solid var(--border); border-radius:var(--r-card);
    padding:16px; box-shadow:var(--shadow-card); color:var(--ink);
  }
  .ms-top{display:flex; gap:13px; align-items:flex-start;}
  .ms-thumb{
    width:46px; height:64px; flex-shrink:0; border-radius:var(--r-thumb);
    background:var(--grad-thumb); border:1px solid var(--thumb-border);
    background-size:cover; background-position:center;
  }
  .ms-info{flex:1; min-width:0;}
  .ms-name{
    font-family:var(--font-serif); font-weight:500; font-size:19px; line-height:1.1;
    letter-spacing:-0.2px; color:var(--ink); display:block;
  }
  .ms-meta{
    font-family:var(--font-sans); font-size:11.5px; line-height:1.3; color:var(--ink-muted);
    margin-top:5px; display:block;
  }
  /* 🔧 Oct 11, 2026 UTC (OI-102, decision 1): eBay listings shown with no basis, in their own panel */
  .ms-ebay-panel{display:flex; flex-direction:column; gap:6px; border:1px dashed rgba(var(--ink-rgb),0.25); border-radius:6px; padding:8px 10px; margin-top:8px;}
  .ms-listing-row{display:flex; align-items:center; justify-content:space-between; gap:8px;}
  /* ➕ Oct 11, 2026 UTC (OI-102, decision 2-2): listings the title screen could not confirm for a missing fact, collapsed until the person looks */
  .ms-unconfirmed{margin-top:10px;}
  .ms-unconfirmed > summary{cursor:pointer; font-family:var(--font-sans); font-size:12.5px; color:var(--ink-muted); padding:4px 0;}
  .ms-unconfirmed-row{display:flex; gap:10px; align-items:flex-start; padding:8px 0; border-top:1px solid var(--border-soft);}
  .ms-unconfirmed-row .ms-thumb{width:40px; height:56px;}
  .ms-unconfirmed-body{flex:1; min-width:0; display:flex; flex-direction:column; gap:4px;}
  .ms-unconfirmed-title{font-family:var(--font-sans); font-size:12.5px; line-height:1.35; color:var(--ink); overflow-wrap:anywhere;}
  .ms-unconfirmed-missing{font-family:var(--font-sans); font-size:11px; color:var(--ink-muted);}
  .ms-unconfirmed-actions{display:flex; align-items:center; gap:10px; flex-wrap:wrap;}
  .ms-confirm-btn{font-family:var(--font-sans); font-size:12px; padding:5px 10px; border-radius:6px; border:1px solid var(--border); background:var(--surface-sunken); color:var(--ink); cursor:pointer;}
  .ms-inset{
    margin-top:14px; background:var(--surface-sunken); border:1px solid var(--border-soft);
    border-radius:var(--r-inset); padding:12px 13px;
    display:flex; align-items:flex-start; gap:12px;
  }
  .ms-inset-col{display:flex; flex-direction:column; gap:2px;}
  .ms-inset-net{margin-left:auto; text-align:right;}
  .ms-micro-label{
    font-family:var(--font-sans); font-size:9.5px; letter-spacing:0.7px; text-transform:uppercase;
    color:var(--ink-faint);
  }
  .ms-buy-price, .ms-comp-price{
    font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:13.5px; color:var(--ink-secondary);
  }
  /* ➕ Oct 21, 2026 UTC (OI-79 (17), H2): the delivered cost over its breakdown ("$42.00 + $5.00 ship", or "+ shipping varies") */
  .ms-cost{display:inline-flex; flex-direction:column; gap:1px;}
  .ms-ship-note{font-family:var(--font-sans); font-size:10px; line-height:1.3; color:var(--ink-muted);}
  .ms-net-label{color:var(--profit-label);}
  .ms-profit{
    font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-weight:600;
    font-size:21px; letter-spacing:-0.5px; color:var(--profit);
  }
  .ms-profit.ms-profit-negative{color:var(--loss);} /* 🔧 Oct 11 (OI-102, F2): a loss is not shown in the profit green */
  .ms-footer{
    margin-top:13px; padding-top:12px; border-top:1px solid var(--border-soft);
    display:flex; align-items:center; gap:8px;
  }
  .ms-edge-pill{
    font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:10.5px; font-weight:500;
    padding:5px 8px; border-radius:var(--r-pill);
    background:var(--profit-soft-bg); color:var(--profit); border:1px solid var(--profit-soft-border);
  }
  .ms-comp-count{font-family:var(--font-sans); font-size:11px; color:var(--ink-muted);}
  .ms-listing-link{
    margin-left:auto; font-family:var(--font-sans); font-weight:600; font-size:11.5px;
    color:var(--link-color); text-decoration:none;
  }

  /* ---------- SCAN ---------- */
  .scan-subtext{font-size:11px; color:rgba(var(--ink-rgb),0.55); margin:-6px 0 12px; line-height:1.5;}
  .scan-zone{
    border:2px dashed rgba(var(--ink-rgb),0.3);
    border-radius:8px;
    padding:26px 14px;
    text-align:center;
    background:var(--slab-white);
    transition:border-color 0.15s ease, background 0.15s ease;
  }
  .scan-zone:active{border-color:var(--red); background:rgba(169,50,38,0.05);}
  .scan-zone-icon{font-size:30px; margin-bottom:6px;}
  .scan-zone-text{font-family:'Space Mono', monospace; font-size:11.5px; letter-spacing:0.04em; color:rgba(var(--ink-rgb),0.55); text-transform:uppercase;}

  .scan-preview-wrap.hidden{display:none;}
  .scan-preview-wrap{
    margin-top:12px; display:flex; gap:12px; align-items:flex-start;
    background:var(--slab-white); border:1px solid rgba(var(--ink-rgb),0.14); border-radius:8px; padding:10px;
  }
  .scan-preview-img-wrap{
    width:72px; aspect-ratio:2.5/3.5; border-radius:5px;
    border:1px solid rgba(var(--ink-rgb),0.15); flex-shrink:0;
    overflow:hidden; position:relative; touch-action:none;
  }
  .scan-preview-img{
    width:100%; height:100%; object-fit:cover; display:block;
    transform-origin:center center;
  }
  .scan-status{flex:1; font-size:12.5px; line-height:1.5;}
  .scan-status .scan-loading{color:rgba(var(--ink-rgb),0.55); font-family:'Space Mono', monospace; font-size:11px;}
  .scan-match-name{font-weight:700; color:var(--felt-deep); display:block; margin-bottom:2px;}
  .scan-conf-badge{
    display:inline-block; font-family:'Space Mono', monospace; font-size:9px; padding:2px 6px; border-radius:3px;
    letter-spacing:0.06em; margin-top:4px;
  }
  .scan-conf-badge.high{background:var(--gold); color:var(--felt-deep);}
  /* ➕ Oct 10, 2026 UTC (release-gate G18): Medium is its own band — the gold tint
     and hairline the cache note already uses, not High's solid gold. */
  .scan-conf-badge.medium{background:rgba(198,151,31,0.16); color:var(--felt-deep); border:1px solid rgba(198,151,31,0.55);}
  .scan-conf-badge.low{background:rgba(169,50,38,0.15); color:var(--red-dark); border:1px solid rgba(169,50,38,0.4);}
  .scan-low-warning{color:var(--red-dark); font-size:11px; margin-top:5px; display:block;}
  .scan-cache-note{color:var(--felt-deep); background:rgba(198,151,31,0.16); border:1px solid rgba(198,151,31,0.4); font-size:10.5px; margin-top:5px; padding:4px 7px; border-radius:4px; display:block;}
  .pregrade-block{
    margin-top:8px; padding-top:8px; border-top:1px dashed rgba(var(--ink-rgb),0.15);
    display:flex; flex-direction:column; gap:3px;
  }
  .pregrade-headline{font-size:12.5px;}
  .pregrade-subs{font-family:'Space Mono', monospace; font-size:10px; color:rgba(var(--ink-rgb),0.55);}
  .scan-rescan-btn{
    margin-top:6px; background:none; border:1px solid rgba(var(--ink-rgb),0.25); color:var(--felt-deep);
    border-radius:4px; padding:5px 9px; font-size:10.5px; font-family:'Space Mono', monospace;
  }
  .scan-rescan-btn:disabled{opacity:0.45;}
  .scan-grade-actions{display:flex; flex-wrap:wrap; gap:6px;}
  /* OI-84 (Oct 4, 2026): the "Grade ready" list on the Scan tab. */
  .grade-ready-list{margin-bottom:12px;}
  .grade-ready-list .pregrade-block{margin-bottom:8px;}

  /* ---------- MULTI-CARD SCAN ---------- */
  .hidden{display:none !important;}
  /* ➕ Oct 4, 2026 UTC (OI-02, decision 1 amended): the parallel suggestion beside the Parallel field */
  .parallel-suggest{margin-top:5px; font-size:11px;}
  .parallel-suggest-btn{display:block; width:100%; text-align:left; font-size:11.5px; padding:6px 8px; border-radius:6px; border:1px dashed rgba(198,151,31,0.7); background:rgba(198,151,31,0.10); color:var(--felt-deep); cursor:pointer;}
  .parallel-suggest-btn:disabled{opacity:0.6; cursor:default; border-style:solid;}
  .parallel-suggest-note{color:var(--felt-deep); opacity:0.75;}
  /* ➕ Oct 4, 2026 UTC (OI-02, decision 2): other parallels and "Not this card?" rows */
  .parallel-suggest-others{margin-top:5px; display:flex; flex-wrap:wrap; gap:5px; align-items:center;}
  .parallel-suggest-chip{font-size:11px; padding:4px 7px; border-radius:12px; border:1px dashed rgba(198,151,31,0.7); background:rgba(198,151,31,0.10); color:var(--felt-deep); cursor:pointer;}
  .parallel-suggest-chip:disabled{opacity:0.6; cursor:default; border-style:solid;}
  .scan-alternates{margin-top:8px; display:flex; flex-direction:column; gap:5px;}
  .scan-alternates-title{font-size:11px; font-weight:600; color:rgba(var(--ink-rgb),0.7);}
  .scan-alt-row, .scan-alt-more{text-align:left; font-size:11.5px; padding:6px 8px; border-radius:6px; border:1px dashed rgba(198,151,31,0.7); background:rgba(198,151,31,0.10); color:var(--felt-deep); cursor:pointer;}
  .scan-alt-more{border-style:solid; background:transparent;}
  .scan-not-returned{font-style:italic; opacity:0.7;}
  /* ➕ Oct 4, 2026 UTC (OI-02, decision 4): the sport selector on the Scan surfaces */
  .scan-sport-field{margin-bottom:10px;}
  .scan-sport-hint{display:block; font-size:11px; color:rgba(var(--ink-rgb),0.55); margin-top:4px; line-height:1.4;}
  .scan-video-wrap{
    position:relative; width:100%; aspect-ratio:4/3;
    background:var(--felt-deep); border-radius:8px; overflow:hidden;
    border:1px solid rgba(var(--ink-rgb),0.2);
    touch-action:none; /* pinch handled manually -> real camera zoom, not CSS */
  }
  .scan-video-wrap video{
    width:100%; height:100%; object-fit:cover; display:block;
  }
  .scan-video-placeholder{
    position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center;
    color:rgba(var(--cream-rgb),0.5);
  }
  .scan-video-wrap.live .scan-video-placeholder{display:none;}
  .scan-multi-controls{display:flex; gap:8px; margin-top:10px;}
  .scan-multi-controls .btn{flex:1;}

  .scan-multi-results{margin-top:12px; display:flex; flex-direction:column; gap:8px;}
  .scan-result-card{
    display:flex; align-items:center; gap:10px;
    background:var(--slab-white); border:1px solid rgba(var(--ink-rgb),0.14); border-radius:7px; padding:9px 10px;
  }
  .scan-result-info{flex:1; min-width:0;}
  .scan-result-info .scan-match-name{font-size:13px;}
  .scan-result-info .scan-meta-line{font-size:11px; color:rgba(var(--ink-rgb),0.55);}
  .scan-add-btn{
    flex-shrink:0; background:var(--gold); color:var(--felt-deep); border:none; border-radius:4px;
    padding:8px 10px; font-size:11px; font-family:'Space Mono', monospace; letter-spacing:0.04em;
  }

  a{color:inherit;}

  /* ➕ Oct 10, 2026 UTC (block C1, Session D, OI-81; decision 3 row D: "the
     server gate is the enforcement; hiding is the affordance"). The body
     carries .free-plan when the account's tier has no paid_features
     (applyAccountGates). The four paid controls — Grade, the two AI
     rationales, the listing generator — are hidden by this rule alone, so
     the code paths that unhide them need no plan check of their own; the
     proxies' 402 is what refuses if one is ever reached. The paid-only note
     shows in their place. */
  .paid-only-note{display:none; font-size:12px; color:var(--felt-deep); margin:6px 0 10px;}
  .free-plan #scan-grade-section,
  .free-plan #m-generate-listing,
  .free-plan #m-ai-rationale-wrap,
  .free-plan #m-bsh-ai-rationale-wrap{display:none !important;}
  .free-plan .paid-only-note{display:block;}

  /* ➕ Oct 21, 2026 UTC (Oct 20 ET; OI-88, H5): FORMER INLINE STYLE ATTRIBUTES.
     Each class is one style attribute's exact value, moved from index.html
     (static markup and innerHTML templates) so no element carries a style
     attribute. They come last so that, at equal specificity, they win as the
     inline value did. The visual check compared every computed property of
     every element before and after the move (infra/flipwell-app/visualScreens.js).
     JS that sets el.style.display still overrides .st-off, as it overrode the
     inline display:none. */
  .st-off{display:none;}
  .st-mt6{margin-top:6px;}
  .st-help{font-size:11px; color:rgba(var(--ink-rgb),0.55); margin:-2px 0 10px; line-height:1.5;}
  .st-mb6{margin-bottom:6px;}
  .st-mb14{margin-bottom:14px;}
  .st-help-tight{font-size:11px; color:rgba(var(--ink-rgb),0.55); margin:-6px 0 14px; line-height:1.5;}
  .st-intro{font-size:10.5px; color:rgba(var(--ink-rgb),0.5); margin:0 0 10px; line-height:1.5;}
  .st-modal-420{max-width:420px; border-radius:16px;}
  .st-m8-0-0{margin:8px 0 0;}
  .st-mt8{margin-top:8px;}
  .st-mt4{margin-top:4px;}
  .st-mt2{margin-top:2px;}
  .st-mt12{margin-top:12px;}
  .st-mt10{margin-top:10px;}
  .st-msg{font-size:13px; line-height:1.5; margin:0 0 16px;}
  .st-fs12{font-size:12px;}
  .st-col8{flex-direction:column; gap:8px;}
  .st-hero-note{display:none; font-size:10.5px; opacity:0.7; margin-top:2px;}
  .st-error{color:var(--red); font-size:12px; margin:-4px 0 10px;}
  .st-overlay-210{align-items:center; z-index:210;}
  .st-center{text-align:center;}
  .st-auth-switch{text-align:center; font-size:12px; margin-top:12px;}
  .st-dim75{opacity:0.75;}
  .st-modal-460{max-width:460px; border-radius:16px;}
  .st-modal-360{max-width:360px; border-radius:16px;}
  .st-sell-foot{margin-top:6px; font-size:10.5px; opacity:0.75;}
  .st-mt14{margin-top:14px;}
  .st-span-all{grid-column:1/-1;}
  .st-tiny-note{font-size:8px; opacity:0.7;}
  .st-fs20{font-size:20px;}
  /* The card sheet's value amount sits in #m-value-display.value-headline, where
     .value-headline .value-amount (two classes) would outrank the one class
     above; the inline value it replaces outranked both. */
  .value-headline .value-amount.st-fs20{font-size:20px;}
  .st-body13{font-size:13px; line-height:1.5;}
  .st-msg-6{font-size:13px; line-height:1.5; margin:0 0 6px;}
  .st-plan{font-size:12px; margin:-4px 0 10px; line-height:1.5;}
  .st-account{font-size:12px; margin:-2px 0 10px; line-height:1.5;}
  .st-delete-msg{font-size:12px; color:var(--red); margin:4px 0 8px; line-height:1.5;}
  .st-help-0{font-size:11px; color:rgba(var(--ink-rgb),0.55); margin:0 0 10px; line-height:1.5;}
  .st-help-6{font-size:11px; color:rgba(var(--ink-rgb),0.55); margin:-6px 0 10px; line-height:1.5;}
  .st-priced-as{font-size:11.5px; margin-top:4px;}
  .st-pick-card{font-size:11.5px; line-height:1.5; margin:0 0 12px; opacity:0.75;}
  .st-grading-note{font-size:10px; color:rgba(var(--ink-rgb),0.55); margin:4px 0 0; line-height:1.4;}
  .st-bsh-note{font-size:10.5px; color:rgba(var(--ink-rgb),0.5); margin:8px 0 0; line-height:1.5;}
  .st-value-note{font-size:10.5px; color:rgba(var(--ink-rgb),0.5); margin:-6px 0 10px;}
  .st-col8-mt10{flex-direction:column; gap:8px; margin-top:10px;}
  .st-off-up4{display:none; margin-top:-4px;}
  .st-row8{display:flex; gap:8px;}
  .st-row8-wrap{display:flex; gap:8px; flex-wrap:wrap; margin-bottom:14px;}
  .st-justify{display:block; margin-top:3px; font-style:italic;}
  .st-sub9{display:block; font-size:9px; opacity:0.6;}
  .st-sub8{display:block; font-size:8px; font-weight:400; line-height:1.3; white-space:normal;}
  .st-felt{color:var(--felt-deep);}
  .st-info{color:var(--felt-deep); font-size:12px; margin:-4px 0 10px;}
  .st-overlay-220{align-items:center; z-index:220;}
  .st-overlay-200{align-items:center; z-index:200;}

  /* ---------- INSTALL GUIDANCE (W10, OI-76; Oct 23, 2026 UTC) ----------
     The iPhone install card sits above every overlay, including the sign-in
     screen (200–220), because a visitor most needs it before signing in:
     the installed app keeps its own storage, so installing first avoids a
     second sign-in. Same palette as the toast. */
  .install-card{
    position:fixed; left:12px; right:12px; bottom:calc(12px + env(safe-area-inset-bottom));
    max-width:420px; margin:0 auto; z-index:230;
    background:var(--felt-deep); color:var(--cream);
    border:1px solid rgba(230,190,85,0.4); border-radius:10px;
    box-shadow:var(--shadow); padding:14px 16px 12px;
  }
  .install-card.hidden{display:none;}
  .install-card-title{font-family:'Anton', sans-serif; font-size:16px; letter-spacing:0.02em; margin:0 28px 4px 0; line-height:1.25;}
  .install-card-lead{font-size:12.5px; margin:0 0 6px; line-height:1.45; opacity:0.85;}
  .install-steps{margin:0 0 10px; padding-left:20px; font-size:12.5px; line-height:1.5;}
  .install-steps li{margin-bottom:4px;}
  .install-steps-settings{font-size:12px; color:rgba(var(--ink-rgb),0.75);}
  .install-card-close{
    position:absolute; top:6px; right:8px; background:none; border:none;
    color:inherit; font-size:22px; line-height:1; padding:6px; opacity:0.7; cursor:pointer;
  }
  .install-card .install-card-ok{
    background:transparent; color:var(--cream); border:1px solid rgba(230,190,85,0.6);
    width:100%;
  }

  /* ---------- ALERTS (OI-85, W4; Oct 23, 2026 UTC) ----------
     The Settings switch and the offer card shown after the first watchlist
     target is saved. The card is an install card with two buttons. */
  .alerts-offer-actions{display:flex; gap:8px;}
  .install-card .alerts-offer-actions .install-card-ok{width:auto; flex:1;}
  .alerts-row{display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:6px;}
  .alerts-label{font-size:14px; color:var(--ink);}
  .alerts-switch{
    position:relative; flex-shrink:0; width:48px; height:28px; padding:0; cursor:pointer;
    border-radius:14px; border:1px solid rgba(var(--ink-rgb),0.25); background:rgba(var(--ink-rgb),0.12);
    transition:background 0.15s;
  }
  .alerts-switch::after{
    content:""; position:absolute; top:3px; left:3px; width:20px; height:20px; border-radius:50%;
    background:var(--slab-white); box-shadow:0 1px 2px rgba(0,0,0,0.25); transition:transform 0.15s;
  }
  .alerts-switch[aria-checked="true"]{background:var(--profit); border-color:var(--profit);}
  .alerts-switch[aria-checked="true"]::after{transform:translateX(20px);}
  .alerts-switch:disabled{opacity:0.45; cursor:default;}
  .alerts-status{margin-bottom:14px;}
  .test-alert{margin:-6px 0 14px;} /* ➕ Oct 23, 2026 UTC (OI-85 decision C): the test-alert button */
  .test-alert-msg{margin:6px 0 0;}
  .digest-move-basis{display:block; font-family:var(--font-sans); font-size:11px; color:var(--ink-faint); margin-top:2px;}

  /* ---------- VERDICT (OI-122; Oct 24, 2026 UTC) ----------
     The verdict block on Collection card detail, Look Up Price, Watchlist and
     Market Scan. Decision 6: GRADE/BUY/BUY TO GRADE green, NEGOTIATE/HOLD
     amber, SELL/SELL RAW blue, PASS grey; the text label is always shown, so
     the colour never carries the meaning alone. Each tone's ink on its own
     fill is at least 4.5:1 in both themes. */
  :root{
    --vd-green-ink:#2F4A3C; --vd-green-bg:#E4EEE7; --vd-green-border:#C5D9CB;
    --vd-amber-ink:#6B4500; --vd-amber-bg:#FAEFD6; --vd-amber-border:#EBD4A0;
    --vd-blue-ink:#1D4A73; --vd-blue-bg:#E3ECF6; --vd-blue-border:#C3D5EA;
    --vd-grey-ink:#4A463E; --vd-grey-bg:#EEEBE4; --vd-grey-border:#DDD8CC;
  }
  @media (prefers-color-scheme: dark){
    :root:not([data-theme="light"]){
      --vd-green-ink:#7FD6A6; --vd-green-bg:rgba(110,203,153,0.14); --vd-green-border:rgba(110,203,153,0.32);
      --vd-amber-ink:#EDC46E; --vd-amber-bg:rgba(237,196,110,0.13); --vd-amber-border:rgba(237,196,110,0.32);
      --vd-blue-ink:#9CC3EC; --vd-blue-bg:rgba(156,195,236,0.13); --vd-blue-border:rgba(156,195,236,0.32);
      --vd-grey-ink:#C4C0B6; --vd-grey-bg:rgba(255,255,255,0.07); --vd-grey-border:rgba(255,255,255,0.16);
    }
  }
  [data-theme="dark"]{
    --vd-green-ink:#7FD6A6; --vd-green-bg:rgba(110,203,153,0.14); --vd-green-border:rgba(110,203,153,0.32);
    --vd-amber-ink:#EDC46E; --vd-amber-bg:rgba(237,196,110,0.13); --vd-amber-border:rgba(237,196,110,0.32);
    --vd-blue-ink:#9CC3EC; --vd-blue-bg:rgba(156,195,236,0.13); --vd-blue-border:rgba(156,195,236,0.32);
    --vd-grey-ink:#C4C0B6; --vd-grey-bg:rgba(255,255,255,0.07); --vd-grey-border:rgba(255,255,255,0.16);
  }
  .vd{margin:12px 0 4px; padding:14px; border-radius:var(--r-inset); background:var(--surface-sunken); border:1px solid var(--border-soft); min-width:0;}
  .vd-compact{margin:10px 0 0; padding:10px 12px;}
  .vd-line{display:flex; flex-wrap:wrap; align-items:center; gap:6px 10px; min-width:0;}
  .vd-badge{
    display:inline-flex; align-items:center; font-family:var(--font-mono); font-weight:600; font-size:13px;
    letter-spacing:0.06em; padding:5px 10px; border-radius:var(--r-chip); border:1px solid; white-space:nowrap;
  }
  .vd-compact .vd-badge{font-size:11px; padding:3px 8px;}
  .vd-tone-green{color:var(--vd-green-ink); background:var(--vd-green-bg); border-color:var(--vd-green-border);}
  .vd-tone-amber{color:var(--vd-amber-ink); background:var(--vd-amber-bg); border-color:var(--vd-amber-border);}
  .vd-tone-blue{color:var(--vd-blue-ink); background:var(--vd-blue-bg); border-color:var(--vd-blue-border);}
  .vd-tone-grey{color:var(--vd-grey-ink); background:var(--vd-grey-bg); border-color:var(--vd-grey-border);}
  .vd-key{font-size:15px; font-weight:600; color:var(--ink); overflow-wrap:anywhere; min-width:0;}
  .vd-compact .vd-key{font-size:13px;}
  .vd-target{margin:4px 0 0; font-size:12px; color:var(--ink-muted);}
  .vd-ask{display:flex; align-items:flex-end; gap:8px; margin:12px 0 2px;}
  .vd-ask .field{margin:0; flex:1; max-width:220px;}
  .vd-ask input{font-size:16px;} /* 16px: iOS Safari does not zoom the page on focus */
  .vd-why{margin:10px 0 0; padding-left:18px; font-size:13.5px; line-height:1.45; color:var(--ink-secondary);}
  .vd-why li{margin:3px 0;}
  .vd-meta{margin:10px 0 0; font-size:12px; color:var(--ink-muted); line-height:1.5;}
  .vd-meta .link-btn{font-size:12px;}
  .vd-conf{font-weight:600; color:var(--ink-secondary);}
  .vd-details{margin-top:10px;}
  .vd-details > summary{cursor:pointer; font-size:13px; font-weight:600; color:var(--link-color); padding:6px 0; min-height:32px; list-style-position:inside;}
  .vd-ai-label{display:block; font-family:var(--font-mono); font-size:10px; letter-spacing:0.08em; text-transform:uppercase; color:var(--ink-muted); margin:6px 0 4px;}
  .vd-ai-text{margin:0 0 8px; font-size:13.5px; line-height:1.5; color:var(--ink-secondary);}
  .vd-ai-status{margin:8px 0 0; font-size:12.5px; color:var(--ink-muted);}
  .vd-ai-status.vd-slow{color:var(--vd-amber-ink);}
  .vd-nums{width:100%; border-collapse:collapse; font-size:12.5px; margin:4px 0 6px;}
  .vd-nums td{padding:4px 0; border-bottom:1px solid var(--border-soft); color:var(--ink-secondary);}
  .vd-nums td:last-child{text-align:right; font-family:var(--font-mono); color:var(--ink);}
  .vd-foot{margin:10px 0 0; font-size:11px; color:var(--ink-faint); line-height:1.4;}
  .vd-empty{margin:8px 0 0; font-size:13px; color:var(--ink-muted);}
  .free-plan .vd-ai{display:none !important;}
  .tile-badge-row .vd-badge{font-size:9px; padding:2px 6px; letter-spacing:0.05em;}
  /* Settings → Your targets */
  .targets-example{margin:4px 0 12px; font-size:12px; color:var(--ink-muted); line-height:1.45;}
  /* 🔧 Oct 24, 2026 UTC, later (the owner's check, item 1): the verdict at the top of card detail — the divider goes below it, not above. */
  .vd-top-panel{margin:4px 0 14px; padding-bottom:14px; border-bottom:1px dashed rgba(var(--ink-rgb),0.2);}
