/* Cyberfrog Cards TMA - vanilla CSS, mobile-first */
:root {
  color-scheme: dark;
  --bg:           #0d0f12;
  --panel:        #161a20;
  --border:       #2a2f36;
  --fg:           #e5e7eb;
  --muted:        #8b9199;
  --accent:       #19c37d;
  --card-bg:      #11161f;
  --card-border:  #2a2f36;

  /* Frog palette defaults - overridden per-card inline. */
  --c-body:   #4d4d4d;
  --c-belly:  #999999;
  --c-accent: #1a1a1a;
  --c-eye:    #999999;
  --gradient-intensity: 1;

  /* Holo pointer defaults. */
  --pointer-x: 50%;
  --pointer-y: 50%;
  --card-opacity: 0.15;
  --background-x: 50%;
  --background-y: 50%;
  --pointer-from-center: 0;
  --pointer-from-top: 0.5;
  --pointer-from-left: 0.5;

  /* Unified sticky toolbar heights. Global .nav lives outside the
     scrolling .screens (so it doesn't need to take sticky offset
     inside .screens), .binder-subnav pins to top: 0 of .screens, and
     downstream sticky chrome (trade-up toolbar) sits at top: var(--subnav-h). */
  --nav-h: 36px;
  --subnav-h: 34px;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* Form inputs need text selection (search field, hue picker numeric, etc). */
input, textarea, [contenteditable] {
  user-select: text;
  -webkit-user-select: text;
}

body {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.45;
  background: var(--bg);
  color: var(--fg);
  /* Use height (not min-height) so the flex:1 .screens child gets a
     bounded height and actually scrolls inside .screens - required for
     position:sticky inside a sub-page to pin to the viewport. */
  height: 100vh;
  height: 100dvh;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* TMA - no text-selection anywhere. Long-press shouldn't pop the iOS
     copy callout, drag-select shouldn't highlight labels on desktop.
     Form inputs (search box, hue picker, etc) opt back in via the rule
     directly below. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

/* TMA is a phone-shaped app. On desktop, render in a centered mobile-width
   column rather than stretching to fill - matches the inside-Telegram
   experience and keeps the layout coherent across surfaces. */
.nav, .screens {
  width: 100%;
  max-width: 480px;
}

/* ---------------------------------------------------------------------------
   Layout
--------------------------------------------------------------------------- */

.nav[hidden] { display: none; }

.nav {
  display: flex;
  gap: 0;
  background: var(--panel);
  flex-shrink: 0;
  /* Global nav sits at the top of the body flex column above .screens,
     so it's already pinned to the viewport. The sticky declaration is
     defensive in case the layout moves it inside a scroll container. */
  position: sticky;
  top: 0;
  z-index: 50;
}

.nav-tab {
  flex: 1;
  padding: 12px 6px;
  background: transparent;
  border: none;
  color: var(--muted);
  font-family: inherit;
  font-size: 0.78em;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  cursor: pointer;
  /* No bottom-stripe on the global nav: the active accent color alone
     reads as active, and dropping the stripe lets .nav + .binder-subnav
     feel like one continuous toolbar with a single active marker under
     the sub-nav. */
  transition: color 0.1s;
}
.nav-tab:hover { color: var(--fg); }
.nav-tab.active {
  color: var(--accent);
}

.screens {
  flex: 1;
  overflow-y: auto;
}

.screen { display: none; padding: 16px; }
.screen.active { display: block; }

/* ---------------------------------------------------------------------------
   Sign-in / welcome screen
   Hides the nav (nav[hidden]) and fills the visible space with a centered
   mascot + headline + CTA. Same dark theme; no separate sheet so it feels
   like the app, not a redirect.
--------------------------------------------------------------------------- */

#screen-signin.active {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  min-height: calc(100dvh - var(--nav-h));
  padding: 32px 20px 16px;
}
.signin-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  width: 100%;
  max-width: 360px;
  gap: 16px;
}
.signin-mascot {
  width: min(60vw, 200px);
  aspect-ratio: 5 / 7;
  display: flex;
  align-items: center;
  justify-content: center;
  perspective: 1200px;
}
.signin-mascot .card { width: 100%; }
.signin-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 1.4em;
  letter-spacing: 0.06em;
  text-align: center;
  margin: 8px 0 0;
  color: var(--fg);
}
.signin-subtitle {
  font-size: 0.85em;
  color: var(--muted);
  text-align: center;
  line-height: 1.6;
  margin: 0 0 4px;
  max-width: 320px;
}
.signin-cta {
  margin-top: 12px;
  min-width: 240px;
  padding: 12px 22px;
  font-size: 0.9em;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}
