/* ═══════════════════════════════════════════════════════════════════════════
   COMON — implemented from "Comon_Option 3.dc.html" (Claude Design).
   Palette, type, radii, shadows and motion below are taken from that file.
   Its prototype styles everything inline; here the same values live in classes.
   ═══════════════════════════════════════════════════════════════════════════ */

@font-face { font-family: Barlow; src: url('/fonts/barlow-400.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: Barlow; src: url('/fonts/barlow-500.woff2') format('woff2'); font-weight: 500; font-display: swap; }
@font-face { font-family: Barlow; src: url('/fonts/barlow-600.woff2') format('woff2'); font-weight: 600; font-display: swap; }
@font-face { font-family: Barlow; src: url('/fonts/barlow-700.woff2') format('woff2'); font-weight: 700; font-display: swap; }
@font-face { font-family: Barlow; src: url('/fonts/barlow-800.woff2') format('woff2'); font-weight: 800; font-display: swap; }
@font-face { font-family: 'Saira Condensed'; src: url('/fonts/saira-600.woff2') format('woff2'); font-weight: 600; font-display: swap; }
@font-face { font-family: 'Saira Condensed'; src: url('/fonts/saira-700.woff2') format('woff2'); font-weight: 700; font-display: swap; }
@font-face { font-family: 'Saira Condensed'; src: url('/fonts/saira-800.woff2') format('woff2'); font-weight: 800; font-display: swap; }

:root {
  /* Accent is switchable in the design's Look panel — four options. */
  --acc: #E8B44A;
  --acc-hi: #FFD070;

  --bg: #141A29;
  --bg-deep: #0B0F1A;
  --bar: #080B14;
  --nav-grad: linear-gradient(180deg, #0E1421, #080B14);

  --s1: #1A2233;
  --s2: #1E2739;
  --s3: #232E45;
  --sunken: #0F1524;
  --panel: linear-gradient(180deg, #1D2639, #151C2B);
  --panel-hi: linear-gradient(180deg, #232E45, #151C2B);
  --tile: linear-gradient(180deg, #1F2A3E, #151C2B);
  --pill: linear-gradient(180deg, #252F45, #161D2C);

  --bd: #2C374F;
  --bd-hi: #33405C;
  --bd-soft: #26314A;
  --bd-pill: #36415C;
  --bd-line: #3C4A66;

  --tx: #EEF2FA;
  --tx-2: #DCE4F2;
  --tx-3: #B9C6DE;
  --tx-4: #9FB0CE;
  --tx-dim: #8FA2C4;
  --tx-faint: #7A88A6;
  --tx-ghost: #5E6D8A;
  --ink: #2A1E05;

  --cyan: #3FD0E0;
  --green: #4FD79B;
  --green-bg: #0F2E22;
  --pink: #FF6FA8;
  --pink-bg: #2E1730;
  --violet: #B79BE8;
  --red: #FF4F45;
  --orange: #FF7A46;

  /* rarity */
  --r-gold: #FFD467; --r-gold-bg: #2E2611;
  --r-secret: #FF6FA8; --r-secret-bg: #2E1730;
  --r-full: #B79BE8; --r-full-bg: #241C3A;
  --r-holo: #3FD0E0; --r-holo-bg: #0F2A31;
  --r-rare: #4FD79B; --r-rare-bg: #0F2E22;

  --f-ui: Barlow, 'Helvetica Neue', Helvetica, sans-serif;
  --f-dis: 'Saira Condensed', 'Helvetica Neue', sans-serif;

  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  /* Replaced at runtime with the bars' measured heights (see measureBars in app.js);
     these are only what the first paint uses. */
  --topbar: calc(var(--safe-t) + 51px);
  --navbar: calc(var(--safe-b) + 95px);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
[hidden] { display: none !important; }

html, body {
  margin: 0; background: var(--bg-deep); color: var(--tx);
  font: 600 13px/1.45 var(--f-ui);
  -webkit-font-smoothing: antialiased;
  /* The layout is a single fixed-width column, so sideways movement is never wanted.
     Locking both the overflow and the overscroll stops a stray horizontal drag from
     rubber-banding the whole page. */
  overflow-x: hidden;
  overscroll-behavior: none;
  touch-action: pan-y;
  user-select: none; -webkit-user-select: none;
}
body { min-height: 100dvh; background: var(--bg); }
button, input { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
h1, h2, h3, p { margin: 0; }
img { display: block; }
input { user-select: text; -webkit-user-select: text; }

/* ── Type ─────────────────────────────────────────────────────────────── */
.dis { font-family: var(--f-dis); font-weight: 800; font-style: italic; }
.lab {                                  /* section label */
  font: 800 11px/1 var(--f-dis); letter-spacing: 2.2px; color: var(--tx-dim);
  text-transform: uppercase;
}
.lab-sm { font: 800 9px/1 var(--f-dis); letter-spacing: 1.2px; color: var(--tx-dim); }
.num { font-variant-numeric: tabular-nums; }
.money-big {
  font: 800 44px/1 var(--f-dis); letter-spacing: -.5px; color: var(--acc);
  font-variant-numeric: tabular-nums; text-shadow: 0 3px 0 rgba(0,0,0,.4);
}

/* ── Chrome ───────────────────────────────────────────────────────────── */
.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 36;
  background: var(--bar); display: flex; gap: 7px;
  padding: calc(var(--safe-t) + 10px) 10px 9px;
  max-width: 520px; margin: 0 auto;
}
.tb-total {
  flex: 1; display: flex; align-items: center; gap: 7px;
  padding: 5px 9px 5px 5px; background: var(--pill);
  border: 1.5px solid var(--bd-pill); border-radius: 16px;
}
.tb-coin {
  width: 22px; height: 22px; flex: none; border-radius: 50%;
  background: linear-gradient(160deg, var(--acc), #9A6E15);
  border: 1.5px solid #F5D68C;
  display: grid; place-items: center;
  font: 800 11px/1 var(--f-ui); color: var(--ink);
}
.tb-total b { flex: 1; text-align: right; font: 700 13px/1 var(--f-ui); color: #FFF; font-variant-numeric: tabular-nums; }
.tb-pill {
  flex: none; min-height: 32px; display: flex; align-items: center; gap: 6px;
  padding: 0 11px; background: var(--pill); border: 1.5px solid var(--bd-pill);
  border-radius: 16px; font: 800 12px/1 var(--f-dis); letter-spacing: 1.2px; color: var(--tx-2);
}
.tb-pill:active { transform: translateY(2px); }
.tb-pill.pro { background: var(--acc); border-color: #7A5410; color: var(--ink); }
.caret { width: 0; height: 0; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 5px solid var(--tx-faint); }

.screen {
  /* The bars are measured exactly, so without this the first element butts right up
     against them. */
  padding: calc(var(--topbar) + 16px) 0 var(--navbar);
  animation: gxFade .2s ease-out;
  max-width: 520px; margin: 0 auto;
}
.pad { padding: 0 14px; }
/* Only the Hub carries the scan dock, so only the Hub needs clearance for it — the
   other screens would just gain dead space at the bottom. */
#s-hub { padding-bottom: calc(var(--navbar) + 120px); }

.nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 25;
  display: flex; justify-content: space-around; gap: 6px;
  padding: 9px 10px calc(var(--safe-b) + 12px); background: var(--nav-grad);
  border-top: 2px solid var(--bd-soft);
  max-width: 520px; margin: 0 auto;
}
.nav-item {
  flex: 1; min-height: 52px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 6px;
  background: transparent; border: 1.5px solid transparent; border-radius: 6px;
  color: var(--tx-ghost);
}
.nav-item:active { transform: translateY(2px); }
.nav-item i { width: 16px; height: 16px; border: 2px solid currentColor; }
.nav-item span { font: 800 9px/1 var(--f-dis); letter-spacing: 1.2px; }
.nav-item.on { background: #17203200; border-color: var(--bd-line); color: var(--acc); }
.nav-item[data-nav="hub"] i    { border-radius: 3px; }
.nav-item[data-nav="dex"] i    { border-radius: 50%; }
.nav-item[data-nav="chase"] i  { transform: rotate(45deg); border-radius: 2px; }
.nav-item[data-nav="profile"] i{ border-radius: 8px 8px 3px 3px; }

/* ── Surfaces ─────────────────────────────────────────────────────────── */
.panel {
  position: relative; overflow: hidden;
  background: var(--panel); border: 2px solid var(--bd-hi);
  border-radius: 6px; padding: 15px 16px 14px;
}
.panel.hi { background: var(--panel-hi); border-color: var(--acc); border-radius: 5px; box-shadow: 0 8px 22px rgba(0,0,0,.5); }
.hatch::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image:
    repeating-linear-gradient(60deg, rgba(255,255,255,.035) 0 1px, transparent 1px 20px),
    repeating-linear-gradient(-60deg, rgba(255,255,255,.035) 0 1px, transparent 1px 20px);
}
.dots::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(circle at 1px 1px, rgba(255,255,255,.07) 1px, transparent 0);
  background-size: 9px 9px;
}
.panel > * { position: relative; }

.tile {
  position: relative; overflow: hidden;
  background: var(--tile); border: 2px solid var(--bd-hi); border-radius: 6px;
  padding: 13px; box-shadow: 0 4px 0 rgba(0,0,0,.45);
  text-align: left;
}
.tile:active { transform: translateY(3px); box-shadow: 0 1px 0 rgba(0,0,0,.45); }
.tile-label { font: 800 16px/1 var(--f-dis); letter-spacing: 1.6px; }

/* ── Buttons ──────────────────────────────────────────────────────────── */
/* Option 3's signature: a flat bottom-offset shadow the button presses into. */
.btn {
  display: block; width: 100%; text-align: center;
  background: linear-gradient(180deg, #F6D07E, #D89A22);
  border: 2px solid #7A5410; border-radius: 6px;
  box-shadow: 0 6px 0 #533708, 0 12px 24px rgba(0,0,0,.5);
  padding: 17px; color: #3A2704;
  font: 900 30px/1 var(--f-dis); font-style: italic; letter-spacing: 2.4px;
  text-shadow: 0 2px 0 rgba(255,255,255,.4);
  transition: transform .06s, box-shadow .06s;
  position: relative; overflow: hidden;
}
.btn:active { transform: translateY(4px); box-shadow: 0 2px 0 #533708, 0 6px 14px rgba(0,0,0,.5); }
.btn .sub { display: block; font: 700 11px/1 var(--f-ui); font-style: normal; letter-spacing: 1.4px; color: rgba(58,39,4,.72); margin-top: 7px; text-shadow: none; }
.btn .shine { position: absolute; top: 0; bottom: 0; width: 44px; background: rgba(255,255,255,.4); animation: gxShine 3.6s ease-in-out infinite; }

/* Pinned just above the tab bar on the Hub. Centred by hand rather than by `margin:
   auto`, because a fixed element is taken out of the flow and stops inheriting the
   520px column the rest of the app sits in. */
.scan-dock {
  position: fixed; z-index: 24;
  left: 50%; transform: translateX(-50%);
  width: calc(100% - 28px); max-width: 492px;
  bottom: calc(var(--navbar) + 10px);
}
.scan-dock:active { transform: translateX(-50%) translateY(4px); box-shadow: 0 2px 0 #533708, 0 6px 14px rgba(0,0,0,.5); }

/* The Scan button's shape and weight, in another colour, so the Hub reads as one stack
   of actions without a second gold bar competing for the eye. */
.btn-alt {
  background: var(--bg); border-width: 1.5px;
  box-shadow: 0 4px 0 rgba(0,0,0,.45), 0 10px 20px rgba(0,0,0,.35);
  font-size: 22px; letter-spacing: 1.8px; padding: 15px;
  text-shadow: none;
}
.btn-alt:active { transform: translateY(3px); box-shadow: 0 1px 0 rgba(0,0,0,.45); }
.btn-alt .sub { color: var(--tx-dim); margin-top: 6px; }
.btn-alt.cyan  { color: #3FD0E0; border-color: #1E5C66; }
.btn-alt.green { color: #4FD79B; border-color: #1F5C46; }

.btn2 {
  display: block; width: 100%; text-align: center; min-height: 52px;
  background: var(--s1); border: 2px solid var(--bd-line); border-radius: 6px;
  box-shadow: 0 4px 0 rgba(0,0,0,.45); padding: 15px;
  font: 800 16px/1 var(--f-dis); letter-spacing: 1.4px; color: var(--tx-2);
  transition: transform .06s, box-shadow .06s;
}
.btn2:active { transform: translateY(3px); box-shadow: 0 1px 0 rgba(0,0,0,.45); }
.btn2.acc { background: var(--acc); border-color: #7A5410; color: var(--ink); }
.btn2.danger { color: var(--red); border-color: #4A2724; }
.btn2.light { background: #F2F5FA; border-color: #FFF; color: #141A29; box-shadow: 0 5px 0 rgba(0,0,0,.45); }

.seg {
  display: flex; gap: 4px; padding: 4px;
  background: var(--sunken); border: 1.5px solid var(--bd); border-radius: 22px;
}
.seg button {
  flex: 1; min-height: 38px; display: flex; align-items: center; justify-content: center; gap: 5px;
  border-radius: 18px; font: 800 12px/1 var(--f-dis); letter-spacing: 1.2px; color: var(--tx-dim);
}
.seg button:active { transform: translateY(1px); }
.seg button.on { background: var(--acc); color: var(--ink); }
.seg .lock { padding: 2px 5px; background: var(--acc); border-radius: 4px; font: 800 8px/1.3 var(--f-ui); color: var(--ink); }
.seg button.on .lock { background: var(--ink); color: var(--acc); }

.chip {
  padding: 8px 11px; border-radius: 5px; background: var(--s1);
  border: 1.5px solid var(--bd); color: var(--tx-dim);
  font: 800 12px/1 var(--f-dis); letter-spacing: 1.2px;
}
.chip:active { transform: translateY(2px); }
.chip.on { background: var(--acc); border-color: #7A5410; color: var(--ink); }
.chip.cy.on { background: var(--cyan); border-color: #14606B; color: #07161A; }

.pill-r {                               /* rarity pill */
  display: inline-block; padding: 3px 6px; border-radius: 4px;
  font: 800 9px/1 var(--f-dis); letter-spacing: 1.1px;
}

.field {
  display: flex; align-items: center; gap: 9px;
  background: var(--sunken); border: 1.5px solid var(--bd); border-radius: 6px;
  padding: 13px 14px;
}
.field input { flex: 1; min-width: 0; background: none; border: 0; outline: none; font: 600 14px var(--f-ui); color: var(--tx); }
.field input::placeholder { color: var(--tx-ghost); }

/* ── Card art ─────────────────────────────────────────────────────────── */
.art {
  position: relative; overflow: hidden; aspect-ratio: 5 / 7;
  background: #1B2438; border: 1.5px solid var(--bd-line); border-radius: 5px;
}
.art img { width: 100%; height: 100%; object-fit: cover; position: relative; z-index: 1; }
.art .tint { position: absolute; inset: 0; background: linear-gradient(155deg, var(--tint, #E8B44A) 0%, transparent 70%); opacity: .5; }
.art .hatch2 { position: absolute; inset: 0; background: repeating-linear-gradient(135deg, rgba(255,255,255,.06) 0 3px, transparent 3px 9px); }
.art .holo {
  position: absolute; inset: -40%; z-index: 2; pointer-events: none; opacity: 0;
  background: conic-gradient(from 140deg, rgba(232,180,74,.9), rgba(63,208,224,.85), rgba(183,155,232,.9), rgba(232,180,74,.9));
  mix-blend-mode: screen; animation: gxHolo 14s linear infinite;
}
/* Over the design's flat placeholder art a slowly turning conic gradient reads as foil.
   Over a real card it's a coloured smear rotating across the artwork — most obvious on
   the full-art cards, which already have their own foil printed in. Holding it still
   keeps the sheen without the drift. */
.art.has-art .holo { animation: none; }
/* The design's foil opacities assume its flat placeholder art; over real card
   photography they wash the card out, so they scale back when an image loads. */
.art[data-r="RARE"] .holo       { opacity: .07; }
.art[data-r="HOLO RARE"] .holo  { opacity: .22; }
.art[data-r="FULL ART"] .holo   { opacity: .30; }
.art[data-r="SECRET"] .holo     { opacity: .32; }
.art[data-r="GOLD"] .holo       { opacity: .34; }
.art.has-art[data-r="RARE"] .holo      { opacity: .04; }
.art.has-art[data-r="HOLO RARE"] .holo { opacity: .09; }
.art.has-art[data-r="FULL ART"] .holo  { opacity: .12; }
.art.has-art[data-r="SECRET"] .holo    { opacity: .12; }
.art.has-art[data-r="GOLD"] .holo      { opacity: .14; }

.art .scrim { position: absolute; inset: 0; z-index: 3; background: linear-gradient(transparent, rgba(8,11,20,.94) 58%); }
.art .cname { position: absolute; left: 6px; right: 6px; bottom: 5px; z-index: 4; font: 800 10px/1.15 var(--f-dis); letter-spacing: .5px; }
.art .cbadge {
  position: absolute; top: 4px; right: 4px; z-index: 4; padding: 2px 4px; border-radius: 3px;
  background: rgba(8,11,20,.82); font: 800 8px/1 var(--f-dis); letter-spacing: .8px;
}
.art.dim { filter: grayscale(1) brightness(.45); }   /* unowned dex slot */

/* ── Bars / charts ────────────────────────────────────────────────────── */
.chart { display: flex; align-items: flex-end; gap: 2px; height: 78px; }
.chart i { flex: 1; border-radius: 2px 2px 0 0; }
.bar { height: 10px; background: var(--sunken); border: 1.5px solid var(--bd); border-radius: 3px; overflow: hidden; }
.bar > i { display: block; height: 100%; }

.delta { font: 700 13px/1 var(--f-ui); font-variant-numeric: tabular-nums; }
.delta.up { color: var(--green); }
.delta.down { color: var(--red); }

/* ── Toast ────────────────────────────────────────────────────────────── */
.toast {
  position: fixed; left: 16px; right: 16px; bottom: calc(var(--navbar) + 14px); z-index: 70;
  padding: 13px 15px; background: var(--green-bg); border: 2px solid var(--green);
  border-radius: 6px; box-shadow: 0 6px 18px rgba(0,0,0,.5);
  font: 800 12px/1.4 var(--f-dis); letter-spacing: 1.4px; color: var(--green);
  animation: gxToast 2.4s ease-out both;
  max-width: 488px; margin: 0 auto;
}
.toast.pink { background: var(--pink-bg); border-color: var(--pink); color: var(--pink); }

.empty {
  border: 2px dashed var(--bd); border-radius: 6px; padding: 30px 20px; text-align: center;
  font: 800 11px/1.9 var(--f-dis); letter-spacing: 1.4px; color: var(--tx-ghost);
}

/* ── Motion (gx* from the design file) ────────────────────────────────── */
@keyframes gxHolo  { to { transform: rotate(360deg) } }
@keyframes gxSweep { 0% { transform: translateY(-24px); opacity: 0 } 12% { opacity: 1 } 88% { opacity: 1 } 100% { transform: translateY(330px); opacity: 0 } }
@keyframes gxUp    { from { transform: translateY(102%) } to { transform: translateY(0) } }
@keyframes gxFade  { from { opacity: 0 } to { opacity: 1 } }
@keyframes gxPop   { 0% { transform: scale(.88) } 64% { transform: scale(1.04) } 100% { transform: scale(1) } }
@keyframes gxGlow  { 0%, 100% { box-shadow: 0 0 0 0 rgba(63,208,224,.5) } 50% { box-shadow: 0 0 22px 4px rgba(63,208,224,.42) } }
@keyframes gxToast { 0% { transform: translateY(20px); opacity: 0 } 10% { transform: translateY(0); opacity: 1 } 84% { opacity: 1 } 100% { transform: translateY(-6px); opacity: 0 } }
@keyframes gxShine { 0% { transform: translateX(-150%) skewX(-18deg) } 100% { transform: translateX(420%) skewX(-18deg) } }
@keyframes gxPulse { 0%, 100% { opacity: .4 } 50% { opacity: 1 } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; }
}

/* ═══════════════════════ SCREENS ═══════════════════════ */

.banner { position: fixed; top: 4px; left: 10px; right: 10px; z-index: 95;
  background: #2E2413; border: 1.5px solid var(--acc); border-radius: 6px;
  padding: 9px 12px; font: 600 11px var(--f-ui); color: #F6D07E; }
.banner code { background: rgba(0,0,0,.4); padding: 1px 4px; border-radius: 3px; }

.scr-title { font-size: 26px; letter-spacing: .6px; }
.scr-sub { font: 600 13px var(--f-ui); color: var(--tx-4); margin-top: 5px; }
.sec { margin-top: 20px; }
/* A label sitting directly on top of full-height buttons crowds them. */
.sec .lab + .grid2 { margin-top: 9px; }
.sec > .lab { display: block; margin-bottom: 10px; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 11px; }

/* ── Sign up ── */
#signup { position: fixed; inset: 0; z-index: 80; overflow: auto;
  background: radial-gradient(110% 55% at 50% 0%, #2C2350 0%, #161D2E 52%, #0A0E18 100%); }
.su-inner { min-height: 100%; display: flex; flex-direction: column; justify-content: center;
  padding: calc(var(--safe-t) + 34px) 20px calc(var(--safe-b) + 34px); max-width: 460px; margin: 0 auto; }
.su-top { text-align: center; }
.su-mark { font-size: 48px; letter-spacing: 2px; text-shadow: 0 4px 0 rgba(0,0,0,.5); }
.su-mark span { color: var(--acc); }
.su-tag { font: 700 12px/1.7 var(--f-ui); letter-spacing: 1.8px; color: var(--tx-dim); margin-top: 10px; }
.su-auth { display: flex; flex-direction: column; gap: 11px; margin-top: 34px; }
.su-auth .btn2 { display: flex; align-items: center; justify-content: center; gap: 12px; min-height: 58px; font-size: 18px; }
.auth-glyph { width: 20px; height: 20px; border: 2px solid currentColor; border-radius: 6px; }
.su-note { font: 600 11px/1.6 var(--f-ui); color: var(--tx-ghost); text-align: center; margin-top: 6px; }
.av { aspect-ratio: 1; border-radius: 5px; border: 2px solid var(--bd); opacity: .8;
  background-image: repeating-linear-gradient(135deg, rgba(0,0,0,.2) 0 3px, transparent 3px 8px); }
.av.on { opacity: 1; border-color: #FFF; }
.field .at { font: 800 15px var(--f-dis); color: var(--tx-ghost); }

/* ── Hub ── */


.pf-row { display: flex; align-items: center; gap: 8px; min-height: 40px; width: 100%; }
.pf-name { font: 800 15px var(--f-dis); letter-spacing: 1px; color: var(--cyan); }
.pf-list { display: flex; flex-direction: column; gap: 6px; margin: 4px 0 12px; padding: 8px;
  background: var(--sunken); border: 1.5px solid var(--bd); border-radius: 6px; }
.pf-item { display: flex; align-items: center; justify-content: space-between; min-height: 44px;
  padding: 0 12px; background: var(--s1); border: 1.5px solid var(--bd); border-radius: 5px;
  font: 800 14px var(--f-dis); letter-spacing: 1px; color: var(--tx-2); }
.pf-item.on { border-color: var(--cyan); color: var(--cyan); }
.pf-item span:last-child { font: 700 12px var(--f-ui); color: var(--tx-dim); }

.pro-card { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; text-align: left; margin-top: 14px; padding: 15px 16px;
  background: linear-gradient(150deg, #2E2413, #191F2E); border: 2px solid var(--acc); border-radius: 6px; }
.pro-card:active { transform: translateY(2px); }
.pro-title { font-size: 17px; letter-spacing: 1.2px; color: var(--acc); }
.pro-pitch { font: 600 12px/1.4 var(--f-ui); color: var(--tx-4); margin-top: 7px; }
.pro-arrow { font: 800 22px var(--f-dis); color: var(--acc); }

.hub-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 11px; margin-top: 16px; }
.hub-tiles .tile { min-height: 104px; display: flex; flex-direction: column; justify-content: space-between; }
.t-ico { position: relative; width: 30px; height: 34px; border: 2.5px solid; border-radius: 3px;
  display: grid; place-items: center; }
.t-ico i { width: 11px; height: 11px; transform: rotate(45deg); }
.t-sub { font: 600 11px var(--f-ui); color: var(--tx-dim); margin-top: 4px; }

/* ── Dex ── */


/* ── Rows (chase / sealed) ── */
.mag { width: 12px; height: 12px; border: 2.5px solid var(--tx-faint); border-radius: 50%; flex: none; }
.rows { display: grid; gap: 9px; }
.row { display: flex; align-items: center; gap: 11px; padding: 10px 11px;
  background: var(--s1); border: 1.5px solid var(--bd); border-radius: 6px; }
.row-art { width: 42px; flex: none; }
.row-mid { flex: 1; min-width: 0; }
.row-name { font: 700 14px var(--f-ui); line-height: 1.2; }
.row-end { display: flex; flex-direction: column; align-items: flex-end; gap: 7px; }
.row-price { font: 800 15px var(--f-dis); color: var(--acc); }
.row-acts { display: flex; gap: 6px; }
.alert-line { color: var(--tx-ghost); margin-top: 3px; }
.act { min-width: 34px; min-height: 30px; padding: 0 9px; border-radius: 5px;
  background: var(--s3); border: 1.5px solid var(--bd-line); color: var(--acc);
  font: 800 13px var(--f-dis); }
.act.sm { min-width: 28px; min-height: 26px; font-size: 11px; }
.act.on { background: var(--green); border-color: #135A3C; color: #06231A; }
.act.owned { background: transparent; border-color: var(--bd); color: var(--tx-ghost); font-size: 10px; letter-spacing: 1px; }
.act.x { color: var(--tx-faint); }
.act.x:active { color: var(--red); border-color: var(--red); }

.qty { justify-content: center; display: flex; align-items: center; gap: 8px; }
.qty button { width: 28px; height: 28px; border-radius: 5px; background: var(--s3);
  border: 1.5px solid var(--bd-line); color: var(--tx-2); font: 800 15px var(--f-ui); }
.qty span { min-width: 18px; text-align: center; font: 700 14px var(--f-ui); }
.qty.big button { width: 44px; height: 44px; font-size: 20px; }
.qty.big { justify-content: center; gap: 18px; }

/* ── Profile ── */
.prof-streak { text-align: center; padding: 9px 12px; box-shadow: none; }

/* ── Detail ── */
.back { font: 800 11px var(--f-dis); letter-spacing: 1.4px; color: var(--tx-dim); margin-bottom: 14px; }
.det-hero { display: flex; gap: 15px; }
.det-art { position: relative; width: 136px; flex: none; padding: 0; }
.det-art .art { box-shadow: 0 6px 0 rgba(0,0,0,.45); }
.det-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.det-name { font-size: 26px; line-height: 1.05; margin-bottom: 6px; }
.det-foot { margin-top: auto; padding-top: 12px; }
.det-val { font: 800 30px var(--f-dis); color: var(--acc); margin-top: 5px; }
.det-chart-head { display: flex; align-items: center; justify-content: space-between; }
.axis { display: flex; justify-content: space-between; margin-top: 7px; }
.comp { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 0; border-bottom: 1.5px solid var(--bd-soft); }
.comp-src { font: 700 13px var(--f-ui); text-transform: capitalize; margin-bottom: 5px; }
.comp-p { font: 800 15px var(--f-dis); }

/* ── Scan ── */
#scan { position: fixed; inset: 0; z-index: 40; overflow: hidden; background: var(--bg-deep); }
#scan video { width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity .4s; }
#scan.live video { opacity: 1; }
.scan-bg { position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(80% 55% at 50% 42%, #232A44, #101627 55%, #0B0F1A); }
/* With the camera live the frame is a hole, not a panel: the dim comes from a big
   spread shadow cast *outward* by the viewfinder, so everything inside the frame is
   the untouched camera feed. */
#scan.live .scan-bg { background: none; }
#scan.live .vf::before { content: ''; position: absolute; inset: 0; border-radius: 10px;
  box-shadow: 0 0 0 100vmax rgba(6,9,16,.66); pointer-events: none; }
/* Three equal columns rather than space-between: the close and batch buttons are
   different widths, which pushed the status pill off centre. */
.scan-hud { position: absolute; top: calc(var(--safe-t) + 14px); left: 14px; right: 14px; z-index: 3;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px; }
.scan-hud > :first-child { justify-self: start; }
.scan-hud > :last-child { justify-self: end; }
.hud-btn { min-width: 38px; min-height: 38px; padding: 0 11px; border-radius: 6px;
  background: rgba(20,26,41,.85); border: 1.5px solid var(--bd-line); color: var(--tx-2);
  font: 800 12px var(--f-dis); letter-spacing: 1.2px; }
.hud-btn.on { background: var(--acc); border-color: #7A5410; color: var(--ink); }
.hud-status { display: flex; align-items: center; gap: 7px; padding: 8px 11px; border-radius: 6px;
  background: rgba(20,26,41,.85); border: 1.5px solid var(--bd-line); }
.hud-status i { width: 7px; height: 7px; border-radius: 2px; background: var(--green); animation: gxPulse 1.4s ease-in-out infinite; }
.hud-status span { font: 800 10px var(--f-dis); letter-spacing: 1.4px; color: var(--green); }
.hud-status[data-s="lock"] i { background: var(--cyan); }
.hud-status[data-s="lock"] span { color: var(--cyan); }

/* Driven off height, not width: a card is tall, and the space between the HUD and the
   shutter row is what actually constrains it. Sized from that, the frame fills a big
   phone without colliding with the controls on a small one. */
/* Fills the space between the HUD and the shutter row — the whole area the camera is
   actually capturing. */
.vf { position: absolute; top: calc(var(--safe-t) + 78px); left: 12px; right: 12px; bottom: 178px;
  z-index: 2; }
/* No card outline in either mode. The capture always used the whole video frame — it
   never cropped to this box — so the guides were describing a crop that doesn't happen.
   Single and batch now show the same open viewfinder. */
.vf-corners, .vf-frame, .vf-card { display: none; }

.vf-sweep { position: absolute; left: 0; right: 0; height: 3px; background: var(--cyan);
  box-shadow: 0 0 22px 7px rgba(63,208,224,.7); animation: gxSweep .95s linear infinite; }

.scan-foot { position: absolute; left: 0; right: 0; bottom: calc(var(--safe-b) + 20px); z-index: 3; padding: 0 16px;
  max-width: 520px; margin: 0 auto; }
.scan-hint { text-align: center; font: 800 10px/1.6 var(--f-dis); letter-spacing: 1.4px;
  color: var(--tx-dim); animation: gxPulse 2s ease-in-out infinite; margin-bottom: 16px; }
/* The hint is already at 800 — the heaviest Saira loaded — so emphasis has to come from
   colour rather than weight. */
.scan-hint b { font-weight: inherit; color: var(--acc); }
.scan-prog-head { display: flex; justify-content: space-between; margin-bottom: 7px;
  font: 800 10px var(--f-dis); letter-spacing: 1.2px; color: var(--cyan); }
#scan-bar { width: 0; background: repeating-linear-gradient(90deg, #3FD0E0 0 6px, #2A96A6 6px 12px); transition: width .12s linear; }
.scan-row { display: flex; align-items: center; justify-content: center; gap: 26px; margin-top: 16px; }
.scan-side { width: 52px; height: 52px; border-radius: 6px; background: rgba(20,26,41,.85);
  border: 1.5px solid var(--bd-line); font: 800 8px var(--f-dis); letter-spacing: .8px; color: var(--tx-dim); }
.scan-side:active { transform: translateY(2px); }
.scan-side.on { background: var(--acc); border-color: #7A5410; color: var(--ink); }
.shutter { width: 86px; height: 86px; border-radius: 50%; border: 5px solid #EEF2FA;
  background: rgba(255,255,255,.06); display: grid; place-items: center; }
.shutter span { width: 62px; height: 62px; border-radius: 50%; background: var(--acc);
  box-shadow: inset 0 -5px 0 rgba(0,0,0,.22); }
.shutter:active { transform: scale(.94); }

/* ── Sheets ── */
.scrim { position: fixed; inset: 0; z-index: 60; background: rgba(8,11,20,.8);
  backdrop-filter: blur(6px); display: flex; align-items: flex-end; justify-content: center; }
.sheet { width: 100%; max-width: 520px; max-height: 90%; overflow-y: auto;
  background: #131A29; border-radius: 10px 10px 0 0; border-top: 3px solid var(--acc);
  padding: 14px 18px 34px; animation: gxUp .34s cubic-bezier(.2,.9,.25,1); }
.grab { width: 46px; height: 5px; border-radius: 3px; background: var(--bd-line); margin: 0 auto 14px; }

/* The appraisal is a screen's worth of controls, not a peek at one — it gets the whole
   viewport, with a close button standing in for the drag handle. */
.sheet.full { max-height: 100%; height: 100%; border-radius: 0; border-top: 0;
  padding: calc(var(--safe-t) + 52px) 18px calc(var(--safe-b) + 30px); }
.sheet-x { position: fixed; top: calc(var(--safe-t) + 10px); right: 14px; z-index: 3;
  width: 38px; height: 38px; display: grid; place-items: center; padding: 0;
  border: 1px solid var(--bd-line); border-radius: 9px; background: rgba(255,255,255,.06);
  color: var(--tx-2); font: 400 24px/1 var(--f-ui); }
.sheet-x:active { background: rgba(255,255,255,.12); }
.sheet-title { font-size: 24px; letter-spacing: 1px; }
.ident { display: flex; gap: 14px; align-items: flex-start; }
.ident-art { position: relative; width: 100px; flex: none; padding: 0; }
.ident-art.pop { animation: gxPop .4s cubic-bezier(.2,1.3,.3,1); }
.ident-name { font-size: 25px; line-height: 1.05; margin-top: 4px; }
.match { display: inline-block; padding: 3px 7px; border-radius: 4px; background: var(--green-bg);
  border: 1.5px solid var(--green); color: var(--green); font: 800 9px var(--f-dis); letter-spacing: 1.1px; }
.range { position: relative; height: 12px; border-radius: 4px; margin-top: 14px;
  background: linear-gradient(90deg, #33405C, #7A88A6, var(--acc)); }
.range .mk { position: absolute; top: 50%; width: 6px; height: 6px; border-radius: 50%;
  background: #FFF; box-shadow: 0 0 0 2px #131A29; transform: translate(-50%, -50%); }
.added { margin-top: 16px; padding: 13px; border-radius: 6px; text-align: center;
  background: var(--green-bg); border: 2px solid var(--green); color: var(--green);
  font: 800 12px var(--f-dis); letter-spacing: 1.4px; }
.chase-hit { display: flex; align-items: center; gap: 9px; margin-bottom: 14px; padding: 11px 12px;
  background: var(--pink-bg); border: 2px solid var(--pink); border-radius: 6px; }
.chase-hit i { width: 11px; height: 11px; background: var(--pink); transform: rotate(45deg); flex: none; }
.chase-hit span { font: 800 10px var(--f-dis); letter-spacing: 1.2px; color: var(--pink); }
.pro-list { margin: 0; padding-left: 18px; font: 600 13px/1.9 var(--f-ui); color: var(--tx-3); }
.pro-note { margin-top: 12px; color: var(--tx-ghost); }

/* ── Showcase (Profile) ── */
.sec-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 11px; }
.sec-note { font: 600 12px var(--f-ui); color: var(--tx-ghost); }
.show-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.show-slot { position: relative; aspect-ratio: 5/7; border-radius: 6px; overflow: hidden; padding: 0; }
.show-slot .art { width: 100%; height: 100%; border-radius: 6px; }
.show-slot:active { transform: translateY(2px); }
.show-slot.empty { display: grid; place-items: center; background: var(--sunken);
  border: 1.5px dashed var(--bd); }
.show-slot.empty span { font: 700 11px/1.4 var(--f-ui); letter-spacing: 1px; text-align: center; color: #3E4A63; }
.show-cap { position: absolute; left: 0; right: 0; bottom: 0; z-index: 5; padding: 6px;
  background: linear-gradient(transparent, rgba(8,11,20,.94) 55%); text-align: left; }
.show-name { display: block; font: 800 12px/1.1 var(--f-dis); letter-spacing: .4px; }
.show-val { display: block; font: 700 11px/1 var(--f-ui); color: var(--acc); margin-top: 5px; }

/* ── Profile ── */
.id-card { position: relative; overflow: hidden; display: flex; align-items: center; gap: 14px;
  padding: 15px; background: var(--panel-hi); border: 2px solid var(--acc); border-radius: 6px;
  box-shadow: 0 5px 0 rgba(0,0,0,.4); }
.id-card > * { position: relative; }
.id-av { width: 64px; height: 64px; flex: none; border: 2px solid #F2F5FA; border-radius: 6px;
  display: grid; place-items: center; font: 800 22px/1 var(--f-dis); color: #FFF;
  text-shadow: 0 2px 3px rgba(0,0,0,.5); }
.id-main { flex: 1; min-width: 0; }
.id-name { font-size: 22px; letter-spacing: .6px; word-break: break-all; }
.id-joined { font: 600 12px var(--f-ui); color: var(--tx-dim); margin-top: 7px; }
.id-streak { flex: none; text-align: center; padding: 8px 11px; background: var(--sunken);
  border: 1.5px solid #38445F; border-radius: 5px; }
.id-streak b { display: block; font-size: 18px; color: var(--acc); margin-top: 6px; }

.tot-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 20px; }
.tot-all { grid-column: 1 / -1; padding: 16px; }
.tot-big { font-size: 40px; margin-top: 10px; }
.mini { padding: 13px; background: linear-gradient(180deg, #1E2739, #151C2B);
  border: 1.5px solid var(--bd-hi); border-radius: 6px; }
.mini-n { font-size: 30px; margin-top: 8px; }
.mini-n.sm { font-size: 26px; }
.mini-sub { font: 600 12px var(--f-ui); color: var(--tx-ghost); margin-top: 7px; }
.mini-name { font-size: 17px; margin-top: 9px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mini-val { font-size: 16px; color: var(--acc); margin-top: 7px; }

.pf-rows { display: flex; flex-direction: column; gap: 9px; }
.pf-big { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 62px; padding: 12px 15px; text-align: left; background: linear-gradient(180deg, #1E2739, #161D2C);
  border: 1.5px solid var(--bd-hi); border-radius: 6px; }
.pf-big:active { transform: translateY(2px); }
.pf-big.on { border-color: var(--acc); }
.pf-big-name { font-size: 15px; letter-spacing: 1px; color: var(--tx-2); }
.pf-big.on .pf-big-name { color: var(--acc); }
.pf-big-text { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.pf-big-sub { font: 600 11px var(--f-ui); color: var(--tx-ghost); }
.pf-big-val { font-size: 17px; color: var(--acc); }

.badges { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.badge { display: flex; flex-direction: column; align-items: center; gap: 9px; padding: 13px 6px;
  background: var(--bg); border: 1.5px solid #242E42; border-radius: 6px; }
.badge-dot { width: 32px; height: 32px; border-radius: 50%; background: #171E2E;
  border: 2px solid #2E3A52; display: grid; place-items: center; }
.badge-dot i { width: 10px; height: 10px; background: #2E3A52; transform: rotate(45deg); }
.badge span:last-child { font: 800 9px/1.35 var(--f-dis); letter-spacing: .8px; text-align: center; color: #3E4A63; }
.badge.on { background: var(--s3); border-color: var(--acc); }
.badge.on .badge-dot { background: #2A2413; border-color: var(--acc); }
.badge.on .badge-dot i { background: var(--acc); }
.badge.on span:last-child { color: var(--acc); }

.signout { display: flex; align-items: center; justify-content: center; width: 100%;
  margin-top: 22px; min-height: 50px; border: 2px solid var(--bd-hi); border-radius: 6px;
  font: 800 12px var(--f-dis); letter-spacing: 1.8px; color: var(--tx-faint); }
.signout:active { transform: translateY(2px); border-color: #D8574F; color: #D8574F; }

/* ── Dex ── */
/* The screen's top padding is transparent, so on the Dex it showed the page background
   as a lighter band above the bar. Painting the section itself keeps the whole top of
   the screen one colour. */
/* A short set (or a filter that leaves one row) used to end the grid partway down,
   exposing the bar colour underneath as a hard horizontal seam. Making the screen a
   flex column and letting the grid take the remaining space carries its background all
   the way to the bottom. */
#s-dex { background: var(--bar); display: flex; flex-direction: column;
  min-height: 100dvh; padding-bottom: 0; }
.dex-top { background: var(--bar); }
.dex-title { text-align: center; font-size: 20px; letter-spacing: 2px; padding: 0 16px 11px; }
.set-nav { display: flex; align-items: stretch; gap: 8px; padding: 0 12px 10px; }
.set-arrow { width: 38px; flex: none; display: grid; place-items: center; background: #222C42;
  border: 1.5px solid #38445F; border-radius: 5px; font: 800 18px var(--f-dis); color: var(--tx-3); }
.set-arrow:active { transform: translateY(2px); }
.set-card { position: relative; flex: 1; min-width: 0; overflow: hidden; padding: 11px 13px;
  display: block; text-align: center;
  background: linear-gradient(180deg, #2A3A56, #1A2438); border: 2px solid var(--cyan);
  border-radius: 5px; box-shadow: 0 0 16px rgba(63,208,224,.22); }
.set-card:active { transform: translateY(2px); }
.set-card::before { content: ''; position: absolute; inset: 0;
  background: linear-gradient(120deg, var(--tint) 0%, transparent 72%); opacity: .4; }
.set-card > * { position: relative; }
.set-card-name { text-align: center; font-size: 19px; letter-spacing: 1.4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.set-card-count { text-align: center; font: 700 13px var(--f-ui); color: #CFE9EF; margin-top: 7px; }
.set-card-bar { height: 9px; margin-top: 8px; background: #0D131F; border: 1.5px solid #3B5566;
  border-radius: 6px; overflow: hidden; }
.set-card-bar i { display: block; height: 100%; border-radius: 6px;
  background: linear-gradient(90deg, #3FD0E0, #9BE9F2); }

.dex-filters { padding: 10px 12px; background: var(--bar); }
.own-chips { display: flex; gap: 7px; }
.own-chip { flex: 1; min-height: 40px; border-radius: 20px; background: var(--s1);
  border: 1.5px solid var(--bd); color: var(--tx-dim);
  font: 800 11px var(--f-dis); letter-spacing: 1.4px; }
.own-chip:active { transform: translateY(2px); }
.own-chip.on { background: var(--acc); border-color: #7A5410; color: var(--ink); }
.own-chip.off { opacity: .45; }
/* The body locks horizontal panning, so this row has to opt back in or the filter
   chips can no longer be scrolled.
   It also bleeds to the panel's edges rather than stopping inside its padding: the row
   is clipped where it ends, and ending mid-panel made that clip look like a stray
   border sitting on top of the chips. */
.rar-chips { display: flex; gap: 7px; overflow-x: auto; scrollbar-width: none;
  touch-action: pan-x; margin: 8px -12px 0; padding: 0 12px 2px; }
.rar-chips::-webkit-scrollbar { display: none; }
/* Only rows that actually overflow get the fade, so a row whose chips all fit isn't
   dimmed at one end for no reason. */
.rar-chips.scrollable {
  -webkit-mask-image: linear-gradient(90deg, #000 0 calc(100% - 34px), transparent 100%);
  mask-image: linear-gradient(90deg, #000 0 calc(100% - 34px), transparent 100%);
}
.rar-chips::-webkit-scrollbar { display: none; }
.rar-chip { flex: none; min-height: 34px; padding: 0 12px; border-radius: 18px;
  background: var(--s1); border: 1.5px solid var(--bd); color: var(--tx-dim);
  font: 700 10px var(--f-ui); letter-spacing: 1.1px; white-space: nowrap; }
.rar-chip.on { border-color: var(--rc); color: var(--rc); }

/* No border between the filters and the grid: the line plus the tonal jump read as a
   stray band. The grid now fades out of the bar colour instead. */
.dex-body { flex: 1; padding: 10px 12px calc(var(--navbar) + 16px);
  background: linear-gradient(180deg, var(--bar) 0, #131A29 70px, #111726); }
.dex-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.slot { position: relative; aspect-ratio: 5/7; border-radius: 6px; padding: 0; }
.slot .art { width: 100%; height: 100%; border-radius: 6px; }
.slot:active { transform: translateY(2px); }
.slot-tag { position: absolute; top: 5px; left: 6px; z-index: 5;
  font: 700 8px var(--f-ui); letter-spacing: .8px; color: rgba(255,255,255,.45); }
.slot-foil { position: absolute; top: 4px; right: 4px; z-index: 5; padding: 2px 5px;
  background: rgba(8,11,20,.85); border: 1px solid; border-radius: 8px;
  font: 800 7px/1.4 var(--f-ui); letter-spacing: .6px; }
.slot-foot { position: absolute; left: 0; right: 0; bottom: 0; z-index: 5;
  display: flex; align-items: baseline; gap: 4px; padding: 6px 6px 7px; min-width: 0;
  background: linear-gradient(transparent, rgba(8,11,20,.9) 40%); }
.slot-num { font: 700 10px var(--f-ui); color: var(--tx-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* ── Card detail extras ── */
.copies { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 16px; padding: 13px 15px; background: var(--s1);
  border: 1.5px solid var(--bd); border-radius: 6px; }
.copies-sub { font: 600 11px var(--f-ui); color: var(--tx-ghost); margin-top: 5px; }
.foil-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px; }
.foil-opt { padding: 12px 6px; border-radius: 6px; background: var(--s1);
  border: 1.5px solid var(--bd); text-align: center; }
.foil-opt:active { transform: translateY(2px); }
.foil-opt b { display: block; font: 800 12px var(--f-dis); letter-spacing: 1.1px; color: var(--tx-2); }
.foil-opt span { display: block; font: 700 12px var(--f-ui); color: var(--tx-dim); margin-top: 6px; }
.foil-opt.on { border-color: var(--fc); }
.foil-opt.on b, .foil-opt.on span { color: var(--fc); }
.foil-opt[disabled] { opacity: .4; }
.det-pills { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }

/* ── Full-screen card viewer ── */
/* The card, the pager and the hint are children of #zoom-body, not of the scrim —
   centring has to live here or they stack left-aligned inside a full-width block. */
/* A gold button that does nothing reads as broken — make "not yet" visible. */
.btn2[disabled] { opacity: .38; }

/* Section labels in the appraisal sheet carry their top margin inline; this is the
   matching gap underneath, so the label isn't touching the control it names. */
#sheet .lab + .seg,
#sheet .lab + .qty,
#sheet .lab + .foil-grid,
#sheet .lab + .cs-rows { margin-top: 9px; }

/* ── Card sheet ── */
.ident-body { min-width: 0; }
.cs-meta { margin-top: 4px; font: 600 11px var(--f-ui); color: var(--tx-ghost); }
.cs-pills { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.pill-plain { color: var(--tx-dim); background: #1A2233; }
.cs-artist { margin-top: 8px; font: 500 11px var(--f-ui); color: var(--tx-ghost); font-style: italic; }
.cs-spread { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 16px; }
.cs-spread > div { padding: 10px 11px; background: var(--sunken);
  border: 1.5px solid var(--bd-soft); border-radius: 5px; }
.cs-spread b { display: block; margin-top: 6px; font: 800 16px var(--f-dis); color: var(--tx); }
.cs-rows { display: flex; flex-direction: column; gap: 1.5px; margin-top: 8px;
  background: var(--bd-soft); border: 1.5px solid var(--bd-soft); border-radius: 5px; overflow: hidden; }
.cs-row { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 12px; background: var(--s1); font: 600 12px var(--f-ui); color: var(--tx-dim); }
.cs-row b { font: 700 13px var(--f-ui); color: var(--tx); }
.cs-note { margin-top: 14px; font: 600 10px var(--f-ui); letter-spacing: .4px; color: var(--tx-ghost); }

/* ── Sign in / sign up ──
   One rhythm for the whole form: 22px between groups, 10px from a label to its
   control, 7px from a control to its helper line. The markup carries no inline
   margins, so nothing drifts when a field is added or a mode hides one. */
.su-form { display: flex; flex-direction: column; margin-top: 30px; }
.su-heading { font-size: 20px; letter-spacing: 1.6px; color: var(--tx-2); margin-bottom: 22px; }
.su-group { margin-bottom: 22px; }
.su-group .lab { display: block; margin-bottom: 10px; }
.av-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; }
.su-hint { margin-top: 7px; font: 800 9px/1.4 var(--f-dis); letter-spacing: 1.2px; color: var(--tx-ghost); }
.field { transition: border-color .15s; }
.pw-eye { flex: none; padding: 4px 2px; font: 800 9px var(--f-dis);
  letter-spacing: 1.2px; color: var(--tx-ghost); }
.su-submit { min-height: 56px; font-size: 17px; }
.su-err { margin: 0 0 14px; padding: 10px 12px; border-radius: 6px;
  background: #2A1414; border: 1.5px solid #5C2A26; color: #FF8A80;
  font: 600 12px/1.5 var(--f-ui); }
.su-back { margin-top: 14px; padding: 12px; font: 800 11px var(--f-dis);
  letter-spacing: 1.4px; color: var(--tx-ghost); }
/* Sits directly under the submit button, so it takes the 14px the back button would
   have taken and the back button then spaces off this instead — the rhythm below the
   form is unchanged whether or not the mode shows it. */
.su-forgot { margin-top: 14px; padding: 4px; font: 800 10px var(--f-dis);
  letter-spacing: 1.2px; color: var(--tx-dim); }
.su-forgot + .su-back { margin-top: 6px; }
/* Left-aligned and readable, unlike the centred one-liner under the mode buttons. */
.su-sent { text-align: left; margin-top: 0; margin-bottom: 16px; }
.su-sent b { color: var(--tx-2); font-weight: 800; word-break: break-all; }

/* ── Full-screen viewer ──
   Sized off height like the scan frame: the card takes whatever room the details and
   pager leave, so it's as large as it can be without pushing them off a short screen. */

/* ── Full-screen card viewer ── */
/* No backdrop-filter here, unlike the other scrims. A filtered ancestor becomes the
   containing block for `position: fixed` descendants, which left the pinned bar hanging
   above the bottom of the screen instead of on it. The background is 96% opaque anyway,
   so the blur was doing almost nothing. */
#zoom-scrim { align-items: flex-start; overflow-y: auto; overflow-x: hidden;
  backdrop-filter: none; -webkit-backdrop-filter: none;
  overscroll-behavior: contain; touch-action: pan-y; justify-content: center;
  /* Fully opaque, not 96%: with the blur gone that last 4% let the screen underneath
     read through as ghost text behind the card. */
  background: radial-gradient(120% 60% at 50% 0%, #1B2338 0%, #10162400 60%), #060910;
  padding: calc(var(--safe-t) + 22px) 16px calc(var(--safe-b) + 22px); }
#zoom-body { display: flex; flex-direction: column; align-items: center;
  width: 100%; max-width: 440px; margin: auto; }
.zoom-scroll { display: flex; flex-direction: column; align-items: center; width: 100%;
  padding-bottom: 96px; }   /* clears the pinned bar */

/* Same pattern as the scan reveal: the thing you came to do stays in reach while the
   detail scrolls under it. */
.zoom-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 8;
  display: grid; grid-template-columns: 104px minmax(0, 1fr); gap: 10px;
  align-items: center; padding: 14px 16px calc(var(--safe-b) + 12px);
  background: linear-gradient(transparent, rgba(6,9,16,.9) 26%, #060910 62%);
  backdrop-filter: blur(10px); }
.zoom-bar .btn2 { min-height: 56px; font-size: 12px; }
.zoom-bar .zoom-primary { min-height: 62px; font-size: 15px; letter-spacing: 1.5px; }
.zoom-bar .zoom-primary.solo { grid-column: 1 / -1; }

/* Price over time. Stretched to fit, so the stroke is drawn non-scaling. */
.pchart-slot { width: 100%; margin-top: 20px; min-height: 104px; }
.pchart { padding: 12px 14px 10px; background: var(--s1);
  border: 1.5px solid var(--bd); border-radius: 8px; }
.pchart-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.pchart-head .delta { font: 800 12px var(--f-dis); }
.pchart-svg { display: block; width: 100%; height: 62px; margin-top: 10px; overflow: visible; }
.pchart-foot { display: flex; justify-content: space-between; gap: 10px; margin-top: 8px;
  font: 600 10px var(--f-ui); color: var(--tx-ghost); }
/* Deletion is permanent, so it doesn't get to look like the button above it. */
.signout.danger-link { margin-top: 10px; color: var(--red); }

.pchart-seg { margin-top: 12px; }
.pchart-seg button { font-size: 10px; }
.pchart-wait { padding: 30px 0; text-align: center;
  font: 800 10px var(--f-dis); letter-spacing: 1.6px; color: var(--tx-ghost); }

.zoom-stage { display: flex; align-items: center; gap: 4px; width: 100%; }
.zoom-edge { width: 30px; flex: none; padding: 0; background: none; border: 0;
  font: 400 30px/1 var(--f-dis); color: var(--tx-3); opacity: .75; }
.zoom-edge:active { opacity: 1; transform: scale(.9); }

.zoom-card { flex: 1; min-width: 0; perspective: 900px; will-change: transform, opacity; }
/* Leave only enough room for the chevrons — the card takes the rest of the width. */
.zoom-stage { padding: 0 2px; }
/* No animation on this element: an `animation-fill-mode: both` keyframe keeps applying
   its transform and wins over the inline one, so the tilt would be silently ignored.
   The entry pop lives on the parent instead. */
/* Width drives the size, capped by what the available height allows. Sizing by height
   with `max-width: 100%` looked fine on a short screen but on a tall one the derived
   width exceeded the viewport, got clamped, and the aspect-ratio box then cropped the
   artwork's left and right edges. */
.zoom-tilt { position: relative; width: min(100%, calc(56vh * 5 / 7), 440px);
  height: auto; aspect-ratio: 5/7; margin: 0 auto;
  transform-style: preserve-3d; touch-action: none; will-change: transform; }
/* A real card is 63x88mm with a ~3mm corner, so the radius is 4.76% of its width.
   Expressed as a percentage pair it stays circular and tracks the card at any size —
   a fixed 10px was far too tight once the card filled the screen, leaving the
   container's own corners visible behind the artwork's rounder ones.
   The vertical figure is the horizontal one scaled by the 5:7 aspect. */
.zoom-tilt .art { width: 100%; height: 100%;
  border-radius: 4.76% / 3.4%;
  border-color: transparent;
  box-shadow: 0 10px 26px rgba(0,0,0,.55); }
.zoom-tilt .art img { border-radius: inherit; }
/* Follows the drag, so the sheen behaves like light on a real foil. */
.zoom-gloss { position: absolute; inset: 0; border-radius: 4.76% / 3.4%; pointer-events: none;
  background: radial-gradient(60% 60% at var(--gx, 50%) var(--gy, 50%),
    rgba(255,255,255,.22), transparent 60%); mix-blend-mode: screen; }

.zoom-name { margin-top: 26px; font-size: 27px; line-height: 1.05; text-align: center; }
.zoom-set { margin-top: 8px; font: 600 12px var(--f-ui); color: var(--tx-4); text-align: center; }
.zoom-pills { display: flex; flex-wrap: wrap; justify-content: center; gap: 7px; margin-top: 12px; }

/* Centred as a block, but the price column has a fixed width so a longer number grows
   to the right instead of nudging the whole row sideways. Sizing that column to its
   content would re-centre everything on each quantity change, which is what this
   replaces. */
.zv { display: flex; flex-direction: column; gap: 5px; }
.zv-lab { font: 800 8px var(--f-dis); letter-spacing: 1.4px; color: var(--tx-ghost); }
.zv-num { font: 800 19px/1 var(--f-dis); color: var(--acc); }
.zv-num.grade { color: var(--violet); }


.zoom-hint { margin-top: 18px; text-align: center;
  font: 700 10px/1.5 var(--f-ui); letter-spacing: 1.4px; color: #4A5771; }
/* Destructive, so it reads as destructive and takes two taps — see drawZoom. */
.zoom-del.armed { border-color: var(--pink); background: var(--pink-bg); color: var(--pink);
  color: var(--pink); }
.zoom-del:active { transform: scale(.97); }


/* ── Captured frame ──
   The photo is taken the moment the shutter is tapped, so it replaces the live feed
   for the rest of the scan: the analysis has everything it needs and the phone can be
   put down. */
.scan-shot { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: 1; animation: gxFade .18s ease-out; }
#scan.frozen video { opacity: 0; }
#scan.frozen .vf::before { content: ''; position: absolute; inset: 0; border-radius: 10px;
  box-shadow: 0 0 0 100vmax rgba(6,9,16,.66); pointer-events: none; }
#scan.frozen .scan-bg { background: none; }
.scan-flash { position: absolute; inset: 0; z-index: 4; background: #FFF; opacity: 0;
  pointer-events: none; }
.scan-flash.fire { animation: gxFlash .3s ease-out; }
@keyframes gxFlash { 0% { opacity: .85; } 100% { opacity: 0; } }

/* ── "tap to enlarge" affordance ──
   This used to be a 30px ring in the corner of a 100px thumbnail, which over real card
   art was effectively invisible — the feature worked and nobody could find it. A label
   costs a strip of the image and removes the guesswork. */
.zoom-cue { position: absolute; left: 0; right: 0; bottom: 0; z-index: 6;
  display: flex; align-items: center; justify-content: center; gap: 5px;
  padding: 5px 4px 6px; background: linear-gradient(transparent, rgba(8,11,20,.92) 45%);
  font: 800 8px/1 var(--f-dis); letter-spacing: 1.1px; color: var(--tx-2);
  border-radius: 0 0 5px 5px; pointer-events: none; }
.zoom-cue .mag { width: 8px; height: 8px; flex: none; border: 1.5px solid currentColor;
  border-radius: 50%; position: relative; }
.zoom-cue .mag::after { content: ''; position: absolute; right: -3px; bottom: -3px;
  width: 4px; height: 1.5px; background: currentColor; transform: rotate(45deg); }
.det-art:active .zoom-cue, .ident-art:active .zoom-cue { color: var(--acc); }
/* A failed scan keeps the photo, so the shutter becomes a retry rather than asking
   for another shot. */
.shutter.retry { background: var(--acc); border-color: #F5D68C; color: var(--ink);
  font: 800 15px var(--f-dis); letter-spacing: 1.4px; }
.hud-status[data-s="fail"] i { background: var(--red); animation: none; }

/* ── Scan reveal ── */
#reveal { position: fixed; inset: 0; z-index: 50; overflow-y: auto; overflow-x: hidden;
  overscroll-behavior: contain; touch-action: pan-y;
  background: radial-gradient(120% 55% at 50% 0%, #24203F 0%, #121828 55%, #080B14 100%); }
/* Root-level so the pack screen can fire it too, not only the single-card reveal. */
#confetti { position: fixed; inset: 0; z-index: 90; pointer-events: none;
  width: 100%; height: 100%; }
#reveal-body { position: relative; z-index: 3; }
/* Bottom padding clears the pinned action bar, so the last section can still be
   scrolled out from under it. */
.rv-inner { display: flex; flex-direction: column; align-items: center;
  max-width: 460px; margin: 0 auto;
  padding: calc(var(--safe-t) + 22px) 10px calc(var(--safe-b) + 108px); }
/* The controls below don't want the card's edge-to-edge margin. */
.rv-inner .zoom-name, .rv-inner .zoom-set, .rv-inner .zoom-pills,
.rv-inner .rv-stats, .rv-inner .rv-detail { padding-inline: 10px; }
.rv-eyebrow { font: 800 10px var(--f-dis); letter-spacing: 2.4px; color: var(--green);
  margin-bottom: 16px; animation: gxFade .5s ease-out both; }
/* The card is the reason you scanned, so it gets the width. `.zoom-card` carries
   `flex: 1` for the viewer's row layout, which in this column would grow its height and
   leave the width shrink-to-fit — hence `flex: none`. */
#rv-card { width: 100%; max-width: 440px; flex: none; perspective: 900px;
  animation: gxReveal .6s cubic-bezier(.2,1.1,.3,1) both; }
@keyframes gxReveal {
  0%   { transform: scale(.72) rotate(-7deg); opacity: 0; }
  60%  { transform: scale(1.03) rotate(1.5deg); opacity: 1; }
  100% { transform: scale(1) rotate(0); opacity: 1; }
}
/* Sized from what's actually left rather than a guessed fraction of the screen: the
   name, set, pills, stat row, the "not this card?" link and the pinned bar come to about
   372px of fixed chrome, so the card takes the rest. That keeps everything down to the
   link on the first screen on a short phone and still fills a tall one. */
#rv-card .zoom-tilt { width: min(100%, calc((100dvh - 372px) * 5 / 7), 440px); }
.rv-inner .zoom-name { margin-top: 20px; }
/* Everything that matters about the card on one line: what it's worth raw, what it's
   worth graded, and how hard it was to pull. Three figures side by side keep the scan
   result on one screen — the odds used to sit in a panel below the fold, which is where
   people stopped reading. Sized in vw so all three fit a narrow phone without wrapping;
   the unit inside a figure ("PACKS", "OF 131") rides along at a smaller weight. */
.stat-row { display: flex; align-items: flex-start; justify-content: center;
  gap: clamp(12px, 4.4vw, 26px); margin-top: 22px; text-align: center; }
.stat-row .zv { display: flex; flex-direction: column; align-items: center; gap: 5px;
  min-width: 0; }
.stat-row .zv-lab { font-size: 8.5px; letter-spacing: 1.4px; white-space: nowrap; }
.stat-row .zv-num { font-size: clamp(15px, 5.2vw, 24px); white-space: nowrap; }
.stat-row .zv-num em { font-style: normal; font-size: .62em; color: var(--tx-ghost); }
/* Discard, details, keep — in that order, weighted so the thing you'll tap most often
   is the widest. The ✕ replaces the old SCAN AGAIN link below the row; two controls that
   both threw the scan away was one too many. */
/* Pinned to the bottom so ADD is always in reach, with the detail scrolling under it.
   The gradient lets content fade out beneath rather than butt against a hard edge. */
.rv-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 6;
  padding: 14px 16px calc(var(--safe-b) + 12px);
  background: linear-gradient(transparent, rgba(11,15,26,.86) 26%, #0B0F1A 62%);
  backdrop-filter: blur(10px); }
/* Equal outer columns so ADD sits dead centre rather than merely being the widest —
   it's the action almost everyone wants, and it's the one your thumb reaches for. */
.rv-actions { display: grid; grid-template-columns: 76px minmax(0, 1fr) 76px; gap: 10px;
  align-items: center; width: 100%; max-width: 460px; margin: 0 auto; }

/* Everything you can change about your copy, below the fold. */
.rv-detail { width: 100%; margin-top: 6px; text-align: left; }
.rv-detail .seg { margin-top: 9px; }
.rv-set { display: flex; flex-direction: column; gap: 12px; margin-top: 9px; padding: 14px;
  background: var(--s1); border: 1.5px solid var(--bd); border-radius: 8px; }
.rv-set-logo { align-self: center; max-width: 62%; max-height: 54px; object-fit: contain; }
.rv-facts { display: grid; gap: 9px; margin: 0; }
.rv-facts > div { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.rv-facts dt { font: 800 9px var(--f-dis); letter-spacing: 1.5px; color: var(--tx-ghost); }
.rv-facts dd { margin: 0; min-width: 0; font: 600 13px var(--f-ui); color: var(--tx-2);
  text-align: right; }
.rv-x { padding: 0; font-size: 18px; font-weight: 400; letter-spacing: 0;
  color: var(--tx-3); }
/* Quiet by design — the match is usually right, and a loud "wrong?" next to the result
   would undercut it. */
.rv-wrong { margin-top: 12px; padding: 10px; background: none; border: 0;
  font: 800 11px var(--f-dis); letter-spacing: 1.6px; color: var(--tx-ghost);
  text-decoration: underline; text-underline-offset: 3px; }
.rv-wrong:active { color: var(--tx-2); }
.rv-actions .btn2 { min-height: 56px; font-size: 13px; }
.rv-actions .rv-primary { min-height: 68px; font-size: 17px; letter-spacing: 1.6px; }

/* Set logos read faster than the name at a glance, which is the whole job of this
   carousel. The name stays in the markup as alt text and as the fallback if the image
   doesn't load — a set with a broken logo shouldn't become unidentifiable. */
.set-card-logo { display: grid; place-items: center; height: 46px; }
.set-card-logo img { max-width: 82%; max-height: 46px; width: auto; height: auto;
  object-fit: contain; filter: drop-shadow(0 2px 6px rgba(0,0,0,.55)); }
.set-card-logo .set-card-name { display: none; }
.set-card-logo.fallback img { display: none; }
.set-card-logo.fallback .set-card-name { display: block; }

/* ── Set picker ── */
.sp-list { max-height: 62vh; overflow-y: auto; margin-top: 12px;
  display: flex; flex-direction: column; gap: 6px; }
.sp-row { display: flex; align-items: center; gap: 12px; width: 100%; padding: 9px 11px;
  background: var(--s1); border: 1.5px solid var(--bd); border-radius: 6px; text-align: left; }
.sp-row.on { border-color: var(--cyan); }
.sp-row:active { transform: translateY(2px); }
.sp-logo { width: 54px; flex: none; display: grid; place-items: center; }
.sp-logo img { max-width: 54px; max-height: 30px; object-fit: contain; }
.sp-all { width: 16px; height: 16px; border: 2px solid var(--violet); border-radius: 50%; }
.sp-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.sp-name { font-size: 14px; letter-spacing: .6px; color: var(--tx-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-sub { font: 600 10px var(--f-ui); color: var(--tx-ghost); }
.sp-count { flex: none; font: 700 12px var(--f-ui); color: var(--tx-dim); }

/* ── Duplicates as a stack ──
   Owning more than one shows as card edges peeking out behind the tile, which reads at
   a glance in a grid; a small "2" pill did not. Layers sit behind via z-index, so the
   tile itself can't clip them. */
.slot[data-stack] > .art { position: relative; z-index: 1; }
.slot[data-stack]::before,
.slot[data-stack]::after {
  content: ''; position: absolute; inset: 0; z-index: 0; border-radius: 6px;
  background: #223049; border: 1.5px solid var(--bd-line);
  box-shadow: 0 2px 6px rgba(0,0,0,.5);
}
.slot[data-stack]::before { transform: translate(3px, -3px); }
.slot[data-stack]::after { display: none; }

.slot-price { margin-left: auto; flex: none; white-space: nowrap;
  font: 800 10px var(--f-dis); letter-spacing: .3px;
  color: var(--acc); text-shadow: 0 1px 2px rgba(0,0,0,.9); }
.row-art { position: relative; padding: 0; background: none; border: 0; }
.row-art .zoom-cue { font-size: 6px; letter-spacing: .6px; padding: 3px 2px 4px; gap: 3px; }
.row-art .zoom-cue .mag { width: 6px; height: 6px; border-width: 1px; }
/* Remove control for a wantlist tile — a span, since a button can't nest in a button. */
.slot-x { position: absolute; top: 4px; right: 4px; z-index: 6; width: 22px; height: 22px;
  display: grid; place-items: center; border-radius: 50%;
  background: rgba(8,11,20,.82); border: 1.5px solid var(--bd-line);
  font: 700 10px var(--f-ui); color: var(--tx-3); }
.slot-x:active { transform: scale(.9); color: var(--red); border-color: var(--red); }
/* Values with no quantity stepper alongside them: centred on their own. */

/* ── Batch scan review ── */
.bt-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.bt-head .ident-name { font-size: 21px; }
.bt-total { font: 800 21px var(--f-dis); color: var(--acc); flex: none; }
.bt-list { max-height: 52vh; overflow-y: auto; margin-top: 14px;
  display: flex; flex-direction: column; gap: 6px; }
.bt-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  background: var(--s1); border: 1.5px solid var(--bd); border-radius: 6px; }
.bt-row.off { opacity: .45; }
.bt-check { width: 20px; height: 20px; flex: none; display: grid; place-items: center;
  border-radius: 5px; border: 1.5px solid var(--bd-line);
  font: 800 11px var(--f-ui); color: var(--ink); background: transparent; }
.bt-row:not(.off) .bt-check { background: var(--acc); border-color: #7A5410; }
.bt-art { width: 34px; flex: none; }
.bt-none { display: grid; place-items: center; width: 34px; aspect-ratio: 5/7;
  border: 1.5px dashed var(--bd-line); border-radius: 4px; color: var(--tx-ghost);
  font: 800 13px var(--f-dis); }
.bt-mid { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.bt-name { font: 700 13px var(--f-ui); color: var(--tx-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bt-end { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 5px; }
.bt-price { font: 800 13px var(--f-dis); color: var(--acc); }
.bt-qty { display: flex; align-items: center; gap: 5px; }
.bt-qty button { width: 20px; height: 20px; border-radius: 4px; background: var(--s3);
  border: 1.5px solid var(--bd-line); color: var(--tx-2); font: 800 12px var(--f-ui); }
.bt-qty b { min-width: 12px; text-align: center; font: 700 11px var(--f-ui); }
/* Batch mode frames a page, not a single card. */
/* Batch mode uses the same frame as a single scan — one card shape, just fit more
   cards inside it. The hint text carries the difference; a second frame size only made
   the corner brackets collide with the screen edges. */

/* ── Pack opening ── */
#pack { position: fixed; inset: 0; z-index: 55; overflow-y: auto; overscroll-behavior: contain;
  background: radial-gradient(120% 55% at 50% 0%, #241E44 0%, #121828 55%, #080B14 100%); }
.pk-inner { display: flex; flex-direction: column; align-items: center;
  max-width: 460px; margin: 0 auto;
  padding: calc(var(--safe-t) + 24px) 16px calc(var(--safe-b) + 24px); }
/* The tray of opened cards below already shows how far through the pack you are, so
   there's no counter competing with it up here. */
.pk-eyebrow { font: 800 10px var(--f-dis); letter-spacing: 2.4px; color: var(--green); }

/* One pile, not a grid. You turn over the card on top, it slides away into the tray,
   and the next one is waiting underneath — the way you actually open a pack. Sized off
   both width and height so a short phone doesn't push the buttons off screen. */
.pk-stage { position: relative; width: min(74vw, 300px, calc(50vh * 5 / 7));
  aspect-ratio: 5/7; margin: 20px auto 4px; }
/* Corners are a percentage of the card, not a fixed px, so the frame follows the
   printed card's radius at any size instead of cutting across it. */
.pk-stage, .pk-shim, .pk-back, .pk-front, .pk-bk, .pk-front .art,
.pk-slot, .pk-slot .art { border-radius: 4.76% / 3.4%; }

/* Offset has to beat what the scale takes off the bottom edge, or the pile hides
   entirely behind the top card and reads as a single card. */
.pk-shim { position: absolute; inset: 0; overflow: hidden;
  transform: translateY(calc(var(--i) * 11px)) rotate(calc(var(--i) * .7deg))
    scale(calc(1 - var(--i) * .02));
  filter: brightness(calc(1 - var(--i) * .22)) saturate(.8);
  box-shadow: 0 12px 24px rgba(0,0,0,.5); }

/* pan-y so a vertical drag still scrolls the screen while a horizontal one is ours to
   handle — see bindPackThrow. */
.pk-card { position: absolute; inset: 0; z-index: 4; padding: 0; background: none; border: 0;
  perspective: 1000px; touch-action: pan-y; animation: pkDeal .34s cubic-bezier(.2,1.1,.3,1); }
.pk-inner3d { position: relative; display: block; width: 100%; height: 100%;
  transform-style: preserve-3d; transition: transform .62s cubic-bezier(.3,1.1,.35,1); }
.pk-card.open .pk-inner3d { transform: rotateY(180deg); }
.pk-card:not(.open):active .pk-inner3d { transform: scale(.96); }
@keyframes pkDeal {
  from { transform: translateY(14px) scale(.94); opacity: 0; }
  to { transform: none; opacity: 1; }
}

.pk-back, .pk-front { position: absolute; inset: 0;
  backface-visibility: hidden; -webkit-backface-visibility: hidden; overflow: hidden;
  box-shadow: 0 14px 30px rgba(0,0,0,.55); }
/* The rarity ring sits on the art itself, so it traces the card rather than boxing it. */
.pk-front { transform: rotateY(180deg); }
.pk-front .art { width: 100%; height: 100%; border: 1.5px solid var(--rc); }

/* What you just turned over, under the pile where it doesn't cover the art. */
/* Height is reserved so the tray and buttons don't jump every time a card turns over,
   and it sits above the pile's drop shadow rather than under it. */
.pk-meta { position: relative; z-index: 6; width: 100%; min-height: 146px;
  margin-top: 14px; text-align: center; }
/* One line, so the reserved height above is exact and the tray doesn't shift when a
   long name would otherwise wrap. The set and number below disambiguate a clipped one. */
.pk-name { font-size: 21px; letter-spacing: .2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pk-set { margin-top: 3px; font: 600 12px var(--f-ui); color: var(--tx-3); }
.pk-meta .stat-row { margin-top: 11px; }

/* Same quiet treatment as the single scan's — the match is usually right. */
.pk-wrong { margin-top: 12px; padding: 8px; background: none; border: 0;
  font: 800 10px var(--f-dis); letter-spacing: 1.5px; color: var(--tx-ghost);
  text-decoration: underline; text-underline-offset: 3px;
  animation: pkMetaIn .36s cubic-bezier(.2,.9,.25,1) both; animation-delay: 300ms; }
.pk-wrong:active { color: var(--tx-2); }
@media (prefers-reduced-motion: reduce) { .pk-wrong { animation: none; } }

/* Per-row corrector in the batch list. */
.bt-fix { margin-top: 6px; padding: 4px 7px; background: none;
  border: 1px solid var(--bd-line); border-radius: 5px;
  font: 800 8px var(--f-dis); letter-spacing: 1.2px; color: var(--tx-3); }
.bt-fix:active { border-color: var(--acc); color: var(--acc); }
/* The picker's rows are buttons. Reset only what the button default overrides — the
   card look itself comes from .row, which these also carry. */
.cp-row { width: 100%; text-align: left; font: inherit; color: inherit; }
.cp-row:active { border-color: var(--acc); }

/* The card turns over, then its details arrive behind it rather than snapping in fully
   formed. Staggered top to bottom so the eye lands on the name first and the figures
   read as the payoff. `both` holds the from-state through the delay, or each line would
   flash at full opacity before its turn. */
.pk-meta .pk-name,
.pk-meta .pk-set,
.pk-meta .stat-row .zv { animation: pkMetaIn .36s cubic-bezier(.2,.9,.25,1) both; }
.pk-meta .pk-set { animation-delay: 60ms; }
.pk-meta .stat-row .zv:nth-child(1) { animation-delay: 120ms; }
.pk-meta .stat-row .zv:nth-child(2) { animation-delay: 180ms; }
.pk-meta .stat-row .zv:nth-child(3) { animation-delay: 240ms; }
@keyframes pkMetaIn {
  from { opacity: 0; transform: translateY(9px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .pk-meta .pk-name, .pk-meta .pk-set, .pk-meta .stat-row .zv { animation: none; }
}

/* The back is ours: the composition every trading card uses — wordmark mirrored top and
   bottom around a centred emblem — drawn in CoMon's marks, not anyone else's artwork. */
.pk-bk { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: space-between; padding: 7% 8%;
  border: 4px solid #16225A;
  background:
    radial-gradient(52% 40% at 50% 47%, rgba(160,205,255,.26), transparent 74%),
    conic-gradient(from 200deg at 50% 47%, rgba(255,255,255,.17), rgba(255,255,255,.01) 18%,
      rgba(255,255,255,.13) 34%, rgba(255,255,255,.01) 52%, rgba(255,255,255,.16) 70%,
      rgba(255,255,255,.01) 86%, rgba(255,255,255,.17)),
    repeating-radial-gradient(circle at 50% 47%, rgba(255,255,255,.026) 0 10px, transparent 10px 34px),
    linear-gradient(160deg, #34479E, #1C2B64 52%, #101A3C);
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,.1), inset 0 0 34px rgba(0,0,0,.45); }
.pk-bk-word { font: 900 clamp(11px, 4.6vw, 21px)/1 var(--f-dis); letter-spacing: 1.5px;
  color: #F2C64B; -webkit-text-stroke: 1.6px #16225A; paint-order: stroke fill; }
.pk-bk-word.flip { transform: rotate(180deg); }
.pk-bk-orb { width: 43%; aspect-ratio: 1; display: grid; place-items: center;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 26%, rgba(255,255,255,.55), transparent 46%),
    linear-gradient(165deg, #F6D77C, #E0A93B 46%, #A9761F);
  box-shadow: 0 0 0 3px #16225A, 0 0 0 5px rgba(246,215,124,.45), 0 10px 22px rgba(0,0,0,.5); }
.pk-bk-orb i { font: 900 clamp(15px, 7vw, 34px)/1 var(--f-dis); font-style: normal;
  color: #16225A; letter-spacing: -1px; }

/* Everything opened so far, filling up under the pile. */
/* Slots are always sized for a full pack of six and centred, so a scan that found four
   cards shows four the same size rather than four stretched to fill the row. BATCH_MAX
   is 6 — keep these in step. */
.pk-tray { display: flex; justify-content: center; gap: 6px; width: 100%; margin-top: 10px; }
.pk-slot { flex: 0 0 calc((100% - 5 * 6px) / 6); min-width: 0; aspect-ratio: 5/7;
  border: 1px dashed rgba(255,255,255,.14); background: rgba(255,255,255,.03);
  overflow: hidden; }
.pk-slot.has { border: 1px solid var(--bd-line); background: none;
  animation: gxPop .34s cubic-bezier(.2,1.2,.3,1) both; }
.pk-slot .art { width: 100%; height: 100%; border: 0; }

.pk-actions { width: 100%; margin-top: 20px; }
.pk-actions .btn2 { min-height: 54px; font-size: 15px; }
