:root {
  --bg: #14120f;
  --panel: #1e1b17;
  --panel-raised: #262220;
  --panel-sunken: #100e0b;
  --border: #3a3530;
  --border-soft: #2c2823;
  --text: #ede6d6;
  --text-muted: #a89f8f;
  /* AGE-196 accessibility pass: was #776f61 (2.76-3.88:1 in real use,
     failed WCAG AA everywhere it's used as text - proxy labels, prices,
     admin metadata). Lightened to clear 4.5:1 against every panel shade
     with margin; see the light-theme blocks below for the mirrored fix. */
  --text-faint: #958f84;

  --color-w: #f8f6d8;
  --color-u: #4aa3d8;
  --color-b: #8b7bc7;
  --color-r: #e0554a;
  --color-g: #3fa66c;
  --color-c: #9a9488;
  --color-m: #d9b64e;

  /* AGE-132: card-type ratio bar palette (2026-08-30). Qualitative 8-way set,
     tuned for the dark ground here; light overrides mirror it in each block
     below. Deliberately distinct from --color-w/u/b/r/g identity pips. */
  --t-creature: #e0714f;
  --t-instant: #5bb0e6;
  --t-sorcery: #a087d6;
  --t-enchantment: #4cc19c;
  --t-artifact: #b0a99b;
  --t-planeswalker: #e8c65f;
  --t-battle: #e885a8;
  --t-land: #9bb154;

  --rarity-common: #a8a29a;
  --rarity-uncommon: #9fb8c4;
  --rarity-rare: #d4af37;
  --rarity-mythic: #e0672a;

  /* Pro View (2026-08-22): the stat-panel "scroll" - a fixed parchment
     palette like the --color-w/u/b/r/g/c/m and --rarity-* tokens above,
     not overridden per theme (aged paper reads fine on either background,
     and it's meant to look the same object regardless of app theme). */
  --parchment-1: #f2e2b8;
  --parchment-2: #e6cd8f;
  --parchment-edge: #b9924a;
  --parchment-text: #4a3a1a;

  /* AGE-131: semantic aliases + the app's first shared design-token layer -
     intentionally not deck-page-specific, AGE-135 extends these app-wide
     rather than inventing a second palette. */
  --accent: var(--color-m);
  --accent-soft: rgba(217, 182, 78, 0.14);
  --accent-border: rgba(217, 182, 78, 0.4);
  --good: var(--color-g);
  --bad: var(--color-r);

  /* Add Card / Filters redesign (2026-08-22): decorative-only gold pair for
     gradients, borders, scrollbar thumbs and the .btn-foil shimmer - never
     used as text color. --accent above already carries that job (fixed for
     contrast under AGE-196) and stays untouched. */
  --accent-bright: #e8c65f;
  --accent-2: #c9973f;
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #f5f1e6;
    --panel: #ffffff;
    --panel-raised: #faf7ef;
    --panel-sunken: #eee7d6;
    --border: #ddd4c0;
    --border-soft: #e6dfcd;
    --text: #211d16;
    --text-muted: #6b6255;
    /* AGE-196: was #948a78 (2.76-3.02:1, failed WCAG AA) - darkened to
       clear 4.5:1 against every panel shade with margin. */
    --text-faint: #6b6356;
    /* AGE-196: --accent had no light-mode override at all (every other
       token here did) - it fell through to --color-m's #d9b64e, which
       renders at 1.7-2.0:1 as text/links in light mode, a severe fail.
       This value is for --accent's TEXT/link use only - the handful of
       solid-fill badges/buttons that pair --accent with near-black text
       (filter count badge, theme toggle, admin badges, etc.) were switched
       to var(--color-m) directly instead, so their appearance is
       unchanged (that combo was already at 9.57:1, plenty of room). */
    --accent: #77642b;
    --accent-soft: rgba(190, 148, 30, 0.12);
    --accent-border: rgba(190, 148, 30, 0.4);
    --accent-bright: #c9a227;
    --accent-2: #b8863f;
    /* AGE-132: type-ratio palette, light-ground variants (darker/less bright
       so segments hold their weight on #ffffff panels). */
    --t-creature: #c65f3f;
    --t-instant: #4a9dd8;
    --t-sorcery: #8b6fc7;
    --t-enchantment: #3fae8c;
    --t-artifact: #9a9488;
    --t-planeswalker: #d9b64e;
    --t-battle: #d46a8f;
    --t-land: #7d9142;
  }
}

/* AGE-182: explicit override - [data-theme] wins over the OS setting in
   both directions ([data-theme="x"] has higher specificity than the bare
   :root/@media rules above, regardless of source order). No attribute
   ("system", the default) falls through to the dark-default/light-media
   pattern above, untouched. Values are exact duplicates of the two blocks
   above, not a new palette. */
:root[data-theme="light"] {
  --bg: #f5f1e6;
  --panel: #ffffff;
  --panel-raised: #faf7ef;
  --panel-sunken: #eee7d6;
  --border: #ddd4c0;
  --border-soft: #e6dfcd;
  --text: #211d16;
  --text-muted: #6b6255;
  --text-faint: #6b6356;
  --accent: #77642b;
  --accent-soft: rgba(190, 148, 30, 0.12);
  --accent-border: rgba(190, 148, 30, 0.4);
  --accent-bright: #c9a227;
  --accent-2: #b8863f;
  --t-creature: #c65f3f;
  --t-instant: #4a9dd8;
  --t-sorcery: #8b6fc7;
  --t-enchantment: #3fae8c;
  --t-artifact: #9a9488;
  --t-planeswalker: #d9b64e;
  --t-battle: #d46a8f;
  --t-land: #7d9142;
}
:root[data-theme="dark"] {
  --bg: #14120f;
  --panel: #1e1b17;
  --panel-raised: #262220;
  --panel-sunken: #100e0b;
  --border: #3a3530;
  --border-soft: #2c2823;
  --text: #ede6d6;
  --text-muted: #a89f8f;
  --text-faint: #958f84;
  /* AGE-196: must be restated here even though it matches the base :root
     default - without it, a user on a light-OS system who explicitly picks
     dark in-app would get the @media(light) block's --accent (equal
     specificity to bare :root, later in source order) instead of this
     block's, breaking the "[data-theme] always wins over OS" guarantee
     every other token here already has. Caught live testing this fix. */
  --accent: var(--color-m);
  --accent-soft: rgba(217, 182, 78, 0.14);
  --accent-border: rgba(217, 182, 78, 0.4);
  --accent-bright: #e8c65f;
  --accent-2: #c9973f;
  /* AGE-132: type-ratio palette, dark-ground - restated for the same
     "[data-theme] always wins over OS" reason as --accent above. */
  --t-creature: #e0714f;
  --t-instant: #5bb0e6;
  --t-sorcery: #a087d6;
  --t-enchantment: #4cc19c;
  --t-artifact: #b0a99b;
  --t-planeswalker: #e8c65f;
  --t-battle: #e885a8;
  --t-land: #9bb154;
}

/* Add Card / Filters redesign (2026-08-22): self-hosted, not linked from
   fonts.googleapis.com - this app's own CSP is font-src 'self'; style-src
   'self' (see public/_headers), so an external Google Fonts <link> would be
   silently blocked outright, and even without that, self-hosting avoids
   sending every visitor's IP to Google (a 2022 Munich court ruling treated
   that as a GDPR violation without consent). Google serves one variable
   file per family/style spanning the whole requested weight range to any
   variable-font-capable browser, so a single file per style below is
   correct, not a truncated subset - each @font-face's font-weight range
   picks the right instance out of that one file. Latin subset only (covers
   the accented Latin-1 characters real card names use, e.g. Dain, Fili). */
@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url("fonts/fraunces-variable.woff2") format("woff2");
}
@font-face {
  font-family: "Fraunces";
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/fraunces-italic-variable.woff2") format("woff2");
}
@font-face {
  font-family: "Work Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/work-sans-variable.woff2") format("woff2");
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  /* Add Card / Filters redesign (2026-08-22): app previously shipped no
     custom typeface at all, just the OS default - Work Sans app-wide, kept
     as the fallback stack so nothing regresses if the self-hosted file
     ever fails to load. */
  font-family: "Work Sans", -apple-system, "Segoe UI", Roboto, sans-serif;
  transition: background-image 0.6s ease;
}

/* Same "outdated scrollbars" report (2026-08-22) that themed .modal's
   scrollbar - that pass only covered modals; the page's own scroll (any
   view taller than the viewport, e.g. the deck page) was still the bare
   OS-default bar. Same thin themed treatment, app-wide this time. */
html {
  scrollbar-width: thin;
  scrollbar-color: var(--accent-2) transparent;
}
html::-webkit-scrollbar { width: 8px; }
html::-webkit-scrollbar-track { background: transparent; }
html::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--accent-2) 55%, transparent);
  border-radius: 999px;
}
html::-webkit-scrollbar-thumb:hover { background: var(--accent-2); }

/* Same redesign: Fraunces (a warm serif, distinct from the Work Sans body
   face) for headings and modal titles app-wide - low-risk since it's a
   font swap only, no layout/behavior change, but touches every modal at
   once via the shared .modal-header h2 rule. */
h1, h2, .modal-header h2 {
  font-family: "Fraunces", Georgia, serif;
  font-weight: 600;
}

/* Topbar/chrome tint (Kevin's 2026-08-14 ask, applyAppWideTheme() in app.js) -
   the real background reskin now lives on every top-level page itself (see
   the #collection-view/#decks-view/#suggestions-view/#audit-view rules
   below, AGE-159's "full reskin everywhere"); this is just the thin chrome
   outside those panels (topbar border, current-deck select) picking up the
   same accent so it doesn't look disconnected from the themed page beneath it. */
body.app-themed .topbar { border-bottom-color: color-mix(in srgb, var(--app-mood-accent) 45%, var(--border)); }

/* AGE-187: back to a single-row .topbar (brand/nav/profile-avatar only) -
   AGE-186's two-row split still read as too busy per Kevin's follow-up.
   Everything else (current deck, stats, History, feedback, sign out) now
   lives inside #profile-dropdown; +Add Card/+New Deck float as a fixed
   bottom-right pair instead of sitting in the bar (see their rules further
   below). .topbar keeps position:sticky, which - same as position:relative -
   establishes the containing block #profile-dropdown's position:absolute
   anchors to, so no extra wrapper element is needed for that. */
.topbar {
  display: flex;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
  padding: 16px 24px;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 20;
}
/* Same bare-[hidden]-loses-to-flex gotcha as .auth-user/.history-items -
   the UA [hidden]{display:none} rule loses to this unconditional display:flex
   at equal specificity, so signed-out visitors would otherwise see the full
   app topbar rendered above the landing/login card. */
.topbar[hidden] { display: none; }

.profile-menu-btn {
  width: 34px; height: 34px; flex: 0 0 auto; margin-left: auto;
  border-radius: 50%; border: 1px solid var(--border); background: var(--panel-raised);
  color: var(--text); font-size: 0.85rem; font-weight: 700; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.profile-menu-btn:hover { border-color: var(--color-m); }
.profile-menu-btn[hidden] { display: none; }

.profile-dropdown {
  position: absolute; top: 100%; right: 24px; margin-top: 8px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35); padding: 14px; z-index: 30;
  min-width: 240px; max-width: 300px;
  display: flex; flex-direction: column; gap: 4px;
}
.profile-dropdown[hidden] { display: none; }
.profile-dropdown .auth-user { flex-direction: column; align-items: stretch; gap: 10px; }
.profile-dropdown .auth-user-username { font-size: 0.95rem; }
.profile-dropdown #auth-signout-btn { width: 100%; }
/* .drawer-section/.drawer-section-label/.drawer-links are AGE-177's mobile
   drawer classes, reused as-is here for visual consistency between the two
   collapsed-menu surfaces instead of writing near-duplicate rules. */
.profile-dropdown .drawer-section { margin-top: 0; padding-top: 10px; border-top: 1px solid var(--border-soft); }
.profile-dropdown .drawer-section:first-child { padding-top: 0; border-top: none; }
.profile-dropdown .stats { flex-wrap: wrap; gap: 10px 16px; }
.profile-dropdown .drawer-utility-links { margin-top: 0; padding-top: 10px; }
.profile-dropdown .nav-drawer-foot { margin-top: 0; padding-top: 10px; }

.topbar h1 {
  font-size: 1.3rem;
  margin: 0;
  background: linear-gradient(90deg, var(--color-m), var(--color-r));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.stats {
  display: flex;
  gap: 20px;
}

.stat { display: flex; flex-direction: column; align-items: center; }
.stat-value { font-size: 1.2rem; font-weight: 700; }
.stat-label { font-size: 0.7rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; }

/* AGE-152: set apart from the real distinct/copies/value trio with a
   divider + muted value color - these are proxy-only/hypothetical figures,
   never part of the real total to their left. */
.stat-proxy { padding-left: 20px; border-left: 1px solid var(--border); }
.stat-proxy .stat-value { color: var(--text-faint); font-weight: 600; }

/* AGE-133: collection value ticker - price-only delta since the previous
   daily snapshot (never conflated with adds/removes, see worker.js
   getValueHistory), plus a small sparkline over up to 30 days. */
.value-ticker { display: flex; align-items: center; gap: 6px; margin-top: 3px; }
.value-sparkline { width: 46px; height: 16px; flex: 0 0 auto; }
.value-sparkline path.line { fill: none; stroke-width: 1.5; }
.value-sparkline path.area { stroke: none; }
.value-ticker-delta { font-size: 0.68rem; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.value-ticker-delta.up { color: var(--color-g); }
.value-ticker-delta.down { color: var(--color-r); }
.value-ticker-delta.flat { color: var(--text-muted); }

.btn {
  background: var(--panel-raised);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 14px;
  cursor: pointer;
  font-size: 0.9rem;
}
.btn:hover { border-color: var(--color-m); }
.btn-primary {
  background: linear-gradient(90deg, var(--color-m), var(--rarity-mythic));
  border: none;
  color: #1a1400;
  font-weight: 600;
}
.btn-danger {
  background: var(--panel-raised);
  border: 1px solid var(--color-r);
  color: var(--color-r);
}
.btn-danger:hover { background: var(--color-r); color: #fff; }
.btn-small { padding: 5px 10px; font-size: 0.78rem; flex: 0 0 auto; }
.btn-link {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  padding: 0;
  text-align: left;
}
.btn-link:hover { text-decoration: underline; }

/* AGE-187: float where the old .feedback-fab circle used to sit - mutually
   exclusive by view already (switchView() in app.js toggles [hidden] on
   whichever one doesn't apply), so no stacking conflict between the two.
   Already display:none below the 860px breakpoint via the existing
   #open-add-card, #open-new-deck rule further down - mobile keeps its own
   separate .add-fab-row "+" button untouched. */
#open-add-card, #open-new-deck {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 50;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.35);
}

.auth-section { display: flex; align-items: center; }
.auth-user { display: flex; align-items: center; gap: 8px; }
/* .auth-user sets display:flex unconditionally - same bare-[hidden] gotcha
   as .stats/.view-tabs above, missed when Stage 1 introduced this element. */
.auth-user[hidden] { display: none; }
.auth-user-email { font-size: 0.8rem; color: var(--text-muted); }
.auth-user-username { font-size: 0.8rem; color: var(--text); font-weight: 600; }

/* ---------- mobile nav chrome (AGE-177) ---------- */
/* Additive layer only: hides the desktop .view-tabs row + a few topbar
   buttons at narrow widths in favor of the drawer/bottom-nav equivalents
   below; everything at wider widths is untouched. */

.menu-btn {
  display: none;
  width: 34px; height: 34px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel-raised); color: var(--text);
  font-size: 1.05rem; cursor: pointer; flex: 0 0 auto;
}

.nav-drawer-backdrop {
  position: fixed; inset: 0; background: rgba(0, 0, 0, 0.55); z-index: 45;
}
.nav-drawer-backdrop[hidden] { display: none; }
.nav-drawer {
  position: absolute; top: 0; left: 0; bottom: 0; width: 78%; max-width: 300px;
  background: var(--panel); border-right: 1px solid var(--border);
  display: flex; flex-direction: column; padding: 18px 14px; gap: 4px; overflow-y: auto;
}
.nav-drawer h2 {
  margin: 0 0 10px; font-size: 1.1rem;
  background: linear-gradient(90deg, var(--color-m), var(--color-r));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.drawer-links { display: flex; flex-direction: column; gap: 2px; }
.drawer-link {
  display: block; width: 100%; text-align: left;
  padding: 11px 10px; border-radius: 8px; border: none; background: none;
  color: var(--text); font-size: 0.92rem; font-family: inherit; cursor: pointer;
}
.drawer-link.active { background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.drawer-section { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border-soft); }
.drawer-section-label {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted); font-weight: 700; margin-bottom: 6px;
}
#current-deck-drawer-slot .current-deck-select { width: 100%; }
.drawer-utility-links { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border-soft); }
/* Kevin's ask, 2026-08-19: matches the artifact, which pins the signed-in
   email + Sign out to the drawer footer (margin-top:auto - .nav-drawer is
   already display:flex; flex-direction:column) instead of the topbar.
   #auth-user's own flex-row styles above are untouched, just wrapped in
   case email + button don't fit on one line at drawer width. */
.nav-drawer-foot { margin-top: auto; padding-top: 14px; border-top: 1px solid var(--border-soft); }
.nav-drawer-foot .auth-user { flex-wrap: wrap; }

.bottom-nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 15;
  display: none; border-top: 1px solid var(--border); background: var(--panel);
  padding: 6px 4px calc(8px + env(safe-area-inset-bottom, 0px));
}
/* Needed for setAppGated()'s signed-out gate (app.js) - [hidden]'s higher
   specificity (0-2-0) correctly beats the plain-class media query rule
   above (0-1-0) regardless of source order, same pattern as .topbar[hidden]
   elsewhere in this file. No `hidden` attribute in the static HTML itself -
   default state is visible-per-media-query, exactly like #topbar. */
.bottom-nav[hidden] { display: none; }
.bottom-nav-btn {
  flex: 1; background: none; border: none; color: var(--text-faint);
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  font-size: 0.62rem; font-family: inherit; padding: 5px 0; cursor: pointer;
}
.bottom-nav-ic { font-size: 1.05rem; }
.bottom-nav-btn.active { color: var(--accent); }
/* Library gets its own elevated art mark instead of the plain icon+label row
   the other two use - it's the tab reached for mid-game, per Kevin's ask. */
.bottom-nav-lib-circle {
  width: 46px; height: 46px; border-radius: 50%; margin: -26px auto 3px;
  background: linear-gradient(145deg, var(--color-m), var(--color-r));
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4), 0 0 0 4px var(--panel);
}
.bottom-nav-lib-circle svg { width: 21px; height: 21px; color: #14120f; }
.bottom-nav-lib.active .bottom-nav-lib-circle { box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4), 0 0 0 4px var(--panel), 0 0 0 6.5px var(--accent-border); }
.bottom-nav-lib .bottom-nav-label { font-weight: 700; }

/* ---------- appearance control (AGE-182) ----------
   Same node relocates between the desktop auth-section and the drawer's
   #drawer-appearance-slot (relocateAppearanceControl() in app.js) - one
   set of rules covers it in both places. */
.theme-seg {
  display: flex; gap: 3px; flex: 0 0 auto;
  background: var(--panel-raised); border: 1px solid var(--border);
  border-radius: 8px; padding: 3px;
}
.theme-seg-btn {
  border: none; background: none; color: var(--text-muted);
  font-size: 0.85rem; line-height: 1; padding: 5px 8px; border-radius: 5px;
  cursor: pointer; font-family: inherit;
}
.theme-seg-btn:hover { color: var(--text); }
/* AGE-196: --color-m not --accent - this pairs a solid fill with hardcoded
   near-black text (9.57:1, plenty of headroom), unlike --accent's now-darker
   light-mode value which exists for text/link use, not fills. Same reasoning
   on every other var(--accent) solid-fill-with-near-black-text rule below. */
.theme-seg-btn.active { background: var(--color-m); color: #14120f; }

/* ---------- mobile card preview overlay (AGE-179 follow-up) ----------
   A real full-screen modal, deliberately not the small .card-tooltip a
   mouse-hover shows - see the markup comment in index.html for why. */
.card-preview-backdrop {
  position: fixed; inset: 0; z-index: 55;
  background: rgba(0, 0, 0, 0.72);
  display: flex; align-items: center; justify-content: center;
  padding: 28px;
}
.card-preview-backdrop[hidden] { display: none; }
.card-preview-card {
  position: relative;
  width: 100%; max-width: 340px;
  border-radius: 14px; overflow: hidden;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
}
.card-preview-card img { width: 100%; display: block; aspect-ratio: 5/7; object-fit: cover; }
.card-preview-close {
  position: absolute; top: 20px; right: 20px; z-index: 1;
  width: 36px; height: 36px; border-radius: 50%;
  background: rgba(20, 18, 15, 0.8); color: #fff; border: none;
  font-size: 1.1rem; line-height: 1; cursor: pointer;
}
/* Kevin's ask (2026-08-21): a way to jump from the mobile tap-preview
   overlay straight to that card's Library page - positioned relative to
   .card-preview-card (not the backdrop, like .card-preview-close above)
   so it tracks the card image itself, bottom-center. */
.card-preview-library-btn {
  position: absolute; bottom: 14px; left: 50%; transform: translateX(-50%); z-index: 1;
  width: 40px; height: 40px; border-radius: 50%;
  background: rgba(20, 18, 15, 0.8); color: #fff; border: none;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
}
.card-preview-library-btn svg { width: 19px; height: 19px; }
/* AGE bugfix 2026-09-02: mobile tap on a [[card-ref]] opens this overlay;
   show a loading line while the Scryfall image resolves, and don't render
   the empty <img> box behind it. */
.card-preview-loading {
  margin: 0; min-height: 320px;
  display: flex; align-items: center; justify-content: center;
  padding: 24px; text-align: center;
  background: var(--panel); color: var(--text-muted); font-size: 0.9rem;
}
.card-preview-loading[hidden] { display: none; }
.card-preview-card img[src=""], .card-preview-card img:not([src]) { display: none; }

.add-fab-row { display: none; justify-content: flex-end; padding: 10px 4px 0; }
.add-fab {
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--panel); border: 1.5px solid var(--accent-border); color: var(--accent);
  font-size: 1.35rem; line-height: 1; cursor: pointer; box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
}
.mobile-only { display: none; }

/* ---------- filter trigger + sheet/popover (AGE-178, extended by AGE-206) ---------- */
/* This row (search + Filters trigger) now shows at every width - it used to
   be mobile-only with .controls shown inline instead at desktop. The sheet/
   popover itself is default-closed via .open (not the [hidden] attribute -
   a viewport-scoped class is what lets the same element be a bottom sheet
   at <=860px and a popover above that without fighting the media query, see
   the comment on relocateSearchInput() in app.js). */

.mobile-filter-bar { display: flex; gap: 8px; }
#mobile-search-slot { flex: 1 1 auto; min-width: 0; }
#mobile-search-slot input[type="search"] {
  width: 100%; background: var(--panel); border: 1px solid var(--border); color: var(--text);
  border-radius: 6px; padding: 8px 10px; font-size: 0.9rem; font-family: inherit;
}
.filter-trigger {
  display: flex; align-items: center; gap: 7px; flex: 0 0 auto;
  background: var(--panel); border: 1px solid var(--border); color: var(--text);
  border-radius: 8px; padding: 8px 12px; font-size: 0.85rem; font-weight: 600; cursor: pointer; font-family: inherit;
}
.filter-trigger:hover, .filter-trigger[aria-expanded="true"] { border-color: var(--color-m); }
/* Kevin's ask (2026-08-26), approved via mockup: Magic's own tap symbol
   (a thin circle+curve) reads lighter than the gear it replaced at the same
   box size, so it's sized up rather than just matching the old icon's box. */
.filter-trigger-icon { width: 19px; height: 19px; stroke-width: 2.3; flex: 0 0 auto; }
.filter-count-badge {
  background: var(--color-m); color: #14120f; font-size: 0.68rem; font-weight: 700;
  border-radius: 999px; padding: 1px 7px;
}
.filter-count-badge[hidden] { display: none; }

/* AGE-206: .filter-group wraps each labeled section of .controls (Color,
   Type, Rarity/set/tag, etc.) - shared column+gap layout at every
   breakpoint, the individual controls inside don't need their own spacing
   rules anymore. .filter-group-label is hidden by default (the mobile sheet
   stays the flat, unlabeled list AGE-178 shipped) and only shown inside the
   desktop popover below, where there's room for it. */
.filter-group { display: flex; flex-direction: column; gap: 8px; }
.filter-group-label {
  display: none; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.03em;
  text-transform: uppercase; color: var(--text-faint);
}
/* Real bug Kevin caught live in the first popover pass: chip rows (Type
   especially, 8 pill buttons) never wrapped, so the popover's fixed width
   forced a horizontal scrollbar instead of flowing to a second line. Fixed
   at both breakpoints, not just the popover, since the mobile sheet had the
   same latent risk (just enough viewport width there that it went
   unnoticed) - a flex item's default min-width:auto floor is the other half
   of the fix, see `.filter-sheet .controls > *` in each @media block below. */
.filter-sheet .controls .chip-group { flex-wrap: wrap; }

/* Kevin's ask (2026-08-26), approved via mockup: Select Cards/Export CSV
   live here now instead of their own row above the grid - a plain
   .filter-group would look identical to Color/Type/etc above it, so a top
   border marks it as the panel's one non-filter section. */
.fp-actions-group { padding-top: 10px; border-top: 1px solid var(--border-soft); }
.fp-action-btn {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  background: var(--panel-raised); border: 1px solid var(--border); color: var(--text);
  border-radius: 8px; padding: 9px 10px; font-size: 0.85rem; font-weight: 600; cursor: pointer; font-family: inherit;
}
.fp-action-btn:hover { border-color: var(--color-m); }
.fp-action-btn svg { width: 16px; height: 16px; flex: 0 0 auto; color: var(--accent); }

/* Inert by default; each @media block below turns display on for its own
   breakpoint so neither one can leak layout (position/width/etc) into the
   other - see AGE-206 build notes for why that matters here specifically. */
.filter-sheet-backdrop { display: none; }
.filter-sheet { display: none; }
.filter-sheet-handle, .filter-sheet-head, .filter-sheet-foot { display: none; }

/* ---------- desktop/tablet: popover anchored under the trigger ---------- */
@media (min-width: 861px) {
  .mobile-filter-bar { margin-bottom: 20px; }

  .filter-sheet-backdrop {
    display: block; position: fixed; inset: 0; z-index: 32; pointer-events: none;
  }
  .filter-sheet-backdrop.open { pointer-events: auto; }
  .filter-sheet {
    display: flex; flex-direction: column;
    position: fixed; width: 340px; max-height: 520px;
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    box-shadow: 0 20px 50px -18px rgba(0, 0, 0, 0.35), 0 4px 14px -6px rgba(0, 0, 0, 0.2);
    opacity: 0; transform: translateY(-6px) scale(0.98); pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease; transform-origin: top right;
    z-index: 33;
  }
  .filter-sheet-backdrop.open .filter-sheet {
    opacity: 1; transform: translateY(0) scale(1); pointer-events: auto;
  }
  .filter-sheet-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 12px 16px; border-bottom: 1px solid var(--border-soft); flex: 0 0 auto;
  }
  .filter-sheet-head h3 { margin: 0; font-size: 0.95rem; }
  .filter-sheet-reset { background: none; border: none; color: var(--accent); font-size: 0.8rem; font-weight: 700; cursor: pointer; font-family: inherit; }
  .filter-sheet .controls {
    display: flex; flex-direction: column; flex-wrap: nowrap; align-items: stretch;
    overflow-y: auto; overflow-x: hidden; padding: 14px 16px; margin: 0; gap: 16px;
  }
  /* min-width:0 overrides the flex item default (min-width:auto), which is
     what let a too-wide child (the unwrapped chip-group, before the fix
     above) force this whole column past the popover's fixed width. */
  .filter-sheet .controls > * { margin: 0; min-width: 0; }
  .filter-group-label { display: block; }
  .filter-sheet .controls select { width: 100%; }
  .filter-sheet-foot { display: block; padding: 12px 16px; border-top: 1px solid var(--border-soft); flex: 0 0 auto; }
  .filter-sheet-done {
    width: 100%; background: var(--color-m); color: #14120f; border: none; border-radius: 8px;
    padding: 10px; font-weight: 700; font-size: 0.85rem; cursor: pointer; font-family: inherit;
  }
}

@media (max-width: 860px) {
  .menu-btn { display: flex; align-items: center; justify-content: center; }
  /* Kevin's report, 2026-08-19: the top tab row never actually hid on
     mobile despite this rule - .view-tabs (class selector, specificity
     0-1-0) tied with the base .view-tabs { display: flex } rule further
     down the file (also 0-1-0), and CSS breaks specificity ties by source
     order, so the later unconditional rule silently won regardless of
     viewport. #view-tabs (the same element already has this id) is
     specificity 1-0-0, which beats the class rule outright - order stops
     mattering. Same fix shape as the .bottom-nav[hidden]/.auth-user[hidden]
     higher-specificity overrides elsewhere in this file. */
  #view-tabs, #open-add-card, #open-new-deck { display: none; }
  /* AGE-187: the desktop-only profile menu has no purpose here - #stats
     relocates to #mobile-stats-slot instead (relocateStats() in app.js,
     same pattern as #current-deck-select/#appearance-control/#auth-user
     below relocating the other direction into the drawer), and
     #open-history/#open-feedback both already have their own separate
     drawer-only equivalents (#drawer-history-btn/#drawer-feedback-btn). */
  #profile-menu-btn, #profile-dropdown { display: none; }
  .bottom-nav { display: flex; }
  /* Kevin's report, 2026-08-19: the FAB sat as a plain block after the whole
     #grid, so on a real collection (300+ cards) it was scrolled far below
     the fold - reachable only by scrolling to the very bottom, effectively
     "no way to add a card". Sticky to the viewport bottom, clearing the
     fixed .bottom-nav underneath it, same safe-area math .bottom-nav uses. */
  .add-fab-row {
    display: flex;
    position: sticky;
    bottom: calc(76px + env(safe-area-inset-bottom, 0px));
    z-index: 10;
    padding-right: 4px;
  }
  .mobile-only { display: block; width: 100%; margin-bottom: 12px; }

  .mobile-filter-bar { padding: 0 0 4px; }

  .filter-sheet-backdrop {
    display: block; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.55); z-index: 40;
    opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
  }
  .filter-sheet-backdrop.open { opacity: 1; pointer-events: auto; }
  .filter-sheet {
    display: flex; flex-direction: column;
    position: absolute; left: 0; right: 0; bottom: 0; max-height: 82%;
    background: var(--panel); border: 1px solid var(--border); border-bottom: none;
    border-radius: 16px 16px 0 0; transform: translateY(100%); transition: transform 0.25s ease;
  }
  .filter-sheet-backdrop.open .filter-sheet { transform: translateY(0); }
  .filter-sheet-handle { display: block; width: 36px; height: 4px; background: var(--border); border-radius: 4px; margin: 10px auto 2px; flex: 0 0 auto; }
  .filter-sheet-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 4px 16px 10px; border-bottom: 1px solid var(--border-soft); flex: 0 0 auto;
  }
  .filter-sheet-head h3 { margin: 0; font-size: 1rem; }
  .filter-sheet-reset { background: none; border: none; color: var(--accent); font-size: 0.82rem; font-weight: 700; cursor: pointer; font-family: inherit; }
  .filter-sheet .controls {
    display: block; overflow-y: auto; padding: 14px 16px; margin: 0;
  }
  .filter-sheet .controls > * { margin-bottom: 12px; }
  .filter-sheet-foot { display: block; padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px)); border-top: 1px solid var(--border-soft); flex: 0 0 auto; }
  .filter-sheet-done { width: 100%; background: var(--color-m); color: #14120f; border: none; border-radius: 10px; padding: 12px; font-weight: 700; font-size: 0.88rem; cursor: pointer; font-family: inherit; }
}