.signin-note {
  font-size: 0.75em;
  color: var(--muted);
  text-align: center;
  margin: 4px 0 0;
  max-width: 320px;
}
.signin-footer {
  width: 100%;
  text-align: center;
  padding: 16px 0 4px;
}
.signin-privacy-link {
  font-size: 0.75em;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
}
.signin-privacy-link:hover { color: var(--fg); }
.signin-footer-sep {
  display: inline-block;
  margin: 0 0.4em;
  font-size: 0.75em;
  color: var(--muted);
}

/* Breathing room at the bottom of the scroll so the last grid row
   doesn't crash into the footer. */
.binder-grid { padding-bottom: 40px; }

/* App footer - copyright line, always visible at bottom of every screen.
   Sits outside .screens so it pins to the bottom of the viewport in the
   body flex column. */
.app-footer {
  width: 100%;
  max-width: 480px;
  padding: 10px 16px;
  font-size: 0.7em;
  letter-spacing: 0.08em;
  color: var(--muted);
  text-align: center;
  border-top: 1px solid var(--border);
  background: var(--panel);
  flex-shrink: 0;
}

/* ---------------------------------------------------------------------------
   Binder sub-nav (View / Claim / Trade Up / Buy Pack)
   Styled as a segmented control matching the global .nav above it.
--------------------------------------------------------------------------- */

.binder-subnav {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  /* Flush against the global .nav above, flush against content below.
     Negative side margins reach over the .screen's 16px horizontal padding;
     no bottom margin so the subnav reads as the last row of one unified
     sticky toolbar. No drop shadow here - downstream chrome (trade-up
     toolbar) carries the shadow when it's sticky, otherwise the grid
     content abuts the subnav cleanly. */
  margin: -16px -16px 0;
  position: sticky;
  top: 0;
  z-index: 49;
}
.binder-subnav-tab {
  flex: 1;
  padding: 10px 4px;
  background: transparent;
  border: none;
  color: var(--muted);
  font-family: inherit;
  font-size: 0.72em;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 0.1s, border-color 0.1s;
  outline: none;
  -webkit-tap-highlight-color: transparent;
}
.binder-subnav-tab:hover { color: var(--fg); }
.binder-subnav-tab:focus,
.binder-subnav-tab:focus-visible { outline: none; box-shadow: none; }
.binder-subnav-tab.active {
  color: #FFFFFF;
  border-bottom-color: #FFFFFF;
}

/* ---------------------------------------------------------------------------
   Card-interior visuals live in /shared/card.css (single source of truth).
   This file only sets the OUTSIDE sizing of card consumer contexts
   (top-card wrap, modal wraps) per technical_approach.md §10.3.
--------------------------------------------------------------------------- */

/* Shared top-card wrapper used by both Profile and Binder View. ONE rule
   so the two contexts can't drift in size, perspective, or framing. No
   border on the top card itself - the active-card indicator lives on
   the grid cell (.active-card-cell). */
.top-card-display {
  display: flex;
  justify-content: center;
  perspective: 1200px;
  margin-bottom: 16px;
}
.top-card-display .card {
  width: min(70vw, 220px);
}

/* Per-edition completion strip on the View sub-page. Sits between the
   sub-nav and the top-card display. One line per LIVE edition; the
   middle-dot separator uses 0.5em padding so the three segments breathe. */
.binder-view-stats {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Clear the sticky unified toolbar above. The subnav has its own
     16px bottom margin; this margin keeps the stats line from sitting
     right against the white active stripe. */
  margin-top: 12px;
  margin-bottom: 10px;
}
.binder-view-stats-line {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.75em;
  letter-spacing: 0.04em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.binder-view-stats-dot { padding: 0 0.5em; }

/* Small uppercase muted label above the binder View top-card. */
.top-card-label {
  font-size: 0.7em;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  text-align: center;
  margin: 4px 0 6px;
}

/* Claim sub-page list. */
.claim-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 8px auto;
  max-width: 360px;
}