/* Hold-to-reset fill for #filter-sheet-done-btn (app.js) - --reset-fill is
   stepped every animation frame while held, 0 to 1 over 2s, so this stays a
   plain scaleX read instead of a CSS transition (a transition would also
   animate the *release* case, which should snap back to empty instantly). */
.filter-sheet-done { position: relative; overflow: hidden; --reset-fill: 0; }
.filter-sheet-done::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.22);
  transform: scaleX(var(--reset-fill));
  transform-origin: left;
  pointer-events: none;
}
.filter-sheet-done.reset-flash::after { background: rgba(255, 255, 255, 0.65); transform: scaleX(1); }

main { padding: 20px 24px 60px; max-width: 1400px; margin: 0 auto; }

/* Must come after the unconditional `main` rule above so the shorthand
   `padding` there doesn't clobber this override at the cascade's equal
   specificity (source order decides) - reserves room for the fixed
   .bottom-nav so it doesn't cover the last row of content. */
@media (max-width: 860px) {
  main { padding-bottom: 84px; }
}

.controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 20px;
}

.controls input[type="search"],
.controls select {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 0.9rem;
}
.controls input[type="search"] { flex: 1 1 220px; }

.chip-group { display: flex; gap: 6px; }
.chip {
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 2px solid var(--border);
  background: var(--panel-raised);
  color: var(--text);
  font-size: 0.75rem;
  font-weight: 700;
  cursor: pointer;
}
/* Kevin's ask, 2026-08-23: each color chip's border matches the mana color
   it represents even before selection (was a neutral --border regardless of
   color), and stays that color when active - only the fill/text flip. */
.chip-w { border-color: var(--color-w); }
.chip-u { border-color: var(--color-u); }
.chip-b { border-color: var(--color-b); }
.chip-r { border-color: var(--color-r); }
.chip-g { border-color: var(--color-g); }
.chip-c { border-color: var(--color-c); }
.chip.active { color: #14120f; }
.chip-w.active { background: var(--color-w); border-color: var(--color-w); }
.chip-u.active { background: var(--color-u); border-color: var(--color-u); }
.chip-b.active { background: var(--color-b); border-color: var(--color-b); }
.chip-r.active { background: var(--color-r); border-color: var(--color-r); }
.chip-g.active { background: var(--color-g); border-color: var(--color-g); }
.chip-c.active { background: var(--color-c); border-color: var(--color-c); }
/* "Multi" never fit the 30px circle other chips use (its label needs real
   width) - was only sized as a pill once .active, so the unselected state
   clipped/bled past its own circle. Pill-shaped at all times now, matching
   .type-chip's treatment. */
.chip-m { width: auto; border-radius: 15px; padding: 0 10px; border-color: var(--color-m); }
.chip-m.active { background: var(--color-m); border-color: var(--color-m); }

.type-chip {
  width: auto;
  height: auto;
  border-radius: 15px;
  padding: 6px 12px;
  font-size: 0.75rem;
  font-weight: 600;
}
.type-chip.active { background: var(--color-m); border-color: var(--color-m); }

/* AGE-155 manual-override follow-up: same shape as .type-chip, distinct
   accent (matches .treatment-badge's purple) so the toggle state reads at a
   glance next to the color/type chips it visually sits alongside. */
.treatment-chip { width: auto; height: auto; border-radius: 15px; padding: 6px 12px; font-size: 0.75rem; font-weight: 600; }
.treatment-chip.active { background: #9b6fd1; border-color: #9b6fd1; color: #14120f; }
.treatment-chip-row { display: flex; flex-wrap: wrap; gap: 6px; }

.foil-toggle { display: flex; align-items: center; gap: 6px; font-size: 0.85rem; color: var(--text-muted); }

.grid {
  display: grid;
  /* Kevin's report, 2026-08-22: liked the denser 150px tile size tried live
     against real cards while previewing the filters-popover mockup, then
     asked for it as a user-facing choice instead of a fixed value - #card-
     size-select in app.js sets --card-min (compact/cozy/comfortable/large,
     150px "cozy" was verified against the longest wrapping names ("Bilbo
     Baggins, Burglar // Take a Glance") and badge rows ("Fracture Foil +1")
     at the low end, 220px "large" at the high end). 130px here matches
     "pro" (2026-08-23: made the default - art-only tiles, no name/badge
     text to wrap, so it doesn't need cozy's extra room). The mobile
     override two columns down stays untouched - card size is a desktop-
     density preference, mobile's 2-column layout doesn't need it.
     --card-min here is the fallback for the brief window before app.js
     applies the saved choice, not a value anyone picks directly. */
  grid-template-columns: repeat(auto-fill, minmax(var(--card-min, 130px), 1fr));
  gap: 16px;
}

.collection-toolbar { display: flex; align-items: center; gap: 10px; margin: 4px 0 10px; flex-wrap: wrap; }

/* AGE-210 follow-up: wishlist / filtered-collection value bar. Compact
   treatment (Kevin's pick over a taller banner) - one line, small type. */
.collection-valuebar {
  display: flex; align-items: baseline; gap: 8px 12px; flex-wrap: wrap;
  background: var(--accent-soft); border: 1px solid var(--accent-border);
  border-radius: 9px; padding: 7px 12px; margin: 0 0 12px;
}
/* display:flex above beats the UA [hidden]{display:none} - same gotcha as
   .stats[hidden], .topbar[hidden] etc. throughout this file. */
.collection-valuebar[hidden] { display: none; }
.collection-valuebar .cv-amt {
  font-weight: 600; font-size: 1.05rem; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.collection-valuebar .cv-lbl { font-size: 0.8rem; color: var(--text-muted); }
.collection-valuebar .cv-basis { margin-left: auto; font-size: 0.7rem; color: var(--text-faint); }
@media (max-width: 480px) {
  .collection-valuebar .cv-basis { margin-left: 0; flex-basis: 100%; }
}
.wl-price.is-est { color: var(--text-muted); }
.wl-drawer-estnote { padding: 4px 11px 8px; font-size: 0.72rem; color: var(--text-faint); font-style: italic; }

/* AGE-210 follow-up: wishlist sort control in the collection toolbar. */
.wishlist-sort-ctrl { display: inline-flex; align-items: center; gap: 6px; }
.wishlist-sort-ctrl[hidden] { display: none; }
.wishlist-sort-ctrl select {
  font: inherit; font-size: 0.82rem; padding: 3px 6px; border-radius: 6px;
  border: 1px solid var(--border); background: var(--panel-raised); color: var(--text); cursor: pointer;
}

.grid-load-more-row { display: flex; justify-content: center; margin: 18px 0; }

/* Kevin's ask (2026-08-26): bulk select in the real Collection grid, not
   just Quick Add/Bulk Import's staging queues. .bulk-select-mode is toggled
   on #grid itself; the per-tile ::before circle doubles as the hit target
   affordance and the checked/unchecked indicator - .card/.pro-tile are
   already position:relative, so no extra wrapper markup is needed. */
#grid.bulk-select-mode .card,
#grid.bulk-select-mode .pro-tile { cursor: pointer; }
#grid.bulk-select-mode .card::before,
#grid.bulk-select-mode .pro-tile::before {
  content: "";
  position: absolute;
  top: 6px;
  left: 6px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 2px solid #fff;
  background: rgba(0, 0, 0, 0.35);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  z-index: 5;
}
#grid.bulk-select-mode .card.bulk-selected::before,
#grid.bulk-select-mode .pro-tile.bulk-selected::before {
  background: var(--color-m);
  border-color: var(--color-m);
}
#grid.bulk-select-mode .card.bulk-selected,
#grid.bulk-select-mode .pro-tile.bulk-selected {
  outline: 2px solid var(--color-m);
  outline-offset: -2px;
}

.card {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--card-rarity-frame, var(--border));
  border-radius: 10px;
  overflow: hidden;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
  border-top: 3px solid var(--card-accent, var(--color-c));
  /* Kevin's report, 2026-08-19: AGE-179's tap-to-preview needed two taps on
     iOS Safari to actually register a click. Root cause is a well-known
     WebKit quirk - an element with a real :hover style (the lift/shadow
     below) but no cursor:pointer gets treated as "hover-only" on first tap
     (just applies :hover, e.g. revealing .edit-btn), and only fires the
     actual click on a second tap. cursor:pointer signals it's immediately
     clickable, so the click - and wireTouchCardPreview()'s handler for it -
     fires on the first tap like everywhere else in this file already does. */
  cursor: pointer;
}
.card:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 20px rgba(0,0,0,0.35);
}

/* Kevin's 2026-08-15 ask: same rarity-frame idea as the app-wide/deck-detail
   reskin (AGE-147/159), scaled down to a per-tile signal instead of a
   full-page one - common/uncommon just get their border tinted via
   --card-rarity-frame above, rare/mythic add a small glow so they still pop
   next to each other despite the small tile size. Hover variants repeat the
   glow alongside the existing lift shadow instead of losing it on hover. */
.card-rarity-rare {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--rarity-rare) 45%, transparent), 0 0 12px color-mix(in srgb, var(--rarity-rare) 25%, transparent);
}
.card-rarity-mythic {
  border-width: 2px;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--rarity-mythic) 55%, transparent), 0 0 16px color-mix(in srgb, var(--rarity-mythic) 35%, transparent);
}
.card-rarity-rare:hover {
  box-shadow: 0 8px 20px rgba(0,0,0,0.35), 0 0 0 1px color-mix(in srgb, var(--rarity-rare) 45%, transparent), 0 0 12px color-mix(in srgb, var(--rarity-rare) 25%, transparent);
}
.card-rarity-mythic:hover {
  box-shadow: 0 8px 20px rgba(0,0,0,0.35), 0 0 0 1px color-mix(in srgb, var(--rarity-mythic) 55%, transparent), 0 0 16px color-mix(in srgb, var(--rarity-mythic) 35%, transparent);
}
.card img { width: 100%; display: block; background: var(--panel-raised); aspect-ratio: 5/7; object-fit: cover; }

.edit-btn {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: rgba(20, 18, 15, 0.75);
  color: #fff;
  font-size: 0.85rem;
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 0.15s ease;
}
.card:hover .edit-btn,
.card:focus-within .edit-btn { opacity: 1; }
.edit-btn:hover { border-color: var(--color-m); }

/* ---------- Pro View card size (Kevin's ask, 2026-08-22) ----------
   Mocked up interactively before this was built (see the "Pro View"
   Artifact from that session) - art-only tile, name as a caption below,
   the usual footer badges moved into a parchment panel shown on hover
   (desktop) or a two-tap reveal (mobile, see the #grid click handler in
   app.js). .pro-stats is nested inside .pro-art (not a sibling) and
   absolutely positioned against it - .pro-art is already the nearest
   positioned ancestor, so inset:0 exactly matches its box (including its
   aspect-ratio-driven height) without touching .pro-name, which sits
   outside .pro-art entirely. */
.pro-tile { position: relative; display: grid; grid-template-columns: 1fr; grid-template-rows: auto auto; gap: 6px; cursor: pointer; }
.pro-art { grid-column: 1; grid-row: 1; }
.pro-art {
  aspect-ratio: 5/7; border-radius: 8px; overflow: hidden; position: relative;
  background: var(--panel-raised); border: 1px solid var(--border);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.pro-art img { width: 100%; height: 100%; object-fit: cover; display: block; position: absolute; top: 0; left: 0; }
.pro-tile:hover .pro-art, .pro-tile.pro-revealed .pro-art { transform: translateY(-2px); box-shadow: 0 8px 18px rgba(0,0,0,0.22); border-color: var(--color-m); }

.pro-stats {
  position: absolute; inset: 0; border-radius: 8px; overflow: hidden;
  display: flex; align-items: flex-end; padding: 8px;
  opacity: 0; transition: opacity 0.15s ease; pointer-events: none;
}
.pro-tile:hover .pro-stats, .pro-tile.pro-revealed .pro-stats { opacity: 1; }
.pro-stats-panel {
  width: 100%; background: linear-gradient(180deg, var(--parchment-1), var(--parchment-2));
  border: 1px solid var(--parchment-edge); border-radius: 6px; color: var(--parchment-text);
  padding: 7px 9px; font-family: "Fraunces", Georgia, serif;
  box-shadow: 0 6px 14px rgba(0,0,0,0.3);
}
.pro-stats-row { display: flex; align-items: center; justify-content: space-between; font-size: 0.66rem; line-height: 1.5; gap: 8px; }
.pro-stats-row b { font-weight: 700; }
.pro-stats-badges { display: flex; gap: 4px; flex-wrap: wrap; justify-content: flex-end; margin-top: 4px; }
.rarity-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 4px; vertical-align: middle; }

.pro-edit-btn { opacity: 0.55; }
.pro-tile:hover .pro-edit-btn, .pro-tile:focus-within .pro-edit-btn, .pro-tile.pro-revealed .pro-edit-btn { opacity: 1; }

/* Kevin's ask, 2026-08-24: wanted the name to "pop" more but stay WCAG AA -
   var(--accent) is already contrast-verified for text use (AGE-196), not
   just a decorative token, so this doesn't reopen that audit. Mocked
   against --text (neutral, brighter) too; --accent won out live. */
.pro-name { grid-row: 2; font-size: 0.72rem; text-align: center; color: var(--accent); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Foil/etched shimmer (Kevin's ask, 2026-08-24) - hover/tap to reveal,
   reusing .pro-revealed (the same class the tap-to-reveal stats panel
   already toggles on mobile, see app.js) rather than inventing a second
   trigger mechanism. Scattered glitter dots + two crossing diagonal
   streaks at different angles/speeds, not one clean symmetric band - reads
   as irregular sparkle instead of a mechanical wipe (mockup-tested against
   real card art: https://claude.ai/code/artifact/8e7dde88-5335-46b6-a3bd-f89d06340653).
   Hidden at rest (opacity:0) since "reveal" was the explicit ask - nothing
   animates for a tile nobody's touching, so cost is zero across a 300+
   card grid until a card is actually hovered/tapped. */
.pro-shimmer {
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    radial-gradient(circle at 15% 30%, rgba(255,255,255,0.9) 0%, transparent 3%),
    radial-gradient(circle at 68% 12%, rgba(255,255,255,0.7) 0%, transparent 2%),
    radial-gradient(circle at 40% 68%, rgba(232,198,95,0.85) 0%, transparent 2.5%),
    radial-gradient(circle at 82% 55%, rgba(255,255,255,0.6) 0%, transparent 1.8%),
    radial-gradient(circle at 25% 85%, rgba(232,198,95,0.75) 0%, transparent 2%),
    radial-gradient(circle at 58% 40%, rgba(255,255,255,0.5) 0%, transparent 1.5%),
    linear-gradient(128deg, transparent 20%, rgba(255,255,255,0.85) 33%, rgba(232,198,95,0.4) 40%, transparent 52%),
    linear-gradient(65deg, transparent 60%, rgba(180,210,255,0.4) 70%, rgba(255,255,255,0.55) 76%, transparent 88%);
  background-size: auto, auto, auto, auto, auto, auto, 250% 250%, 220% 220%;
  background-position: 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, -60% -60%, 140% 40%;
  opacity: 0;
  transition: background-position 0.9s ease, opacity 0.2s ease;
}
.pro-tile:hover .pro-shimmer,
.pro-tile.pro-revealed .pro-shimmer {
  background-position: 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 60% 60%, -40% -20%;
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .pro-shimmer { transition: none !important; }
}

/* Pro V2 shimmer override (Kevin's ask, 2026-09-16): the streak stops above
   were tuned against ProView's tall 5:7 .pro-art box; on Pro V2's wide
   626:457 .pro2-art crop the same angle/percentages compress into a much
   shorter vertical span and read as a hard wedge instead of a soft glow.
   Fix: strip the streaks off the base layer here (dots only, unchanged -
   they were never the problem) and move them to their own blurred ::after,
   with wider/softer transition stops. Mockup-approved variant C:
   https://claude.ai/artifact/SHjjHtSu25JgM5BL2kSEAM - .pro-tile-v2 already
   has overflow:hidden + border-radius, so the blurred layer's -15% inset
   bleed is clipped at the tile edge for free. */
.pro-tile-v2 .pro-shimmer {
  background-image:
    radial-gradient(circle at 15% 30%, rgba(255,255,255,0.9) 0%, transparent 3%),
    radial-gradient(circle at 68% 12%, rgba(255,255,255,0.7) 0%, transparent 2%),
    radial-gradient(circle at 40% 68%, rgba(232,198,95,0.85) 0%, transparent 2.5%),
    radial-gradient(circle at 82% 55%, rgba(255,255,255,0.6) 0%, transparent 1.8%),
    radial-gradient(circle at 25% 85%, rgba(232,198,95,0.75) 0%, transparent 2%),
    radial-gradient(circle at 58% 40%, rgba(255,255,255,0.5) 0%, transparent 1.5%);
}
.pro-tile-v2 .pro-shimmer::after {
  content: "";
  position: absolute; inset: -15%;
  background-image:
    linear-gradient(128deg, transparent 10%, rgba(255,255,255,0.65) 33%, rgba(232,198,95,0.32) 43%, transparent 62%),
    linear-gradient(65deg, transparent 50%, rgba(180,210,255,0.32) 68%, rgba(255,255,255,0.4) 76%, transparent 94%);
  background-size: 260% 260%, 230% 230%;
  background-position: -60% -60%, 140% 40%;
  filter: blur(3px);
  opacity: 0;
  transition: background-position 0.9s ease, opacity 0.2s ease;
}
.pro-tile-v2:hover .pro-shimmer::after,
.pro-tile-v2.pro-revealed .pro-shimmer::after {
  background-position: 60% 60%, -40% -20%;
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .pro-tile-v2 .pro-shimmer::after { transition: none !important; }
}

/* "Pro v2" card size (2026-08-26, mockup-approved) - art_crop tile with a
   permanent name/type/mana footer. Mirrors the approved Library mockup's
   .tile. Shares .pro-tile for the grid click handler + bulk-select styling;
   .pro-tile-v2 overrides the "pro" layout back to a bordered card body. */
.pro-tile-v2 {
  display: flex; flex-direction: column; gap: 0;
  border: 1px solid var(--border); border-radius: 10px; overflow: hidden;
  background: var(--panel); cursor: pointer;
  transition: transform 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
}
.pro-tile-v2:hover, .pro-tile-v2:focus-within {
  transform: translateY(-3px); border-color: var(--color-m);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.28);
}
.pro2-art { position: relative; }
.pro2-art img {
  display: block; width: 100%; aspect-ratio: 626 / 457;
  object-fit: cover; background: var(--panel-sunken);
}
.pro2-meta { padding: 9px 11px 11px; display: flex; flex-direction: column; gap: 3px; }
.pro2-name {
  font-family: "Fraunces", Georgia, serif;
  font-weight: 600; font-size: 0.86rem; line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.pro2-type {
  font-size: 0.7rem; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pro2-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 6px; margin-top: 4px;
}
.pro2-pips { display: inline-flex; gap: 3px; flex-wrap: wrap; }
.pro2-qty { font-size: 0.68rem; color: var(--text-muted); white-space: nowrap; }
.pro2-badges { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 5px; }
.pro2-badges:empty { display: none; }

/* Shared mana pips (also used by the Library results grid). */
.mana-pip {
  width: 15px; height: 15px; border-radius: 50%;
  font-size: 9px; font-weight: 700; color: #1a1400;
  display: inline-flex; align-items: center; justify-content: center;
}
.mana-pip-W { background: var(--color-w); }
.mana-pip-U { background: var(--color-u); }
.mana-pip-B { background: var(--color-b); color: #f3eef8; }
.mana-pip-R { background: var(--color-r); }
.mana-pip-G { background: var(--color-g); }
.mana-pip-C, .mana-pip-X, .mana-pip-num { background: var(--color-c); }

/* Drawer footer version string (Kevin's standing rule - bump every deploy). */
.app-version {
  padding: 8px 12px 4px;
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.app-version:empty { display: none; }

/* Shared "smart search": the descriptor button + describe-mode state.
   wireSmartSearch() adds .ss-field to each search input's parent and injects
   the .ss-wand button. Every card-search box in the app uses this. */
.ss-field { position: relative; }
/* left padding for the wand is set inline by wireSmartSearch() so it beats
   the various per-box `padding` shorthands (.deck-add-card input etc.). */
.ss-wand {
  position: absolute; left: 5px; top: 50%; transform: translateY(-50%);
  width: 27px; height: 27px; border: 0; border-radius: 7px;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; color: var(--text-faint); cursor: pointer;
  font-size: 14px; line-height: 1; z-index: 2;
  transition: color 0.12s ease, background 0.12s ease;
}
.ss-wand:hover { color: var(--color-m); background: var(--accent-soft); }
.ss-wand:focus-visible { outline: 2px solid var(--color-m); outline-offset: 1px; }
.ss-field.describe-on > input { border-color: var(--color-m); box-shadow: inset 0 0 0 1px var(--accent-border); }
.ss-field.describe-on .ss-wand { color: #1a1400; background: var(--color-m); }
/* New Deck wizard's commander field hand-rolls the wand instead of calling
   wireSmartSearch() (its "describe" means a freeform concept for the build
   assistant, not a translated Scryfall query - see setCmdrDescribing in
   app.js) - so it needs this same left padding applied statically instead of
   the inline style wireSmartSearch() sets on every other search box. */
#nd-cmdr-search { padding-left: 38px; }

/* describe-mode translated-query chip (Collection / Deck / Commander).
   Library keeps its own #library-query-edit-wrap; this is the compact
   inline version for the other surfaces. */
.describe-chip {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin: 9px 0 4px; padding: 8px 11px;
  background: var(--panel); border: 1px solid var(--border-soft);
  border-left: 3px solid var(--color-m); border-radius: 8px;
}
.describe-chip[hidden] { display: none; }
.describe-chip .lbl { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint); }
.describe-chip input {
  flex: 1; min-width: 180px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.8rem;
  background: var(--panel-sunken); color: var(--accent-bright, var(--accent));
  border: 1px solid var(--border); border-radius: 6px; padding: 5px 8px;
}
.describe-chip input:focus { outline: none; border-color: var(--color-m); }
.describe-chip .src { font-size: 0.78rem; color: var(--text-muted); }

/* Collection describe + "search every card" merged results grid. Reuses
   .library-tile; owned tiles get the accent ring + quantity, catalog tiles
   render dashed with a "not owned" tag. */
.describe-scope-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 8px 0 2px; font-size: 0.82rem; color: var(--text-muted);
}
.describe-scope-row[hidden] { display: none; }
.describe-scope-row .count { margin-left: auto; font-size: 0.75rem; color: var(--text-faint); }
.library-tile.tile-owned { box-shadow: inset 0 0 0 2px var(--accent-border); }
.library-tile.tile-unowned { border-style: dashed; }
.library-tile .tile-badge {
  font-size: 0.6rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  padding: 2px 6px; border-radius: 4px;
}
.library-tile .tile-badge.owned { background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent-border); }
.library-tile .tile-badge.unowned { color: var(--text-faint); border: 1px dashed var(--border); }
.library-tile .library-tile-foot { display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-top: 7px; }

/* Deck / Commander suggestion rows: owned vs catalog grouping + action label. */
.deck-suggestion-item .sugg-action {
  font-size: 0.66rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-faint); white-space: nowrap; margin-left: auto; padding-left: 8px;
}
.deck-suggestion-item.sugg-owned .sugg-action { color: var(--accent); }
.deck-suggestion-group {
  padding: 6px 12px; font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--text-faint); background: var(--panel-sunken);
}

/* Library describe-a-card results grid + editable translated query. */
.library-query-edit-wrap { margin: 10px 0 4px; display: flex; flex-direction: column; gap: 4px; }
.library-query-edit-wrap[hidden] { display: none; }
.library-query-edit-row { display: flex; gap: 8px; align-items: center; }
#library-query-edit {
  flex: 1; min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.82rem;
  background: var(--panel-sunken); color: var(--accent-bright, var(--accent));
  border: 1px solid var(--border); border-radius: 6px; padding: 6px 9px;
}
#library-query-edit:focus { outline: none; border-color: var(--color-m); }
.library-setbar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; margin: 8px 0 2px;
}
.library-setbar[hidden] { display: none; }
#library-setbar-status { font-variant-numeric: tabular-nums; }

.library-results-grid {
  display: grid; gap: 16px; margin-top: 14px;
  grid-template-columns: repeat(auto-fill, minmax(184px, 1fr));
}
.library-results-grid[hidden] { display: none; }
.library-tile {
  border: 1px solid var(--border); border-radius: 10px; overflow: hidden;
  background: var(--panel); cursor: pointer; text-align: left;
  font-family: inherit; color: var(--text); padding: 0;
  transition: transform 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
}
.library-tile:hover, .library-tile:focus-visible {
  transform: translateY(-3px); border-color: var(--color-m);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.28); outline: none;
}
.library-tile img {
  display: block; width: 100%; aspect-ratio: 626 / 457;
  object-fit: cover; background: var(--panel-sunken);
}
.library-tile .library-tile-meta { padding: 9px 11px 11px; }
.library-tile .library-tile-name {
  font-family: "Fraunces", Georgia, serif;
  font-weight: 600; font-size: 0.86rem; line-height: 1.25;
}
.library-tile .library-tile-type { font-size: 0.7rem; color: var(--text-muted); margin-top: 3px; }
.library-tile .library-tile-mana { margin-top: 6px; display: flex; gap: 3px; flex-wrap: wrap; }

.card-body { padding: 10px; }
.card-name { font-weight: 600; font-size: 0.9rem; margin-bottom: 4px; }
.card-meta { display: flex; justify-content: space-between; align-items: center; font-size: 0.75rem; color: var(--text-muted); }

.rarity-badge {
  display: inline-block;
  width: 10px; height: 10px;
  border-radius: 50%;
}
.rarity-common { background: var(--rarity-common); }
.rarity-uncommon { background: var(--rarity-uncommon); }
.rarity-rare { background: var(--rarity-rare); }
.rarity-mythic { background: var(--rarity-mythic); }

.card-footer { display: flex; justify-content: space-between; align-items: center; margin-top: 6px; font-size: 0.8rem; gap: 6px; }
.card-badges { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; justify-content: flex-end; }
.foil-badge {
  background: linear-gradient(90deg, #d9b64e, #4aa3d8, #e0554a);
  color: #14120f;
  font-weight: 700;
  font-size: 0.65rem;
  padding: 1px 6px;
  border-radius: 8px;
}
/* AGE-155 phase 3: distinct from .foil-badge on purpose - etched cards are
   priced off a different Scryfall field (price_usd_etched) and shouldn't
   visually read as "just foil". Cool metallic tone vs foil's warm gradient. */
.etched-badge {
  background: linear-gradient(90deg, #7d8b9a, #a8b6c4, #7d8b9a);
  color: #14120f;
  font-weight: 700;
  font-size: 0.65rem;
  padding: 1px 6px;
  border-radius: 8px;
}
.pending-badge {
  background: var(--color-u);
  color: #14120f;
  font-weight: 700;
  font-size: 0.65rem;
  padding: 1px 6px;
  border-radius: 8px;
}

/* AGE-152: proxy cards never contribute to collection value (see
   getStats/writeValueSnapshot) - the dashed accent border is a persistent,
   always-visible signal distinct from the other badges, since it's a
   property of the card that changes how its value is read everywhere, not
   just another attribute tag. */
.card-proxy { border-style: dashed; border-color: var(--text-faint); }
.card-proxy .card-footer > span:first-child { color: var(--text-faint); }
.proxy-badge {
  background: transparent;
  border: 1px solid var(--text-faint);
  color: var(--text-faint);
  font-weight: 700;
  font-size: 0.65rem;
  padding: 0 5px;
  border-radius: 8px;
}

/* AGE-153: condition badges - pill mode is a 5-step green-to-red scale,
   deliberately its own token set rather than reusing the W/U/B/R/G mana
   colors, which already mean something else on these same cards via
   --card-accent. */
.condition-badge { font-size: 0.65rem; }
.condition-pill {
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 8px;
  color: #14120f;
}
.condition-pill.condition-nm { background: #3fa66c; }
.condition-pill.condition-lp { background: #7ab648; }
.condition-pill.condition-mp { background: #d9b64e; }
.condition-pill.condition-hp { background: #d8823f; }
.condition-pill.condition-dmg { background: #e0554a; }
.condition-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--panel-raised);
  border: 1px solid var(--border);
}
.condition-icon.condition-nm { color: #3fa66c; }
.condition-icon.condition-lp { color: #7ab648; }
.condition-icon.condition-mp { color: #d9b64e; }
.condition-icon.condition-hp { color: #d8823f; }
.condition-icon.condition-dmg { color: #e0554a; }

/* Condition filter chips: same pill/icon markup as the on-card badge (see
   conditionBadgeHtml/renderConditionFilters) wrapped in a clickable button -
   dimmed until toggled active, so "which conditions are selected" reads
   clearly without a second, differently-styled control. */
.condition-chip-group { align-items: center; }
.condition-filter-chip {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  opacity: 0.4;
  transition: opacity 0.15s ease;
}
.condition-filter-chip:hover { opacity: 0.75; }
.condition-filter-chip.active { opacity: 1; }
.condition-filter-chip.active .condition-icon { box-shadow: 0 0 0 2px currentColor; }
.condition-filter-chip.active .condition-pill { box-shadow: 0 0 0 2px var(--text); }

.empty-state { text-align: center; color: var(--text-muted); margin-top: 60px; }
.landing {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px 20px;
  background:
    radial-gradient(circle at 20% 15%, var(--accent-soft), transparent 55%),
    radial-gradient(circle at 85% 85%, rgba(74, 163, 216, 0.1), transparent 50%),
    var(--bg);
}
/* Same bare-[hidden]-loses-to-unconditional-display gotcha as .topbar[hidden]
   above - missed this one the first time, which is exactly how a signed-in
   Kevin still saw the login card rendered over his own topbar. */
.landing[hidden] { display: none;
}

.landing-card {
  display: flex;
  max-width: 780px;
  width: 100%;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
}

.landing-art {
  flex: 0 0 42%;
  position: relative;
}

.landing-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* /assets/landing-banner.jpg is an 822x1914 portrait ensemble, composed
     for this exact use - characters stacked down the left/center, all
     facing right toward the form. Its aspect ratio nearly matches the
     desktop panel's, so default centering already works there; mobile
     crops down to a short band and needs its own vertical target below
     (the boy+robot cluster reads best at that height). */
  object-position: 50% 12%;
  display: block;
  filter: saturate(1.05);
}

.landing-art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 60%, rgba(0, 0, 0, 0.35));
  pointer-events: none;
}

.landing-content {
  flex: 1;
  padding: 40px 36px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  border-left: 1px solid var(--border-soft);
}

.landing-eyebrow {
  margin: 0;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-faint);
}

.landing-title {
  margin: 0 0 2px;
  font-size: 2.1rem;
  font-weight: 700;
  background: linear-gradient(90deg, var(--color-m), var(--color-r));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.landing-flavor {
  margin: 0 0 4px;
  font-style: italic;
  color: var(--text-muted);
}

.landing-desc {
  margin: 0 0 14px;
  color: var(--text-muted);
  line-height: 1.5;
}

.btn-landing-signin {
  align-self: flex-start;
  padding: 10px 22px;
  font-size: 0.95rem;
}

.landing-status {
  margin: 10px 0 0;
  color: var(--bad);
  font-size: 0.85rem;
  min-height: 1.2em;
}

.landing-restricted {
  margin: 4px 0 0;
  font-size: 0.75rem;
  color: var(--text-faint);
}
.landing-restricted a { color: var(--text-faint); }
.landing-restricted a:hover { color: var(--accent); }

.landing-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0;
  color: var(--text-faint);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.landing-divider::before,
.landing-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border-soft);
}

.landing-email-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.landing-email-form input {
  background: var(--panel-raised);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 0.9rem;
}
.landing-email-form .btn-small { align-self: flex-start; }

@media (max-width: 640px) {
  .landing-card { flex-direction: column; }
  /* flex-basis alone isn't a "definite height" for a column flex item, so
     the img's height:100% below was resolving against its own intrinsic
     ratio instead of this box - explicit height fixes what flex-basis
     couldn't. */
  .landing-art { flex: 0 0 220px; height: 220px; }
  .landing-art img { object-position: 50% 100%; }
  .landing-content { border-left: none; border-top: 1px solid var(--border-soft); }
}
.muted { color: var(--text-muted); }
.small { font-size: 0.75rem; }

.beta-form { display: flex; flex-direction: column; gap: 12px; margin: 6px 0 14px; }
.beta-field { display: flex; flex-direction: column; gap: 4px; }
.beta-field label { font-size: 0.8rem; color: var(--text-muted); }
.beta-field input {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 9px 10px;
  font-size: 0.9rem;
  font-family: inherit;
}
.beta-field input:focus { outline: none; border-color: var(--color-m); box-shadow: 0 0 0 3px var(--accent-border); }
.beta-message { margin: 0; font-size: 0.85rem; min-height: 1.2em; }
.beta-message.error { color: var(--bad); }
.beta-message.success { color: var(--good); }

.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.6);
  display: flex; align-items: center; justify-content: center;
  /* Kevin's report, 2026-08-19: on mobile, the fixed .bottom-nav (z-index:15)
     rendered ON TOP of every modal, covering the bottom of its content (most
     visibly the AGE-184 sheets' submit button, since a bottom-anchored sheet
     necessarily has its lowest content right where the nav bar sits). Any
     open modal should sit above all chrome, always - bumped past
     .bottom-nav for every modal, not just the two sheets, since the same
     bug was latent for all of them. */
  z-index: 20;
}
.modal-backdrop[hidden] { display: none; }
.modal {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  width: min(420px, 90vw);
  max-height: 85vh;
  overflow-y: auto;
  /* Add Card / Filters redesign (2026-08-22): app-wide, every modal shares
     this rule - a thin themed scrollbar (Kevin's "outdated scrollbars"
     report) instead of the default OS bar, plus a soft gold-tinted shadow
     instead of a flat drop shadow. Firefox via scrollbar-width/-color,
     Chrome/Safari/Edge via the ::-webkit- rules below. */
  scrollbar-width: thin;
  scrollbar-color: var(--accent-2) transparent;
  box-shadow: 0 20px 50px -18px rgba(0, 0, 0, 0.5), 0 4px 14px -6px rgba(0, 0, 0, 0.3);
}
.modal::-webkit-scrollbar,
.modal-body textarea::-webkit-scrollbar,
.filter-sheet .controls::-webkit-scrollbar { width: 8px; }
.modal::-webkit-scrollbar-track,
.modal-body textarea::-webkit-scrollbar-track,
.filter-sheet .controls::-webkit-scrollbar-track { background: transparent; }
.modal::-webkit-scrollbar-thumb,
.modal-body textarea::-webkit-scrollbar-thumb,
.filter-sheet .controls::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--accent-2) 55%, transparent);
  border-radius: 999px;
}
.modal::-webkit-scrollbar-thumb:hover,
.modal-body textarea::-webkit-scrollbar-thumb:hover,
.filter-sheet .controls::-webkit-scrollbar-thumb:hover { background: var(--accent-2); }
.modal-body textarea, .filter-sheet .controls {
  scrollbar-width: thin;
  scrollbar-color: var(--accent-2) transparent;
}
.modal-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}
/* AGE-184: drag handle for the two mobile bottom sheets (Add Card, Feedback)
   - hidden here, shown only inside the mobile .modal-sheet treatment below. */
.modal-sheet-handle { display: none; }
.modal-header h2 { margin: 0; font-size: 1.05rem; }
.settings-section-heading { margin: 6px 0 0; padding-top: 12px; border-top: 1px solid var(--border); font-size: 0.95rem; }
.land-style-select { width: 100%; }
.btn-close { background: none; border: none; color: var(--text); font-size: 1.3rem; cursor: pointer; }
.modal-body { padding: 18px; display: flex; flex-direction: column; gap: 12px; }
.modal-body label { display: flex; flex-direction: column; gap: 4px; font-size: 0.85rem; }
.modal-body input, .modal-body select {
  background: var(--panel-raised);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 8px;
}
.form-fields { display: flex; flex-direction: column; gap: 10px; border-top: 1px solid var(--border); padding-top: 12px; }
.search-result { display: flex; gap: 12px; align-items: center; }
.search-result img { width: 70px; border-radius: 6px; }
.search-result-info div { margin-bottom: 2px; }

.modal-wide { width: min(560px, 94vw); }
/* Edit Card modal's card art matches the hover-tooltip size (360px, see
   .card-tooltip) - needs its own wider modal, not the shared .modal-wide
   used by the printing picker. */
#edit-card-modal .modal-wide { width: min(760px, 94vw); }

.edit-layout { display: flex; flex-direction: row; gap: 18px; align-items: flex-start; }
.edit-image-col { flex: 0 0 360px; }
.edit-image-col img { width: 100%; border-radius: 10px; display: block; background: var(--panel-raised); aspect-ratio: 5/7; object-fit: cover; }
#library-flip-btn { margin-top: 8px; width: 100%; }
.edit-controls-col { flex: 1 1 auto; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.edit-card-name { font-weight: 700; font-size: 1.05rem; }

@media (max-width: 480px) {
  .edit-layout { flex-direction: column; }
  .edit-image-col { flex: none; width: 100%; max-width: 360px; margin: 0 auto; }
}

/* AGE-144: Rules Breakdown gets its own larger overlay instead of reusing
   the Edit Card modal's compact two-column shape - bigger art, a highlighted
   type-line band, and abilities as scannable cards instead of a plain list. */
.modal-rules-breakdown { width: min(880px, 94vw); max-height: 88vh; }

.rules-breakdown-layout { display: flex; flex-direction: row; gap: 22px; align-items: flex-start; }
.rules-breakdown-image-col { flex: 0 0 300px; position: sticky; top: 0; }
.rules-breakdown-image-col img {
  width: 100%; border-radius: 12px; display: block;
  background: var(--panel-raised); aspect-ratio: 5/7; object-fit: cover;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
}
.rules-breakdown-timing-box {
  margin-top: 12px; background: var(--panel-raised); border: 1px solid var(--border);
  border-radius: 10px; padding: 12px 14px;
}
.rules-breakdown-timing-box .btn-icon { font-size: 0.85rem; vertical-align: middle; }

.rules-breakdown-content-col { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 16px; }
.rules-breakdown-card-name { font-weight: 700; font-size: 1.3rem; }
.rules-breakdown-typeline-raw { color: var(--text-muted); font-size: 0.9rem; margin-top: -10px; }

.rules-breakdown-label {
  font-weight: 700; font-size: 0.75rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 8px;
}

.rules-breakdown-typebox { background: var(--accent-soft); border: 1px solid var(--accent-border); border-radius: 10px; padding: 12px 14px; }
.rules-breakdown-typebox-text { font-size: 0.95rem; line-height: 1.5; }

.rules-breakdown-ability-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; }
.rules-breakdown-ability-card { background: var(--panel-raised); border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; }
.rules-breakdown-ability-quote {
  font-style: italic; font-size: 0.9rem; margin-bottom: 6px;
  padding-left: 10px; border-left: 2px solid var(--accent-border);
}
.rules-breakdown-ability-explain { font-size: 0.9rem; line-height: 1.5; color: var(--text-muted); }

@media (max-width: 640px) {
  .rules-breakdown-layout { flex-direction: column; }
  .rules-breakdown-image-col { flex: none; width: 100%; max-width: 260px; margin: 0 auto; position: static; }
  .rules-breakdown-ability-grid { grid-template-columns: 1fr; }
}

/* ---------- Deck critique (AGE-129, restructured 2026-08-13) ---------- */
.critique-box {
  background: var(--panel-raised); border: 1px solid var(--border);
  border-radius: 10px; padding: 12px 14px; margin-top: 12px;
}
.critique-box:first-child { margin-top: 0; }
.critique-box p, .critique-box div { font-size: 0.9rem; line-height: 1.5; }
.critique-sw-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.critique-sw-grid .critique-box { margin-top: 0; }
.critique-sw-grid .critique-box:first-child { border-left: 2px solid var(--color-g); }
.critique-sw-grid .critique-box:last-child { border-left: 2px solid var(--color-r); }

.critique-synergy-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; }
.critique-synergy-card { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; }
.critique-synergy-cards { font-weight: 700; font-size: 0.85rem; margin-bottom: 6px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.critique-synergy-explain { font-size: 0.85rem; line-height: 1.5; color: var(--text-muted); }
.critique-loop-badge {
  font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  border-radius: 999px; padding: 2px 8px;
}
.critique-loop-hard { background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent-border); }
.critique-loop-soft { background: var(--panel-raised); color: var(--text-muted); border: 1px solid var(--border); }

.strategy-gameplan-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.strategy-gameplan-phase { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; }
.strategy-gameplan-phase-label {
  font-weight: 700; font-size: 0.7rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 6px;
}
.strategy-gameplan-phase div { font-size: 0.85rem; line-height: 1.5; color: var(--text-muted); }

@media (max-width: 640px) {
  .critique-sw-grid { grid-template-columns: 1fr; }
  .critique-synergy-grid { grid-template-columns: 1fr; }
  .strategy-gameplan-grid { grid-template-columns: 1fr; }
}

.qty-label { display: flex; flex-direction: column; gap: 6px; font-size: 0.85rem; }

.edit-receive-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-raised);
}
.edit-receive-row[hidden] { display: none; }
.edit-receive-actions { display: flex; gap: 8px; }
.qty-stepper {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  width: fit-content;
}
.qty-btn {
  background: var(--panel-raised);
  border: none;
  color: var(--text);
  font-size: 1.3rem;
  font-weight: 700;
  width: 44px;
  cursor: pointer;
  line-height: 1;
}
.qty-btn:hover { background: var(--color-m); color: #1a1400; }
.qty-stepper input[type="number"] {
  width: 64px;
  border: none;
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  border-radius: 0;
  text-align: center;
  font-size: 1.05rem;
  -moz-appearance: textfield;
  appearance: textfield;
}
.qty-stepper input[type="number"]::-webkit-inner-spin-button,
.qty-stepper input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.confirm-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 4px; }

/* Any class below that sets `display` unconditionally needs an explicit
   [hidden] override - the browser's own [hidden]{display:none} rule is a
   user-agent (lowest-priority) style, so it loses to ANY normal author rule
   setting display on the same element regardless of selector specificity. */
.form-fields[hidden],
.search-result[hidden] { display: none; }

.tab-group { display: flex; gap: 6px; border-bottom: 1px solid var(--border); padding-bottom: 10px; }
/* .tab-group's own display:flex above has the same specificity as the UA
   [hidden]{display:none} rule and comes later in the cascade, so it wins -
   setting .hidden on a .tab-group (e.g. #add-mode-tabs in wishlist-add mode)
   does nothing without this override. */
.tab-group[hidden] { display: none; }
.tab {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 0.85rem;
  font-weight: 600;
  padding: 4px 2px;
  cursor: pointer;
  border-bottom: 2px solid transparent;
}
.tab.active { color: var(--text); border-bottom-color: var(--color-m); }

/* Add Card redesign (2026-08-22): scoped to #add-mode-tabs specifically,
   not the base .tab-group/.tab above - .view-tabs (top nav) already has
   its own pill treatment and reuses the same base classes, so a change
   here must not touch it. Segmented pill control with a sliding indicator
   (positioned by switchAddMode() in app.js) instead of the plain
   underline every other .tab-group still uses. */
#add-mode-tabs {
  position: relative;
  border-bottom: none;
  padding-bottom: 0;
  background: var(--panel-raised);
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  padding: 3px;
  gap: 2px;
}
#add-mode-tabs .tab-indicator {
  position: absolute;
  top: 3px; bottom: 3px; left: 3px;
  width: calc(33.333% - 4px);
  background: linear-gradient(155deg, var(--accent-bright), var(--accent-2));
  border-radius: 7px;
  transition: transform 0.28s cubic-bezier(.65,0,.35,1);
  box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.4);
}
#add-mode-tabs .tab {
  position: relative;
  z-index: 1;
  flex: 1;
  text-align: center;
  border-bottom: none;
  padding: 8px 6px;
  border-radius: 7px;
  transition: color 0.2s ease;
}
#add-mode-tabs .tab.active { color: #1a1400; }
#add-mode-tabs .tab:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  #add-mode-tabs .tab-indicator { transition: none; }
}

/* Add Card redesign (2026-08-22): opt-in modifier, not a .btn-primary
   redefinition - keeps the blast radius to the four Add Card CTAs this
   was actually scoped for (Search/Import/Add to Queue/Add All/Add to
   Collection) rather than every primary button app-wide. Fixes the
   inconsistency Kevin flagged: Search (plain .btn) didn't match Import/
   Add to Queue (.btn-primary) even though all four do the same job. */
.btn-foil {
  background: linear-gradient(115deg, var(--accent-bright) 0%, var(--accent-2) 30%, var(--color-m) 55%, var(--accent-2) 78%, var(--accent-bright) 100%);
  background-size: 220% 100%;
  background-position: 0% 0%;
  border: none;
  color: #1a1400;
  font-weight: 600;
  transition: background-position 0.6s ease, box-shadow 0.15s ease;
}
.btn-foil:hover { background-position: 100% 0%; }
@media (prefers-reduced-motion: reduce) {
  .btn-foil { transition: none; }
}

.modal-body textarea {
  background: var(--panel-raised);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 8px;
  font-family: ui-monospace, "SFMono-Regular", Consolas, monospace;
  font-size: 0.8rem;
  resize: vertical;
}

/* Kevin's report (2026-08-22): Quick Add's entry form reappears empty right
   above this panel once a batch finishes (ready for the next one), and with
   nothing marking the boundary it read as one continuous, confusing form -
   "no clear separation between the cards we just imported and the new set
   you want to also add". A titled, bordered, slightly-raised panel makes
   this read as its own distinct "here's what just happened" card instead. */
.bulk-results-panel {
  margin-top: 18px;
  padding: 14px 14px 4px;
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-top: 3px solid var(--good);
  border-radius: 10px;
}
/* Quick Add redesign follow-up (2026-08-22): "Just Added" is now its own
   step (#quick-added-section), replacing the intake form entirely instead
   of sitting below it - .bulk-results-panel above has no margin-top to
   collapse against here since it's the first thing on the page, and this
   button needs its own breathing room from the results panel above it. */
#quick-added-section .bulk-results-panel,
#bulk-added-section .bulk-results-panel { margin-top: 0; }
#quick-back-to-intake-btn, #bulk-back-to-intake-btn { margin-top: 16px; }
.bulk-results-heading {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: "Fraunces", Georgia, serif;
  font-weight: 600;
  font-size: 0.95rem;
  margin: 0 0 8px;
}
.bulk-results-heading::before {
  content: "\2713";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--good);
  color: #0d1f14;
  font-size: 0.68rem;
  font-weight: 700;
}
.bulk-results-list { list-style: none; padding: 0; margin: 0; max-height: 280px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }
.bulk-results-list li { font-size: 0.8rem; padding: 4px 8px; border-radius: 4px; }
.bulk-ok, .bulk-warn { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.bulk-ok { background: rgba(63, 166, 108, 0.15); color: var(--color-g); }
.bulk-warn { background: rgba(217, 182, 78, 0.15); color: var(--color-m); }
.bulk-fail { background: rgba(224, 85, 74, 0.15); color: var(--color-r); }

/* AGE-209 follow-up: import retry affordance */
.bulk-results-summary { font-size: 0.85rem; margin: 2px 0 8px; }
.bulk-results-summary.has-failed { color: var(--color-r); font-weight: 600; }
.bulk-retry-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }

/* AGE-154: bulk-import review - per-card tagging (foil/condition/proxy) plus
   a select-and-apply-to-many toolbar, right after a paste import completes. */
/* Kevin's report (2026-08-21): no accent-color set anywhere meant checkboxes
   rendered in the browser's default (often light-on-light) styling, easy to
   miss against this app's dark panels, especially on mobile - most visible
   on the bulk-results select checkboxes below but applied globally since the
   same default styling affects every checkbox in the app. */
/* Add Card / Filters redesign (2026-08-22): Kevin's follow-up report - even
   with accent-color set, the native OS checkbox still read as "bland,
   manilla-folder" (his words) next to the rest of the app's design system.
   Fully custom via appearance:none + a generated checkmark - pure CSS on
   the existing selector, so every checkbox in the app (Filters' Foil
   only/On order only/Proxy only/Show date added, Add Card's Proxy/Shelved,
   Quick Add's select-all and its dynamically-rendered per-row checkboxes,
   Bulk Import's row-select) picks this up with no markup or JS changes. */
input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 17px;
  height: 17px;
  margin: 0;
  border-radius: 5px;
  border: 1.5px solid var(--border);
  background: var(--panel-raised);
  display: inline-block;
  vertical-align: middle;
  position: relative;
  cursor: pointer;
  flex-shrink: 0;
  transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
input[type="checkbox"]:hover { border-color: var(--accent-2); }
input[type="checkbox"]:checked {
  background: linear-gradient(155deg, var(--accent-bright), var(--accent-2));
  border-color: var(--accent-2);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 2px;
  width: 4px;
  height: 8px;
  border: solid #1a1400;
  border-width: 0 2px 2px 0;
  transform: rotate(40deg);
}
input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}
input[type="checkbox"]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.bulk-select-all-row { display: flex; gap: 8px; margin-bottom: 6px; }
.bulk-row-select { display: flex; }
.bulk-row-select input[type="checkbox"] { width: 17px; height: 17px; }
/* AGE-135 follow-up (2026-08-22): same thumbnail treatment as .rec-row's
   img (rounded, 5/7, sunken placeholder bg) - Kevin's ask to bring the
   thumbnail upgrade to the bulk-add results list too, not just the search
   dropdowns. card.image_url comes free on every result row already
   (processBulkLines' baseResult always carries `card`), no extra fetch. */
.bulk-row-thumb { width: 28px; border-radius: 4px; aspect-ratio: 5/7; object-fit: cover; flex: 0 0 auto; background: var(--panel-sunken); }
.bulk-row-name { flex: 1 1 auto; min-width: 160px; }
.bulk-row-tags { display: flex; align-items: center; gap: 8px; font-size: 0.72rem; color: var(--text); flex-wrap: wrap; }
.bulk-row-tags select { font-size: 0.72rem; padding: 1px 3px; }
.bulk-tag-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  padding: 8px;
  margin-bottom: 6px;
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-radius: 6px;
}
/* Kevin's report (2026-08-26): #collection-bulk-toolbar showed on page load
   despite its `hidden` attribute - same bug class as the #view-tabs fix
   above (AGE-... 2026-08-19 build note higher in this file). This class's
   other users (Quick Add/Bulk Import's toolbars) never toggle their own
   `hidden` directly - a parent section's hidden state controls their
   visibility instead - so nothing here needed an [hidden] override until
   the Collection grid's own toggle (setBulkSelectMode in app.js) started
   setting it directly. The plain `display:flex` above is an author rule and
   always beats the UA stylesheet's implicit `[hidden]{display:none}`,
   `hidden` attribute or not - needs its own explicit override, same as
   `.filter-count-badge[hidden]` below already has. */
.bulk-tag-toolbar[hidden] { display: none; }
.bulk-tag-group { display: flex; align-items: center; gap: 6px; font-size: 0.78rem; }
.bulk-tag-group input[type="text"] { width: 130px; font-size: 0.78rem; padding: 4px 6px; }
/* AGE-155 manual-override follow-up: the treatment chip row is wide/wraps
   unlike the other groups' single control, so it gets its own full-width
   line in the toolbar instead of squeezing in alongside them. */
.bulk-tag-group-treatments { flex-basis: 100%; align-items: flex-start; flex-wrap: wrap; }
.bulk-tag-group-treatments .treatment-chip-row { flex: 1 1 auto; }

/* AGE-199: Quick Add - set+number entry, queued locally then reviewed/
   submitted through the same bulk-import pipeline (POST /api/collection/bulk)
   and results view (renderBulkResults) the Bulk Import tab already uses.
   Originally a single-line collector-number input where Enter submitted
   immediately - Kevin's follow-up (2026-08-21): every submit dismissed the
   phone's on-screen keyboard, breaking the "keep going" flow he wanted.
   Now a textarea, one collector number per line, where Enter is just a
   newline (native textarea behavior, no JS needed) - the whole stack gets
   typed in one continuous keyboard session, submitted once at the end. */
#quick-number {
  width: 100%;
  font-family: ui-monospace, "SFMono-Regular", Consolas, monospace;
  font-size: 1rem;
  resize: vertical;
}

.quick-queue-list { display: flex; flex-direction: column; gap: 8px; margin: 10px 0; }
.quick-queue-item {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 8px 10px;
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent-2);
  border-radius: 8px;
  transition: border-color 0.15s ease;
}
.quick-queue-item:hover { border-color: var(--accent-2); }
.quick-queue-item .quick-queue-label { flex: 1 1 auto; font-family: "Fraunces", Georgia, serif; font-weight: 600; font-size: 0.9rem; }
.quick-queue-item .qty-stepper { flex: 0 0 auto; }
.quick-queue-item input[type="number"] { width: 40px; }
/* AGE-199 follow-up (2026-08-21): per-card finish/location so a mostly-
   nonfoil batch can still have a few foils or a different shelf without a
   second pass through Edit Card - Kevin's own description of the workflow
   ("select all, apply the common case, then go down the list and fix the
   few that differ") is exactly what the checkbox + toolbar above enables. */
.quick-queue-item select[data-queue-finish] { flex: 0 0 auto; font-size: 0.78rem; padding: 3px 4px; }
.quick-select-all { display: flex; align-items: center; gap: 6px; font-size: 0.78rem; font-weight: 600; }
/* Follow-up (2026-08-22): "SET #NUM" text alone gave Kevin nothing to judge
   finish/location by - a small thumbnail (from the read-only preview
   lookup, /api/quick-add/preview) plus the resolved name now stand in for
   the plain label until/if the lookup resolves. */
.quick-queue-thumb { width: 32px; height: 44px; object-fit: cover; border-radius: 4px; border: 1px solid var(--border-soft); flex: 0 0 auto; background: var(--panel); }
.quick-queue-label.muted { font-weight: 400; }
.quick-queue-notfound { color: var(--danger, #c0392b); }
/* Location: a real <select> of existing shelves (Kevin: a bare text field
   with datalist hints "wasn't a real way to select current ones" on
   mobile) with a "+ New location..." escape hatch that swaps the same
   flex slot for a text input + a small (x) to go back to the list -
   shared shape between each queue row and the toolbar's own apply-to-
   selected control. */
.quick-location-cell, .quick-location-new { flex: 1 1 130px; min-width: 110px; display: flex; align-items: center; gap: 4px; }
.quick-location-cell select, .quick-location-new input[type="text"] {
  flex: 1 1 auto; min-width: 0; font-size: 0.78rem; padding: 3px 6px;
  background: var(--panel); border: 1px solid var(--border); color: var(--text); border-radius: 4px;
}

.date-filter { display: flex; align-items: center; gap: 6px; font-size: 0.8rem; color: var(--text-muted); }
.date-filter input[type="date"] {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 6px 8px;
  font-size: 0.8rem;
}

.card-date { margin-top: 4px; }

.drawer-backdrop { justify-content: flex-end; }
.drawer {
  width: min(440px, 92vw);
  height: 100%;
  max-height: 100%;
  border-radius: 0;
}

.timeline { position: relative; padding-left: 18px; }
.timeline::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 6px;
  bottom: 6px;
  width: 2px;
  background: var(--border);
}

.history-entry { position: relative; margin-bottom: 18px; }
.history-entry::before {
  content: "";
  position: absolute;
  left: -18px;
  top: 5px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--panel-raised);
  border: 2px solid var(--border);
}
.history-entry.history-notable::before {
  background: var(--color-m);
  border-color: var(--color-m);
  box-shadow: 0 0 0 3px rgba(217, 182, 78, 0.2);
}

.history-entry-header {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 0.85rem;
  margin-bottom: 4px;
}
.history-when { font-weight: 600; }
.history-source { color: var(--text-muted); font-size: 0.75rem; }
.notable-badge {
  background: var(--color-m);
  color: #1a1400;
  font-size: 0.65rem;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 8px;
}

.history-items { list-style: none; padding: 0; margin: 6px 0 0; display: flex; flex-direction: column; gap: 2px; }
.history-items[hidden] { display: none; }
.history-items li {
  font-size: 0.78rem;
  color: var(--text-muted);
  padding: 3px 6px;
  border-radius: 4px;
  cursor: pointer;
}
.history-items li:hover { background: var(--panel-raised); color: var(--text); }
.history-items li.history-unlinked { cursor: default; }
.history-items li.history-unlinked:hover { background: none; color: var(--text-muted); }
.history-item-notable { color: var(--color-m) !important; font-weight: 600; }
.history-item-notable:hover { color: var(--text) !important; }

.card-tooltip {
  position: fixed;
  z-index: 50;
  pointer-events: none;
  width: 360px;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
  border: 1px solid var(--border);
}
.card-tooltip img { width: 100%; display: block; }
.card-tooltip[hidden] { display: none; }

.text-tooltip {
  position: fixed;
  z-index: 50;
  pointer-events: none;
  max-width: 260px;
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 0.78rem;
  color: var(--text);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}
.text-tooltip[hidden] { display: none; }

.keyword-pill-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.keyword-pill-row[hidden] { display: none; }
.keyword-pill {
  background: var(--panel-raised);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 0.7rem;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 10px;
  cursor: default;
}
.keyword-pill:hover { border-color: var(--color-m); }

/* AGE-148: freeform card tags - shown in the Edit Card modal (CRUD) and as
   a location badge on the grid card front (read-only glance). tag-pill and
   location-badge deliberately reuse .keyword-pill's shape/sizing rather than
   introducing a new pill scale. */
.edit-tags-box { border-top: 1px solid var(--border); padding-top: 10px; }

/* Art Focal Point (Kevin's ask, 2026-08-22/23) - the picker shows the
   whole, uncropped art_crop image (not letterboxed to 5:7) so there's room
   to place the frame precisely; the frame marks the real crop window
   (frame size shrinks with zoom, same math as computeArtFocalCrop in
   app.js) at zoom 1 the frame equals the actual object-fit:cover crop, not
   an arbitrary box. Frame position/size moved via CSSOM in app.js, never a
   style="" attribute (this app's CSP is style-src 'self' - see the note on
   renderManaCurve elsewhere in app.js). Dimming outside the frame uses one
   oversized box-shadow instead of a separate overlay element - same trick
   as the approved mockup. */
.edit-focal-picker { position: relative; border-radius: 8px; overflow: hidden; border: 1px solid var(--border); margin: 8px 0; touch-action: none; }
.edit-focal-picker img { width: 100%; display: block; user-select: none; -webkit-user-drag: none; }
.edit-focal-frame {
  position: absolute; border: 2px solid var(--color-m); border-radius: 4px;
  box-shadow: 0 0 0 2000px rgba(0, 0, 0, 0.55);
  cursor: grab; touch-action: none; user-select: none;
}
.edit-focal-frame:active { cursor: grabbing; }
.edit-focal-frame::before, .edit-focal-frame::after {
  content: ""; position: absolute; background: var(--color-m); opacity: 0.55;
}
.edit-focal-frame::before { top: 50%; left: 6px; right: 6px; height: 1px; }
.edit-focal-frame::after { left: 50%; top: 6px; bottom: 6px; width: 1px; }
.edit-focal-zoom-row { display: flex; align-items: center; gap: 8px; margin-top: 6px; font-size: 0.78rem; color: var(--text-muted); }
.edit-focal-zoom-row input[type="range"] { flex: 1; }
.edit-focal-full-card-row { display: flex; align-items: center; gap: 8px; margin-top: 10px; font-size: 0.78rem; color: var(--text-muted); }
.tag-pill-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
.tag-pill {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--panel-raised);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 0.7rem;
  font-weight: 600;
  padding: 3px 6px 3px 9px;
  border-radius: 10px;
}
.tag-pill.tag-pill-location { border-color: var(--color-u); color: var(--color-u); }
.tag-pill-remove {
  background: none; border: none; cursor: pointer;
  color: inherit; opacity: 0.6; font-size: 0.85rem; line-height: 1; padding: 0 2px;
}
.tag-pill-remove:hover { opacity: 1; }
.edit-tags-add-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.edit-tags-add-row input[type="text"] { flex: 1 1 140px; }
.tag-location-toggle { display: flex; align-items: center; gap: 4px; font-size: 0.78rem; white-space: nowrap; }

.location-badge {
  background: transparent;
  border: 1px solid var(--color-u);
  color: var(--color-u);
  font-weight: 700;
  font-size: 0.65rem;
  padding: 0 5px;
  border-radius: 8px;
}

/* AGE-214 inc.6: "N available" - own qty minus copies shelved in decks that
   subtract from availability. Only rendered when something is committed. */
.avail-badge {
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  color: var(--text);
  font-weight: 700;
  font-size: 0.65rem;
  padding: 0 5px;
  border-radius: 8px;
  white-space: nowrap;
}

/* AGE-155 phase 1: extended art / showcase / borderless / specialty-foil
   tracking - a distinct purple/violet tone since foil/proxy/location/
   pending already claim gold/faint/blue/blue-accent respectively. */