/* Buy Pack sub-page CTA. */
.buypack-cta {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin: 8px auto 0;
  max-width: 360px;
  padding: 20px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  text-align: center;
}
.buypack-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 1.4em;
  letter-spacing: 0.06em;
  color: var(--fg);
  margin: 0;
}
.buypack-blurb {
  font-size: 0.85em;
  color: var(--muted);
  margin: 0;
}
.buypack-price {
  font-size: 0.95em;
  color: #FFD700;
  letter-spacing: 0.06em;
  font-weight: 600;
}

/* Count badge. */
.count-badge {
  position: absolute;
  bottom: 5px;
  right: 5px;
  background: rgba(0,0,0,0.65);
  color: var(--accent);
  font-family: ui-monospace, monospace;
  font-size: 0.68em;
  padding: 1px 5px;
  border-radius: 8px;
  z-index: 20;
  pointer-events: none;
}

/* Selected state in tradeup grid: matches the .active-card-cell white ring
   so "this is being acted on" reads the same in both modes. */
.tradeup-selected {
  box-shadow: 0 0 0 3px #FFFFFF, 0 0 20px 4px rgba(255,255,255,0.30);
  border-radius: 6%;
}

/* Active card + trade-up selection "peek out of the sleeve" - a small
   translate-up on the cell wrapper (NOT the inner .card, so it doesn't
   compose with the holo rotate transform). */
.active-card-cell,
.tradeup-selected {
  transform: translateY(-6px);
  transition: transform 180ms cubic-bezier(0.2, 0.8, 0.25, 1),
              box-shadow 180ms cubic-bezier(0.2, 0.8, 0.25, 1);
}

/* ---------------------------------------------------------------------------
   Card stage: featured card wrapper
--------------------------------------------------------------------------- */

.card-stage {
  position: relative;
  display: inline-block;
}

/* ---------------------------------------------------------------------------
   Profile screen
--------------------------------------------------------------------------- */

.profile-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.profile-stat {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.profile-stat-label {
  font-size: 0.68em;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  color: var(--muted);
}

/* Logout + Delete sit side-by-side on the profile screen. Both gate on
   a native confirm() dialog before doing anything destructive, so no
   in-app two-stage arming styles are needed. */
.profile-actions {
  display: flex;
  flex-direction: row;
  gap: 10px;
  align-items: stretch;
  justify-content: center;
  margin-top: 24px;
  padding-bottom: 12px;
}
.profile-actions .btn { flex: 1 1 0; min-width: 0; }
.profile-logout {
  color: var(--muted);
  border-color: rgba(255, 255, 255, 0.18);
}
.profile-logout:hover:not(:disabled) {
  color: var(--fg);
  border-color: var(--accent);
}
.profile-delete {
  color: #ff8c8c;
  border-color: rgba(255, 140, 140, 0.40);
}
.profile-delete:hover:not(:disabled) {
  color: #ffffff;
  border-color: #ff6b6b;
  background: rgba(255, 107, 107, 0.12);
}

.profile-stat-value {
  font-size: 1.05em;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}

/* Display name (preferred: @username, then first_name, then User #<id>).
   Sits above the active-card cell. Muted monospace per spec so the
   identity reads as a tag, not a heading. */
.profile-display-name {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.78em;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  color: var(--muted);
  text-align: center;
  margin: 8px 0 4px;
}

/* "Viewing X's profile" banner shown when ?user=<id> is in the URL.
   `display: flex` overrides the default `display: none` for [hidden], so
   we re-pin `display: none` when the attribute is present. Same trick is
   used by `.profile-referral-block` below. */
.profile-view-banner {
  background: rgba(25, 195, 125, 0.10);
  border: 1px solid rgba(25, 195, 125, 0.45);
  border-radius: 6px;
  padding: 8px 12px;
  margin-bottom: 12px;
  font-size: 0.82em;
  color: var(--fg);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}
.profile-view-banner[hidden] { display: none; }
.profile-view-back {
  color: #19c37d;
  font-size: 0.85em;
  text-decoration: none;
  letter-spacing: 0.04em;
}
.profile-view-back:hover { text-decoration: underline; }

/* Referral link block. Read-only input + a Copy button that flips to
   "Copied!" for 1.5s after a click. Hidden on other users' profiles. */
.profile-referral-block {
  margin-top: 18px;
  padding: 12px 14px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.profile-referral-block[hidden] { display: none; }
.profile-referral-label {
  font-size: 0.68em;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  color: var(--muted);
  margin-bottom: 6px;
}
.profile-referral-row {
  display: flex;
  gap: 8px;
}
.profile-referral-link {
  flex: 1;
  min-width: 0;
  background: rgba(0, 0, 0, 0.30);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 8px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.78em;
}
.profile-referral-copy {
  padding: 6px 12px;
  font-size: 0.78em;
  min-width: 70px;
}
.profile-referral-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
.profile-referral-title {
  font-size: 0.85em;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  color: var(--fg);
  font-weight: 600;
}
/* Round (i) button next to the "Referrals" header. Opens a cardview-style
   modal explaining the two-leg reward rules. */
.profile-referral-info {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.06);
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.7em;
  font-style: italic;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.profile-referral-info:hover { color: var(--fg); border-color: var(--fg); }
.profile-referral-stat {
  margin-top: 10px;
  font-size: 0.82em;
  color: var(--muted);
  display: flex;
  justify-content: space-between;
}
.profile-referral-stat-value {
  color: var(--fg);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
/* Referral rules modal - simple cardview-styled body. The .cardview-backdrop
   class supplies the dimmer + center; we only need to style the inner
   panel. */
.referral-rules-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 22px 22px 18px;
  max-width: 360px;
  color: var(--fg);
}
.referral-rules-title {
  font-size: 1.0em;
  font-weight: 600;
  letter-spacing: 0.04em;
  margin-bottom: 14px;
  text-align: center;
}
.referral-rules-list {
  margin: 0;
  padding-left: 18px;
  font-size: 0.85em;
  line-height: 1.5;
}
.referral-rules-list li { margin-bottom: 8px; }
.referral-rules-list li strong { color: #19c37d; }
.set-completion-breakdown {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.set-completion-line {
  font-size: 0.85em;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   Binder: active-card ring + new-badge
--------------------------------------------------------------------------- */

/* White ring on the cell wrapper marks the active card. Matches the
   white border applied to the Binder View top-card so the in-grid
   active card and the top-card display are visually paired. */
.active-card-cell {
  box-shadow: 0 0 0 3px #FFFFFF, 0 0 20px 4px rgba(255,255,255,0.30);
  border-radius: 6%;
}

/* "NEW" badge for cards the user has acquired but not yet inspected. */
.new-badge {
  position: absolute;
  top: 5px;
  right: 5px;
  background: var(--accent);
  color: #0d0f12;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 1px 5px;
  border-radius: 4px;
  z-index: 20;
  pointer-events: none;
  line-height: 1.4;
}

/* Trade-up confirm: Cancel + Confirm in a centered row (not column).
   Cancel on the left, Confirm on the right. Both buttons size to content. */
.cardview-actions.tradeup-confirm-actions {
  flex-direction: row;
  justify-content: center;
  gap: 12px;
}
.cardview-actions.tradeup-confirm-actions .btn {
  width: auto;
  min-width: 130px;
  flex: 0 0 auto;
}

/* ---------------------------------------------------------------------------
   Cooldown controls
--------------------------------------------------------------------------- */

.drop-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.drop-label {
  font-size: 0.75em;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  flex: 0 0 60px;
}

.timer {
  flex: 1;
  font-size: 0.82em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

/* Pending-claims chip on the Free Pack row. Hidden when zero pending;
   visible as a compact "N pending" pill between the timer and the Claim
   button. */
.pending-count {
  font-size: 0.72em;
  color: var(--fg);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px 8px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.btn {
  background: transparent;
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 14px;
  font-family: inherit;
  font-size: 0.78em;
  letter-spacing: 0.08em;
  cursor: pointer;
  white-space: nowrap;
  min-height: 34px;
}
.btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.btn-primary { border-color: rgba(25,195,125,0.45); color: var(--fg); }
.btn-primary:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.btn-buy {
  display: block;
  width: 100%;
  text-align: center;
  padding: 12px;
  margin-top: 4px;
  font-size: 0.85em;
  letter-spacing: 0.08em;
  border-color: rgba(255,255,255,0.45);
  color: #fff;
}
.btn-buy:hover:not(:disabled) { border-color: #fff; }
.btn-danger { border-color: rgba(255,107,107,0.55); color: #ff6b6b; }
.btn-danger:hover:not(:disabled) { border-color: #ff6b6b; color: #ff6b6b; }

/* ---------------------------------------------------------------------------
   Binder grid (per-edition sections)
--------------------------------------------------------------------------- */

.binder-grid {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.binder-edition {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.binder-edition-header {
  margin: 0;
  font-size: 0.95em;
  font-weight: 700;
  color: var(--fg, #e5e7eb);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.binder-edition-header.locked {
  color: var(--muted, #8b9199);
  font-weight: 600;
}
.binder-edition-grid {
  display: grid;
  /* Column count is driven by --binder-cols (set on #screen-binder from
     localStorage.binderGridCols, default 3). User-tunable 1-4 via the
     header selector. */
  grid-template-columns: repeat(var(--binder-cols, 3), 1fr);
  gap: 10px;
}


.binder-edition-grid .locked-cell {
  position: relative;
  filter: grayscale(0.8) brightness(0.6);
}
.binder-edition-grid .locked-cell .lock-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.6em;
  color: rgba(255, 255, 255, 0.9);
  text-shadow: 0 1px 4px rgba(0,0,0,0.7);
  pointer-events: none;
}

/* Locked to 3 cols across breakpoints since the app is centered at 480px max. */

/* ---------------------------------------------------------------------------
   Binder trade-up mode
--------------------------------------------------------------------------- */

.binder-header {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

/* Search input (View sub-page). Browsers render a native × clear control
   on type="search" by default; we don't suppress it. The wrap is just
   here in case we need a positioned manual clear button later. */
.binder-search-wrap {
  flex: 1 1 140px;
  min-width: 140px;
  display: flex;
  align-items: center;
}
.binder-search {
  width: 100%;
  background: transparent;
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 10px;
  font-family: inherit;
  font-size: 0.95em;
  /* Let the platform render the native × clear control. */
}
.binder-search::-webkit-search-cancel-button {
  -webkit-appearance: searchfield-cancel-button;
  cursor: pointer;
}
.binder-search:focus { outline: none; border-color: var(--accent); }

/* Hide / Show missing checkbox toggle. Explicit sizing on the native
   checkbox keeps it visually aligned with the label baseline at any
   parent font-size - default checkboxes render with weird vertical
   offset depending on the OS/browser. */
.binder-hide-missing-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85em;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  white-space: nowrap;
}
.binder-hide-missing-label input {
  width: 14px;
  height: 14px;
  margin: 0;
  flex: 0 0 14px;
  cursor: pointer;
  accent-color: var(--accent);
}

.binder-grid-cols-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85em;
  line-height: 1;
  color: var(--muted);
}
.binder-grid-cols {
  background: transparent;
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 8px;
  font-family: inherit;
  font-size: 0.95em;
  cursor: pointer;
}
.binder-grid-cols:focus { outline: none; border-color: var(--accent); }

/* NEW section: pinned above the per-edition grid when the user has
   unseen acquisitions. Mirrors the standard edition section layout. */
.binder-new-section {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 18px;
}
.binder-new-section[hidden] { display: none; }
.binder-new-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.binder-new-label {
  font-size: 0.8em;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.binder-new-mark-all {
  font-size: 0.72em;
  padding: 4px 10px;
  min-height: 0;
}

/* Sticky chrome on the Trade Up sub-page: keeps toolbar + tier filter
   pinned to the top of the scroll container while the grid scrolls.
   Negative margins on the outer subpage padding (16px) so the chrome
   reaches the edges; the inner toolbar has its own padding + radius. */
.binder-tradeup-chrome {
  position: sticky;
  /* Sticks flush below the unified sticky toolbar. --subnav-h must match
     the actual rendered subnav height (34px = 32px content + 2px border)
     or there will be a visible gap. Top padding gives the toolbar
     breathing room from the subnav. */
  top: var(--subnav-h);
  z-index: 30;
  background: var(--panel);
  margin: 0 -16px 10px;
  padding: 10px 16px 6px;
  box-shadow: 0 4px 12px -4px rgba(0,0,0,0.55);
}

.binder-tradeup-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  margin-bottom: 10px;
  position: relative;
  z-index: 31;
}

.binder-tradeup-toolbar .selected-count { flex: 1; min-width: 0; }
.binder-tradeup-toolbar .tradeups-today {
  font-size: 0.78em;
  color: var(--muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0 6px;
  border-left: 1px solid var(--border);
  white-space: nowrap;
}
.binder-tradeup-toolbar .tradeups-today--maxed {
  color: #ff8c8c;
  letter-spacing: 0.04em;
}

/* Tier-filter + show-singles share one row to save vertical space. */
.binder-tradeup-filter-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.binder-tradeup-filter-row .tier-filter { flex: 1 1 auto; }
.binder-tradeup-filter-row .tradeup-singles-toggle {
  flex: 0 0 auto;
  font-size: 0.74em;
  white-space: nowrap;
}

.tradeup-singles-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* Match height to the tier-filter buttons so the checkbox+label
     row sits aligned in the filter strip. */
  height: 28px;
  font-size: 0.78em;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  white-space: nowrap;
  vertical-align: middle;
}
.tradeup-singles-toggle input {
  width: 14px;
  height: 14px;
  margin: 0;
  flex: 0 0 14px;
  cursor: pointer;
  accent-color: var(--accent);
  vertical-align: middle;
}

.selected-count {
  font-size: 0.75em;
  color: var(--muted);
}

.tier-filter {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 12px;
  background: var(--panel);
  position: relative;
  z-index: 31;
}

/* Inside the sticky chrome wrapper, the bottom margin lives on the
   chrome itself (10px gap before the grid) - drop the inner one to
   keep the sticky block compact. */
.binder-tradeup-chrome .tier-filter { margin-bottom: 8px; }

.tier-filter-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  border-radius: 16px;
  padding: 4px 12px;
  font-family: inherit;
  font-size: 0.72em;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  cursor: pointer;
}
.tier-filter-btn:hover { color: var(--fg); border-color: var(--fg); }
.tier-filter-btn.active { color: var(--accent); border-color: var(--accent); }

.tradeup-warning {
  color: #ff6b6b;
  font-size: 0.82em;
  padding: 8px 12px;
  border: 1px solid rgba(255,107,107,0.45);
  border-radius: 6px;
  background: rgba(255,107,107,0.08);
  margin-bottom: 8px;
}

/* Floating card view rules live in /shared/card-view.css (SSOT). */

/* ---------------------------------------------------------------------------
   Toast
--------------------------------------------------------------------------- */

.toast {
  position: fixed;
  /* Sit above the app footer (~30px tall) with a 24px gap so the toast
     reads independently and doesn't crash into the copyright line. */
  bottom: 56px;
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--fg);
  font-size: 0.78em;
  padding: 8px 16px;
  border-radius: 8px;
  opacity: 0;
  transition: opacity 0.2s, transform 0.2s;
  pointer-events: none;
  z-index: 200;
  white-space: nowrap;
  max-width: 90vw;
}
.toast.visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
/* Bolder claim-ready toast: tappable, accent border-left, larger type. */
.toast--clickable {
  font-size: 0.95em;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 12px 18px 12px 14px;
  border-left: 4px solid var(--accent);
  pointer-events: auto;
}
/* Achievement-unlocked toast: gold border + trophy prefix. Stacks
   visually with the claim-ready style if both fire (different variant
   class, same visible/transform mechanics). */
.toast--achievement {
  font-size: 0.92em;
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 12px 18px 12px 14px;
  border-left: 4px solid #FFD700;
  color: #FFD700;
}

/* Achievement tile (Profile screen). Hidden by design: only contains
   badges the user has already earned; locked achievements NEVER appear
   here. The tile collapses via a tap on its header; collapse state
   persists in localStorage. */
.achievement-tile {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  margin: 16px 0;
  overflow: hidden;
}
.achievement-tile[hidden] { display: none; }
.achievement-tile-header {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  background: transparent;
  border: none;
  cursor: pointer;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.10em;
  font-size: 0.72em;
  font-family: inherit;
  text-align: left;
  min-height: 0;
}
.achievement-tile-header:hover { color: var(--fg); }
.achievement-tile-label  { flex: 0 0 auto; }
.achievement-tile-count {
  flex: 1 1 auto;
  text-align: left;
  color: #FFD700;
  font-weight: 700;
}
.achievement-tile-caret {
  flex: 0 0 auto;
  font-size: 1.4em;
  line-height: 1;
  color: var(--fg);
  transition: transform 0.15s;
}
.achievement-tile.collapsed .achievement-tile-caret { transform: rotate(-90deg); }
.achievement-tile.collapsed .achievement-row { display: none; }
.achievement-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0 14px 12px;
  justify-content: flex-start;
}
.achievement-badge {
  background: rgba(255, 215, 0, 0.10);
  border: 1px solid rgba(255, 215, 0, 0.35);
  color: #FFD700;
  font-size: 0.75em;
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 4px 10px;
  border-radius: 999px;
  cursor: pointer;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.achievement-badge::before { content: '\1F3C6 '; }

/* Achievement info popup (cardview-styled centered modal). */
.achievement-info-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.32);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  display: flex; align-items: center; justify-content: center;
  z-index: 200;
  padding: 24px;
}
.achievement-info-card {
  background: var(--panel);
  border: 1px solid rgba(255, 215, 0, 0.45);
  border-radius: 12px;
  padding: 24px 22px 18px;
  width: min(86vw, 320px);
  text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  box-shadow: 0 0 32px rgba(255, 215, 0, 0.12);
}
.achievement-info-trophy {
  font-size: 2.4em;
  line-height: 1;
}
.achievement-info-name {
  font-family: 'Orbitron', sans-serif;
  font-size: 1.1em;
  color: #FFD700;
  letter-spacing: 0.06em;
  margin: 0;
}
.achievement-info-desc {
  color: var(--fg);
  font-size: 0.88em;
  margin: 0;
  line-height: 1.5;
}
.achievement-info-date {
  color: var(--muted);
  font-size: 0.78em;
  margin: 0;
  letter-spacing: 0.04em;
}
.achievement-info-close {
  margin-top: 8px;
  min-width: 120px;
}

/* Per-edition stats span appended inline to .binder-edition-header. */
.binder-edition-stats {
  margin-left: 1em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.85em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  text-transform: none;
}

/* ---------------------------------------------------------------------------
   Trade-up confirm view
   Custom backdrop singleton; reuses .cardview-backdrop base styles for
   the dim + close button positioning, then layers a vertical stack of
   thumbnails -> arrow -> ?-card.
--------------------------------------------------------------------------- */

.tradeup-confirm-stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 20px 16px;
  max-width: 380px;
  width: 100%;
  margin: auto;
}
.tradeup-confirm-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 1.1em;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--fg);
}
.tradeup-confirm-thumbs {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 6px;
  width: 100%;
}
.tradeup-confirm-thumb {
  position: relative;
  container-type: inline-size;
}
.tradeup-confirm-thumb .card {
  width: 100%;
}
.tradeup-confirm-thumb.last-copy {
  outline: 2px solid #ff6b6b;
  outline-offset: 1px;
  border-radius: 6%;
}
.tradeup-confirm-arrow {
  font-size: 2.4em;
  color: var(--muted);
  line-height: 1;
}
.tradeup-confirm-result {
  width: min(60vw, 180px);
  aspect-ratio: 5 / 7;
}
.tradeup-confirm-mystery {
  width: 100%;
  height: 100%;
  background: rgba(255,255,255,0.04);
  border: 1px dashed rgba(255,255,255,0.25);
  border-radius: 6%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  color: var(--muted);
}
.tradeup-confirm-mystery-glyph {
  font-family: 'Orbitron', sans-serif;
  font-size: 5em;
  font-weight: 800;
  color: rgba(255,255,255,0.55);
  line-height: 1;
}
.tradeup-confirm-mystery-label {
  font-family: 'Orbitron', sans-serif;
  font-size: 0.72em;
  letter-spacing: 0.14em;
  color: var(--fg);
}
.tradeup-confirm-backdrop .cardview-actions {
  display: flex;
  flex-direction: row;
  gap: 10px;
  justify-content: center;
  width: 100%;
  margin-top: 4px;
}
.tradeup-confirm-backdrop .cardview-actions .btn {
  flex: 1;
  max-width: 180px;
}
.tradeup-confirm-backdrop .tradeup-warning {
  width: 100%;
  text-align: center;
}

/* ---------------------------------------------------------------------------
   Utility
--------------------------------------------------------------------------- */

.loading, .error, .empty-state {
  padding: 20px;
  text-align: center;
  color: var(--muted);
  font-size: 0.82em;
}
.error { color: #ff6b6b; }

/* ---------------------------------------------------------------------------
   Leaderboard
   Sub-nav matches .binder-subnav (segmented control). Rows mirror
   .profile-stat panel styling (panel bg + border + radius). The "me"
   chip at the top of each board uses the same panel style so it visually
   anchors the list. Search shares the row style with the boards.
--------------------------------------------------------------------------- */

.leaderboard-subnav {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  margin: -16px -16px 0;
  position: sticky;
  top: 0;
  z-index: 49;
}
.leaderboard-subnav-tab {
  flex: 1;
  padding: 10px 4px;
  background: transparent;
  border: none;
  color: var(--muted);
  font-family: inherit;
  font-size: 0.72em;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 0.1s, border-color 0.1s;
  outline: none;
  -webkit-tap-highlight-color: transparent;
}
.leaderboard-subnav-tab:hover { color: var(--fg); }
.leaderboard-subnav-tab.active {
  color: #FFFFFF;
  border-bottom-color: #FFFFFF;
}

.leaderboard-subpage {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 12px;
  padding-bottom: 40px;
}
.leaderboard-subpage[hidden] { display: none; }

/* "Your rank" chip at the top of the Collectors / Rarity boards.
   Same panel style as .profile-stat so it anchors the list. Empty
   div is hidden via :empty so unauthenticated / un-ranked users
   don't see a stray panel. */
.leaderboard-me {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 14px;
  font-size: 0.85em;
  color: var(--fg);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.leaderboard-me:empty { display: none; }
.leaderboard-me-label {
  color: var(--muted);
  font-size: 0.75em;
  text-transform: uppercase;
  letter-spacing: 0.10em;
}
.leaderboard-me-value {
  font-variant-numeric: tabular-nums;
}
.leaderboard-me-rank {
  color: var(--accent);
  font-weight: 600;
}

.leaderboard-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.leaderboard-row {
  display: grid;
  grid-template-columns: 36px 1fr auto;
  align-items: center;
  gap: 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 14px;
  cursor: pointer;
  transition: border-color 0.1s, background 0.1s;
  text-align: left;
  font-family: inherit;
  color: var(--fg);
  font-size: 0.88em;
  width: 100%;
}
.leaderboard-row:hover { border-color: var(--accent); }
.leaderboard-row-rank {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.85em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.leaderboard-row-rank.is-me { color: var(--accent); }
.leaderboard-row-name {
  color: var(--fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.leaderboard-row-score {
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-size: 0.85em;
}

.leaderboard-empty {
  color: var(--muted);
  font-size: 0.8em;
  text-align: center;
  padding: 24px 8px;
}

.leaderboard-search-wrap {
  position: sticky;
  top: 32px;        /* clear the sticky subnav */
  background: var(--bg);
  padding: 8px 0 4px;
  z-index: 5;
}
.leaderboard-search {
  width: 100%;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  color: var(--fg);
  font-family: inherit;
  font-size: 0.9em;
  outline: none;
}
.leaderboard-search::placeholder { color: var(--muted); }
.leaderboard-search:focus { border-color: var(--accent); }

/* ---------------------------------------------------------------------------
   Mobile responsive
--------------------------------------------------------------------------- */

@media (max-width: 360px) {
  .top-card-display .card { width: min(80vw, 200px); }
  .binder-edition-grid { gap: 6px; }
}

/* ---------------------------------------------------------------------------
   Focus halos + tap highlight: stripped from every interactive element.
   Per product spec - the OS-style focus ring on tap/click is visual noise
   in a touch-first TMA. NOTE: this hurts keyboard navigation (no visible
   focus indicator on Tab); intentional trade-off requested by the user.
--------------------------------------------------------------------------- */

button:focus, button:focus-visible,
select:focus, select:focus-visible,
input:focus, input:focus-visible,
.nav-tab:focus, .nav-tab:focus-visible,
.binder-subnav button:focus, .binder-subnav button:focus-visible {
  outline: none;
  -webkit-tap-highlight-color: transparent;
}

/* ---------------------------------------------------------------------------
   Hide every scrollbar. Touch + trackpad scrolling still works; the
   visual gutter is just suppressed. Drives both Firefox (scrollbar-width)
   and WebKit (display: none on the pseudo-element).
--------------------------------------------------------------------------- */

.screens, .screens *, html, body { scrollbar-width: none; -ms-overflow-style: none; }
.screens::-webkit-scrollbar, *::-webkit-scrollbar { display: none; width: 0; height: 0; }