.treatment-badge {
  background: transparent;
  border: 1px solid #9b6fd1;
  color: #9b6fd1;
  font-weight: 700;
  font-size: 0.65rem;
  padding: 0 5px;
  border-radius: 8px;
}
.treatment-badge-row { display: flex; flex-wrap: wrap; gap: 4px; }
.treatment-badge-row[hidden] { display: none; }

.edit-explanation-box { border-top: 1px solid var(--border); padding-top: 10px; }
.edit-explanation-label {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); margin-bottom: 4px;
}
.btn-icon {
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 2px 4px;
}
.btn-icon:hover { color: var(--color-m); }

#edit-explanation { margin: 0; }
.jargon-term { border-bottom: 1px dotted var(--text-muted); cursor: help; }
.jargon-term:hover { border-bottom-color: var(--color-m); color: var(--text); }

/* Every [[card-ref]] is now clickable - opens the card's full-screen preview
   (see the project-wide listener near openCardRefPreview). Deck Strategy refs
   are the one exception: there a click adds the card to the deck instead. */
.card-ref { border-bottom: 1px solid var(--color-u); color: var(--color-u); cursor: pointer; }
.card-ref:hover { color: var(--text); border-bottom-color: var(--text); }

.history-expand-btn {
  background: none;
  border: none;
  color: var(--color-m);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  padding: 4px 0;
  margin-top: 4px;
  text-align: left;
}
.history-expand-btn:hover { text-decoration: underline; }

/* .stats sets display:flex unconditionally, so the bare [hidden] attribute
   toggled from JS needs the same explicit override as the other elements
   noted above, or it silently stays visible. */
.stats[hidden] { display: none; }

.view-tabs { display: flex; gap: 4px; background: var(--panel-raised); border: 1px solid var(--border); border-radius: 8px; padding: 3px; }
/* .view-tabs sets display:flex unconditionally - same bare-[hidden] gotcha
   as .stats above, needs the explicit override or AGE-55's signed-out gate
   won't actually hide the tab bar. */
.view-tabs[hidden] { display: none; }
.view-tabs .tab { border-radius: 6px; padding: 6px 14px; border-bottom: none; }
.view-tabs .tab.active { background: var(--color-m); color: #1a1400; border-bottom-color: transparent; }

.current-deck-select {
  background: var(--panel-raised);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 8px;
  padding: 7px 10px;
  font-size: 0.85rem;
  max-width: 200px;
}
body.app-themed .current-deck-select { border-color: color-mix(in srgb, var(--app-mood-accent) 45%, var(--border)); }

/* AGE-213: deck list brought forward to the Library/Collection pattern -
   a .lib-head, a real toolbar (count + value + New Deck button, no FAB),
   and richer tiles (commander art, format chip, colour pips, completion,
   value, last-edited). */
.decks-head { max-width: 62ch; }
.deck-list-bar {
  display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap;
  padding: 12px 0 18px; border-bottom: 1px solid var(--border-soft); margin-bottom: 20px;
}
.deck-list-bar .dlb-count { font-size: 0.9rem; color: var(--text-muted); }
.deck-list-bar .dlb-count b { color: var(--text); font-variant-numeric: tabular-nums; }
.deck-list-bar .dlb-value {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9rem;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.deck-list-bar .dlb-value[hidden] { display: none; }
.deck-list-bar .dlb-value .lbl {
  color: var(--text-faint); font-size: 0.7rem; text-transform: uppercase;
  letter-spacing: 0.1em; margin-right: 6px;
}
.deck-list-bar .btn-primary { margin-left: auto; }

.deck-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(248px, 1fr)); gap: 16px; }
.deck-tile {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  cursor: pointer;
  display: flex; flex-direction: column;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.deck-tile:hover { transform: translateY(-3px); box-shadow: 0 10px 26px rgba(0,0,0,0.28); border-color: var(--accent-border); }
.deck-tile-art {
  aspect-ratio: 16 / 10; position: relative; padding: 12px 13px;
  display: flex; flex-direction: column; justify-content: flex-end;
  background: var(--deck-art, linear-gradient(150deg, var(--panel-raised), var(--panel-sunken)));
  background-size: cover; background-position: center 22%;
}
.deck-tile-art::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(10,8,6,0.74), rgba(10,8,6,0.04) 62%);
}
.deck-tile-art .deck-tile-cmdr {
  position: relative; z-index: 1; font-family: "Fraunces", Georgia, serif; font-weight: 600;
  font-size: 0.72rem; color: rgba(255,255,255,0.82); text-shadow: 0 1px 3px rgba(0,0,0,0.6);
}
.deck-tile-body { padding: 12px 13px 13px; display: flex; flex-direction: column; gap: 8px; }
.deck-tile-name { font-family: "Fraunces", Georgia, serif; font-weight: 600; font-size: 1.02rem; line-height: 1.2; }
.deck-tile-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.deck-fmt-chip {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.62rem;
  letter-spacing: 0.08em; text-transform: uppercase; padding: 2px 7px; border-radius: 5px;
  background: var(--panel-sunken); border: 1px solid var(--border-soft); color: var(--text-muted);
}
.deck-pips { display: inline-flex; gap: 3px; }
.deck-pip { width: 13px; height: 13px; border-radius: 50%; border: 1px solid rgba(0,0,0,0.28); }
.deck-pip-w { background: var(--color-w); } .deck-pip-u { background: var(--color-u); }
.deck-pip-b { background: var(--color-b); } .deck-pip-r { background: var(--color-r); }
.deck-pip-g { background: var(--color-g); } .deck-pip-c { background: var(--color-c); }
.deck-tile-foot {
  display: flex; align-items: baseline; justify-content: space-between;
  border-top: 1px solid var(--border-soft); padding-top: 8px;
  font-size: 0.8rem; color: var(--text-muted);
}
.deck-tile-foot .deck-tile-val {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--text); font-variant-numeric: tabular-nums;
}
.deck-tile-edited { font-size: 0.72rem; color: var(--text-faint); display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }

/* AGE-224 Phase 2: "Public" badge on a deck tile (public decks only). */
.vis-badge {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.58rem;
  letter-spacing: 0.06em; text-transform: uppercase; font-weight: 600;
  padding: 2px 6px 2px 5px; border-radius: 5px;
  color: var(--color-u); background: color-mix(in srgb, var(--color-u) 16%, transparent);
}
.vis-badge svg { width: 11px; height: 11px; }
.deck-tile-art .vis-badge { position: absolute; z-index: 1; top: 10px; right: 10px; }
.deck-tile--banner .deck-ban-meta .vis-badge { background: rgba(0,0,0,0.34); color: #cfe6f5; }

/* AGE-224: multi-select on the deck list. "Select" enters a mode - the list
   bar swaps for a selection bar, every tile shows a checkbox, and a sticky
   bulk bar appears once something's ticked. */
.deck-list-bar .dlb-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.deck-list-bar .dlb-actions .btn-primary { margin-left: 0; }
/* .deck-list-bar sets display:flex, which beats the [hidden] UA rule - the
   codebase's own per-component pattern (see .dlb-value[hidden]) is an
   explicit override. */
.deck-list-bar[hidden] { display: none; }

.deck-sel-bar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 12px 0 16px; border-bottom: 1px solid var(--accent-border); margin-bottom: 20px;
  min-height: 58px;
}
.deck-sel-bar[hidden] { display: none; }
.deck-sel-count { font-family: "Fraunces", Georgia, serif; font-weight: 600; font-size: 1rem; }
.deck-sel-count b { color: var(--accent); font-variant-numeric: tabular-nums; }
.deck-sel-bar .dlb-actions { margin-left: auto; display: flex; gap: 14px; align-items: center; }

/* tile checkbox - hidden until the list is in select mode. The base
   .deck-tile has no `position`, so anchor the absolutely-positioned check. */
.deck-tile { position: relative; }
.deck-tile-check {
  position: absolute; z-index: 2; top: 10px; left: 10px;
  width: 24px; height: 24px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.85); background: rgba(10, 8, 6, 0.45);
  display: none; align-items: center; justify-content: center;
}
.deck-tile-check svg { width: 14px; height: 14px; color: #fff; opacity: 0; transition: opacity 0.12s ease; }
#deck-list-view.selecting .deck-tile { cursor: default; }
#deck-list-view.selecting .deck-tile:hover { transform: none; box-shadow: none; border-color: var(--border); }
#deck-list-view.selecting .deck-tile-check { display: flex; }
#deck-list-view.selecting .deck-tile.is-sel { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
#deck-list-view.selecting .deck-tile.is-sel .deck-tile-check { background: var(--accent); border-color: var(--accent); }
#deck-list-view.selecting .deck-tile.is-sel .deck-tile-check svg { opacity: 1; color: var(--bg); }
#deck-list-view.selecting .deck-tile:not(.is-sel) .deck-tile-art { filter: saturate(0.6) brightness(0.72); }

.deck-bulk-bar {
  position: sticky; bottom: 14px; z-index: 5; margin-top: 20px;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 14px; border-radius: 12px;
  background: var(--panel-raised); border: 1px solid var(--accent-border);
  box-shadow: 0 14px 40px rgba(0, 0, 0, 0.4);
}
.deck-bulk-bar[hidden] { display: none; }
.deck-bulk-bar .dbb-count { font-size: 0.85rem; color: var(--text-muted); }
.deck-bulk-bar .dbb-count b { color: var(--text); font-variant-numeric: tabular-nums; }
.deck-bulk-bar .dlb-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* ============ AGE-225: deck-list View + Sort controls ============ */
.dlb-menu { position: relative; display: inline-flex; }
.dlb-menu .btn[hidden] { display: none; }
.dlb-pop {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; width: 232px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
  padding: 11px; box-shadow: 0 16px 44px rgba(0, 0, 0, 0.42);
}
.dlb-pop[hidden] { display: none; }
.dlb-pop-view { width: 264px; }
.dlb-pop-head {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.6rem;
  letter-spacing: 0.11em; text-transform: uppercase; color: var(--text-faint);
  margin: 0 0 7px; font-weight: 700; display: flex; justify-content: space-between;
}
.dlb-pop-head + * { margin-bottom: 13px; }
.dlb-pop-view input.dlb-crop { margin-bottom: 2px; }

.dlb-lay-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.dlb-lay {
  display: flex; flex-direction: column; gap: 5px; align-items: stretch;
  border: 1px solid var(--border); border-radius: 8px; padding: 7px;
  background: var(--panel-raised); color: var(--text); cursor: pointer;
  font-family: inherit; font-size: 0.72rem; font-weight: 500; text-align: left; line-height: 1.2;
}
.dlb-lay:hover { border-color: var(--accent-border); }
.dlb-lay[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); }
.dlb-lay-mini { height: 26px; border-radius: 4px; overflow: hidden; position: relative; background: linear-gradient(120deg, var(--color-b), var(--color-u)); }
.dlb-lay-mini::after { content: ""; position: absolute; }
.dlb-lay-mini.m-cards::after { left: 0; right: 0; bottom: 0; height: 9px; background: var(--panel); }
.dlb-lay-mini.m-right::after { inset: 0; background: linear-gradient(90deg, transparent 42%, rgba(0,0,0,0.75)); }
.dlb-lay-mini.m-label::after { left: 0; right: 0; bottom: 0; height: 10px; background: rgba(0,0,0,0.74); }
.dlb-lay-mini.m-overlay::after { inset: 0; background: linear-gradient(105deg, rgba(0,0,0,0.72), transparent 70%); }

.dlb-dens { display: flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
.dlb-dens button {
  flex: 1; background: var(--panel-raised); border: none; color: var(--text-muted);
  font-family: inherit; font-size: 0.74rem; padding: 7px 0; cursor: pointer;
}
.dlb-dens button + button { border-left: 1px solid var(--border); }
.dlb-dens button[aria-pressed="true"] { background: var(--accent); color: var(--bg); font-weight: 600; }

input.dlb-crop { width: 100%; accent-color: var(--accent); cursor: pointer; }

.dlb-sort-opt {
  display: block; width: 100%; text-align: left; background: none; border: none;
  color: var(--text-muted); font-family: inherit; font-size: 0.83rem; cursor: pointer;
  padding: 8px 9px; border-radius: 7px; position: relative;
}
.dlb-sort-opt:hover { background: var(--panel-raised); color: var(--text); }
.dlb-sort-opt[aria-pressed="true"] { color: var(--text); font-weight: 600; }
.dlb-sort-opt[aria-pressed="true"]::after {
  content: "\2713"; position: absolute; right: 9px; color: var(--accent);
}

/* ---- banner layouts: their own grid track (wider min = fewer columns) ---- */
#deck-grid[data-layout^="banner-"] {
  grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr));
  gap: 10px;
}
#deck-grid[data-density="compact"] { --deck-ban-h: 66px; --deck-card-ar: 16/7; --deck-card-pad: 9px 10px 10px; }
#deck-grid[data-density="cozy"]    { --deck-ban-h: 84px; --deck-card-ar: 16/10; --deck-card-pad: 12px 13px 13px; }
#deck-grid[data-density="roomy"]   { --deck-ban-h: 104px; --deck-card-ar: 16/13; --deck-card-pad: 14px 14px 15px; }

/* card layout picks up the density vars */
#deck-grid[data-layout="cards"] .deck-tile-art { aspect-ratio: var(--deck-card-ar, 16/10); background-position: center var(--deck-art-crop, 22%); }
#deck-grid[data-layout="cards"] .deck-tile-body { padding: var(--deck-card-pad, 12px 13px 13px); }

/* ---- the banner tile ---- */
.deck-tile--banner {
  height: var(--deck-ban-h, 84px);
  border-radius: 10px; overflow: hidden; cursor: pointer; display: block;
  border: 1px solid var(--border); background: var(--panel);
  background-image: var(--deck-art);
  background-size: cover; background-position: center var(--deck-art-crop, 28%);
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.deck-tile--banner:hover { transform: translateY(-2px); box-shadow: 0 8px 22px rgba(0,0,0,0.3); border-color: var(--accent-border); }
.deck-ban-scrim { position: absolute; inset: 0; z-index: 1; }
.deck-ban-body { position: absolute; z-index: 2; min-width: 0; }
.deck-ban-name {
  font-family: "Fraunces", Georgia, serif; font-weight: 600; font-size: 0.98rem; color: #fff;
  text-shadow: 0 1px 5px rgba(0,0,0,0.75); line-height: 1.13;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.deck-ban-meta { display: flex; align-items: center; gap: 8px; margin-top: 5px; font-size: 0.71rem; color: rgba(255,255,255,0.82); }
.deck-ban-meta .deck-fmt-chip { background: rgba(0,0,0,0.28); border-color: rgba(255,255,255,0.22); color: rgba(255,255,255,0.72); }
.deck-ban-meta .deck-pip { border-color: rgba(0,0,0,0.45); }
.deck-ban-count { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-variant-numeric: tabular-nums; }
.deck-ban-val { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: rgba(255,255,255,0.74); }
.deck-ban-warn { color: #ff8a7a; font-weight: 700; }
.deck-ban-bar {
  position: absolute; left: 0; bottom: 0; height: 3px; z-index: 3;
  width: var(--deck-completion, 0%); background: var(--accent);
}
.deck-tile-cur {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.54rem;
  letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700; color: var(--accent);
  border: 1px solid var(--accent-border); border-radius: 4px; padding: 1px 5px; vertical-align: middle;
}
.deck-tile--banner .deck-tile-cur { color: #fff; border-color: rgba(255,255,255,0.6); }

/* banner variant: text on the right, art open on the left */
.deck-tile--banner-right .deck-ban-scrim { background: linear-gradient(90deg, rgba(8,6,5,0) 24%, rgba(8,6,5,0.55) 54%, rgba(8,6,5,0.9) 100%); }
.deck-tile--banner-right .deck-ban-body { right: 13px; top: 50%; transform: translateY(-50%); max-width: 66%; text-align: right; }
.deck-tile--banner-right .deck-ban-meta { justify-content: flex-end; flex-wrap: wrap; }

/* banner variant: text in a bottom band */
.deck-tile--banner-label .deck-ban-scrim { background: linear-gradient(0deg, rgba(8,6,5,0.92) 0%, rgba(8,6,5,0.32) 46%, rgba(8,6,5,0) 74%); }
.deck-tile--banner-label .deck-ban-body { left: 13px; right: 13px; bottom: 9px; }
.deck-tile--banner-label .deck-ban-meta .deck-ban-val { margin-left: auto; }

/* banner variant: soft diagonal veil, text left */
.deck-tile--banner-overlay .deck-ban-scrim { background: linear-gradient(105deg, rgba(8,6,5,0.86) 0%, rgba(8,6,5,0.48) 44%, rgba(8,6,5,0.12) 78%); }
.deck-tile--banner-overlay .deck-ban-body { left: 14px; top: 50%; transform: translateY(-50%); max-width: 82%; }
.deck-tile--banner-overlay .deck-ban-meta .deck-ban-val { margin-left: 10px; }

/* select mode on banners */
#deck-list-view.selecting .deck-tile--banner { cursor: default; }
#deck-list-view.selecting .deck-tile--banner:hover { transform: none; box-shadow: none; border-color: var(--border); }
#deck-list-view.selecting .deck-tile--banner:not(.is-sel) { filter: saturate(0.5) brightness(0.6); }
#deck-list-view.selecting .deck-tile--banner.is-sel { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
.deck-tile--banner .deck-tile-check { top: 9px; left: 9px; }

@media (max-width: 640px) {
  /* keep the toolbar to one row - Sort / View go icon-only */
  .deck-list-bar .dlb-actions { gap: 6px; }
  .dlb-btn-lbl { display: none; }
  #deck-sort-btn, #deck-view-btn { padding: 7px 9px; }
  .dlb-pop { width: min(264px, calc(100vw - 32px)); }
}

/* AGE-213: the desktop floating FABs for New Deck (a mobile pattern on a
   desktop layout) are replaced by the real button in .deck-list-bar; the
   separate mobile button is now redundant too. */
#open-new-deck { display: none; }
#mobile-open-new-deck { display: none; }

/* AGE-213 "Ambient identity" - replaces the AGE-147 per-deck reskin and its
   AGE-159 app-wide version (heavy gradient + rarity frame + AI mood
   textures, all retired). The current deck now tints the app through a soft
   off-canvas wash on <body>, one hairline under the deck-detail header, an
   in-family accent thread, and the nav deck-chip. Driven by
   body[data-deck-theme="ambient"] + --deck-id-1 / --deck-id-2 / --deck-id-accent,
   set in app.js from the current deck's colour identity; wash intensity
   scales with commander rarity via [data-deck-rarity]. #deck-detail-view
   keeps a .deck-theme marker class for its own hairline, themed to whatever
   deck is actually open (not necessarily the current one). */
#deck-detail-view,
#collection-view,
#decks-view,
#suggestions-view,
#audit-view,
#roadmap-view {
  border-radius: 14px;
}
#deck-detail-view { padding: 18px; }

body[data-deck-theme="ambient"] {
  --deck-id-wash: 7%;
  background-image:
    radial-gradient(135% 92% at 99% -14%, color-mix(in srgb, var(--deck-id-1, var(--color-c)) var(--deck-id-wash), transparent) 0%, transparent 60%),
    radial-gradient(105% 82% at 0% 114%, color-mix(in srgb, var(--deck-id-2, var(--color-c)) calc(var(--deck-id-wash) - 2%), transparent) 0%, transparent 58%);
  background-attachment: fixed;
  background-repeat: no-repeat;
}
body[data-deck-theme="ambient"][data-deck-rarity="rare"]   { --deck-id-wash: 9%; }
body[data-deck-theme="ambient"][data-deck-rarity="mythic"] { --deck-id-wash: 12%; }
@media (prefers-color-scheme: light) {
  body[data-deck-theme="ambient"]                            { --deck-id-wash: 13%; }
  body[data-deck-theme="ambient"][data-deck-rarity="rare"]   { --deck-id-wash: 16%; }
  body[data-deck-theme="ambient"][data-deck-rarity="mythic"] { --deck-id-wash: 20%; }
}

/* in-family accent thread - --deck-id-accent is the identity hue mixed
   toward the Archivist gold, never a full hue swap */
body[data-deck-theme="ambient"] .lib-eyebrow { color: var(--deck-id-accent); }

/* deck-detail header hairline - themed to the open deck via .deck-theme */
#deck-detail-view.deck-theme .deck-head {
  position: relative;
}
#deck-detail-view.deck-theme .deck-head::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--deck-id-1, var(--border)), var(--deck-id-2, var(--border)) 55%, transparent);
}

/* nav deck-chip - the legible "which deck is driving the theme" source */
.deck-chip {
  display: flex; align-items: center; gap: 8px; flex: 0 0 auto;
  padding: 4px 12px 4px 4px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--panel-raised);
}
.deck-chip[hidden] { display: none; }
.deck-chip-crop {
  width: 24px; height: 24px; border-radius: 50%; flex: 0 0 auto;
  background-size: cover; background-position: center 18%;
  background-color: color-mix(in srgb, var(--deck-id-1, var(--color-c)) 45%, var(--panel));
  border: 1px solid rgba(0, 0, 0, 0.25);
}
.deck-chip-name { font-size: 0.8rem; font-weight: 600; max-width: 210px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.deck-chip-pips { display: inline-flex; gap: 2px; }
.deck-chip-pips i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; border: 1px solid rgba(0, 0, 0, 0.25); }
@media (max-width: 860px) { .deck-chip { display: none !important; } }

/* AGE-213 increment 4: deck-theme picker (Off / Ambient / Masthead). Reuses
   .theme-seg / .theme-seg-btn; these rules just make the 3 text buttons fill
   the width of whichever collapsed-menu surface they're relocated into. */
.decktheme-seg { margin-top: 8px; width: 100%; }
.decktheme-seg .theme-seg-btn { flex: 1 1 0; text-align: center; }

/* AGE-213 increment 4: the "masthead" band - one cinematic deck strip
   directly under the nav (sibling of #topbar, normal flow so it scrolls away
   with the page). Shown only for deck_theme_preference === "masthead";
   pages themselves stay neutral (the wash is scoped to
   body[data-deck-theme="ambient"] and never fires here). Themed via the
   --deck-id-* props app.js sets on the element. */
.deck-masthead {
  position: relative;
  display: flex; align-items: center; gap: 12px;
  padding: 14px 24px; min-height: 64px;
  border-bottom: 1px solid var(--border);
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--deck-id-1, var(--color-c)) 26%, var(--panel)) 0%,
      color-mix(in srgb, var(--deck-id-2, var(--color-c)) 18%, var(--panel)) 60%,
      var(--panel) 100%);
  overflow: hidden;
}
.deck-masthead[hidden] { display: none; }
.deck-masthead-art {
  position: absolute; inset: 0 0 0 auto; width: min(46%, 520px);
  background-size: cover; background-position: center 22%;
  /* fades into the band from the right so the name stays readable */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 55%);
  mask-image: linear-gradient(90deg, transparent, #000 55%);
  opacity: 0.46; pointer-events: none;
}
.deck-masthead-name {
  position: relative; z-index: 1;
  font-family: "Fraunces", Georgia, serif; font-weight: 600; font-size: 1.15rem;
  color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.deck-masthead-pips { position: relative; z-index: 1; display: inline-flex; gap: 4px; flex: 0 0 auto; }
.deck-masthead-pips i {
  width: 12px; height: 12px; border-radius: 50%; display: inline-block;
  border: 1px solid rgba(0, 0, 0, 0.3);
}
@media (max-width: 860px) {
  .deck-masthead { padding: 11px 14px; min-height: 52px; }
  .deck-masthead-name { font-size: 1.02rem; }
}

/* AGE-213 increment 3: deck-detail is a single scroll now - a header band
   (commander crop + name + subline + actions), a value bar, and an
   always-visible compact stats strip, then the In Deck hero with its own
   sticky toolbar. The old stack of 7 open <details class="acc"> accordions
   is gone; the utility blocks (Commander / Add / Assistant / Shopping / Buy)
   are lighter .deck-section collapsibles below. .acc itself is untouched -
   the Audit page still uses it. */
.deck-head { padding: 12px 0 15px; margin: 12px 0 18px; }
.deck-head-main { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start; }
.deck-head-thumb {
  flex: 0 0 auto; width: 54px; height: 54px; border-radius: 10px;
  background-size: cover; background-position: center 22%;
  background-color: color-mix(in srgb, var(--deck-id-1, var(--color-c)) 40%, var(--panel));
  border: 1px solid var(--border);
}
.deck-head-thumb.is-empty { background-image: none; }
.deck-head-title { flex: 1 1 240px; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.deck-name-input {
  width: 100%;
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 1.15rem;
  font-weight: 600;
  font-family: "Fraunces", Georgia, serif;
}
.deck-head-sub { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 0.82rem; color: var(--text-muted); }
.deck-head-sub b { color: var(--text); font-weight: 600; }
.deck-head-sub .deck-fmt-chip { flex: 0 0 auto; }
.deck-head-sub .deck-head-dot { color: var(--text-faint); }
.deck-head-sub .deck-head-nocmdr { color: var(--color-m); }
.deck-head-sub .deck-pips { display: inline-flex; gap: 3px; vertical-align: middle; }
.deck-head-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.deck-head-actions select { background: var(--panel); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 6px 8px; font-size: 0.82rem; }
.deck-kebab-wrap { position: relative; }
.deck-head-kebab { font-size: 1.1rem; line-height: 1; }
.deck-kebab-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 30;
  background: var(--panel); border: 1px solid var(--border); border-radius: 9px;
  box-shadow: 0 14px 36px rgba(0, 0, 0, 0.35); padding: 8px;
}
.deck-kebab-menu[hidden] { display: none; }

/* AGE-224 Phase 2: per-deck Private/Public switch + share link */
.vis-control { position: relative; }
.vis-control[hidden] { display: none; }
.vis-trigger {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--panel); border: 1px solid var(--border); color: var(--text);
  border-radius: 6px; padding: 6px 9px; font-family: inherit; font-size: 0.82rem; cursor: pointer;
}
.vis-trigger:hover { border-color: var(--color-m); }
.vis-trigger-icon { display: inline-flex; }
.vis-trigger-icon svg { width: 14px; height: 14px; }
.vis-trigger .vis-chev { width: 12px; height: 12px; opacity: 0.6; }
.vis-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 31;
  width: 258px; max-width: calc(100vw - 32px);
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 6px; box-shadow: 0 14px 36px rgba(0, 0, 0, 0.35);
}
.vis-menu[hidden] { display: none; }
.vis-opt {
  display: flex; gap: 10px; width: 100%; text-align: left; padding: 9px 10px;
  border: none; background: none; border-radius: 7px; cursor: pointer; align-items: flex-start; color: var(--text);
}
.vis-opt:hover { background: var(--panel-raised); }
.vis-opt > svg { width: 15px; height: 15px; flex: 0 0 auto; margin-top: 1px; color: var(--text-muted); }
.vis-opt.active > svg { color: var(--accent); }
.vis-opt-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.vis-opt-t { font-size: 0.85rem; font-weight: 600; }
.vis-opt-d { font-size: 0.75rem; color: var(--text-muted); }
.vis-opt-check { width: 15px; height: 15px; flex: 0 0 auto; margin-left: auto; color: var(--accent); opacity: 0; }
.vis-opt.active .vis-opt-check { opacity: 1; }

.deck-share-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 12px 0 0; padding: 9px 12px; border-radius: 8px;
  background: color-mix(in srgb, var(--color-u) 10%, var(--panel-sunken));
  border: 1px solid color-mix(in srgb, var(--color-u) 30%, transparent);
}
.deck-share-row[hidden] { display: none; }
.deck-share-row .dsr-lbl {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--color-u); font-weight: 600;
}
.deck-share-row code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.8rem;
  background: var(--panel); border: 1px solid var(--border-soft); border-radius: 5px;
  padding: 4px 8px; color: var(--text); overflow-wrap: anywhere;
}
.deck-share-row .dsr-note { font-size: 0.74rem; color: var(--text-faint); flex: 1 1 100%; }

/* ===== AGE-224 Phase 3: shared read-only deck view (/d/<id>) ===== */
.deck-shared-banner {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 0 0 14px; padding: 10px 14px; border-radius: 9px;
  font-size: 0.85rem; color: var(--text);
  background: color-mix(in srgb, var(--color-u) 12%, var(--panel-raised));
  border: 1px solid color-mix(in srgb, var(--color-u) 28%, transparent);
}
.deck-shared-banner[hidden] { display: none; }
.deck-shared-banner svg { width: 15px; height: 15px; color: var(--color-u); flex: 0 0 auto; }
.deck-shared-banner b { font-weight: 600; }
.deck-shared-banner .deck-shared-home { margin-left: auto; color: var(--color-u); font-weight: 600; text-decoration: none; white-space: nowrap; }
.deck-shared-banner .deck-shared-home:hover { text-decoration: underline; }

.deck-shared-strategy { margin: 16px 0 0; padding: 14px 16px; border: 1px solid var(--border-soft); border-radius: 10px; background: var(--panel); }
.deck-shared-strategy[hidden] { display: none; }
.deck-shared-strategy h4 { margin: 0 0 8px; font-size: 0.95rem; }
.deck-shared-strategy #deck-shared-strategy-body { font-size: 0.88rem; color: var(--text-muted); line-height: 1.6; }

.shared-deck-error { text-align: center; padding: 48px 20px; display: flex; flex-direction: column; align-items: center; gap: 16px; }
.shared-deck-error p { color: var(--text-muted); max-width: 42ch; margin: 0; }

/* Read-only: strip every edit surface from the reused deck detail. */
#deck-detail-view.shared-view .deck-head-actions,
#deck-detail-view.shared-view #deck-meta-status,
#deck-detail-view.shared-view #deck-commander-section .deck-commander-change-label,
#deck-detail-view.shared-view #deck-commander-section .deck-add-card,
#deck-detail-view.shared-view .indeck-toolbar [aria-label="Card reasons"],
#deck-detail-view.shared-view .indeck-search,
#deck-detail-view.shared-view .deck-tile2 .qty-stepper,
#deck-detail-view.shared-view .deck-tile2-foot:last-child,
#deck-detail-view.shared-view .deck-dense-row .qty-stepper,
#deck-detail-view.shared-view .deck-dense-row .btn-close { display: none; }

/* The deck name input reads as plain text (still an <input>, just disabled). */
#deck-detail-view.shared-view .deck-name-input {
  border-color: transparent; background: transparent; padding-left: 0; cursor: default;
  color: var(--text); opacity: 1;
}
body.shared-deck-page #open-new-deck,
body.shared-deck-page #mobile-open-new-deck { display: none !important; }

.deck-valuebar.deck-valuebar { margin: 14px 0 0; }

.deck-stats-strip {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
  margin-top: 14px;
}
.deck-stat-cell {
  background: var(--panel); border: 1px solid var(--border-soft);
  border-radius: 10px; padding: 10px 12px; min-width: 0;
}
.deck-stat-cell h4 {
  margin: 0 0 8px; font-size: 0.68rem; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--text-muted); font-weight: 700;
}
.deck-stat-cell .mana-curve { height: 62px; }
.deck-stat-cell .legality-list { max-height: 92px; }
@media (max-width: 860px) {
  .deck-stats-strip { grid-template-columns: repeat(2, 1fr); }
}

/* ---- lighter deck-detail collapsible (replaces .acc on the Decks page) ---- */
details.deck-section {
  background: var(--panel); border: 1px solid var(--border-soft);
  border-radius: 10px; margin-bottom: 12px; overflow: visible;
}
details.deck-section > summary.deck-section-summary {
  list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; gap: 8px;
  padding: 11px 14px; font-weight: 600; font-size: 0.9rem;
}
details.deck-section > summary.deck-section-summary::-webkit-details-marker { display: none; }
details.deck-section > summary.deck-section-summary::before {
  content: "\25B8"; color: var(--text-faint); font-size: 0.7rem; flex: 0 0 auto;
}
details.deck-section[open] > summary.deck-section-summary::before { content: "\25BE"; }
details.deck-section > summary.deck-section-summary:hover { color: var(--accent); }
.deck-section-body { padding: 2px 14px 16px; }
.deck-section-summary .deck-section-count { font-weight: 400; color: var(--text-muted); font-size: 0.8rem; }
/* assistant keeps its own boxed look + sunken header strip */
details.deck-section.assistant { padding: 0; border-color: var(--border); overflow: hidden; }
details.deck-section.assistant > summary.deck-section-summary { background: var(--panel-sunken); padding: 13px 20px; }

/* ---- AGE-214 inc.5: Location & moves + move sheet ---- */
.deck-section-count.warn { color: var(--bad); font-weight: 600; }
.lm-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 8px; margin: 4px 0 14px; }
.lm-cell {
  border: 1px solid var(--border-soft); border-radius: 9px;
  background: var(--panel-sunken); padding: 9px 11px;
}
.lm-cell .lm-k { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-faint); }
.lm-cell .lm-v { margin-top: 3px; font-size: 0.9rem; }
.lm-cell .lm-v.warn { color: var(--bad); }
.lm-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.lm-reshelve {
  margin-top: 12px; border: 1px solid var(--border-soft); border-radius: 9px;
  background: var(--panel-sunken); padding: 11px 13px;
}
.lm-reshelve label { display: block; font-size: 0.74rem; font-weight: 600; color: var(--text-muted); margin-bottom: 5px; }
.lm-reshelve select, .lm-reshelve-new {
  width: 100%; max-width: 320px; background: var(--panel); border: 1px solid var(--border);
  color: var(--text); border-radius: 8px; padding: 8px 10px; font: inherit; font-size: 0.85rem;
}
.lm-reshelve-new { margin-top: 8px; }
.lm-reshelve-note { font-size: 0.75rem; color: var(--text-faint); margin: 8px 0; line-height: 1.5; }

.move-sheet { margin-top: 16px; }
.move-sheet .ms-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.ms-block { border: 1px solid var(--border-soft); border-radius: 11px; background: var(--panel); margin-bottom: 12px; overflow: hidden; }
.ms-block > .ms-block-head {
  padding: 10px 13px; border-bottom: 1px solid var(--border-soft);
  display: flex; align-items: center; gap: 9px; font-size: 0.9rem; font-weight: 600;
}
.ms-block > .ms-block-head .ms-n {
  margin-left: auto; font-size: 0.76rem; font-weight: 400; color: var(--text-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.ms-row {
  display: grid; grid-template-columns: 20px 1fr auto; gap: 10px; align-items: center;
  padding: 8px 13px; border-top: 1px solid var(--border-soft); font-size: 0.85rem;
}
.ms-row:first-child { border-top: 0; }
.ms-row .ms-from { color: var(--text-muted); font-size: 0.78rem; }
.ms-row .ms-to { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.74rem; color: var(--text-muted); }
.ms-row.moved > span:not(.ms-to) { text-decoration: line-through; opacity: 0.6; }
.ms-row.patch { grid-template-columns: 1fr auto; }
.ms-row .ms-find {
  border: 1px solid var(--accent-border); background: var(--accent-soft); color: var(--text);
  border-radius: 7px; padding: 4px 10px; font-size: 0.75rem; font-weight: 600; cursor: pointer;
}
.ms-block.buy .ms-row { grid-template-columns: 1fr auto; }
.ms-foot { padding: 10px 13px; display: flex; justify-content: flex-end; gap: 12px; font-size: 0.85rem; border-top: 1px solid var(--border-soft); }
.ms-empty { padding: 10px 13px; font-size: 0.84rem; color: var(--text-muted); }

.ms-text { border: 1px solid var(--border-soft); border-radius: 11px; background: var(--panel-sunken); margin-top: 8px; }
.ms-text-head { display: flex; align-items: center; gap: 8px; padding: 9px 13px; border-bottom: 1px solid var(--border-soft); font-size: 0.8rem; color: var(--text-muted); }
.ms-text-head button { margin-left: auto; }
.ms-text pre { margin: 0; padding: 13px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.75rem; line-height: 1.6; color: var(--text); white-space: pre-wrap; overflow-x: auto; }

/* deck-list tile: lent a card out */
.deck-tile-flag { color: var(--bad); font-size: 0.72rem; font-weight: 600; }
/* In Deck tile: this copy is on loan from another deck until the move is done */
.deck-tile2-borrowed, .dd-borrowed {
  display: inline-block; font-size: 0.62rem; font-weight: 700; letter-spacing: 0.04em;
  background: var(--bad); color: #fff; border-radius: 4px; padding: 1px 5px; margin-top: 3px;
}
.dd-borrowed { margin: 0 0 0 6px; }

@media print {
  body > *:not(#deck-detail-view),
  #deck-detail-view > *:not(#deck-lm-section),
  #deck-lm-section .deck-section-body > *:not(#deck-move-sheet),
  #deck-move-sheet > *:not(.ms-text),
  .ms-text-head { display: none !important; }
  #deck-lm-section, #deck-lm-section .deck-section-body, #deck-move-sheet, .ms-text { display: block !important; border: 0; background: #fff; color: #000; }
  .ms-text pre { color: #000; font-size: 11pt; }
}

/* ---- In Deck hero + sticky toolbar ---- */
.indeck-wrap { margin-top: 4px; }
.indeck-toolbar {
  position: sticky; top: 56px; z-index: 12;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  padding: 10px 0; margin-bottom: 4px;
  background: var(--bg);
  border-bottom: 1px solid var(--border-soft);
}
.indeck-toolbar h2 { margin: 0; font-size: 1.05rem; font-family: "Fraunces", Georgia, serif; }
.indeck-count { font-size: 0.8rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.indeck-tb-spacer { flex: 1 1 auto; }
.deck-sort-select {
  background: var(--panel); border: 1px solid var(--border); color: var(--text);
  border-radius: 8px; padding: 6px 8px; font-size: 0.8rem;
}
.deck-filter-anchor { position: relative; }
.deck-filter-trigger { display: inline-flex; align-items: center; gap: 6px; }
.deck-filter-trigger[aria-expanded="true"] { border-color: var(--accent-border); background: var(--accent-soft); }
.deck-filter-badge {
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px;
  background: var(--color-m); color: #1a1400; font-size: 0.68rem; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}
.deck-filter-badge[hidden] { display: none; }
.deck-filter-pop {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 40; width: 290px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.4); padding: 14px 15px;
}
.deck-filter-pop[hidden] { display: none; }
.deck-filter-pop-head { display: flex; justify-content: space-between; align-items: center; font-weight: 600; font-size: 0.9rem; margin-bottom: 10px; }
.deck-fp-label {
  font-size: 0.62rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-faint); font-weight: 700; margin: 12px 0 6px;
}
.deck-fp-label:first-of-type { margin-top: 0; }
.deck-fp-pips { display: flex; gap: 8px; }
.deck-fp-pip {
  width: 26px; height: 26px; border-radius: 50%; border: 2px solid var(--border);
  cursor: pointer; padding: 0;
}
.deck-fp-pip[aria-pressed="true"] { border-color: var(--accent-bright, var(--accent)); box-shadow: 0 0 0 2px var(--accent-soft); }
.deck-fp-done { width: 100%; margin-top: 14px; }
@media (max-width: 860px) {
  .indeck-toolbar { top: 0; }
}

/* ---- In Deck card tiles (bespoke - deck cards carry no finish/condition) ---- */
.deck-card-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px; margin: 10px 0 40px;
}
.deck-card-grid.picking-replace .deck-tile2 { cursor: pointer; border-color: var(--color-r); }
.deck-card-grid.picking-replace .deck-tile2:hover { background: rgba(224, 85, 74, 0.12); }
.deck-tile2 {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 10px; overflow: hidden; display: flex; flex-direction: column;
  border-top: 3px solid var(--deck-tile-rarity, var(--border));
}
.deck-tile2 > img { width: 100%; aspect-ratio: 5/7; object-fit: cover; object-position: center 12%; display: block; background: var(--panel-sunken); }
.deck-tile2-body { padding: 7px 9px 9px; display: flex; flex-direction: column; gap: 5px; flex: 1; }
.deck-tile2-name { font-size: 0.8rem; font-weight: 600; line-height: 1.2; }
.deck-tile2-type { font-size: 0.68rem; color: var(--text-faint); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.deck-tile2-warn { font-size: 0.68rem; color: var(--color-m); }
.deck-tile2-foot { display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-top: auto; }
.deck-tile2-price { font-size: 0.72rem; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--text-muted); }
.deck-tile2-actions { display: flex; gap: 4px; }
.deck-tile2 .qty-stepper { display: inline-flex; align-items: center; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
.deck-tile2 .qty-stepper span { min-width: 20px; text-align: center; font-size: 0.75rem; font-variant-numeric: tabular-nums; }
.deck-tile2 .qty-btn { width: 22px; height: 22px; font-size: 0.9rem; background: var(--panel-raised); border: 0; color: var(--text); cursor: pointer; }
.deck-tile2 .btn-icon, .deck-tile2 .btn-close { width: 22px; height: 22px; font-size: 0.85rem; flex: 0 0 auto; }

/* ---- AGE-223 inc.1: per-card role badge + reason (deck list) ---- */
.role-badge {
  font-size: 0.6rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 1px 6px; border-radius: 4px; background: var(--panel-sunken); border: 1px solid var(--border-soft);
  color: var(--text-faint); vertical-align: middle; white-space: nowrap;
}
.role-badge-payoff { color: var(--color-b); border-color: color-mix(in srgb, var(--color-b) 45%, transparent); }
.role-badge-answer { color: var(--color-u); border-color: color-mix(in srgb, var(--color-u) 45%, transparent); }
.role-badge-ramp { color: var(--color-g); border-color: color-mix(in srgb, var(--color-g) 45%, transparent); }
.dl-why-row { display: flex; align-items: flex-start; gap: 6px; }
.dl-why {
  font-size: 0.74rem; color: var(--text-muted); line-height: 1.4;
}
.dl-why.hidden { display: none; }
.whybtn {
  flex: 0 0 auto; border: 1px solid var(--border); background: var(--panel); color: var(--text-faint);
  width: 18px; height: 18px; border-radius: 5px; cursor: pointer; font-size: 0.68rem; line-height: 1; padding: 0;
}
.whybtn:hover { border-color: var(--accent-border); color: var(--text); }
.dd-why-wrap { padding: 0 12px 7px 38px; border-top: 0; margin-top: -4px; }
.dd-why-wrap .dl-why-row { max-width: 640px; }

/* ---- AGE-223 inc.2: the Build Report ---- */
.report-toolbar { display: flex; align-items: center; justify-content: flex-end; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.report-toolbar .freshness {
  display: flex; align-items: center; gap: 7px; font-size: 0.78rem; color: var(--text-muted);
  background: color-mix(in srgb, var(--color-m) 12%, var(--panel)); border: 1px solid var(--accent-border);
  border-radius: 999px; padding: 4px 11px; margin-right: auto;
}
.report-toolbar .freshness.hidden { display: none; }
.report-toolbar .freshness .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--color-m); flex: 0 0 auto; }
.report-panel { background: var(--panel); border: 1px solid var(--border-soft); border-radius: 11px; padding: 14px 16px; margin-bottom: 12px; }
.report-panel h3 { margin: 0 0 8px; font-size: 0.95rem; font-family: "Fraunces", Georgia, serif; }
.report-gameplan { margin: 0; font-size: 0.88rem; line-height: 1.6; }

.cov-row { display: grid; grid-template-columns: 150px 1fr auto 24px; gap: 10px; align-items: center; padding: 6px 0; border-top: 1px solid var(--border-soft); font-size: 0.82rem; }
.cov-row:first-child { border-top: 0; }
.cov-name { font-weight: 600; }
.cov-track { height: 6px; border-radius: 4px; background: var(--panel-sunken); overflow: hidden; }
.cov-fill { height: 100%; border-radius: 4px; }
.cov-fill.cov-good { background: var(--good); }
.cov-fill.cov-warn { background: var(--color-m); }
.cov-fill.cov-bad { background: var(--bad); }
.cov-val { font-variant-numeric: tabular-nums; white-space: nowrap; }
.cov-val.cov-good { color: var(--good); }
.cov-val.cov-warn { color: var(--color-m); }
.cov-val.cov-bad { color: var(--bad); }
.cov-tgt { color: var(--text-faint); font-weight: 400; }
.cov-toggle {
  width: 22px; height: 22px; border-radius: 6px; border: 1px solid var(--border); background: var(--panel);
  color: var(--text-faint); cursor: pointer; font-size: 0.85rem; line-height: 1; padding: 0;
}
.cov-toggle:hover { border-color: var(--accent-border); color: var(--text); }
.cov-detail { padding: 4px 0 10px; font-size: 0.78rem; color: var(--text-muted); }
.cov-detail.hidden { display: none; }
.cov-note { margin: 0 0 6px; }
.cov-chipline { display: flex; flex-wrap: wrap; gap: 5px; }
.cov-chip { font-size: 0.7rem; background: var(--panel-sunken); border: 1px solid var(--border-soft); border-radius: 999px; padding: 2px 8px; }

.flag-item { padding: 10px 0; border-top: 1px solid var(--border-soft); }
.flag-item:first-child { border-top: 0; }
.flag-item .fn { font-weight: 600; font-size: 0.88rem; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.flag-tag {
  font-size: 0.62rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--bad); border: 1px solid color-mix(in srgb, var(--bad) 45%, transparent); border-radius: 4px; padding: 1px 6px;
}
.fwhy { font-size: 0.8rem; color: var(--text-muted); line-height: 1.5; margin: 4px 0 8px; }
.finder .finder-bar { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }

/* ---- In Deck dense list (editing a 99-card deck) ---- */
.deck-dense-list { display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; margin: 10px 0 40px; }
.deck-dense-hdr {
  font-size: 0.6rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-faint); font-weight: 700; padding: 10px 12px 4px;
  background: var(--panel-sunken);
}
.deck-dense-row {
  display: grid; grid-template-columns: 26px 1fr auto auto auto auto;
  align-items: center; gap: 10px; padding: 6px 12px;
  border-top: 1px solid var(--border-soft); font-size: 0.82rem;
}
.deck-dense-row:first-child, .deck-dense-hdr + .deck-dense-row { border-top: 0; }
.deck-dense-row > img { width: 24px; aspect-ratio: 5/7; object-fit: cover; border-radius: 3px; background: var(--panel-sunken); }
.deck-dense-row .dd-name { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.deck-dense-row .dd-mv { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--text-muted); font-size: 0.72rem; }
.deck-dense-row .dd-price { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--text-muted); font-size: 0.72rem; }
.deck-dense-row .qty-stepper { display: inline-flex; align-items: center; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
.deck-dense-row .qty-stepper span { min-width: 18px; text-align: center; font-size: 0.72rem; }
.deck-dense-row .qty-btn { width: 20px; height: 20px; font-size: 0.85rem; background: var(--panel-raised); border: 0; color: var(--text); cursor: pointer; }
.deck-card-grid > p, .deck-dense-list > p { grid-column: 1 / -1; margin: 8px 2px; }

.deck-commander-card { display: flex; gap: 12px; align-items: center; margin: 8px 0 12px; }
.deck-commander-card img { width: 90px; border-radius: 8px; }
.deck-commander-name { font-weight: 600; }

.deck-second-commander-suggestions { display: flex; flex-direction: column; gap: 8px; margin: 8px 0; }
.second-commander-suggestion {
  display: flex;
  gap: 10px;
  align-items: center;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
}
.second-commander-suggestion img { width: 48px; border-radius: 6px; flex: 0 0 auto; }
.second-commander-suggestion-info { flex: 1; }

.library-search-wrap { position: relative; flex: 1 1 260px; }
.library-search-wrap input { width: 100%; }

/* AGE-198: NOT .library-search-wrap - that class's `flex: 1 1 260px` is a
   width basis in its original row-flex parent (.controls), but this input
   sits inside a `.modal-body label` (display:flex; flex-direction:column),
   where the same rule becomes a HEIGHT basis instead - stretched the wrap
   to 260px tall and dragged the suggestions dropdown's `top: 100%` down
   with it. Plain position:relative, no flex-basis, fixes it. */
.name-search-wrap { position: relative; }
.name-search-wrap input { width: 100%; }

.deck-add-card { position: relative; margin: 14px 0; }
.deck-add-card input { width: 100%; background: var(--panel); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 8px 10px; }
.type-chip-group { flex-wrap: wrap; margin-top: 6px; }

/* AGE-121/AGE-123: two lookalike type-chip rows sit close together on this
   page (one filters what you're browsing to add, one filters what's already
   in the deck) - a small uppercase caption directly above each row is the
   whole fix, cheaper than restyling the chips themselves and consistent
   with the app's existing .rec-group-label convention. */
.deck-filter-label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); margin: 12px 0 4px; }
.deck-suggestions {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  max-height: 260px;
  overflow-y: auto;
  z-index: 5;
}
.deck-suggestions[hidden] { display: none; }
/* AGE-135: reuses .rec-row's exact type scale (name 0.85rem/600, secondary
   line 0.74rem muted) and thumbnail treatment (rounded, 5/7, sunken
   placeholder bg) - img/.sugg-meta are absent for callers with no image or
   type data (see renderSuggestions), so the row degrades to name-only. */
.deck-suggestion-item { display: flex; align-items: center; gap: 10px; padding: 6px 10px; cursor: pointer; }
.deck-suggestion-item:hover { background: var(--panel-raised); }
.deck-suggestion-item img { width: 28px; border-radius: 4px; aspect-ratio: 5/7; object-fit: cover; flex: 0 0 auto; background: var(--panel-sunken); }
.deck-suggestion-item .sugg-main { flex: 1; min-width: 0; }
.deck-suggestion-item .sugg-name { font-size: 0.85rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.deck-suggestion-item .sugg-meta { font-size: 0.74rem; color: var(--text-muted); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.deck-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin: 16px 0; }
.deck-stat-block { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 14px; }
.deck-stat-block h3 { margin: 0 0 10px; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }

.mana-curve { display: flex; align-items: flex-end; gap: 6px; height: 100px; }
.curve-bar { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; }
.curve-bar-fill { width: 100%; background: var(--color-m); border-radius: 3px 3px 0 0; min-height: 2px; }
.curve-bar-count { font-size: 0.7rem; color: var(--text-muted); margin-top: 2px; }
.curve-bar-label { font-size: 0.7rem; color: var(--text-muted); margin-top: 2px; }

.color-balance-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; font-size: 0.8rem; }
.color-balance-label { width: 16px; font-weight: 700; }
.color-balance-bar { flex: 1; height: 8px; background: var(--panel-raised); border-radius: 4px; overflow: hidden; }
.color-balance-fill { height: 100%; }
.color-balance-count { width: 24px; text-align: right; color: var(--text-muted); }

/* AGE-132: type ratio bar. Color-coded per card type (2026-08-30) - a
   qualitative 8-way palette, deliberately NOT the W/U/B/R/G colour-identity
   pips used elsewhere, so a segment reads on sight instead of hover-only.
   Legend chips below the bar drive the same deckCardListTypeFilter as the
   segments (the type chips themselves now live in the Filter popover). */
.type-ratio-bar { display: flex; height: 16px; border-radius: 6px; overflow: hidden; background: var(--panel-raised); margin: 8px 0 0; }
.type-ratio-segment { background: var(--color-m); border: none; border-right: 2px solid var(--panel); padding: 0; cursor: pointer; transition: opacity 0.15s, filter 0.15s; min-width: 6px; }
.type-ratio-segment:last-child { border-right: none; }
.type-ratio-segment.dimmed { opacity: 0.3; }
.type-ratio-segment.active { box-shadow: inset 0 0 0 2px var(--text); filter: saturate(1.35) brightness(1.08); }

.type-seg-Creature { background: var(--t-creature); }
.type-seg-Instant { background: var(--t-instant); }
.type-seg-Sorcery { background: var(--t-sorcery); }
.type-seg-Enchantment { background: var(--t-enchantment); }
.type-seg-Artifact { background: var(--t-artifact); }
.type-seg-Planeswalker { background: var(--t-planeswalker); }
.type-seg-Battle { background: var(--t-battle); }
.type-seg-Land { background: var(--t-land); }

.type-legend { display: flex; flex-wrap: wrap; gap: 6px 8px; margin: 12px 0 8px; }
.type-legend:empty { display: none; }
.type-legend-chip {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--panel-raised); padding: 3px 10px 3px 7px;
  font-size: 0.78rem; color: var(--text-muted); cursor: pointer;
  transition: border-color 0.15s, color 0.15s, opacity 0.15s;
}
.type-legend-chip:hover { border-color: var(--accent-border); }
.type-legend-chip.active { border-color: var(--accent-border); color: var(--text); background: var(--accent-soft); }
.type-legend-chip.dimmed { opacity: 0.4; }
.type-legend-sw { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.type-legend-chip .ct { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.type-legend-chip .pct { color: var(--text-faint); font-size: 0.72rem; }

.land-count-headline { font-weight: 700; font-size: 1rem; margin-bottom: 6px; }
.land-count-bar { height: 8px; background: var(--panel-raised); border-radius: 4px; overflow: hidden; margin-bottom: 6px; }
.land-count-fill { height: 100%; background: var(--color-g); }
.land-count-low { color: var(--color-r); }
.land-count-high { color: var(--color-m); }
.land-count-healthy { color: var(--color-g); }

.callout-warning { font-size: 0.78rem; color: var(--color-r); background: rgba(224, 85, 74, 0.12); padding: 6px 8px; border-radius: 4px; margin: 6px 0; }

.legality-panel .legality-ok { color: var(--color-g); font-size: 0.85rem; margin: 0; }
.legality-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; max-height: 160px; overflow-y: auto; }
.legality-list li { font-size: 0.78rem; color: var(--color-r); background: rgba(224, 85, 74, 0.12); padding: 4px 8px; border-radius: 4px; }

/* AGE-220: bracket audit banner - sits under the deck head, shows whether
   the 99 actually matches its stored power bracket. */
.deck-bracket-check { margin: 8px 0 4px; border-radius: 8px; padding: 9px 12px; border: 1px solid var(--border); background: var(--panel); }
.deck-bracket-check.over { border-color: color-mix(in srgb, var(--color-m) 55%, var(--border)); background: color-mix(in srgb, var(--color-m) 10%, var(--panel)); }
.dbc-head { display: flex; align-items: flex-start; gap: 8px; }
.dbc-dot { flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; background: var(--color-g); }
.deck-bracket-check.over .dbc-dot { background: var(--color-m); }
.dbc-title { font-size: 0.82rem; font-weight: 600; line-height: 1.4; }
.dbc-list { list-style: none; padding: 0; margin: 8px 0 0; display: flex; flex-direction: column; gap: 5px; }
.dbc-list li { font-size: 0.78rem; color: var(--text-muted); padding-left: 16px; position: relative; }
.dbc-list li::before { content: "\2022"; position: absolute; left: 4px; color: var(--color-m); }
.dbc-foot { font-size: 0.76rem; color: var(--text-muted); margin: 8px 0 0; font-style: italic; }

/* AGE-244: Upgrade Bracket - target-bracket picker, Quick/Full tier cards,
   swap rows. Ported from the approved mockup's .bu-* classes verbatim (same
   property values), just onto this app's real custom-property names. */
.bu-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.bu-label { font-size: 0.76rem; color: var(--text-muted); }
.bu-seg { display: inline-flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
.bu-seg button { padding: 5px 10px; background: var(--panel); border: 0; border-right: 1px solid var(--border-soft); font-size: 0.78rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.bu-seg button:last-child { border-right: 0; }
.bu-seg button[aria-pressed="true"] { background: var(--accent-bright); color: #241d00; font-weight: 700; }
.bu-seg button[disabled] { opacity: 0.4; cursor: not-allowed; }
.bu-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 0.78rem; color: var(--text-muted); }
.bu-toggle input { accent-color: var(--accent-bright); width: 14px; height: 14px; }
.bu-pending { margin-top: 10px; }
.bu-tiers { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 10px; }
@media (max-width: 560px) { .bu-tiers { grid-template-columns: 1fr; } }
.bu-tier { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; background: var(--panel); position: relative; }
.bu-tier.recommended { border-color: var(--accent-border); background: var(--accent-soft); }
.bu-tier-badge { position: absolute; top: -9px; right: 10px; font-size: 0.58rem; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 700; background: var(--accent-bright); color: #241d00; padding: 2px 7px; border-radius: 999px; }
.bu-tier .name { font-weight: 700; font-size: 0.86rem; }
.bu-tier .desc { font-size: 0.76rem; color: var(--text-muted); margin: 3px 0 8px; }
.bu-tier .bu-cast-btn { width: 100%; justify-content: center; display: inline-flex; align-items: center; gap: 5px; }
.bu-cost-pip {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 1.1rem; height: 1.1rem; border-radius: 50%; font-size: 0.62rem; font-weight: 800;
  background: radial-gradient(circle at 35% 28%, var(--panel-raised), var(--border) 78%);
  box-shadow: inset 0 0 0 1px var(--border);
}
.bu-lock-note { font-size: 0.72rem; color: var(--color-r); margin-top: 6px; }
.bu-verdict { font-size: 0.84rem; margin-top: 10px; padding: 8px 11px; border-radius: 8px; background: var(--panel-raised); border: 1px solid var(--border-soft); }
.bu-swap-row { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: center; padding: 8px 10px; border: 1px solid var(--border-soft); border-radius: 8px; background: var(--panel-raised); margin-top: 8px; font-size: 0.8rem; }
.bu-swap-row .cut { color: var(--color-r); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--color-r) 60%, transparent); }
.bu-swap-row .arrow { color: var(--text-faint); }
.bu-swap-row .add b { color: var(--text); display: block; }
.bu-swap-row .add small { color: var(--text-faint); font-size: 0.7rem; }
.bu-swap-row .bu-move-btn { grid-column: 1 / -1; margin-top: 4px; font-size: 0.72rem; padding: 4px 9px; border-radius: 6px; border: 1px solid var(--accent-border); background: var(--accent-soft); color: var(--accent-2); font-weight: 600; justify-self: start; }
.bu-swap-row .bu-move-btn.done, .bu-swap-row .bu-move-btn:disabled { opacity: 0.6; cursor: default; }
.bu-redo-btn { margin-top: 10px; }
@media (max-width: 560px) { .bu-swap-row { grid-template-columns: 1fr; } .bu-swap-row .arrow { display: none; } }

/* Deck Balance (survivability coverage - removal/wipes/protection vs a
   target scaled to this deck's own speed/commander-centrality, not a fixed
   rule). Reuses the land-count-bar meter pattern. */
.balance-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 0.8rem; }
.balance-row-label { width: 72px; flex: 0 0 auto; }
.balance-bar { flex: 1; height: 8px; background: var(--panel-raised); border-radius: 4px; overflow: hidden; }
.balance-bar-fill { height: 100%; }
.balance-bar-fill.balance-low { background: var(--color-r); }
.balance-bar-fill.balance-healthy { background: var(--color-g); }
.balance-bar-fill.balance-high { background: var(--color-m); }
.balance-row-count { width: 100px; flex: 0 0 auto; text-align: right; }
.balance-row-count.balance-low { color: var(--color-r); }
.balance-row-count.balance-healthy { color: var(--color-g); }
.balance-row-count.balance-high { color: var(--color-m); }

.balance-fill-group { margin: 6px 0 10px 80px; }
.balance-fill-subhead { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-muted); margin: 4px 0; }
.balance-fill-empty { font-size: 0.76rem; color: var(--text-muted); font-style: italic; margin: 0 0 10px 80px; }
.balance-cut-group { margin: 6px 0 10px 80px; }
.balance-cut-btn:hover { border-color: var(--color-r); color: var(--color-r); }

.deck-card-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 40px; }
.deck-card-row { display: flex; align-items: center; gap: 12px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; }
.deck-card-row img { width: 44px; border-radius: 4px; aspect-ratio: 5/7; object-fit: cover; }
.deck-card-row-info { flex: 1; min-width: 0; }
.deck-card-row-name { font-weight: 600; font-size: 0.88rem; }
.deck-card-warn { font-size: 0.72rem; color: var(--color-m); margin-top: 2px; }
.deck-card-row .qty-stepper { flex: 0 0 auto; }
.deck-card-row .qty-stepper span { padding: 0 12px; display: flex; align-items: center; font-size: 0.9rem; }
.deck-card-row .qty-btn { width: 32px; font-size: 1rem; }
.deck-card-row .btn-close { flex: 0 0 auto; }
.deck-card-row .btn-icon { flex: 0 0 auto; }
.deck-card-timing-toggle { font-size: 0.75rem; color: var(--color-m); text-decoration: none; display: inline-block; margin-top: 4px; }
.deck-card-timing-toggle:hover { text-decoration: underline; }

/* AGE-123: hard 99-card limit's inline replace prompt - reuses the existing
   deck-card-list rather than a modal, so rows become clickable in place. */
.deck-replace-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: rgba(224, 85, 74, 0.12); color: var(--color-r);
  border: 1px solid var(--color-r); border-radius: 8px;
  padding: 8px 12px; margin-bottom: 10px; font-size: 0.82rem;
}
.deck-replace-banner[hidden] { display: none; }
.deck-card-list.picking-replace .deck-card-row {
  cursor: pointer; border-color: var(--color-r);
}
.deck-card-list.picking-replace .deck-card-row:hover { background: rgba(224, 85, 74, 0.12); }

.deck-buylist-header { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.deck-buylist-header h3 { margin: 0; font-size: 0.95rem; }
.deck-buylist-header-actions { display: flex; gap: 8px; }
.deck-buylist { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.buylist-row { display: flex; align-items: center; gap: 12px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; }
.buylist-row img { width: 40px; border-radius: 4px; aspect-ratio: 5/7; object-fit: cover; }
.buylist-row-info { flex: 1; min-width: 0; }
.buylist-row-line { font-weight: 600; font-size: 0.85rem; font-family: ui-monospace, "SF Mono", Consolas, monospace; }
.buylist-row-price { font-size: 0.85rem; width: 64px; text-align: right; color: var(--text-muted); }
.buylist-row-subtotal { font-size: 0.9rem; width: 72px; text-align: right; font-weight: 600; }
.buylist-total { text-align: right; font-weight: 700; padding: 8px 10px; font-size: 0.95rem; }

/* AGE-242: the approved three-view deck shell. Keep selectors scoped to the
   deck detail so the app's top-level view tabs and wizard panels are not
   affected. */
.deck-views {
  margin: 18px 0 24px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}
.deck-views .views {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 8px 16px 0;
  border-bottom: 1px solid var(--border-soft);
  overflow-x: auto;
  scrollbar-width: thin;
}
.deck-views .views button {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  margin: 0 20px 0 0;
  padding: 9px 2px 11px;
  border: 0;
  background: transparent;
  color: var(--text-faint);
  font-family: "Fraunces", Georgia, serif;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
}
.deck-views .views button:hover { color: var(--text); }
.deck-views .views button[aria-selected="true"] { color: var(--text); }
.deck-views .views button[aria-selected="true"]::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  height: 2px;
  border-radius: 2px 2px 0 0;
  background: var(--accent-bright);
}
.deck-views .views button[hidden],
.deck-view-panel[hidden],
.v-badge[hidden] { display: none; }
.v-badge {
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 1.4;
}
.panelstage { position: relative; overflow: hidden; touch-action: pan-y; }
.deck-view-panel {
  min-width: 0;
  padding: 16px 18px 20px;
  animation: deck-panel-in 0.22s ease;
}
@keyframes deck-panel-in { from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: none; } }
.deck-view-panel > .deck-stats-strip { margin-top: 0; }

/* AGE-227/AGE-243 poster rework: the wallpaper stays a clean, full-bleed
   image at all times - no wide dark scrim wash, no "the read" panel
   stacked on top of it (that moved out to be a normal sibling section
   below - see .wp-overlay further down, no longer inside .wp-stage at
   all). The only things ever drawn over the art are (a) a small caption +
   the Illuminate card + its controls, shown on hover (desktop) or after
   scrolling the page at all (touch - see .wp-symbol + JS), and (b) that
   same caption/card, always visible with no reveal gating, whenever there
   is no image yet (.locked - nothing to protect by hiding chrome). */
.wp-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 12px;
  background: #0a0d16;
  isolation: isolate;
}
.wp-stage.wp-fmt-mobile { aspect-ratio: 9 / 16; }
.wp-stage:not(.wp-mobile-frame).wp-fmt-mobile { max-width: 360px; margin-inline: auto; }
.wp-empty {
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    radial-gradient(circle at 72% 24%, rgba(120, 102, 47, 0.38), transparent 34%),
    radial-gradient(circle at 20% 72%, rgba(54, 78, 112, 0.38), transparent 42%),
    linear-gradient(145deg, #151a26, #080a10 72%);
}
.wp-hero-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 0.3s ease; }
.wp-hero-img.on { opacity: 1; }

/* Touch scroll cue - desktop relies on hovering the poster instead, see
   .wp-chrome below and the matchMedia('(hover: hover)') gate in JS. */
.wp-symbol { display: none; }
.wp-stage.wp-touch .wp-symbol {
  display: block; position: absolute; z-index: 3; left: 50%; bottom: 16px; transform: translateX(-50%);
  width: 26px; height: 38px; color: #e6b26e; pointer-events: none;
  filter: drop-shadow(0 0 7px rgba(230, 178, 110, 0.7));
  transition: opacity 0.25s ease;
}
.wp-symbol .chev { opacity: 0.22; animation: wp-chev-glow 1.8s ease-in-out infinite; }
.wp-symbol .chev1 { animation-delay: 0s; }
.wp-symbol .chev2 { animation-delay: 0.16s; }
.wp-symbol .chev3 { animation-delay: 0.32s; }
.wp-stage.wp-revealed .wp-symbol { opacity: 0; }
@keyframes wp-chev-glow { 0%, 100% { opacity: 0.2; } 35% { opacity: 1; } 70% { opacity: 0.2; } }
@media (prefers-reduced-motion: reduce) { .wp-symbol .chev { animation: none; opacity: 0.7; } }

.wp-chrome {
  position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column; justify-content: flex-end;
  opacity: 0; transform: translateY(24px); pointer-events: none;
  transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.wp-stage.wp-revealed .wp-chrome,
.wp-stage.wp-no-image .wp-chrome { opacity: 1; transform: none; pointer-events: auto; }

.wp-facts { position: relative; margin-top: auto; padding: 20px 20px 18px; color: #fff; }
.wp-facts-row { display: flex; align-items: flex-end; flex-wrap: nowrap; gap: 18px; }
.wp-textblock {
  position: relative; display: inline-block; max-width: 100%; min-width: 0;
  background: rgba(14, 11, 8, 0.5); backdrop-filter: blur(14px) saturate(1.25);
  border: 1px solid rgba(201, 150, 95, 0.45); border-radius: 12px; padding: 12px 16px;
}
.wp-textblock::before {
  content: ""; position: absolute; inset: -46px; pointer-events: none;
  background: radial-gradient(60% 90% at 30% 55%, rgba(230, 178, 110, 0.55), transparent 72%);
  filter: blur(6px);
}
.wp-eyebrow {
  position: relative; color: #ffe3b0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.62rem; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase;
}
.wp-facts h2 {
  position: relative; margin: 4px 0 3px; color: #fff;
  font-family: "Fraunces", Georgia, serif; font-size: clamp(1.3rem, 3.4vw, 1.85rem);
  text-shadow: 0 0 26px rgba(230, 178, 110, 0.65), 0 0 4px rgba(0, 0, 0, 0.4);
}
.wp-facts p { position: relative; margin: 0; color: rgba(255, 255, 255, 0.92); font-size: 0.8rem; }

.wp-card-group { display: flex; flex-direction: column; align-items: flex-end; gap: 9px; flex: none; margin-left: auto; }
.wp-stage.wp-fmt-mobile .wp-card-group { align-items: flex-start; margin-left: 0; }
.wp-stage.wp-fmt-mobile .wp-facts-row { flex-direction: column; align-items: flex-start; }

/* Illuminate/Regenerate as a miniature proxy card, not a flat chip - reuses
   .spellcard-chip/.spellcard-cast-btn/.spellcard-lock-note/.spellcard-status
   (wireSpellCardChip targets those class names directly) inside a new
   card-shaped shell. The card is tucked to just its title bar by default;
   opening it (data-open) reveals the art/rules and, only then, the real
   Cast/Regenerate button - reading the card and using it are two separate
   steps. */
.wp-proxy-card {
  width: 118px; border-radius: 9px; overflow: hidden;
  background: linear-gradient(155deg, #d9b26e, #6b4a1e 55%, #d9b26e);
  box-shadow: 0 8px 20px -10px rgba(0, 0, 0, 0.65);
}
.wp-proxy-title {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 6px;
  margin: 0; padding: 6px 9px; border: 0; background: rgba(18, 14, 10, 0.78); color: #fff;
  font: inherit; text-align: left; cursor: pointer;
}
.wp-proxy-title:hover { background: rgba(30, 24, 16, 0.85); }
.wp-proxy-name { font-family: "Fraunces", Georgia, serif; font-weight: 700; font-size: 0.66rem; color: #fff; }
.wp-proxy-cost {
  flex: none; width: 15px; height: 15px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #ded8ca, #9b9488 72%); color: #241f18;
  font-size: 0.56rem; font-weight: 800; display: flex; align-items: center; justify-content: center;
}
.wp-proxy-body-outer { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.35s cubic-bezier(0.4, 0, 0.2, 1); }
.wp-proxy-card[data-open="true"] .wp-proxy-body-outer { grid-template-rows: 1fr; }
.wp-proxy-body-inner { overflow: hidden; }
.wp-proxy-art {
  display: flex; align-items: center; justify-content: center; height: 64px; margin: 3px 3px 0;
  background: radial-gradient(circle at 60% 25%, #2c2140, #0c0a12 75%);
}
.wp-proxy-art svg { width: 56%; height: 56%; }
.wp-proxy-type { display: block; margin: 0 3px; padding: 2px 6px; background: rgba(40, 30, 18, 0.9); color: #f0e2c4; font-size: 0.52rem; font-style: italic; }
/* .spellcard-chip's real base rule (used everywhere else in the app) is a
   bordered flex-row chip with its own background/margin/padding/transition
   - all overridden here to a plain stacked block sitting flush inside the
   card's cream rules box, since only wireSpellCardChip's targeted-by-class
   behavior is being reused, not its default flat-chip look. */
.wp-proxy-card .spellcard-chip {
  display: block; margin: 0 3px 3px; padding: 5px 6px; border: 0; border-radius: 0 0 5px 5px;
  background: rgba(244, 234, 210, 0.95); color: #241d12; font-size: 0.56rem; line-height: 1.3;
  transition: none;
}
.wp-proxy-card .spellcard-chip.tapped { transform: none; } /* the card itself doesn't need the flat chip's tap wiggle */
.wp-proxy-card .spellcard-chip:not(.affordable) { filter: none; } /* greyed at the card level instead, see :has() below */
.wp-proxy-card .spellcard-cost-pip { display: none; } /* real cost already shown as the card's corner pip */
.wp-proxy-card .spellcard-body { display: block; }
.wp-proxy-card .spellcard-name { display: none; } /* the card's own title bar already names it */
.wp-proxy-card .spellcard-rules { display: block; margin-top: 0; color: inherit; font-size: inherit; }
.wp-proxy-card .spellcard-lock-note { display: block; margin-top: 4px; color: #a3341f; font-size: 0.6rem; }
.wp-proxy-card .spellcard-cast-btn {
  display: block; width: 100%; margin-top: 5px; padding: 6px 0; border: 0; border-radius: 5px;
  background: var(--accent-2); color: #241a06; font: inherit; font-weight: 700; font-size: 0.6rem;
  letter-spacing: 0.02em; text-align: center; cursor: pointer;
}
.wp-proxy-card .spellcard-cast-btn:disabled { background: var(--border); color: var(--text-faint); cursor: not-allowed; }
.wp-proxy-card .spellcard-status { display: flex; margin-top: 4px; font-size: 0.58rem; color: #6b5a34; }
/* Greys the whole card off the SAME .affordable class wireSpellCardChip
   already manages (mana/hand check) - no separate lock state to keep in
   sync by hand. This is independent of .wp-no-image (below): a deck can
   have a wallpaper already and still show this if a Regenerate is
   currently unaffordable. */
.wp-proxy-card:has(.spellcard-chip:not(.affordable)) { filter: grayscale(0.55); opacity: 0.85; }

.wp-controls { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.wp-stage.wp-fmt-mobile .wp-controls { justify-content: flex-start; }
.wp-stage.wp-no-image .wp-controls { display: none; }
.wp-style-picker { display: flex; align-items: center; gap: 7px; }
.wp-swatch {
  position: relative; width: 44px; height: 44px; border-radius: 9px; overflow: hidden; cursor: pointer;
  border: 2px solid rgba(255, 255, 255, 0.25); padding: 0; background: #111; flex: none;
}
.wp-swatch img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wp-swatch.active { border-color: var(--accent-2); box-shadow: 0 0 0 2px rgba(201, 150, 95, 0.35); }
.wp-swatch.active::after {
  content: "\2713"; position: absolute; top: 2px; right: 2px; width: 14px; height: 14px; border-radius: 50%;
  background: var(--accent-2); color: #241a06; font-size: 0.6rem; font-weight: 800; display: flex; align-items: center; justify-content: center;
}
.wp-fmt-seg { display: inline-flex; border: 1px solid rgba(255, 255, 255, 0.28); border-radius: 7px; overflow: hidden; backdrop-filter: blur(6px); }
.wp-fmt-seg button {
  background: rgba(16, 14, 11, 0.62); color: #fff; border: 0; padding: 6px 11px; font-size: 0.78rem; font-weight: 600;
  display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
}
.wp-fmt-seg button + button { border-left: 1px solid rgba(255, 255, 255, 0.22); }
.wp-fmt-seg button svg { width: 13px; height: 13px; }
.wp-fmt-seg button[aria-pressed="true"] { background: var(--accent-2); color: #241a06; }
.wp-dl-btn {
  background: rgba(16, 14, 11, 0.62); backdrop-filter: blur(6px); color: #fff; border: 1px solid rgba(255, 255, 255, 0.28); border-radius: 7px;
  padding: 6px 11px; font-size: 0.78rem; font-weight: 600; display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
}
.wp-dl-btn svg { width: 13px; height: 13px; }
.wp-gen-error { color: #f5b8b0; font-size: 0.76rem; margin-top: 6px; }

.wp-dl-toast {
  position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 8px); z-index: 40; white-space: nowrap;
  background: var(--color-g); color: #06210f; font-size: 0.8rem; font-weight: 600;
  padding: 8px 16px; border-radius: 8px; box-shadow: 0 10px 24px -10px rgba(0, 0, 0, 0.4);
  opacity: 0; transition: opacity 0.2s ease, transform 0.2s ease; pointer-events: none;
}
.wp-dl-toast.show { opacity: 1; transform: translate(-50%, 0); }

/* Hand-placed layout for the native 9:16 mobile crop - the tall portrait
   shape wants a different arrangement than the wide 16:9 desktop crop's
   left-text/right-card row, so this only applies to .wp-fmt-mobile. Needs
   the wrapper chain flattened to position:static so the individually
   absolute pieces fall through to .wp-chrome (inset:0, no padding of its
   own) as their shared containing block instead of .wp-facts. */
.wp-stage.wp-fmt-mobile .wp-facts,
.wp-stage.wp-fmt-mobile .wp-facts-row,
.wp-stage.wp-fmt-mobile .wp-card-group,
.wp-stage.wp-fmt-mobile .wp-controls,
.wp-stage.wp-fmt-mobile .wp-style-picker,
.wp-stage.wp-fmt-mobile .wp-fmt-seg {
  position: static; display: block;
}
.wp-stage.wp-fmt-mobile .wp-fmt-seg { border: 0; background: none; backdrop-filter: none; }
.wp-stage.wp-fmt-mobile .wp-textblock,
.wp-stage.wp-fmt-mobile .wp-proxy-card,
.wp-stage.wp-fmt-mobile .wp-swatch,
.wp-stage.wp-fmt-mobile .wp-fmt-seg button,
.wp-stage.wp-fmt-mobile .wp-dl-btn {
  position: absolute; z-index: 5;
}
.wp-stage.wp-fmt-mobile .wp-textblock { left: 0; top: 77%; }
/* The card's title bar sits low, close above the text card - opening it
   (title fixed by `top`, body growing below) would unfurl straight down
   into that text card. There's clean open art above it instead, so anchor
   by `bottom` and reverse the internal stacking (title last in flex order
   = renders at the bottom) - opening it now grows upward into the empty
   space above instead. */
.wp-stage.wp-fmt-mobile .wp-proxy-card {
  left: 62%; top: auto; bottom: 24.9%;
  display: flex; flex-direction: column-reverse;
}
.wp-stage.wp-fmt-mobile .wp-style-picker .wp-swatch:nth-child(1) { left: 0; top: 69%; }
.wp-stage.wp-fmt-mobile .wp-style-picker .wp-swatch:nth-child(2) { left: 16%; top: 69%; }
.wp-stage.wp-fmt-mobile .wp-fmt-seg button[data-format="desktop"] { left: 32%; top: 71%; }
.wp-stage.wp-fmt-mobile .wp-fmt-seg button[data-format="mobile"] { left: 33%; top: 65%; }
.wp-stage.wp-fmt-mobile .wp-dl-btn { left: 0; top: 0; }

/* "The read" - AGE-243: a normal card BELOW the poster now, not an overlay
   stacked on top of the art (that was the original complaint - covering
   the wallpaper you just spent mana generating). Structurally unchanged
   from before (same collapse/expand classes + localStorage prefs in JS),
   just no longer absolutely anchored into .wp-stage's bottom edge. */
.wp-overlay {
  margin-top: 16px;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-raised);
  transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.wp-overlay.expanded { max-height: 20000px; }
.wp-overlay.collapsed { max-height: 50px; }
.wp-handle {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 15px;
  border: 0;
  border-bottom: 1px solid var(--border-soft);
  background: transparent;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}
.wp-handle-grab { width: 28px; height: 3px; flex: none; border-radius: 2px; background: var(--border); }
.wp-handle-label { min-width: 0; font-family: "Fraunces", Georgia, serif; font-size: 0.9rem; font-weight: 600; }
.wp-handle-label b { color: var(--text-muted); font-family: inherit; font-size: 0.76rem; font-weight: 400; }
.wp-handle-chev { width: 15px; height: 15px; flex: none; margin-left: auto; color: var(--text-faint); transition: transform 0.3s; }
.wp-overlay.collapsed .wp-handle-chev { transform: rotate(180deg); }
.wp-scroll { padding: 2px 16px 16px; }
.analysis-feature { padding: 16px 0; border-top: 1px solid var(--border-soft); }
.analysis-feature:first-child { border-top: 0; }
.analysis-feature h3 { margin: 0 0 9px; font-family: "Fraunces", Georgia, serif; font-size: 1rem; }
.analysis-feature #deck-critique-spellcard + #deck-critique-text { margin-bottom: 0; }

.get-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; margin-bottom: 14px; }
.get-head h2 { margin: 0 0 4px; font-family: "Fraunces", Georgia, serif; font-size: 1.2rem; }
.get-sub { margin: 0; color: var(--text-muted); font-size: 0.82rem; line-height: 1.5; }
.assistant-settings-btn { flex: 0 0 auto; }
.get-group { padding: 18px 0; border-top: 1px solid var(--border-soft); }
.get-group > h3 { margin: 0 0 5px; font-family: "Fraunces", Georgia, serif; font-size: 1.02rem; }
.get-group > .get-sub { margin-bottom: 10px; }
.get-subsection {
  margin-top: 9px;
  overflow: hidden;
  border: 1px solid var(--border-soft);
  border-radius: 9px;
  background: var(--panel-raised);
}
.get-subsection > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  list-style: none;
  color: var(--text);
  font-size: 0.86rem;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
}
.get-subsection > summary::-webkit-details-marker { display: none; }
.get-subsection > summary::before { content: "\25B8"; flex: none; color: var(--text-faint); font-size: 0.68rem; }
.get-subsection[open] > summary::before { content: "\25BE"; }
.get-subsection > .deck-section-body,
.get-subsection-body { padding: 2px 12px 14px; }
.get-subsection .deck-card-list { margin-bottom: 0; }
#bracketMoveGroup:empty::before {
  content: "No bracket moves yet.";
  color: var(--text-muted);
  font-size: 0.8rem;
}

.pane-summary { font-size: 0.85rem; color: var(--text-muted); margin: 0 0 16px; font-style: italic; }

/* AGE-223 inc.5: "Ask about this deck" rules assistant - its own chat pane
   in the Deck Assistant, built from the Build Report mockup sketch
   (claude.ai artifact 9f31e12c). */
.ask-chat {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 140px;
  max-height: 460px;
  overflow-y: auto;
  padding: 14px;
  background: var(--panel-sunken);
  border: 1px solid var(--border-soft);
  border-radius: 10px;
}
.ask-empty { margin: 4px 0 0; }
.ask-empty p { margin: 0 0 10px; font-size: 0.85rem; color: var(--text-muted); font-style: italic; }
.ask-examples { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.ask-ex {
  appearance: none;
  text-align: left;
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  font: inherit;
  font-size: 0.83rem;
  padding: 8px 11px;
  border-radius: 8px;
  cursor: pointer;
}
.ask-ex:hover { border-color: var(--accent-border); background: var(--accent-soft); }
.ask-msg {
  max-width: 88%;
  padding: 10px 13px;
  border-radius: 12px;
  font-size: 0.88rem;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.ask-msg.user {
  align-self: flex-end;
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
}
.ask-msg.assistant {
  align-self: flex-start;
  background: var(--panel);
  border: 1px solid var(--border-soft);
}
.ask-msg.assistant.error { color: var(--bad); border-color: var(--bad); }
.ask-msg .mtg-spinner-wrap { padding: 4px 0; }
.ask-input-row { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
#ask-input {
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  font: inherit;
  font-size: 0.88rem;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
  color: var(--text);
}
#ask-input:focus { outline: none; border-color: var(--accent-border); box-shadow: 0 0 0 3px var(--accent-soft); }
.ask-input-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* Generate Deck used to live buried in the gear-icon settings modal
   (Kevin's 2026-08-12 feedback: "kind of hidden") - surfaced as a callout
   at the top of the Suggestions tab instead, settings modal keeps only
   Priorities reordering. */
.suggestions-generate-row {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 12px 14px;
  margin: 0 0 16px;
  background: var(--panel-raised);
  border: 1px solid var(--border-soft);
  border-radius: 8px;
}
/* display:flex above beats the UA [hidden]{display:none} rule - same
   bare-[hidden] gotcha as .stats[hidden], .topbar[hidden] etc. throughout
   this file. Hidden outside Commander format (AGE-242, non-Commander decks
   have no color identity/priorities for Generate to build from). */
.suggestions-generate-row[hidden] { display: none; }
.suggestions-generate-row .btn-primary {
  flex: 0 0 auto;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
/* currentColor picks up .btn-primary's dark text color (#1a1400) - an emoji
   bolt renders in its own fixed yellow, which barely reads against the same
   orange/gold gradient background (Kevin's 2026-08-12 contrast feedback).
   An inline SVG guarantees the icon matches the button text everywhere. */
.suggestions-generate-row .btn-bolt-icon { flex: 0 0 auto; }
.suggestions-generate-row p { margin: 0; flex: 1 1 220px; }

/* Shared recommendation row - used by Suggestions, Balance's fill
   candidates, and Replace. One component, one Add button, everywhere a
   card is suggested (recRow() in app.js). */
.rec-group { margin-bottom: 18px; }
.rec-group:last-child { margin-bottom: 0; }
.rec-group-label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-faint); margin: 0 0 8px; display: flex; align-items: center; gap: 8px; }
.rec-group-label .count { color: var(--text-muted); font-weight: 700; }
.rec-row { display: grid; grid-template-columns: 36px 1fr auto auto; align-items: center; gap: 12px; padding: 8px 10px; border-radius: 8px; border: 1px solid transparent; }
.rec-row:hover { background: var(--panel-raised); border-color: var(--border-soft); }
.rec-row img { width: 36px; border-radius: 4px; aspect-ratio: 5/7; object-fit: cover; background: var(--panel-sunken); }
.rec-main { min-width: 0; }
.rec-name { font-size: 0.86rem; font-weight: 600; }
.rec-reason { font-size: 0.74rem; color: var(--text-muted); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rec-price { font-size: 0.76rem; color: var(--text-faint); font-variant-numeric: tabular-nums; text-align: right; flex: 0 0 auto; }
.rec-price.owned { color: var(--good); }
.rec-add { appearance: none; font-family: inherit; background: var(--panel-raised); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 6px 12px; font-size: 0.78rem; font-weight: 600; cursor: pointer; }
.rec-add:hover { border-color: var(--accent); color: var(--accent); }
.rec-add:disabled { opacity: 0.6; cursor: default; }

/* Replace tab's weak-card picker - a compact list, not a tile grid
   (Kevin's decision, 2026-08-12), radio-style single selection. */
.replace-weak-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 18px; }
.replace-weak-item { display: flex; align-items: center; justify-content: space-between; gap: 12px; background: var(--panel-raised); border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px; cursor: pointer; font-size: 0.82rem; }
.replace-weak-item:hover { border-color: var(--accent-border); }
.replace-weak-item.selected { border-color: var(--accent); background: var(--accent-soft); }
.replace-weak-item-name { font-weight: 600; }
.replace-weak-item-reason { color: var(--text-muted); font-size: 0.76rem; font-style: italic; }

/* MTG-themed loading state (Fill Remaining Slots / Optimize Deck) - a
   spinning five-color mana wheel built from the same --color-w/u/b/r/g
   tokens used everywhere else, no external assets. */
.mtg-spinner-wrap { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 28px 0; }
.mtg-spinner {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: conic-gradient(var(--color-w), var(--color-u), var(--color-b), var(--color-r), var(--color-g), var(--color-w));
  animation: mtg-spin 1.1s linear infinite;
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 7px), #000 calc(100% - 6px));
}
@keyframes mtg-spin { to { transform: rotate(360deg); } }
.mtg-spinner-label { font-size: 0.8rem; color: var(--text-muted); font-style: italic; }

/* AGE-112: claimed-card cross-deck signaling. Informational only - never
   excludes a card from recommendation, just flags that a copy is already
   spoken for elsewhere (or that there aren't enough copies to go around). */
.claim-badge {
  display: inline-block;
  margin-top: 4px;
  font-size: 0.65rem;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 8px;
  color: #14120f;
}
.claim-badge-claimed { background: var(--color-u); }
.claim-badge-insufficient { background: var(--color-r); color: #fff; }

/* AGE-113: drag-orderable priority list. Plain HTML5 drag-and-drop, no
   library - matches this project's zero-dependency convention. */
.priority-list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.priority-item {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  cursor: grab;
  font-size: 0.82rem;
}
.priority-item:active { cursor: grabbing; }
.priority-item.dragging { opacity: 0.4; }
.priority-item.drag-over { border-color: var(--color-m); }
.priority-item-rank { flex: 0 0 auto; width: 22px; text-align: center; font-weight: 700; color: var(--text-muted); }
.priority-item-label { flex: 1; }
.priority-item-desc { color: var(--text-muted); font-size: 0.75rem; }

.suggestions-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 6px; }
.suggestions-header p { margin: 0; max-width: 640px; }

.archetype-list { display: flex; flex-direction: column; gap: 14px; margin-top: 12px; }
.archetype-card { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 14px; }
.archetype-card-header { display: flex; align-items: center; gap: 14px; }
.archetype-commander-img { width: 64px; border-radius: 6px; aspect-ratio: 5/7; object-fit: cover; flex: 0 0 auto; }
.archetype-card-info { flex: 1; min-width: 0; }
.archetype-commander-name { font-weight: 700; font-size: 1rem; }
.archetype-progress-label { font-size: 0.78rem; color: var(--text-muted); margin-top: 4px; }
.archetype-progress-bar { height: 6px; background: var(--panel-raised); border-radius: 3px; overflow: hidden; margin-top: 4px; width: 100%; max-width: 320px; }
.archetype-progress-fill { height: 100%; background: var(--color-m); }
.archetype-build-btn { flex: 0 0 auto; }
.archetype-preview { display: flex; gap: 6px; margin-top: 12px; flex-wrap: wrap; }
.archetype-preview img { width: 56px; border-radius: 4px; aspect-ratio: 5/7; object-fit: cover; }
.archetype-timing-toggle { font-size: 0.78rem; color: var(--color-m); text-decoration: none; display: inline-block; margin-top: 10px; }
.archetype-timing-toggle:hover { text-decoration: underline; }
.archetype-timing-tips { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }
/* sets display:flex unconditionally, so it needs the same explicit [hidden]
   override as every other such class in this file (see .stats above) - the
   bare [hidden] attribute loses to any normal-priority author rule. */
.archetype-timing-tips[hidden] { display: none; }
.archetype-timing-tip { font-size: 0.8rem; color: var(--text-muted); }
.archetype-timing-tip strong { color: var(--text); }

.audit-launch-row { display: flex; align-items: center; gap: 20px; margin: 14px 0 26px; flex-wrap: wrap; }
.audit-spot-check { display: flex; align-items: center; gap: 8px; }
.audit-spot-size { display: flex; align-items: center; gap: 6px; font-size: 0.85rem; color: var(--text-muted); }
.audit-spot-size input { width: 56px; background: var(--panel); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 6px 8px; text-align: center; }

.audit-history-heading { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); margin: 24px 0 10px; }
.audit-history-list { display: flex; flex-direction: column; gap: 8px; }
.audit-history-entry { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.audit-history-summary { display: flex; align-items: center; gap: 12px; padding: 10px 12px; font-size: 0.85rem; cursor: pointer; }
.audit-history-summary:hover { background: var(--panel-raised); }
.audit-history-mode { font-weight: 600; }
.audit-history-when { color: var(--text-muted); flex: 1; }
.audit-history-stats { color: var(--text-muted); font-size: 0.78rem; }
.audit-corrected { color: var(--color-m); font-weight: 600; }
.audit-history-expand-icon { color: var(--text-muted); font-size: 0.75rem; flex: 0 0 auto; }
.audit-history-items-wrap { padding: 4px 12px 12px; border-top: 1px solid var(--border); }
.audit-history-items-wrap[hidden] { display: none; }
.audit-history-item-list { display: flex; flex-direction: column; gap: 2px; margin-top: 6px; }
.audit-history-item-list[hidden] { display: none; }
.audit-history-item-row { display: flex; justify-content: space-between; gap: 10px; font-size: 0.78rem; padding: 3px 6px; border-radius: 4px; }
.audit-history-item-row:hover { background: var(--panel-raised); }

.audit-resume-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: var(--panel-raised);
  border: 1px solid var(--color-u);
  border-radius: 8px;
  padding: 12px 16px;
  margin-bottom: 16px;
}
/* Same gotcha as .stats/.form-fields/.search-result/.history-items above:
   the bare [hidden] attribute loses to any normal-priority author rule that
   sets display, so it needs this explicit override or it never visually
   hides regardless of what the JS sets .hidden to. */
.audit-resume-banner[hidden] { display: none; }

.audit-step-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; }
.audit-step-header h2 { margin: 0 0 4px; }
.audit-step-header p { margin: 0; max-width: 620px; }
.audit-step-actions { display: flex; gap: 8px; flex: 0 0 auto; }

.audit-group { margin-bottom: 22px; }
.audit-group-header { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); margin-bottom: 8px; padding-bottom: 4px; border-bottom: 1px solid var(--border); }
.audit-row { display: flex; align-items: center; gap: 12px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; margin-bottom: 6px; }
.audit-row img { width: 40px; border-radius: 4px; aspect-ratio: 5/7; object-fit: cover; }
.audit-row-info { flex: 1; min-width: 0; }
.audit-row-name { font-weight: 600; font-size: 0.85rem; }
.audit-row-meta { font-size: 0.72rem; color: var(--text-muted); }
.audit-row-digital { font-size: 0.78rem; color: var(--text-muted); width: 90px; text-align: right; }
.audit-row .qty-stepper { flex: 0 0 auto; }
.audit-row .qty-stepper input[type="number"] { width: 48px; }
.audit-row .qty-btn { width: 32px; font-size: 1rem; }
.audit-row.audit-row-mismatch { border-color: var(--color-m); }
.audit-row.audit-row-pending { border-color: var(--color-u); }
.audit-onorder-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 0.68rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  flex: 0 0 auto;
}
.audit-onorder-field input {
  width: 48px;
  background: var(--panel-raised);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 6px;
  text-align: center;
  font-size: 0.9rem;
  text-transform: none;
}

.audit-diff-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 30px; }
.audit-diff-row { display: flex; align-items: center; gap: 12px; background: var(--panel); border: 1px solid var(--color-m); border-radius: 8px; padding: 10px 12px; }
.audit-diff-row img { width: 40px; border-radius: 4px; aspect-ratio: 5/7; object-fit: cover; }
.audit-diff-row-info { flex: 1; min-width: 0; }
.audit-diff-row-name { font-weight: 600; font-size: 0.85rem; }
.audit-diff-row-change { font-size: 0.8rem; white-space: nowrap; }
.audit-diff-up { color: var(--color-g); }
.audit-diff-down { color: var(--color-r); }
.audit-diff-removed { color: var(--color-r); font-weight: 600; }
.audit-diff-pending { color: var(--color-u); font-weight: 600; }
.audit-diff-received { color: var(--color-g); font-weight: 600; }

.audit-row-info { display: flex; flex-direction: column; gap: 2px; }
.audit-switch-print-btn {
  background: none;
  border: none;
  color: var(--color-m);
  font-size: 0.7rem;
  cursor: pointer;
  padding: 2px 0 0;
  text-align: left;
  align-self: flex-start;
}
.audit-switch-print-btn:hover { text-decoration: underline; }

.printing-jump-input {
  width: 100%;
  max-width: 240px;
  background: var(--panel-raised);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 0.85rem;
}
.printing-tile-jump-highlight { border-color: var(--color-m) !important; box-shadow: 0 0 0 3px rgba(217, 182, 78, 0.3); }

.printing-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 12px;
  max-height: 60vh;
  overflow-y: auto;
}
.printing-tile {
  position: relative;
  cursor: pointer;
  border: 2px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  background: var(--panel);
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.printing-tile:hover { border-color: var(--color-m); transform: translateY(-2px); }
.printing-tile img { width: 100%; display: block; aspect-ratio: 5/7; object-fit: cover; background: var(--panel-raised); }
.printing-tile-info { padding: 6px 8px; }
.printing-tile-set { font-size: 0.72rem; font-weight: 600; }
.printing-tile-current { border-color: var(--color-g); }
.printing-tile-badge {
  position: absolute;
  top: 4px;
  right: 4px;
  background: var(--color-g);
  color: #14120f;
  font-size: 0.6rem;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 8px;
}

/* ---------- Roadmap tab (AGE-173) ---------- */
.btn-ghost {
  background: transparent;
  border: 1px solid var(--border-soft);
  color: var(--text-muted);
}
.btn-ghost:hover { border-color: var(--accent-border); color: var(--text); }

.roadmap-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
  margin-top: 12px;
}
@media (max-width: 700px) {
  .roadmap-columns { grid-template-columns: 1fr; }
}
.roadmap-column {
  background: var(--panel-sunken);
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 80px;
}
.roadmap-column h3 {
  margin: 0 0 2px;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--accent);
}
.roadmap-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: border-color 0.15s ease;
}
.roadmap-card:hover { border-color: var(--accent-border); }
.roadmap-card-badges {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.roadmap-badge {
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 7px;
  border-radius: 999px;
  line-height: 1.5;
}
.roadmap-badge-id {
  background: var(--panel-sunken);
  border: 1px solid var(--border-soft);
  color: var(--text-faint);
  font-family: monospace;
}
.roadmap-badge-priority { color: #14120f; }
.roadmap-badge-priority-urgent { background: var(--color-r); }
.roadmap-badge-priority-high { background: var(--rarity-mythic); }
.roadmap-badge-priority-medium { background: var(--color-m); }
/* AGE-196: -low pairs --text-faint as a solid fill, which the shared
   .roadmap-badge-priority's near-black text (#14120f) only had contrast
   against because text-faint used to be a lighter/darker (theme-dependent)
   shade before this pass's contrast fix moved it toward mid-gray in both
   themes - #14120f is under 3.5:1 on it now. var(--panel) reads as a clean
   knockout instead (white-on-gray in light mode, near-black-on-gray in
   dark mode) and clears 4.5:1 in both. */
.roadmap-badge-priority-low { background: var(--text-faint); color: var(--panel); }
.roadmap-card-title a {
  color: var(--text);
  font-weight: 600;
  text-decoration: none;
  font-size: 0.92rem;
  line-height: 1.35;
}
.roadmap-card-title a:hover { color: var(--accent); text-decoration: underline; }
.roadmap-card-note {
  margin: 0;
  font-style: italic;
  border-left: 2px solid var(--accent-border);
  padding-left: 8px;
  line-height: 1.4;
}
.roadmap-card-note-empty {
  border-left-color: var(--border-soft);
  color: var(--text-faint);
}
.roadmap-card-meta {
  margin: 0;
  font-size: 0.72rem;
  color: var(--text-faint);
}
.roadmap-card-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 2px;
}

/* ---------- Admin Users Panel (AGE-Users-Panel) ---------- */
/* Sibling of #topbar, not #admin-view - stays visible while an admin
   browses other tabs under a target user's data during view-as. Sticky
   (neither .deck-replace-banner nor .audit-resume-banner is - this is the
   one banner that needs to survive a view switch and stay in view while
   scrolling). */
.view-as-banner {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: rgba(224, 85, 74, 0.12);
  color: var(--color-r);
  border-bottom: 1px solid var(--color-r);
  padding: 8px 16px;
  font-size: 0.85rem;
}
.view-as-banner[hidden] { display: none; }

.admin-users-list { display: flex; flex-direction: column; gap: 8px; }
.admin-user-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
}
.admin-user-info { flex: 1; min-width: 200px; }
.admin-user-email { font-weight: 600; font-size: 0.88rem; }
.admin-user-meta { font-size: 0.72rem; color: var(--text-faint); }
.admin-user-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.admin-user-badge {
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 7px;
  border-radius: 999px;
  line-height: 1.5;
  background: var(--panel-sunken);
  border: 1px solid var(--border-soft);
  color: var(--text-faint);
}
.admin-user-badge-creator, .admin-user-badge-admin { background: var(--color-m); border-color: var(--color-m); color: #14120f; }
.admin-user-badge-revoked, .admin-user-badge-banned { background: var(--color-r); border-color: var(--color-r); color: #fff; }

.admin-entitlements-group { display: flex; flex-direction: column; gap: 8px; }
.admin-entitlements-row { display: flex; align-items: center; gap: 8px; }
.admin-entitlements-row label { font-size: 0.88rem; }
.admin-entitlements-ai { margin-top: 4px; padding-top: 8px; border-top: 1px solid var(--border-soft); }

/* ---------- Feedback screenshot attach (AGE-173) ---------- */
.feedback-screenshot-label {
  display: block;
  margin: 8px 0;
  padding: 8px 10px;
  border: 1px dashed var(--border-soft);
  border-radius: 6px;
  color: var(--text-muted);
  font-size: 0.8rem;
  cursor: pointer;
  text-align: center;
}
.feedback-screenshot-label:hover { border-color: var(--accent-border); color: var(--text); }

/* ---------- accordions: Deck Detail sections + Audit set groups (AGE-180) ----------
   Native <details>/<summary>, zero custom JS - collapse is a free browser
   feature. Every accordion defaults open (open attribute / groupDiv.open = true
   in renderAuditChecklist()) so the desktop always-expanded layout is
   unchanged; this only adds the *option* to collapse, nothing that was
   visible before is hidden on load. */
details.acc {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  margin-bottom: 16px;
  padding: 0 16px 16px;
  overflow: hidden;
}
details.acc > summary.acc-summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 -16px;
  padding: 14px 16px;
  font-weight: 700;
  font-size: 0.95rem;
  user-select: none;
}
details.acc > summary.acc-summary::-webkit-details-marker { display: none; }
details.acc > summary.acc-summary::after {
  content: "\25BC";
  font-size: 0.65rem;
  color: var(--text-muted);
  transition: transform 0.2s ease;
  flex: 0 0 auto;
}
details.acc[open] > summary.acc-summary::after { transform: rotate(180deg); }
details.acc > summary.acc-summary:hover { color: var(--accent); }
.acc-summary-count { font-weight: 400; color: var(--text-muted); font-size: 0.82rem; }

/* audit set groups keep their existing uppercase-divider look instead of the
   boxed-card treatment above - just add the same toggle chrome. */
details.audit-group.acc {
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
}
.audit-group-header.acc-summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0 0 8px;
}
.audit-group-header.acc-summary::-webkit-details-marker { display: none; }
.audit-group-header.acc-summary::after {
  content: "\25BC";
  font-size: 0.6rem;
  color: var(--text-faint);
  transition: transform 0.2s ease;
}
details.audit-group.acc[open] > .audit-group-header.acc-summary::after { transform: rotate(180deg); }

/* ---------- mobile responsive pass (AGE-181) ---------- */
/* CSS-only, deliberately placed last so it wins the cascade against
   everything above by source order without needing extra specificity.
   Reuses the same 860px breakpoint as AGE-177/178 - one mobile boundary
   across the whole redesign. */
@media (max-width: 860px) {
  /* -- card grid + tile: name/price stay prominent, everything else shrinks -- */
  .grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .card-body { padding: 8px; }
  .card-name { font-size: 0.82rem; margin-bottom: 3px; }
  .card-meta { font-size: 0.68rem; }
  .card-footer { font-size: 0.74rem; margin-top: 4px; }
  .card-badges { gap: 3px; }
  .card-badges span { font-size: 0.6rem; padding: 1px 5px; }
  .edit-btn { width: 22px; height: 22px; font-size: 0.72rem; top: 4px; right: 4px; }

  /* -- topbar: drop redundant/secondary chrome now covered by the drawer -- */
  .topbar { padding: 10px 14px; gap: 10px; }
  /* #open-history already has a drawer equivalent (AGE-177) - the topbar
     copy is now just clutter at this width. */
  #open-history { display: none; }
  .stats { gap: 12px; }
  .stat-label { font-size: 0.62rem; }
  /* Sparkline/delta and the proxy breakout are bonus detail, not core
     numbers - still on desktop, just not worth the width here. */
  .value-ticker, .stat-proxy { display: none; }

  /* -- main content padding: tighter side margins, more room for the grid -- */
  main { padding-left: 14px; padding-right: 14px; padding-top: 14px; }

  /* -- deck analysis panel: the Win Condition/Key Synergies text stacked
     FOUR padding levels (main > .deck-view-panel > .wp-scroll >
     .critique-box, ~62px combined per side) vs. the Rules Breakdown
     modal's two (.modal-body > .rules-breakdown-ability-card, ~32px) for
     comparable boxed content - Kevin's report, side-by-side screenshots.
     .deck-view-panel already provides the outer gutter every deck tab
     shares; .wp-scroll's own side padding here was pure redundant
     stacking on top of it. -- */
  .wp-scroll { padding-left: 0; padding-right: 0; }

  /* -- modals: Kevin's reported bug - centered fixed-height modals could
     push the close button off the top of the visual viewport, reachable
     only by pinching out. Fix: full-screen modals with a header pinned via
     `sticky` to the top of the (now-scrolling) backdrop, so the close
     button is always on-screen without ever needing to zoom. -- */
  .modal-backdrop {
    align-items: flex-start;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .modal, .modal-wide, #edit-card-modal .modal-wide, .modal-rules-breakdown {
    width: 100%;
    max-width: 100%;
    max-height: none;
    min-height: 100%;
    border-radius: 0;
  }
  .modal-header {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--panel);
  }

  /* -- AGE-179: touch card preview - pointer-events:auto (unlike desktop's
     hover-follow tooltip, which must stay click-through) so a tap directly
     on it can close it, per wireTouchCardPreview() in app.js. Capped so it
     can't overflow narrower phones despite the fixed 360px desktop width. -- */
  .card-tooltip { pointer-events: auto; max-width: calc(100vw - 24px); }

  /* -- AGE-184: Add Card + Feedback as slide-up bottom sheets, matching the
     artifact - opt-in via .modal-sheet, so these compound-class selectors
     naturally out-specify the plain .modal-backdrop/.modal-header rules
     above regardless of order, without touching any other modal. The
     [hidden] open/close mechanism (app.js) is untouched - this only changes
     how the modal looks/animates while visible. -- */
  .modal-backdrop.modal-sheet {
    align-items: flex-end;
    padding: 0;
  }
  .modal-backdrop.modal-sheet .modal {
    width: 100%;
    max-width: 100%;
    max-height: 86%;
    min-height: 0;
    border-radius: 16px 16px 0 0;
    display: flex;
    flex-direction: column;
    animation: modal-sheet-in 0.22s ease;
  }
  .modal-backdrop.modal-sheet .modal-sheet-handle {
    display: block;
    width: 36px; height: 4px;
    background: var(--border); border-radius: 4px;
    margin: 10px auto 2px; flex: 0 0 auto;
  }
  .modal-backdrop.modal-sheet .modal-header {
    position: static;
    flex: 0 0 auto;
    padding: 4px 18px 12px;
  }
  .modal-backdrop.modal-sheet .modal-body {
    overflow-y: auto;
    padding-bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  }
  @keyframes modal-sheet-in {
    from { transform: translateY(100%); }
    to { transform: translateY(0); }
  }
}

/* ===== AGE-165: Library tab layout (2026-08-27, mockup-approved) =====
   Scoped entirely under #library-view / .lib-*. Reuses the app's existing
   token set + Fraunces/Work Sans - no new palette. The single-card result
   no longer borrows .edit-layout / .edit-explanation-box from the Edit Card
   modal (those stay untouched); Library gets its own classes so the two can
   diverge. Data (prices, set codes, labels) is set in the system monospace
   for a catalog-ledger read. */

#library-view { max-width: 1120px; }

.lib-head { margin-bottom: 22px; }
.lib-eyebrow {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.68rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 6px;
}
.lib-head h1 { margin: 0; font-size: 1.9rem; line-height: 1.1; }
.lib-dek { margin: 8px 0 0; max-width: 62ch; color: var(--text-muted); font-size: 0.9rem; }
.lib-dek code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--panel-sunken); border: 1px solid var(--border-soft);
  border-radius: 4px; padding: 0 4px; font-size: 0.85em;
}

.lib-search-block { max-width: 680px; margin-bottom: 18px; }
.lib-controls { margin-bottom: 12px; }
.lib-controls .library-search-wrap input[type="search"] {
  padding: 11px 13px; font-size: 0.95rem; border-radius: 9px;
}

.lib-examples { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }
.lib-examples[hidden] { display: none; }
.lib-examples-label {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.62rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-faint); margin-right: 2px;
}
.lib-chip {
  font: inherit; font-size: 0.8rem; cursor: pointer;
  padding: 5px 11px; border-radius: 999px;
  background: var(--panel-raised); border: 1px solid var(--border);
  color: var(--text-muted);
  transition: background 0.14s, color 0.14s, border-color 0.14s;
}
.lib-chip:hover, .lib-chip:focus-visible {
  background: var(--accent-soft); border-color: var(--accent-border);
  color: var(--text); outline: none;
}

.lib-gets {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
  max-width: 780px; margin-top: 26px;
}
.lib-gets[hidden] { display: none; }
.lib-get {
  background: var(--panel-raised); border: 1px solid var(--border);
  border-radius: 10px; padding: 14px 15px;
}
.lib-get-k {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.6rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent);
}
.lib-get h3 { margin: 7px 0 4px; font-size: 0.95rem; }
.lib-get p { margin: 0; font-size: 0.8rem; color: var(--text-muted); line-height: 1.5; }

/* ---- single-card result ---- */
.lib-result { display: grid; grid-template-columns: 290px 1fr; gap: 34px; align-items: start; }
.lib-result[hidden] { display: none; }

.lib-card-col { position: sticky; top: 88px; display: flex; flex-direction: column; gap: 12px; }
.lib-card-img {
  width: 100%; border-radius: 12px; display: block;
  background: var(--panel-raised); aspect-ratio: 5 / 7; object-fit: contain;
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.5);
}
#library-flip-btn { width: 100%; }

.lib-printings { border-top: 1px solid var(--border); padding-top: 11px; }
.lib-printings-label {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.62rem; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 9px;
}
.lib-printings-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(40px, 1fr)); gap: 6px;
}
.lib-printings.clamped:not(.expanded) .lib-printings-grid {
  max-height: 196px; overflow: hidden;
  -webkit-mask-image: linear-gradient(#000 72%, transparent);
          mask-image: linear-gradient(#000 72%, transparent);
}
.lib-printings-more { margin-top: 9px; font-size: 0.72rem; }
.lib-printings-more[hidden] { display: none; }
.lib-printing {
  position: relative; padding: 0; cursor: pointer;
  border: 1px solid var(--border); border-radius: 5px; overflow: hidden;
  background: var(--panel-raised); aspect-ratio: 5 / 7;
  transition: transform 0.12s, border-color 0.14s;
}
.lib-printing img { width: 100%; height: 100%; object-fit: cover; object-position: center 16%; display: block; }
.lib-printing-code {
  position: absolute; left: 0; right: 0; bottom: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.5rem;
  color: #f3eeda; background: linear-gradient(transparent, rgba(0, 0, 0, 0.82));
  padding: 7px 2px 2px; text-align: center; letter-spacing: 0.03em;
}
.lib-printing:hover { transform: translateY(-2px); border-color: var(--accent-border); }
.lib-printing:focus-visible { outline: 2px solid var(--color-m); outline-offset: 1px; }
.lib-printing[aria-current="true"] { border-color: var(--color-m); box-shadow: 0 0 0 1px var(--color-m); }

.lib-detail { min-width: 0; }
.lib-card-name { font-family: "Fraunces", Georgia, serif; font-weight: 600; font-size: 1.55rem; line-height: 1.15; }
.lib-meta-line { display: flex; flex-wrap: wrap; align-items: center; gap: 9px; margin-top: 6px; color: var(--text-muted); font-size: 0.9rem; }
.lib-mana { display: inline-flex; gap: 3px; }
.lib-set { margin-top: 3px; color: var(--text-faint); font-size: 0.8rem; }

.lib-ledger {
  display: flex; flex-wrap: wrap; margin-top: 16px;
  border: 1px solid var(--border); border-radius: 10px; overflow: hidden;
  background: var(--panel-raised);
}
.lib-ledger[hidden] { display: none; }
.lib-ledger-cell { flex: 1 1 25%; min-width: 84px; padding: 9px 13px; border-right: 1px solid var(--border); }
.lib-ledger-cell:last-child { border-right: none; }
.lib-ledger-k {
  display: block;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.56rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-faint);
}
.lib-ledger-v {
  display: block; margin-top: 2px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.95rem; font-variant-numeric: tabular-nums; color: var(--text);
}

.lib-legality { margin-top: 12px; }
#library-switch-print-btn { margin-top: 6px; align-self: flex-start; }

.lib-sections { margin-top: 26px; display: flex; flex-direction: column; gap: 22px; }
.lib-section-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 9px; }
.lib-tab-label {
  display: inline-block;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.62rem; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-muted);
  background: var(--panel-sunken); border: 1px solid var(--border-soft);
  border-radius: 5px 5px 5px 0; padding: 4px 9px;
}
.lib-prose { max-width: 64ch; font-size: 0.9rem; line-height: 1.6; }
.lib-prose#library-rules-breakdown-content { max-width: 68ch; }

/* ---- ownership + wishlist (AGE-165 phase A, 2026-08-28) ---- */
.lib-ownership { margin-top: 14px; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.lib-ownership[hidden] { display: none; }
.lib-own-status {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 0.85rem; font-weight: 600; color: var(--text);
}
.lib-own-status::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--good); box-shadow: 0 0 0 3px color-mix(in srgb, var(--good) 22%, transparent);
}
.lib-own-status.is-other { color: var(--text-muted); font-weight: 500; }
.lib-own-status.is-other::before { background: var(--text-faint); box-shadow: none; }
.lib-own-status.is-none { display: none; }
#library-wishlist-btn.is-on {
  background: var(--accent-soft); border-color: var(--accent-border); color: var(--accent);
}

/* owned marker on the printing thumbnails */
.lib-printing--owned::after {
  content: ""; position: absolute; top: 3px; right: 3px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--good); border: 1.5px solid var(--panel);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--good) 55%, transparent);
}

/* Owned / Wishlist segmented toggle (Collection toolbar) */
.lib-seg { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: var(--panel-raised); }
.lib-seg-btn {
  font: inherit; font-size: 0.8rem; font-weight: 600; cursor: pointer;
  padding: 5px 13px; border: none; background: none; color: var(--text-muted);
  display: inline-flex; align-items: center; gap: 6px;
}
.lib-seg-btn[aria-pressed="true"] { background: var(--color-m); color: #1a1400; }
.lib-seg-count {
  font-size: 0.68rem; font-variant-numeric: tabular-nums;
  background: color-mix(in srgb, currentColor 16%, transparent);
  border-radius: 999px; padding: 0 5px; min-width: 16px; text-align: center;
}
.lib-seg-count[hidden] { display: none; }

/* .grid sets display:grid, which beats the [hidden] UA rule - toggle this
   class instead when swapping the Owned <-> Wishlist grids. */
.grid.grid-off { display: none; }

/* ---- Wishlist v2 (AGE-210): compact faces, printings revealed inline ---- */
/* Column width follows the Owned grid's card-size setting (--card-min, set by
   applyCardSize); [data-size="pro"|"pro2"] swap the face layout to match
   renderProCard / renderProV2Card. */
#wishlist-grid.wl-groups {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--card-min, 150px), 1fr));
  gap: 13px;
  align-items: start;
}
#wishlist-grid.wl-groups.grid-off { display: none; }

.wl-card { position: relative; }
/* open card claims ~2 tracks (the drawer's width) rather than the whole row,
   so it stays compact and neighbours flow beside it */
.wl-card.open { grid-column: span 2; }
@media (max-width: 560px) { .wl-card.open { grid-column: 1 / -1; } }

.wl-face {
  width: 100%; text-align: left; font: inherit; color: var(--text); cursor: pointer;
  padding: 0; background: var(--panel); border: 1px solid var(--border);
  border-radius: 10px; overflow: hidden; display: flex; flex-direction: column;
  transition: border-color 0.12s ease, transform 0.12s ease;
}
.wl-face:hover { border-color: var(--accent-border); transform: translateY(-2px); }
.wl-card.open .wl-face { display: none; }
.wl-face-art { position: relative; aspect-ratio: 5 / 7; background: var(--panel-sunken); }
.wl-face-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wl-face-count {
  position: absolute; top: 6px; left: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.7rem; font-weight: 600; color: #fff;
  background: rgba(20, 18, 15, 0.78); border-radius: 5px; padding: 1px 6px;
}
/* magnifier -> full-card overlay; sibling of the .wl-face button */
.wl-face-zoom {
  position: absolute; top: 6px; right: 6px; z-index: 3; padding: 0;
  width: 26px; height: 26px; border-radius: 6px; cursor: pointer;
  display: grid; place-items: center; line-height: 1;
  border: 1px solid rgba(255, 255, 255, 0.3); color: #fff;
  background: rgba(20, 18, 15, 0.68);
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.wl-face-zoom:hover { background: var(--accent); color: #1a1400; border-color: var(--accent); }
.wl-card.open .wl-face-zoom { display: none; }
.wl-face-body { padding: 8px 9px 9px; display: flex; flex-direction: column; gap: 4px; }
.wl-face-name { font-weight: 600; font-size: 0.85rem; line-height: 1.25; }
.wl-face-meta {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 0.7rem; color: var(--text-faint); font-variant-numeric: tabular-nums;
}
/* name-over-art, shown only in "pro" (art-only) mode */
.wl-face-proname {
  display: none; position: absolute; left: 0; right: 0; bottom: 0;
  padding: 14px 8px 6px; font-size: 0.72rem; font-weight: 600; color: #fff;
  background: linear-gradient(180deg, transparent, rgba(10, 9, 7, 0.82));
  line-height: 1.2;
}

/* "pro" - art-only crop tile, name overlaid (mirrors renderProCard) */
#wishlist-grid[data-size="pro"] .wl-face-body { display: none; }
#wishlist-grid[data-size="pro"] .wl-face-proname { display: block; }

/* "pro2" - art-crop tile with the name/meta below (mirrors renderProV2Card) */
#wishlist-grid[data-size="pro2"] .wl-face-art { aspect-ratio: 626 / 457; }

.wl-drawer {
  display: none; border: 1px solid var(--accent-border); border-radius: 10px;
  background: var(--panel-raised); overflow: hidden; width: 100%;
}
.wl-card.open .wl-drawer { display: block; }
.wl-drawer-head {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; padding: 9px 11px;
  border-bottom: 1px solid var(--border-soft);
  background: linear-gradient(180deg, var(--panel-raised),
    color-mix(in srgb, var(--panel-raised) 84%, var(--card-accent, var(--accent)) 16%));
}
.wl-drawer-title { font-weight: 600; font-size: 0.9rem; }
.wl-drawer-count { font-size: 0.72rem; color: var(--text-muted); }
.wl-drawer-actions { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.wl-drawer-close {
  font: inherit; font-size: 0.95rem; line-height: 1; color: var(--text-faint);
  background: none; border: none; cursor: pointer; padding: 4px 6px;
}
.wl-drawer-close:hover { color: var(--text); }
.wl-drawer-body {
  padding: 11px; display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
}

.wl-tile {
  border: 1px solid var(--border); border-radius: 9px;
  background: var(--panel); overflow: hidden; cursor: pointer;
  display: flex; flex-direction: column;
  transition: border-color 0.12s ease, transform 0.12s ease;
}
.wl-tile:hover { border-color: var(--accent-border); transform: translateY(-2px); }
.wl-tile.is-foil { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
/* whole card, not the art crop - in the wishlist you're judging the printing */
.wl-tile-art { position: relative; aspect-ratio: 5 / 7; background: var(--panel-sunken); }
.wl-tile-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wl-heart {
  position: absolute; top: 6px; right: 6px; width: 24px; height: 24px;
  border-radius: 50%; border: 1px solid rgba(255, 255, 255, 0.28);
  background: rgba(20, 18, 15, 0.68); color: #fff; cursor: pointer;
  font-size: 0.75rem; line-height: 1; display: grid; place-items: center;
  opacity: 0.7; transition: opacity 0.12s ease, background 0.12s ease, border-color 0.12s ease;
}
.wl-tile:hover .wl-heart { opacity: 1; }
.wl-heart:hover { background: var(--bad); border-color: var(--bad); }
.wl-tile-zoom {
  position: absolute; top: 5px; left: 5px; width: 22px; height: 22px; padding: 0;
  border-radius: 6px; cursor: pointer; display: grid; place-items: center; line-height: 1;
  border: 1px solid rgba(255, 255, 255, 0.28); color: #fff; background: rgba(20, 18, 15, 0.62);
  opacity: 0.7; transition: opacity 0.12s ease, background 0.12s ease, border-color 0.12s ease;
}
.wl-tile:hover .wl-tile-zoom { opacity: 1; }
.wl-tile-zoom:hover { background: var(--accent); color: #1a1400; border-color: var(--accent); }
@media (hover: none) { .wl-tile-zoom { opacity: 1; } }
.wl-tile-foot { padding: 6px 7px 7px; display: flex; flex-direction: column; gap: 4px; }
.wl-tile-line1 { display: flex; align-items: baseline; justify-content: space-between; gap: 4px; }
.wl-setcode {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.62rem; color: var(--text); letter-spacing: 0.02em; white-space: nowrap;
}
.wl-price {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.66rem; color: var(--accent); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.wl-tile-line2 { display: flex; align-items: center; gap: 6px; }
.wl-chip {
  font-size: 0.6rem; letter-spacing: 0.03em; text-transform: uppercase;
  border-radius: 4px; padding: 2px 6px; border: 1px solid var(--border-soft);
  color: var(--text-muted); background: var(--panel-sunken);
}
.wl-chip-foil { color: var(--color-u); border-color: color-mix(in srgb, var(--color-u) 45%, var(--border)); }
.wl-chip-etched { color: var(--rarity-mythic); border-color: color-mix(in srgb, var(--rarity-mythic) 45%, var(--border)); }
.wl-prio { display: inline-flex; gap: 2px; margin-left: auto; }
.wl-prio i { width: 5px; height: 5px; border-radius: 50%; background: var(--border); }
.wl-prio i.on { background: var(--accent); }
.wl-note {
  font-size: 0.64rem; color: var(--text-muted); font-style: italic;
  border-top: 1px dashed var(--border-soft); padding-top: 4px; line-height: 1.3;
}
/* "I have this -> collection" - per printing in the drawer, and on the face
   of a single-printing card so it needn't be opened */
.wl-have {
  margin-top: 2px; font: inherit; font-size: 0.62rem; font-weight: 600; cursor: pointer;
  padding: 4px 0; border-radius: 5px; text-align: center;
  border: 1px solid var(--accent-border); background: var(--accent-soft); color: var(--accent);
}
.wl-have:hover { background: var(--accent); color: #1a1400; border-color: var(--accent); }
.wl-face-have {
  position: absolute; left: 8px; right: 8px; bottom: 8px; z-index: 2;
  font: inherit; font-size: 0.68rem; font-weight: 600; cursor: pointer;
  padding: 5px 0; border-radius: 6px; text-align: center;
  border: 1px solid var(--accent-border); color: #fff;
  background: color-mix(in srgb, var(--accent) 82%, rgba(10, 9, 7, 0.9));
  opacity: 0; transition: opacity 0.12s ease;
}
.wl-card:hover .wl-face-have, .wl-face:focus-visible + .wl-face-have { opacity: 1; }
.wl-face-have:hover { background: var(--accent); color: #1a1400; }
.wl-card.open .wl-face-have { display: none; }
@media (hover: none) { .wl-face-have { opacity: 1; } }

/* wishlist marker on the "other printings" thumbnails (opposite the owned dot) */
.lib-printing--wished::before {
  content: "\2665"; position: absolute; top: 1px; left: 4px; z-index: 2;
  font-size: 0.62rem; line-height: 1; color: var(--accent);
  text-shadow: 0 0 3px rgba(0, 0, 0, 0.75);
}

/* wishlist printing editor */
#wish-editor-sub { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.wish-field { margin-top: 14px; }
.wish-field-label {
  display: block; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.6rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: 6px;
}
.wish-opts { display: flex; flex-wrap: wrap; gap: 5px; }
.wish-opts button {
  font: inherit; font-size: 0.78rem; cursor: pointer;
  padding: 6px 11px; border-radius: 7px;
  border: 1px solid var(--border); background: var(--panel-sunken); color: var(--text-muted);
}
.wish-opts button[aria-pressed="true"] {
  background: var(--accent-soft); border-color: var(--accent-border); color: var(--accent);
}
#wish-editor-note {
  width: 100%; font: inherit; font-size: 0.85rem; padding: 8px 10px;
  border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel-sunken); color: var(--text); resize: vertical;
}
.wish-error { color: var(--bad); min-height: 1em; }
.wish-editor-foot { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.wish-editor-foot .wish-editor-remove { margin-left: auto; }

/* ---- wishlist buying-sheet export (AGE-210) ---- */
.modal.wl-export { width: min(560px, 94vw); }
.wl-export-fmt { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.wl-export-fmt .wish-field-label { margin: 0; }
.wl-export-note { font-size: 0.72rem; color: var(--text-faint); margin: -4px 0 4px; }
.wl-export-selbar {
  display: flex; align-items: center; gap: 12px; font-size: 0.72rem; color: var(--text-muted);
  padding-top: 8px; border-top: 1px solid var(--border-soft);
}
.wl-export-selbar button {
  font: inherit; font-size: 0.72rem; color: var(--accent); background: none; border: 0; cursor: pointer; padding: 0;
}
.wl-export-count { margin-left: auto; font-variant-numeric: tabular-nums; }

.wl-export-list {
  max-height: 240px; overflow-y: auto;
  border: 1px solid var(--border-soft); border-radius: 8px; background: var(--panel-sunken);
}
.wl-export-grp { border-bottom: 1px solid var(--border-soft); }
.wl-export-grp:last-child { border-bottom: 0; }
.wl-export .wl-export-grp-head {
  display: flex; flex-direction: row; align-items: center; gap: 8px;
  padding: 7px 11px; background: var(--panel-raised); cursor: pointer; font-size: 0.82rem;
}
.wl-export-grp-head .nm { font-weight: 600; }
.wl-export-grp-head .ct { color: var(--text-faint); font-size: 0.68rem; }
.wl-export .wl-export-row {
  display: flex; flex-direction: row; align-items: center; gap: 9px;
  padding: 7px 11px 7px 30px; font-size: 0.78rem; cursor: pointer;
  border-left: 2px solid transparent;
}
.wl-export-row:hover { background: var(--panel-raised); }
.wl-export-row.on { background: var(--accent-soft); border-left-color: var(--accent); }
.wl-export-grp-head.on, .wl-export-grp-head.part { color: var(--text); }
.wl-export-row .set { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.03em; }
.wl-export-row .fin {
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-faint);
  border: 1px solid var(--border-soft); border-radius: 4px; padding: 1px 5px;
}
.wl-export-row .fin.x { color: var(--color-u); border-color: color-mix(in srgb, var(--color-u) 45%, var(--border)); }
.wl-export-row .pr {
  margin-left: auto; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
/* custom checkbox - a clear checkmark in the box, not just a tint */
.wl-export input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 19px; height: 19px; flex: none; margin: 0; padding: 0; cursor: pointer; position: relative;
  border: 1.5px solid var(--border); border-radius: 5px; background: var(--panel);
  transition: background 0.1s ease, border-color 0.1s ease;
}
.wl-export input[type="checkbox"]:hover { border-color: var(--accent-border); }
.wl-export input[type="checkbox"]:checked {
  background: var(--accent); border-color: var(--accent-bright);
}
.wl-export input[type="checkbox"]:checked::after {
  content: ""; position: absolute; left: 6px; top: 2px; width: 4px; height: 9px;
  border: solid #1a1400; border-width: 0 2.5px 2.5px 0; transform: rotate(43deg);
}
.wl-export input[type="checkbox"]:indeterminate {
  background: var(--accent-soft); border-color: var(--accent-border);
}
.wl-export input[type="checkbox"]:indeterminate::after {
  content: ""; position: absolute; left: 3.5px; top: 7.5px; width: 10px; height: 2.5px;
  border-radius: 1px; background: var(--accent);
}
.wl-export input[type="checkbox"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.wl-export-preview .wish-field-label { margin: 0 0 5px; }
.wl-export-preview pre {
  margin: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.72rem; line-height: 1.55;
  color: var(--text); background: var(--panel-sunken); border: 1px solid var(--border-soft); border-radius: 8px;
  padding: 9px 11px; max-height: 130px; overflow: auto; white-space: pre;
}
.wl-export-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.wl-export-tot { font-size: 0.82rem; color: var(--text-muted); }
.wl-export-tot b { color: var(--text); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.wl-export-toast { font-size: 0.72rem; color: var(--good); }
#wl-export-download { margin-left: auto; }
/* full-screen modal treatment kicks in at <=860px (the whole modal scrolls),
   so drop the inner scroll caps - one scroll, not nested. */
@media (max-width: 860px) {
  .wl-export-list { max-height: none; }
  .wl-export-preview pre { max-height: 200px; }
}

@media (max-width: 560px) {
  .wl-tile { width: 100%; }
}

@media (max-width: 860px) {
  .lib-result { grid-template-columns: 1fr; gap: 22px; }
  .lib-card-col { position: static; max-width: 300px; }
  .lib-gets { grid-template-columns: 1fr; max-width: 420px; }
}
/* Phones: let the card image fill the column so it lines up with the
   price/rarity ledger and the detail text below it (was capped at 300px and
   left-aligned, leaving the art visibly short of the ledger's right edge). */
@media (max-width: 600px) {
  .lib-card-col { max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
  .lib-chip, .lib-printing { transition: none; }
  .lib-printing:hover { transform: none; }
}

/* ============================================================
   AGE-214 - New Deck wizard (overlay). Uses .modal-backdrop for the
   app's focus-trap / Escape plumbing; .nd-wizard scopes everything else.
   ============================================================ */
.nd-wizard { display: grid; place-items: center; padding: 24px; overflow-y: auto; }
.nd-wiz { width: min(720px, 100%); background: var(--panel); border: 1px solid var(--border);
  border-radius: 16px; box-shadow: 0 30px 80px rgba(0,0,0,.5); overflow: hidden;
  display: flex; flex-direction: column; max-height: calc(100vh - 48px); }

.nd-wiz-banner { position: relative; height: 112px; overflow: hidden; background: #14102b; border-bottom: 1px solid var(--border-soft); }
:root[data-theme="light"] .nd-wiz-banner, :root:not([data-theme="dark"]) .nd-wiz-banner { background: #241d47; }
.nd-wiz-banner canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; image-rendering: pixelated; }
.nd-wiz-banner .cap { position: absolute; right: 12px; bottom: 7px; font-family: var(--font-mono); font-size: 0.56rem; letter-spacing: 0.14em; text-transform: uppercase; color: rgba(232,198,95,.55); z-index: 1; }

.nd-wiz-head { padding: 16px 20px 12px; border-bottom: 1px solid var(--border-soft); }
.nd-wiz-head .eyebrow { font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); }
.nd-wiz-head h2 { margin: 4px 0 0; font-size: 1.3rem; }
.nd-wiz-steps { display: flex; gap: 6px; margin-top: 12px; flex-wrap: wrap; }
.nd-wiz-steps .st { display: flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-faint); }
.nd-wiz-steps .st .dot { width: 20px; height: 20px; border-radius: 50%; border: 1px solid var(--border); display: grid; place-items: center; font-family: var(--font-mono); font-size: 0.66rem; }
.nd-wiz-steps .st[data-state="current"] { color: var(--text); }
.nd-wiz-steps .st[data-state="current"] .dot { border-color: var(--accent-bright); background: var(--accent-soft); color: var(--text); }
.nd-wiz-steps .st[data-state="done"] .dot { background: var(--color-m); color: #14120f; border-color: transparent; }
.nd-wiz-body { padding: 18px 20px; overflow-y: auto; }
.nd-wiz-body h3 { margin: 0 0 4px; font-size: 1.05rem; }
.nd-wiz-body .sub { color: var(--text-muted); font-size: 0.85rem; margin: 0 0 16px; max-width: 60ch; }
.nd-wiz-foot { padding: 14px 20px; border-top: 1px solid var(--border-soft); display: flex; align-items: center; gap: 10px; }
.nd-wiz-foot .grow { margin-left: auto; }
.nd-wiz-err { color: var(--bad); font-size: 0.78rem; font-weight: 600; }
.nd-wiz-err[hidden] { display: none; }
.nd-wiz-page[hidden] { display: none; }

.nd-wizard .opt { display: flex; gap: 12px; align-items: flex-start; padding: 13px 14px; border: 1px solid var(--border); border-radius: 11px; cursor: pointer; margin-bottom: 10px; background: var(--panel-raised); }
.nd-wizard .opt:hover { border-color: var(--accent-border); }
.nd-wizard .opt.sel { border-color: var(--accent-bright); background: var(--accent-soft); }
.nd-wizard .opt .oi { font-size: 1.1rem; line-height: 1.2; }
.nd-wizard .opt .ot { font-weight: 600; font-size: 0.92rem; }
.nd-wizard .opt .od { color: var(--text-muted); font-size: 0.8rem; margin-top: 3px; }

.nd-wizard .field { margin-bottom: 14px; }
.nd-wizard .field > label { display: block; font-size: 0.78rem; font-weight: 600; color: var(--text-muted); margin-bottom: 5px; }
.nd-wizard .field input[type="text"], .nd-wizard .field select, .nd-wizard .field textarea {
  width: 100%; background: var(--panel-sunken); border: 1px solid var(--border); color: var(--text);
  border-radius: 9px; padding: 9px 11px; font-size: 0.9rem; font-family: inherit;
}
.nd-wizard .field textarea { resize: vertical; min-height: 62px; }
.nd-wizard .check { display: flex; gap: 9px; align-items: flex-start; padding: 8px 0; font-size: 0.86rem; }
.nd-wizard .check input { margin-top: 2px; }
.nd-wizard .check .cd { color: var(--text-muted); font-size: 0.78rem; }

.nd-wizard .eligible { margin-top: 14px; padding: 11px 13px; border-radius: 10px; border: 1px solid var(--accent-border);
  background: var(--accent-soft); font-size: 0.85rem; display: flex; gap: 8px; align-items: baseline; }
.nd-wizard .eligible b { font-family: var(--font-mono); font-size: 1.05rem; }

.nd-wizard .review-list { border: 1px solid var(--border-soft); border-radius: 11px; overflow: hidden; }
.nd-wizard .review-row { display: grid; grid-template-columns: 150px 1fr; gap: 12px; padding: 10px 13px; border-top: 1px solid var(--border-soft); font-size: 0.85rem; }
.nd-wizard .review-row:first-child { border-top: 0; }
.nd-wizard .review-row .rk { color: var(--text-faint); font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; }

.nd-cmdr-mode { display: inline-flex; flex-wrap: wrap; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; margin-bottom: 10px; }
.nd-cmdr-mode button { border: 0; background: var(--panel); color: var(--text-muted); font: inherit; font-size: 0.76rem; font-weight: 600; padding: 6px 13px; cursor: pointer; }
.nd-cmdr-mode button + button { border-left: 1px solid var(--border); }
.nd-cmdr-mode button[aria-pressed="true"] { background: var(--accent-soft); color: var(--text); }
.nd-cmdr-panel[hidden] { display: none; }
.nd-id-readout { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 12px; padding: 9px 12px; border-radius: 9px; background: var(--panel-sunken); border: 1px solid var(--border-soft); font-size: 0.8rem; color: var(--text-muted); }
.nd-id-readout[hidden] { display: none; }

/* Kevin's 2026-09-17 ask: small thumbnails of both picked commanders shown
   together, above the text identity readout - previously neither commander
   showed any card art anywhere in this step. */
.nd-cmdr-duo { display: flex; gap: 8px; margin-top: 12px; }
.nd-cmdr-duo[hidden] { display: none; }
.nd-cmdr-duo img { width: 64px; aspect-ratio: 5/7; object-fit: cover; border-radius: 7px; border: 1px solid var(--border); background: var(--panel-raised); }
.nd-cmdr-duo img[hidden] { display: none; }

.imp-review { margin-top: 12px; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.imp-review[hidden] { display: none; }
.imp-review > header { display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: var(--panel-sunken); border-bottom: 1px solid var(--border-soft); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-faint); }
.imp-review > header .seg { margin-left: auto; display: inline-flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
.imp-review > header .seg button { border: 0; background: var(--panel); color: var(--text-muted); font: inherit; font-size: 0.66rem; letter-spacing: 0.04em; padding: 3px 9px; cursor: pointer; text-transform: none; }
.imp-review > header .seg button[aria-pressed="true"] { background: var(--accent-soft); color: var(--text); }
.imp-scroll { max-height: 216px; overflow-y: auto; }
.imp-line { display: grid; grid-template-columns: 16px 1fr auto; gap: 9px; align-items: center; padding: 6px 12px; border-top: 1px solid var(--border-soft); font-size: 0.82rem; }
.imp-line:first-child { border-top: 0; }
.imp-line .st-ico { text-align: center; font-size: 0.82rem; }
.imp-line.ok .st-ico { color: var(--good); }
.imp-line.amb .st-ico { color: var(--accent-bright); }
.imp-line.gap .st-ico { color: var(--bad); }
.imp-line .ln-name { font-weight: 600; }
.imp-line .ln-sub { display: block; color: var(--text-faint); font-size: 0.7rem; font-family: var(--font-mono); margin-top: 1px; }

.pull-preview { margin-top: 12px; border: 1px solid var(--bad); border-radius: 10px; background: color-mix(in srgb, var(--bad) 9%, var(--panel)); padding: 10px 13px; font-size: 0.83rem; }
.pull-preview[hidden] { display: none; }
.pull-preview h4 { margin: 0 0 6px; font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--bad); }
.pull-preview ul { margin: 0 0 6px; padding-left: 17px; color: var(--text-muted); line-height: 1.55; }
.pull-preview .fine { color: var(--text-faint); font-size: 0.74rem; }

.nd-wizard .nd-hint { font-weight: 400; color: var(--text-faint); }
.nd-wizard .mt-s { margin-top: 12px; }
.nd-wizard .mt-m { margin-top: 14px; }
.nd-wizard #nd-grade { width: auto; padding: 2px 6px; border-radius: 6px; }
.nd-wizard .nd-review-note { border-color: var(--border); background: var(--panel-sunken); }
.nd-wizard #nd-wiz-status { margin-top: 10px; }
.nd-wizard code { font-family: var(--font-mono); font-size: 0.85em; }
.nd-wizard .nd-ro-name { color: var(--text); }
.nd-wizard .imp-empty .ln-sub { padding: 8px 0; }

/* AGE-216: commander step - inspiration grid, second-commander panel,
   strategy pick-list, name-last. CSP blocks inline style= so everything
   is class-driven. */
.nd-wizard .nd-link {
  background: none; border: 0; padding: 0; font: inherit; font-size: 0.8rem;
  color: var(--accent); cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
}
.nd-wizard .nd-link:hover { color: var(--accent-bright); }
.nd-wizard .nd-link[hidden] { display: none; }
.nd-wizard .nd-blk-note { color: var(--text-muted); font-size: 0.82rem; margin: 2px 0 10px; }
.nd-wizard .nd-blk-note b { color: var(--text); font-weight: 600; }

.nd-inspire { margin-top: 12px; }
.nd-inspire[hidden] { display: none; }
.nd-inspire-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 9px; }
.nd-inspire-head .k { font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); }
.nd-inspire-head .h { font-size: 0.84rem; color: var(--text); font-weight: 600; }
.nd-inspire-head .m { color: var(--text-faint); font-size: 0.74rem; font-family: var(--font-mono); }

.nd-cmdr-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.nd-cmdr-tile {
  text-align: left; cursor: pointer; font: inherit; color: inherit; padding: 0; overflow: hidden;
  background: var(--panel-raised); border: 1px solid var(--border); border-radius: 10px;
  display: flex; flex-direction: column;
}
.nd-cmdr-tile:hover { border-color: var(--accent-border); }
.nd-cmdr-tile.sel { border-color: var(--accent-bright); box-shadow: inset 0 0 0 1px var(--accent-bright); }
.nd-cmdr-tile .art { display: block; width: 100%; height: 58px; object-fit: cover; object-position: center 22%; border-bottom: 1px solid var(--border-soft); background: var(--panel-raised); }
.nd-cmdr-tile .ti { padding: 7px 9px 9px; display: flex; flex-direction: column; gap: 4px; }
.nd-cmdr-tile .tn { font-weight: 600; font-size: 0.82rem; line-height: 1.2; }
.nd-cmdr-tile .tm { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.nd-cmdr-tile .ts { font-family: var(--font-mono); font-size: 0.64rem; color: var(--text-faint); }
.nd-cmdr-tile .tw { font-size: 0.72rem; color: var(--text-muted); line-height: 1.35; }
.nd-cmdr-tile .t2c {
  align-self: flex-start; font-family: var(--font-mono); font-size: 0.56rem; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--accent-2); border: 1px solid var(--accent-border);
  border-radius: 999px; padding: 1px 6px;
}

.nd-second[hidden], .nd-strat-field[hidden] { display: none; }
.nd-second, .nd-strat-field { border-top: 1px solid var(--border-soft); padding-top: 14px; margin-top: 4px; }
.nd-second #nd-second-all { display: inline-block; margin-top: 8px; }
.nd-second .deck-add-card { margin-top: 8px; }

.nd-rec-list { display: flex; flex-direction: column; gap: 7px; }
.nd-rec {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  background: var(--panel-raised); border: 1px solid var(--border); border-radius: 9px;
}
.nd-rec.sel { border-color: var(--accent-bright); box-shadow: inset 0 0 0 1px var(--accent-bright); }
.nd-rec .sw { width: 38px; height: 38px; border-radius: 6px; flex: none; object-fit: cover; object-position: center; border: 1px solid var(--border-soft); background: var(--panel-raised); }
.nd-rec .rb { flex: 1; min-width: 0; }
.nd-rec .rn { font-weight: 600; font-size: 0.84rem; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.nd-rec .flag { font-family: var(--font-mono); font-size: 0.54rem; letter-spacing: 0.04em; text-transform: uppercase; border-radius: 999px; padding: 1px 5px; }
.nd-rec .flag.best { color: var(--accent-2); border: 1px solid var(--accent-border); }
.nd-rec .flag.mono { color: var(--text-faint); border: 1px solid var(--border); }
.nd-rec .rw { font-size: 0.74rem; color: var(--text-muted); line-height: 1.35; }
.nd-rec .ri { font-size: 0.7rem; color: var(--text-faint); font-family: var(--font-mono); margin-top: 2px; }
.nd-rec .btn-set {
  flex: none; font: inherit; font-size: 0.74rem; font-weight: 600; cursor: pointer;
  background: var(--color-m); color: #14120f; border: 0; border-radius: 7px; padding: 5px 12px;
}
.nd-rec .btn-set.ghost { background: transparent; color: var(--accent); border: 1px solid var(--accent-border); }
.nd-rec .btn-set:hover { background: var(--accent-bright); }

#nd-second-skip { display: inline-block; margin-top: 10px; }
#nd-second-change { flex: none; }

.nd-strat-evolve { font-size: 0.76rem; color: var(--accent-2); margin: 0 0 10px; }
.nd-strat-evolve[hidden] { display: none; }
.nd-strat-grid { display: flex; flex-direction: column; gap: 7px; }
.nd-strat {
  text-align: left; cursor: pointer; font: inherit; color: inherit;
  background: var(--panel-raised); border: 1px solid var(--border); border-radius: 9px; padding: 9px 11px;
  display: flex; flex-direction: column; gap: 3px;
}
.nd-strat:hover { border-color: var(--accent-border); }
.nd-strat.sel { border-color: var(--accent-bright); box-shadow: inset 0 0 0 1px var(--accent-bright); }
.nd-strat .sl { font-weight: 600; font-size: 0.85rem; }
.nd-strat .sl .pairtag { font-family: var(--font-mono); font-size: 0.54rem; letter-spacing: 0.04em; text-transform: uppercase; color: var(--accent-2); border: 1px solid var(--accent-border); border-radius: 999px; padding: 1px 5px; margin-left: 6px; }
.nd-strat .sd { font-size: 0.76rem; color: var(--text-muted); }
.nd-strat .sw { font-size: 0.72rem; color: var(--text-faint); line-height: 1.4; }
.nd-strat .sw b { color: var(--accent-2); font-weight: 600; font-family: var(--font-mono); font-size: 0.58rem; letter-spacing: 0.05em; text-transform: uppercase; margin-right: 5px; }
#nd-strat-own-toggle { margin-top: 10px; display: inline-block; }
/* This ID rule's display:inline-block outranks .nd-wizard .nd-link[hidden]
   (class-level, lower specificity) - same bug shape as the Decks popover fix
   above, just an ID this time. Pre-existing latent bug, surfaced now that
   the unified commander field (setCmdrDescribing/pickUnownedCommander) hides
   this toggle in a state that previously was never reached. */
#nd-strat-own-toggle[hidden] { display: none; }
.nd-strat-field textarea { margin-top: 8px; }

.nd-name-row { display: flex; gap: 8px; align-items: center; }
.nd-name-row input { flex: 1; }
#nd-name-cycle { flex: none; }
.nd-name-src { font-size: 0.74rem; color: var(--text-faint); margin: 6px 0 0; }
.nd-name-src[hidden] { display: none; }
.nd-name-src b { color: var(--text-muted); font-weight: 600; }

/* AGE-219: wizard "How should it build?" - bracket / priority / land style + reasoning */
.nd-buildplan[hidden] { display: none; }
.nd-buildplan .nd-bp-hr { border: 0; border-top: 1px solid var(--border-soft); margin: 20px 0 18px; }
.nd-bp-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.nd-bp-row .field { margin-bottom: 6px; }
.nd-bp-hint { font-size: 0.78rem; color: var(--text-muted); margin: 5px 0 0; }
.nd-bp-strat { background: var(--panel-sunken); border: 1px solid var(--border-soft); border-radius: 9px; padding: 9px 11px; display: flex; flex-direction: column; gap: 2px; }
.nd-bp-strat b { font-size: 0.9rem; }
.nd-bp-strat span { font-size: 0.74rem; color: var(--text-faint); font-family: var(--font-mono); letter-spacing: 0.03em; }
.nd-bp-default { margin-top: 12px; padding: 11px 13px; border-radius: 10px; border: 1px solid var(--accent-border); background: var(--accent-soft); font-size: 0.85rem; line-height: 1.5; }
.nd-bp-default b { font-weight: 600; }
.nd-bp-default i { color: var(--text-muted); }

/* Kevin's 2026-09-16 ask: "is my collection actually enough here?" - same
   box treatment as .nd-bp-default for the good-news state, .pull-preview's
   warning tint for the short state (toggled via the .short modifier). */
.nd-bp-fit { margin-top: 12px; padding: 11px 13px; border-radius: 10px; border: 1px solid var(--accent-border); background: var(--accent-soft); font-size: 0.85rem; line-height: 1.5; }
.nd-bp-fit[hidden] { display: none; }
.nd-bp-fit.short { border-color: var(--bad); background: color-mix(in srgb, var(--bad) 9%, var(--panel)); }
.nd-bp-fit b { font-weight: 600; }
.nd-bp-fit-candidates { margin-top: 8px; }
.nd-bp-fit-candidates[hidden] { display: none; }
.nd-bp-fit-candidates ul { margin: 4px 0 0; padding-left: 17px; color: var(--text-muted); line-height: 1.6; }

.nd-wiz-collect-summary { margin-bottom: 14px; padding: 11px 13px; border-radius: 10px; border: 1px solid var(--accent-border); background: var(--accent-soft); font-size: 0.85rem; line-height: 1.5; display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.nd-wiz-collect-summary[hidden] { display: none; }
.nd-wiz-collect-summary b { font-weight: 600; }

.nd-bp-adv { margin-top: 12px; border: 1px solid var(--border-soft); border-radius: 10px; background: var(--panel-raised); }
.nd-bp-adv > summary { cursor: pointer; padding: 10px 13px; font-size: 0.8rem; font-weight: 600; color: var(--text-muted); list-style: none; }
.nd-bp-adv > summary::-webkit-details-marker { display: none; }
.nd-bp-adv > summary::before { content: "\25B8"; color: var(--text-faint); margin-right: 7px; }
.nd-bp-adv[open] > summary::before { content: "\25BE"; }
.nd-bp-adv-body { padding: 4px 13px 15px; display: flex; flex-direction: column; gap: 16px; }
.nd-bp-label { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 7px; }

.nd-prio { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.nd-prio-row { display: grid; grid-template-columns: 20px 1fr auto auto; align-items: center; gap: 9px; padding: 7px 9px; border: 1px solid var(--border-soft); border-radius: 8px; background: var(--panel); }
.nd-prio-row.top { border-color: var(--accent-border); background: var(--accent-soft); }
.nd-prio-row .r { font-family: var(--font-mono); font-size: 0.78rem; color: var(--text-faint); text-align: center; }
.nd-prio-row .m { min-width: 0; display: flex; flex-direction: column; }
.nd-prio-row .n { font-weight: 600; font-size: 0.83rem; }
.nd-prio-row .w { font-size: 0.72rem; color: var(--text-muted); line-height: 1.35; }
.nd-prio-row .x { font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-faint); }
.nd-prio-row .mv { display: flex; gap: 2px; }
.nd-prio-row .mv button { width: 21px; height: 21px; line-height: 1; border: 1px solid var(--border); background: var(--panel-raised); color: var(--text-muted); border-radius: 5px; cursor: pointer; font-size: 0.7rem; }
.nd-prio-row .mv button:hover:not(:disabled) { border-color: var(--accent); color: var(--text); }
.nd-prio-row .mv button:disabled { opacity: 0.3; cursor: default; }
#nd-prio-reset { margin-top: 8px; display: inline-block; }

.nd-seg { display: inline-flex; flex-wrap: wrap; padding: 3px; gap: 3px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; }
.nd-seg button { font: inherit; font-size: 0.78rem; border: 0; background: none; color: var(--text-muted); padding: 5px 11px; border-radius: 6px; cursor: pointer; }
.nd-seg button[aria-pressed="true"] { background: var(--accent-bright); color: #14120f; font-weight: 600; }

.nd-bp-explain { margin-top: 14px; background: var(--panel-sunken); border: 1px solid var(--border-soft); border-radius: 10px; padding: 13px 15px; }
.nd-bp-explain h4 { margin: 0 0 9px; font-size: 0.9rem; }
.nd-ex-row { display: flex; gap: 10px; font-size: 0.82rem; padding: 6px 0; border-top: 1px solid var(--border-soft); }
.nd-ex-row:first-of-type { border-top: 0; }
.nd-ex-k { flex: none; width: 92px; color: var(--text-faint); font-weight: 600; font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.04em; padding-top: 1px; }
.nd-ex-v { min-width: 0; line-height: 1.45; }
.nd-ex-v b { font-variant-numeric: tabular-nums; }
.nd-ex-note { color: var(--text-muted); font-size: 0.78rem; margin-top: 3px; }
.nd-ex-sub { color: var(--text-faint); font-size: 0.76rem; }
.nd-sc { display: block; }
.nd-sc.muted { color: var(--text-faint); }
.nd-sc b { color: var(--accent-2); }

.deck-bracket-field { display: inline-flex; align-items: center; gap: 5px; }
.deck-bracket-field[hidden] { display: none; }
.deck-bracket-field > span { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-faint); }

@media (max-width: 560px) {
  .nd-wizard { padding: 0; place-items: stretch; }
  .nd-wiz { width: 100%; max-height: 100vh; border-radius: 0; border: 0; }
  .nd-cmdr-grid { grid-template-columns: repeat(2, 1fr); }
  .nd-bp-row { grid-template-columns: 1fr; }
}

/* ---------- AGE-226 phase 4: mana economy - header pill + spell-card component ----------
   Real balance is one colorless number (mana_balance) - the header pill splits
   it cosmetically across the current deck's commander color identity, purely
   for flavor (Kevin, 2026-09-05: "it doesn't matter [about odd splits]
   because all the cards are going to be colorless, this is more just for the
   theme"). The spell-card is a compact inline retrofit of the mockup's
   vertical card concept (name + cost + rules + tap-to-cast + locked state) -
   not the full vertical card shape or the per-theme graveyard particle FX,
   neither of which fit the existing Assistant accordion panes or have a real
   per-deck data source yet. See AGE-226/227 in Linear for the full history. */

.manapill {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 10px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--panel-raised); color: var(--text); font-size: 0.8rem; font-weight: 700;
  font-variant-numeric: tabular-nums; cursor: pointer; position: relative;
}
.manapill[hidden] { display: none; }
.manapill:hover, .manapill[aria-expanded="true"] { border-color: var(--accent-border); background: var(--accent-soft); }
.manapill .mp-part { display: inline-flex; align-items: center; gap: 3px; }
.mana-drop { width: 11px; height: 11px; border-radius: 50% 50% 50% 0; transform: rotate(45deg); display: inline-block; flex: none; box-shadow: inset 0 0 0 1px rgba(0,0,0,0.25); }
.mana-drop.mp-w { background: #e8e4d0; }
.mana-drop.mp-u { background: #4a90d9; }
.mana-drop.mp-b { background: #4a3a5c; }
.mana-drop.mp-r { background: #d9534f; }
.mana-drop.mp-g { background: #4a9a5a; }
.mana-drop.mp-c { background: var(--text-muted); }

.manapanel {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; width: 270px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 12px 30px -12px rgba(0,0,0,0.55); padding: 14px 16px; display: none;
}
.manapanel.open { display: block; }
.manapanel .mp-tier { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-m); font-weight: 700; }
.manapanel .mp-rows { display: grid; gap: 6px; margin: 10px 0; }
.manapanel .mp-row { display: flex; justify-content: space-between; align-items: baseline; font-size: 0.85rem; }
.manapanel .mp-row .mp-val { font-weight: 700; font-variant-numeric: tabular-nums; }
.manapanel .mp-row .mp-val small { color: var(--text-faint); font-weight: 400; }
.manapanel .mp-untap { font-size: 0.76rem; color: var(--text-muted); }
.manapanel hr { border: 0; border-top: 1px dashed var(--border-soft); margin: 10px 0; }
.manapanel .mp-costs { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.manapanel .mp-costs li { display: flex; justify-content: space-between; font-size: 0.79rem; color: var(--text-muted); }
.manapanel .mp-costs li.mp-short { color: var(--color-r); font-weight: 700; }
.manapanel .mp-costs li.mp-free .mp-c { color: var(--color-g); font-weight: 700; }

.spellcard-chip {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px; margin: 8px 0;
  border-radius: 10px; border: 1px solid var(--border);
  background: linear-gradient(155deg, var(--panel-raised), var(--panel) 65%);
  transition: transform 0.35s cubic-bezier(0.34,1.56,0.64,1), filter 0.3s ease;
}
.spellcard-chip.affordable:hover { border-color: var(--accent-border); }
.spellcard-chip.tapped { transform: scale(0.98) rotate(-0.6deg); }
.spellcard-chip:not(.affordable) { filter: grayscale(0.55) brightness(0.88); }
.spellcard-cost-pip {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 28px; height: 28px; border-radius: 50%;
  background: radial-gradient(circle at 35% 28%, var(--panel-raised), var(--border) 78%);
  color: var(--text); font-size: 0.76rem; font-weight: 800;
  box-shadow: inset 0 0 0 1px var(--border);
}
.spellcard-cost-pip.free { background: var(--accent-soft); color: var(--color-g); font-size: 0.6rem; }
.spellcard-body { flex: 1 1 auto; min-width: 0; }
.spellcard-name { font-weight: 700; font-size: 0.87rem; color: var(--text); }
.spellcard-rules { font-size: 0.76rem; color: var(--text-muted); margin-top: 2px; }
.spellcard-lock-note { font-size: 0.73rem; color: var(--color-r); margin-top: 4px; }
.spellcard-lock-note[hidden] { display: none; }
.spellcard-cast-btn { flex: none; }
.spellcard-status { flex: none; font-size: 0.73rem; color: var(--text-muted); display: flex; align-items: center; gap: 5px; }
.spellcard-status[hidden] { display: none; }
.spellcard-status .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--color-m); animation: spellcardPulse 1s ease-in-out infinite; }
@keyframes spellcardPulse { 50% { opacity: 0.35; } }

@media (max-width: 560px) {
  .manapanel { right: -8px; width: 250px; }
  .spellcard-chip { flex-wrap: wrap; }
}
