/* ============================================================================
   Incremental Solitaire — "cozy card room"
   Warm paper UI, vintage-green felt play surface, gold accents, plum prestige.
   Design tokens up top; component styles below. All class names are JS hooks —
   restyled, never renamed.
   ========================================================================== */

:root {
  /* — Paper / warm neutrals — */
  --paper:        #efe3cc;   /* page */
  --paper-2:      #f6eeda;   /* raised surfaces (panel, cards-in-panel) */
  --paper-3:      #fcf7ec;   /* highest surfaces */
  --line:         #d8c7a3;   /* hairline borders on warm surfaces */
  --line-soft:    #e6d8ba;

  /* — Ink — */
  --ink:          #2e2519;
  --ink-2:        #5d4d36;   /* secondary text */
  --ink-3:        #8a795d;   /* muted text */

  /* — Felt play surface — */
  --felt:         #2f4f43;
  --felt-2:       #3a5e50;
  --felt-edge:    #233b32;
  --felt-ink:     #e9e2cf;   /* text on felt */
  --felt-ink-2:   #b9c4b3;

  /* — Wood / brand brown — */
  --wood:         #8b6a3b;
  --wood-dark:    #6e5128;
  --wood-deep:    #5a4120;

  /* — Gold accent (currency / affordability) — */
  --gold:         #c8932f;
  --gold-bright:  #e7b54e;
  --gold-soft:    rgba(201, 147, 47, 0.16);

  /* — Card colors — */
  --card-face:    #fffdf7;
  --card-red:     #c0392b;
  --card-black:   #2b2519;

  /* — Prestige (plum) — */
  --plum:         #221c33;
  --plum-2:       #2e2647;
  --plum-line:    #443a63;
  --plum-ink:     #ece7fb;
  --violet:       #8a6bff;
  --violet-2:     #b08cff;

  /* — Radii — */
  --r-sm: 7px;
  --r:    11px;
  --r-lg: 16px;
  --r-xl: 22px;
  --r-pill: 999px;

  /* — Elevation — */
  --sh-1: 0 1px 2px rgba(60, 42, 18, 0.10);
  --sh-2: 0 2px 8px rgba(60, 42, 18, 0.12), 0 1px 2px rgba(60, 42, 18, 0.10);
  --sh-3: 0 8px 24px rgba(40, 28, 12, 0.18), 0 2px 6px rgba(40, 28, 12, 0.12);
  --sh-card: 0 2px 5px rgba(20, 30, 24, 0.28), 0 8px 18px rgba(20, 30, 24, 0.14);

  /* — Type — */
  --font-display: 'Fraunces', 'Iowan Old Style', Georgia, serif;
  --font-ui: 'Nunito', ui-rounded, 'SF Pro Rounded', system-ui, sans-serif;

  /* — Layout — */
  --shell-max: 1240px;
  --panel-w: 320px;
  --ease: cubic-bezier(0.32, 0.72, 0.36, 1);

  /* — Cards (scalable) — one knob sizes the whole card so phones can shrink it.
     Desktop stays at scale 1 → 70×100 with the original type. The mobile media
     query at the bottom lowers all three together. --card-w / --card-h are kept
     as PLAIN px values (no calc) because the JS fan/drop math parseFloats them. */
  --card-scale: 1;
  --card-w: 70px;
  --card-h: 100px;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }

body {
  font-family: var(--font-ui);
  color: var(--ink);
  background-color: var(--paper);
  /* soft warm atmosphere: a top glow + a faint paper grain */
  background-image:
    radial-gradient(120% 80% at 50% -10%, rgba(255, 248, 232, 0.85), transparent 55%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E");
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

#app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* ============================ Topbar ===================================== */

.topbar {
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  gap: 1rem;
  /* Safe-area aware: max() with the (0 on desktop) insets leaves desktop exactly
     as before, but clears the notch / rounded corners on phones in any rotation. */
  padding: max(0.6rem, env(safe-area-inset-top))
           max(clamp(0.9rem, 3vw, 2rem), env(safe-area-inset-right))
           0.6rem
           max(clamp(0.9rem, 3vw, 2rem), env(safe-area-inset-left));
  background: linear-gradient(180deg, rgba(246, 238, 218, 0.92), rgba(238, 226, 200, 0.88));
  backdrop-filter: blur(10px) saturate(1.1);
  -webkit-backdrop-filter: blur(10px) saturate(1.1);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset, 0 6px 20px -12px rgba(60, 42, 18, 0.35);
}

/* the coin bank — a prominent gold pill sitting on the felt */
.coins {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.5rem;
  letter-spacing: 0.01em;
  padding: 0.3rem 1.1rem 0.3rem 0.85rem;
  color: var(--gold-bright);
  background: linear-gradient(180deg, rgba(22, 32, 26, 0.55), rgba(10, 16, 12, 0.62));
  border: 1.5px solid var(--gold);
  border-radius: var(--r-pill);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 4px 14px rgba(0, 0, 0, 0.32);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
  white-space: nowrap;
  /* Equal-width digits: the count ticking up must not change the pill's width
     (it used to nudge the whole header on every landing coin). */
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum';
}
.coins .coin-icon { font-size: 1.35rem; filter: saturate(1.15) drop-shadow(0 1px 1px rgba(0, 0, 0, 0.4)); }
/* Live stat chips inside the bank: total coin multiplier + recent win rate. */
.coin-stats {
  display: inline-flex; align-items: center; gap: 0.3rem;
  margin-left: 0.15rem;
}
.coin-stats .stat-chip {
  font-family: var(--font-ui); font-weight: 800; font-size: 0.72rem;
  letter-spacing: 0;
  color: rgba(252, 247, 236, 0.85);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(231, 181, 78, 0.45);
  border-radius: var(--r-pill);
  padding: 0.12rem 0.45rem;
  white-space: nowrap;
  cursor: default;
}
#coin-count { display: inline-block; min-width: 1ch; }

.title {
  flex: 1;
  margin: 0;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.1rem, 1rem + 1vw, 1.6rem);
  letter-spacing: 0.01em;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.build-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-left: 0.6rem;
  padding: 5px 13px;
  font-family: var(--font-ui);
  vertical-align: middle;
  background: var(--paper-3);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  box-shadow: var(--sh-1);
}
.build-tag .build-label {
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.build-tag .build-emoji {
  font-size: 1.15rem;
  letter-spacing: 2px;
  line-height: 1;
}

.topbar-actions { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; justify-content: flex-end; }

/* feedback flash when logging a frustration press */
#frustrated.pulse { animation: frustrated-pulse 360ms var(--ease); }
@keyframes frustrated-pulse {
  0% { transform: scale(1); }
  40% { transform: scale(1.18) rotate(-4deg); background: #f6d7c4; border-color: var(--wood); }
  100% { transform: scale(1); }
}

/* ============================ Buttons =================================== */

.btn-primary,
.btn-ghost {
  font: inherit;
  font-weight: 700;
  cursor: pointer;
  border-radius: var(--r-pill);
  transition: transform 0.12s var(--ease), background 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.btn-primary:active,
.btn-ghost:active { transform: translateY(1px); }

.btn-primary {
  border: none;
  color: #fff;
  padding: 0.5rem 1.15rem;
  background: linear-gradient(180deg, #a07c45, var(--wood-dark));
  box-shadow: 0 2px 0 var(--wood-deep), var(--sh-2);
}
.btn-primary:hover { background: linear-gradient(180deg, #b08951, #7a5a2c); }
.btn-primary:active { box-shadow: 0 1px 0 var(--wood-deep); }

.btn-ghost {
  background: var(--paper-3);
  border: 1px solid var(--line);
  color: var(--ink-2);
  padding: 0.4rem 0.7rem;
  box-shadow: var(--sh-1);
  line-height: 1;
  text-decoration: none;
}
.btn-ghost:hover { background: #fff; border-color: var(--wood); color: var(--ink); box-shadow: var(--sh-2); }
.btn-ghost.muted { opacity: 0.45; }

/* Debug dropdown — sim/editor/stuck/stats live here, out of a playtester's way */
.debug-menu { position: relative; display: inline-flex; }
.debug-pop {
  position: absolute; right: 0; top: calc(100% + 6px);
  display: flex; flex-direction: column; gap: 2px;
  min-width: 190px; padding: 6px; z-index: 60;
  background: var(--paper-3);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--sh-3);
}
.debug-pop[hidden] { display: none; }
.debug-item {
  display: block; width: 100%; text-align: left; text-decoration: none;
  font: inherit; font-size: 0.85rem; color: var(--ink-2);
  background: none; border: none; border-radius: 8px;
  padding: 0.42rem 0.6rem; cursor: pointer; white-space: nowrap; line-height: 1.2;
}
.debug-item:hover { background: var(--paper); color: var(--ink); }

/* Shown only inside the phone breakpoints (e.g. Reset moved into the 🐞 menu). */
.mobile-only { display: none; }

:where(button, a, input):focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* ============================ Layout ==================================== */

.play-area {
  flex: 1;
  width: 100%;
  max-width: var(--shell-max);
  margin: 0 auto;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(1rem, 2.5vw, 2rem);
  padding: clamp(1rem, 2.5vw, 2.25rem);
}

/* The felt play surface: holds the coin bank + the board grid. */
.felt {
  flex: 0 1 auto;
  min-width: 0;
  /* Stand a generous, viewport-driven felt height so the play surface feels like
     a real table; columns compress (via --fan) to fit rather than growing it.
     It only grows past this if a column is too tall even at minimum spacing. */
  min-height: clamp(440px, calc(100dvh - 8rem), 800px);
  align-self: flex-start;
  border-radius: var(--r-xl);
  padding: clamp(1.25rem, 2.5vw, 1.9rem);
  padding-bottom: clamp(2rem, 4vw, 3rem);
  /* vintage felt: directional sheen + edge vignette + faint weave */
  background:
    radial-gradient(130% 100% at 50% -5%, rgba(255, 255, 255, 0.10), transparent 55%),
    linear-gradient(180deg, var(--felt-2), var(--felt));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.10),
    inset 0 0 0 1px rgba(0, 0, 0, 0.20),
    inset 0 0 90px rgba(0, 0, 0, 0.28),
    var(--sh-3);
  position: relative;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: clamp(0.8rem, 2vw, 1.4rem);
}
.felt::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0.5;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)' opacity='0.05'/%3E%3C/svg%3E");
}
.boards.cols-2 { grid-template-columns: 1fr 1fr; }

/* the board grid inside the felt (sits above the felt's noise/sheen) */
.boards {
  position: relative; z-index: 1;
  flex: 1 1 auto; min-width: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
}

/* the coin "bank" sitting on the felt, above the boards */
/* Coin bank, in the header's flow just after the "Game N" label; the action
   group is pinned to the right (margin-left:auto), so the gap between absorbs
   the bank's width changes — it grows in place WITHOUT pushing the buttons or
   reflowing the felt. The count uses tabular numerals + a reserved width so a
   ticking total never jitters; the coin-hit pulse is a transform (no reflow). */
.board-head .coins {
  font-size: 1.15rem;
  padding: 0.2rem 0.85rem 0.2rem 0.65rem;
}
.board-head .coins .coin-icon { font-size: 1.05rem; }
.board-head .board-actions { margin-left: auto; }
/* Fixed-width count slot. The bank string is kept to <=5 chars (full below
   100k, abbreviated above — see fmtBank), so this slot never changes width:
   the number can't shove the chips, nor widen the header into the buttons. */
.board-head #coin-count { min-width: 5ch; text-align: left; }
.board-head .coins { flex-shrink: 0; }
/* The bank rides ABOVE its neighbors so the coin-hit shake can briefly scale /
   overlap them rather than push them aside — overlap is fine while it vibrates. */
.board-head .coins { position: relative; z-index: 3; }
/* Action buttons keep their labels on ONE line and never shrink, so a busy
   header can't wrap "New Game" / "Undo" / "Auto" onto two rows. */
.btn-new-this, .btn-undo, .btn-auto, .btn-cascade { white-space: nowrap; flex-shrink: 0; }

.side-panel {
  flex: 0 0 var(--panel-w);
  align-self: stretch;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-height: calc(100vh - 5rem);
  overflow: auto;
  padding-right: 2px;
}

/* Side-panel head: holds the hoisted coin bank + New Game in the landscape app
   layout (see the landscape @media block). Hidden everywhere else — the bank
   rides in the felt header there. Declared HERE, before the media queries, so the
   landscape `display: flex` overrides it instead of the other way around. */
.panel-head { display: none; }

/* ============================ Board ===================================== */

.board { display: flex; flex-direction: column; gap: 1.1rem; position: relative; z-index: 1; }

.board-head {
  display: flex; align-items: center; gap: 0.5rem;
  /* ONE line, always: auto-mode chips (tank readout, ⏸) must never push the
     header onto a second row — that bounced the whole felt. flex-start + the
     action group's margin-left:auto keeps label/bank left and buttons right,
     with a flexible gap that soaks up the bank's width changes. */
  justify-content: flex-start;
  flex-wrap: nowrap;
  /* CRITICAL: the header must NOT drive the board's (and thus the felt's) width
     — otherwise a growing coin total (more digits) widens the felt, and since
     the play area centers the felt, the whole board jitters side-to-side as the
     count animates up. width:0 + min-width:100% makes the header take the
     board's width (set by the 7-column tableau) instead of dictating it; the
     bank grows into the flexible gap, layout stays put. */
  width: 0;
  min-width: 100%;
}
/* Action group sits at the row's end; New Game is last so it stays put as
   buttons appear. (No margin-left:auto — space-between balances the coin bank.) */
.board-actions { display: flex; align-items: center; gap: 0.5rem; }
.board-head > span:first-child {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--felt-ink);
  letter-spacing: 0.01em;
}

/* per-board buttons live on the felt → light, outlined treatment */
.btn-new-this, .btn-undo, .btn-auto {
  font: inherit; font-weight: 700; font-size: 0.82rem; cursor: pointer;
  border-radius: var(--r-pill);
  padding: 0.28rem 0.8rem;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.28);
  color: var(--felt-ink);
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.12s var(--ease);
}
/* New Game is the primary per-board action — a touch larger/bolder to "meet in
   the middle" with the coin bank now sharing its row. */
.btn-new-this { font-size: 0.95rem; font-weight: 800; padding: 0.34rem 1.05rem; }
.btn-new-this:hover, .btn-undo:hover:not(:disabled), .btn-auto:hover { background: rgba(255, 255, 255, 0.18); }
.btn-new-this:active, .btn-undo:active, .btn-auto:active { transform: translateY(1px); }
.btn-undo:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-auto.on { background: var(--violet); border-color: var(--violet-2); color: #fff; }
.btn-auto.paused { background: rgba(255,255,255,0.06); }

.top-row { display: flex; gap: clamp(1rem, 3vw, 2.25rem); flex-wrap: wrap; }
.foundations { display: flex; gap: 0.5rem; }
/* roomier gap so the drawn cards don't crowd the stock */
.stock-waste { display: flex; gap: clamp(1rem, 2.6vw, 1.85rem); }

/* light section signage — tells a new player what each area is, low-key on felt */
.board-section { display: flex; flex-direction: column; gap: 0.3rem; }
.section-label {
  font-family: var(--font-display);
  font-size: 0.6rem; font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.32);
  padding-left: 2px; user-select: none; pointer-events: none;
}

/* ============================ Piles & cards ============================= */

.pile {
  width: var(--card-w); height: var(--card-h);
  border-radius: var(--r);
  display: flex; align-items: center; justify-content: center;
  font-size: calc(1.6rem * var(--card-scale));
  color: rgba(255, 255, 255, 0.22);
  /* empty placeholder: soft inset well on the felt */
  border: 1.5px solid rgba(255, 255, 255, 0.14);
  background: rgba(0, 0, 0, 0.14);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.25);
}
.pile.foundation { font-size: calc(1.9rem * var(--card-scale)); color: rgba(255, 255, 255, 0.3); position: relative; }
/* Towers stack the top + the card beneath, both filling the slot (the under one
   only shows while the new top card is flying in on a drop). */
.pile.foundation .card { position: absolute; top: 0; left: 0; }

.pile.waste {
  width: auto; min-width: var(--card-w);
  align-items: stretch; justify-content: flex-start;
  padding: 0; border-color: transparent; background: none; box-shadow: none;
}
.pile.waste:not(:empty) { border-color: transparent; }
.pile.waste .card { flex-shrink: 0; }
.pile.waste .card + .card { margin-left: calc(-45px * var(--card-scale)); }

.tableau { display: flex; gap: clamp(0.5rem, 1.4vw, 0.85rem); padding-top: 0.5rem; }
.column { width: var(--card-w); min-height: var(--card-h); display: flex; flex-direction: column; position: relative; }
/* Stacked cards overlap by --fan (a negative top-margin set live by
   fitTableauSpacing to fit the felt). Same rule drives the drag/touch ghosts so
   they cascade identically. */
.column .card:not(:first-child),
.touch-ghost .card + .card,
.drag-ghost .card + .card { margin-top: var(--fan, -56px); }
.empty-slot {
  width: var(--card-w); height: var(--card-h);
  border-radius: var(--r);
  border: 1.5px dashed rgba(255, 255, 255, 0.22);
  background: rgba(0, 0, 0, 0.10);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.2);
}

.card {
  position: relative;
  width: var(--card-w); height: var(--card-h);
  border-radius: var(--r);
  background: linear-gradient(160deg, #fffefb, var(--card-face) 60%, #f6eddd);
  border: 1px solid rgba(120, 95, 55, 0.35);
  box-shadow: var(--sh-card);
  font-family: var(--font-ui);
  font-weight: 800;
  user-select: none;
  transition: box-shadow 0.15s ease, transform 0.12s var(--ease);
}
.card[data-source] { cursor: grab; touch-action: none; } /* touch-action: enables pointer-drag on touch */

/* Floating clone that follows the finger during a touch drag. */
.touch-ghost {
  position: fixed; z-index: 2000; width: var(--card-w);
  display: flex; flex-direction: column;
  pointer-events: none; opacity: 0.92;
  filter: drop-shadow(0 8px 12px rgba(20, 30, 24, 0.4));
}

/* Drop-target landing highlight: a dashed outline the SIZE of the card (or run)
   being dragged, positioned at the exact landing slot (--land-top / --land-height
   set in JS — the bottom of the column, as tall as the run), that fades in by
   PROXIMITY to the cursor (--near 0..1) so moving between two legal spots
   crossfades smoothly. Only legal targets get any --near. */
[data-drop-target] { position: relative; }
[data-drop-target]::after {
  content: '';
  position: absolute;
  left: -2px; right: -2px;
  top: calc(var(--land-top, 0px) - 2px);
  height: calc(var(--land-height, 100px) + 4px);
  border: 2px dashed var(--gold-bright);
  border-radius: var(--r);
  opacity: var(--near, 0);
  transition: opacity 140ms ease;
  pointer-events: none;
  z-index: 4;
  box-sizing: border-box;
}
.card[data-source]:hover { box-shadow: var(--sh-card), 0 0 0 1.5px var(--gold-bright); transform: translateY(-1px); }

/* face-down: warm woven back with an inset frame */
.card.face-down {
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,0.05) 0 7px, transparent 7px 14px),
    linear-gradient(150deg, #8d6c3e, var(--wood-dark));
  border-color: var(--wood-deep);
}
.card.face-down::before {
  content: '';
  position: absolute; inset: 5px;
  border-radius: 7px;
  border: 1.5px solid rgba(255, 245, 220, 0.22);
  background:
    radial-gradient(60% 50% at 50% 45%, rgba(255, 240, 210, 0.10), transparent 70%);
}

.card.red   { color: var(--card-red); }
.card.black { color: var(--card-black); }

/* corner indices + center pip — classic stacked rank-over-suit (the fully
   visible top card of each pile/column). */
.card .cc {
  position: absolute;
  display: flex; flex-direction: column; align-items: center;
  line-height: 0.92;
}
.card .cc b { font-size: calc(1.25rem * var(--card-scale)); font-weight: 800; letter-spacing: -0.02em; }
.card .cc i { font-style: normal; font-size: calc(1rem * var(--card-scale)); margin-top: 1px; }
.card .cc.tl { top: calc(5px * var(--card-scale)); left: calc(6px * var(--card-scale)); }
.card .cc.br { bottom: calc(5px * var(--card-scale)); right: calc(6px * var(--card-scale)); transform: rotate(180deg); }

/* Covered cards in a tight stack: rank and suit SIDE BY SIDE ("7♠") so the whole
   index lives in the short strip that peeks out above the next card. */
.card.compact .cc { flex-direction: row; align-items: center; gap: 1px; line-height: 1; }
.card.compact .cc i { margin-top: 0; }
.card .pip {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: calc(2.8rem * var(--card-scale));
  opacity: 0.16;
}

/* "Send them all!" roll-up tally: a big gold running total on a dark felt chip
   over the board; pops on each card, then DETONATES into confetti + coins. */
.cascade-tally {
  position: fixed; z-index: 1500;
  transform: translate(-50%, -50%);
  text-align: center;
  pointer-events: none;
  padding: 0.65rem 1.7rem 0.75rem;
  background: linear-gradient(180deg, rgba(22, 32, 26, 0.82), rgba(10, 16, 12, 0.88));
  border: 2px solid var(--gold);
  border-radius: 18px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.5), 0 0 26px rgba(231, 181, 78, 0.28),
              inset 0 1px 0 rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.cascade-tally-num {
  font-family: var(--font-display);
  font-size: 3.2rem; font-weight: 800; line-height: 1.05;
  color: var(--gold-bright);
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.55), 0 0 22px rgba(231, 181, 78, 0.5);
}
.cascade-tally.pop .cascade-tally-num { animation: tally-pop 200ms ease-out; }
@keyframes tally-pop { 0% { transform: scale(1.14); } 100% { transform: scale(1); } }
.cascade-tally-sub {
  font-family: var(--font-ui); font-weight: 800; font-size: 0.85rem;
  color: #fcf7ec; opacity: 0.85;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}
/* The detonation: a fast blow-out as the confetti + coin burst takes over. */
.cascade-tally.done { animation: tally-done 0.45s ease-out forwards; }
@keyframes tally-done {
  0% { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.4); }
}

/* 💰 Coin log (debug): a BG-style event feed of payout formulas, newest on top.
   pointer-events: none so it never blocks the felt under it. */
.coin-log {
  position: fixed; left: 10px; bottom: 10px; z-index: 900;
  display: flex; flex-direction: column; gap: 2px;
  max-width: min(540px, 92vw);
  pointer-events: none;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.72rem; line-height: 1.35;
}
.coin-log-row {
  color: #e9dfc8;
  background: rgba(12, 18, 14, 0.84);
  border: 1px solid rgba(231, 181, 78, 0.32);
  border-radius: 6px;
  padding: 0.16rem 0.5rem;
  animation: coin-log-in 180ms ease-out;
}
.coin-log-row:first-child { color: #fff; border-color: rgba(231, 181, 78, 0.75); }
@keyframes coin-log-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* Golden card (prestige perk): gilded face with a slow sweeping sheen — pays
   ×10, so it should read as treasure at a glance without hiding the pips. */
.card.golden {
  background: linear-gradient(160deg, #fffbe8 0%, #f9ecbe 45%, #fff6d6 100%);
  border-color: #c8932f;
  box-shadow: var(--sh-card), 0 0 0 1.5px rgba(200, 147, 47, 0.9), 0 0 10px 1px rgba(231, 181, 78, 0.55);
  overflow: hidden;
}
.card.golden::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 32%, rgba(255, 255, 255, 0.7) 48%, transparent 64%);
  transform: translateX(-110%);
  animation: golden-sheen 3s ease-in-out infinite;
  pointer-events: none;
}
@keyframes golden-sheen {
  0% { transform: translateX(-110%); }
  55%, 100% { transform: translateX(110%); }
}

/* sparkle: golden glow on auto-sent cards */
.card.sparkle::after {
  content: '';
  position: absolute; inset: -3px;
  border-radius: 13px;
  box-shadow: 0 0 18px 5px rgba(231, 181, 78, 0.95);
  pointer-events: none;
  animation: sparkle-fade 820ms ease-out forwards;
}
@keyframes sparkle-fade { 0% { opacity: 0; } 18% { opacity: 1; } 100% { opacity: 0; } }

/* ghost card swooping to a foundation (path driven by Web Animations) */
.fly-card {
  position: fixed; margin: 0; z-index: 1500; pointer-events: none;
  box-shadow: var(--sh-card), 0 0 16px 3px rgba(231, 181, 78, 0.6);
}
/* glowing mote trailing the swoop */
.fly-spark {
  position: fixed; z-index: 1499; pointer-events: none;
  width: 8px; height: 8px; border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, var(--gold-bright) 45%, transparent 72%);
  filter: drop-shadow(0 0 4px rgba(255, 225, 150, 0.9));
}
/* cards bursting out of the foundations on a win */
.win-card { position: fixed; margin: 0; z-index: 1520; pointer-events: none; box-shadow: var(--sh-card); }

/* clicked card with no legal auto-move: the locked-column shake + a red ring */
.card.deny,
.card[data-source]:hover.deny { /* the red "no" ring beats the gold hover ring */
  animation: deny-shake 360ms ease-in-out;
  box-shadow: var(--sh-card), 0 0 0 2px #d8504a, 0 0 12px 2px rgba(216, 80, 74, 0.6);
  /* no z-index bump: a denied card (and its run) shouldn't sort above its neighbours */
}
/* New Game button shimmers after a win */
.btn-primary.shimmer { animation: ng-shimmer 1.3s ease-in-out infinite; }
@keyframes ng-shimmer {
  0%, 100% { box-shadow: 0 2px 0 var(--wood-deep), var(--sh-2); }
  50%      { box-shadow: 0 2px 0 var(--wood-deep), 0 0 18px 5px rgba(231, 181, 78, 0.9); }
}
@media (prefers-reduced-motion: reduce) {
  .card.deny { animation: none; }
  .btn-primary.shimmer { animation: none; box-shadow: 0 2px 0 var(--wood-deep), 0 0 14px 3px rgba(231, 181, 78, 0.7); }
}

/* badges (👁 etc.) */
.badge-strip {
  position: absolute; top: 4px; right: 4px;
  display: flex; flex-direction: column; gap: 2px; align-items: flex-end;
  pointer-events: none; z-index: 2;
}
.badge {
  font-size: 0.85rem; line-height: 1;
  background: rgba(255, 250, 240, 0.95);
  border-radius: 6px; padding: 1px 4px;
  box-shadow: var(--sh-1);
}

.stock { position: relative; }

/* xray chip on the visible top edge of a locked/face-down tableau card */
.xray-chip {
  position: absolute; top: 5px; left: 6px;
  background: rgba(255, 250, 240, 0.96);
  padding: 1px 5px; border-radius: 5px;
  font-size: 0.75rem; font-weight: 800; line-height: 1.15;
  box-shadow: var(--sh-1); pointer-events: none; z-index: 2;
}
.xray-chip.red { color: var(--card-red); }
.xray-chip.black { color: var(--card-black); }

/* foundation lookahead ring */
.card.hint-target {
  box-shadow: 0 0 0 2px var(--hint-color), 0 0 14px 2px var(--hint-color), var(--sh-card);
}
.card.hint-red { --hint-color: #e0564a; }
.card.hint-black { --hint-color: #4f86e0; }

/* "playing this helps a foundation" — a golden shimmer that pulses, plus a
   little wiggle every ~5s to draw the eye. In-universe nudge, no badge. */
.card.legal-hint {
  z-index: 4;
  animation: hint-glow 2.1s ease-in-out infinite, hint-wiggle 5s ease-in-out infinite;
}
@keyframes hint-glow {
  0%, 100% { box-shadow: var(--sh-card), 0 0 0 2px var(--gold), 0 0 9px 2px rgba(231, 181, 78, 0.4); }
  50%      { box-shadow: var(--sh-card), 0 0 0 2px var(--gold-bright), 0 0 20px 5px rgba(231, 181, 78, 0.8); }
}
@keyframes hint-wiggle {
  0%, 84%, 100% { transform: translateY(0) rotate(0deg); }
  88% { transform: translateY(-5px) rotate(-3.5deg); }
  92% { transform: translateY(-4px) rotate(3.5deg); }
  96% { transform: translateY(-1px) rotate(-1deg); }
}
/* Covered cards in a hinted run: glow with the run, but no wiggle (a transform
   would break the tight stacked overlap) and no z-index bump (keep stack order). */
.card.legal-hint-run {
  animation: hint-glow 2.1s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .card.legal-hint,
  .card.legal-hint-run {
    animation: none;
    box-shadow: var(--sh-card), 0 0 0 2px var(--gold-bright), 0 0 14px 3px rgba(231, 181, 78, 0.6);
  }
}

/* stock pile lookahead chips */
.stock-hint-strip {
  position: absolute; top: 5px; right: 5px;
  display: flex; flex-direction: column; gap: 2px; align-items: flex-end;
  pointer-events: none; z-index: 2;
}
.stock-hint-chip {
  background: rgba(255, 250, 240, 0.96);
  padding: 1px 5px; border-radius: 4px;
  font-size: 0.7rem; font-weight: 800; line-height: 1.15;
  box-shadow: var(--sh-1);
}
.stock-hint-chip.red { color: var(--card-red); }
.stock-hint-chip.black { color: var(--card-black); }

/* locked columns */
.column.locked { cursor: not-allowed; }
.column.locked .card { filter: brightness(0.82) saturate(0.65); }
.lock-overlay {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.7rem;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.55));
  pointer-events: none; z-index: 3;
}
/* the lock dropping onto a locked column at the end of a deal */
.lock-overlay.slam { animation: lock-slam 380ms cubic-bezier(0.3, 1.5, 0.5, 1) both; }
@keyframes lock-slam {
  0%   { transform: translateY(-72px) scale(2.8); opacity: 0; }
  60%  { transform: translateY(0) scale(0.8); opacity: 1; }
  76%  { transform: scale(1.12); }
  100% { transform: scale(1); opacity: 1; }
}

/* shockwave: a card jolts upward as the lock's impact ripples up the column */
.card.ripple { animation: card-ripple 300ms cubic-bezier(0.3, 1.3, 0.5, 1); }
@keyframes card-ripple {
  0%   { transform: translateY(0); }
  40%  { transform: translateY(-11px); }
  72%  { transform: translateY(3px); }
  100% { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .lock-overlay.slam, .card.ripple { animation: none; }
}
.column.deny { animation: deny-shake 360ms ease-in-out; }
.column.deny .card { box-shadow: var(--sh-card), 0 0 0 2px #d8504a, 0 0 12px 2px rgba(216, 80, 74, 0.7); }
@keyframes deny-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-5px); }
  40% { transform: translateX(5px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(3px); }
}

/* drag image container */
.drag-ghost {
  position: fixed; top: 0; left: -9999px; width: var(--card-w);
  display: flex; flex-direction: column; pointer-events: none;
}

/* ============================ Coins FX ================================= */

.coins #coin-count { transition: transform 120ms ease-out; }
#coin-count.tick { animation: coin-pop 220ms ease-out; }
@keyframes coin-pop {
  0% { transform: scale(1); color: inherit; }
  40% { transform: scale(1.35); color: var(--gold); }
  100% { transform: scale(1); color: inherit; }
}
/* the whole coin pill "catches" arriving coins with a gold flash */
.coins.coin-hit { animation: coin-hit 300ms ease-out; }
@keyframes coin-hit {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.12); border-color: var(--gold-bright); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 0 18px 3px rgba(231, 181, 78, 0.9); }
  100% { transform: scale(1); }
}

/* Big black-outlined "+N" that pops, lingers, then swells and bursts apart
   (the burst at ~58% lines up with EXPLODE_AT in render.js, when it explodes
   into coins). 900ms total. */
.coin-pop {
  position: fixed; pointer-events: none; z-index: 1600;
  font-family: var(--font-display);
  font-weight: 900; font-size: 2.4rem; line-height: 1;
  color: var(--gold-bright);
  -webkit-text-stroke: 3px #17100a;
  paint-order: stroke fill;
  text-shadow: 0 3px 4px rgba(0, 0, 0, 0.55), 0 0 16px rgba(255, 220, 130, 0.7);
  transform: translate(-50%, -50%);
  animation: coin-pop-burst 900ms cubic-bezier(0.2, 0.85, 0.3, 1) forwards;
}
@keyframes coin-pop-burst {
  0%   { opacity: 0; transform: translate(-50%, -40%) scale(0.4); }
  12%  { opacity: 1; transform: translate(-50%, -62%) scale(1.5); }   /* pop, overshoot */
  24%  { transform: translate(-50%, -66%) scale(1.12); }
  58%  { opacity: 1; transform: translate(-50%, -70%) scale(1.12); }  /* linger */
  74%  { opacity: 1; transform: translate(-50%, -74%) scale(1.7); }   /* swell */
  100% { opacity: 0; transform: translate(-50%, -82%) scale(2.5); }   /* explode */
}

/* face-down ghosts sweeping from the waste back onto the deck on recycle */
.recycle-ghost {
  position: fixed; z-index: 1550; pointer-events: none;
  width: var(--card-w); height: var(--card-h);
}

/* individual coins arcing from the earn point into the counter */
.coin-fly {
  position: fixed; pointer-events: none; z-index: 1590;
  width: 1em; height: 1em; border-radius: 50%;
  font-size: 1.6rem; line-height: 1;
  will-change: transform, opacity;
}
/* Minted metal coins drawn in CSS (identical on every platform — no emoji): a
   layered body gradient with an off-centre specular, a raised rim, an engraved
   inner ring, and a softly embossed star. Per-metal colour ramp via vars. */
.coin-fly.coin-copper, .coin-fly.coin-silver, .coin-fly.coin-gold {
  background:
    radial-gradient(circle at 34% 26%, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0) 34%),
    radial-gradient(circle at 50% 52%, var(--c-hi), var(--c-mid) 56%, var(--c-lo));
  box-shadow:
    inset 0 0 0 0.06em var(--c-rim),
    inset 0 0.06em 0.06em rgba(255, 255, 255, 0.55),
    inset 0 -0.1em 0.12em rgba(0, 0, 0, 0.32),
    0 0.05em 0.12em rgba(0, 0, 0, 0.42);
}
.coin-fly.coin-copper::before, .coin-fly.coin-silver::before, .coin-fly.coin-gold::before {
  content: ''; position: absolute; inset: 0.17em; border-radius: 50%;
  box-shadow: inset 0 0 0 0.035em var(--c-ring), inset 0 0.05em 0.06em rgba(0, 0, 0, 0.2);
}
.coin-fly.coin-copper::after, .coin-fly.coin-silver::after, .coin-fly.coin-gold::after {
  content: '★'; position: absolute; inset: 0; display: grid; place-items: center;
  font-size: 0.52em; line-height: 1; color: var(--c-lo); opacity: 0.45;
  text-shadow: 0 0.025em 0 rgba(255, 255, 255, 0.45);
}
.coin-fly.coin-gold   { --c-hi: #fff3c6; --c-mid: #e8b84f; --c-lo: #9f6f1d; --c-rim: #caa24a; --c-ring: rgba(120, 84, 22, 0.5);
  filter: drop-shadow(0 0 0.16em rgba(231, 181, 78, 0.75)); }
.coin-fly.coin-silver { --c-hi: #ffffff; --c-mid: #c7ced7; --c-lo: #828d99; --c-rim: #aab2bd; --c-ring: rgba(78, 88, 99, 0.45); }
.coin-fly.coin-copper { --c-hi: #ffd9b2; --c-mid: #c47f44; --c-lo: #7d4a22; --c-rim: #b07a47; --c-ring: rgba(90, 55, 26, 0.5); }
/* Jackpot tier keeps the 💰 emoji (rare, ≥50k) with a golden glow. */
.coin-fly.coin-bag {
  display: grid; place-items: center; border-radius: 0;
  filter: drop-shadow(0 0 0.3em rgba(231, 181, 78, 0.95)) drop-shadow(0 2px 3px rgba(0, 0, 0, 0.4));
}
@media (prefers-reduced-motion: reduce) {
  .coins.coin-hit { animation: none; }
  .coin-pop { animation: coin-pop-fade 800ms ease forwards; }
}
@keyframes coin-pop-fade {
  0% { opacity: 0; } 15% { opacity: 1; } 80% { opacity: 1; } 100% { opacity: 0; }
}

/* ============================ Upgrade panel ============================ */

.panel-title {
  margin: 0.25rem 0 0.5rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.chain { margin-bottom: 1rem; }
.chain-head {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink-2);
  margin-bottom: 0.45rem;
  cursor: pointer;
  user-select: none;
}

.node {
  display: flex; align-items: center; gap: 0.5rem;
  background: var(--paper-3);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 0.5rem 0.65rem;
  margin-bottom: 0.45rem;
  box-shadow: var(--sh-1);
  position: relative;
  overflow: hidden;
  transition: border-color 0.15s ease, box-shadow 0.2s ease, transform 0.12s var(--ease);
}
.node.locked { opacity: 0.6; background: var(--paper-2); }
.node.maxed { background: var(--paper-2); }

/* Category accent: a coloured left spine + an eyebrow word group related
   upgrades at a glance (colour + a label, no per-upgrade icons to maintain).
   The spine is a ::before so it survives the gold border swap when affordable. */
.node[data-node-id]::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: var(--accent, var(--line)); z-index: 1; pointer-events: none;
}
.node-cat {
  font-family: var(--font-display);
  font-size: 0.6rem; font-weight: 700;
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--accent, var(--ink-3));
  line-height: 1.1; margin-bottom: 1px; opacity: 0.92;
}
.chain-core       { --accent: #8a8170; }
.chain-board      { --accent: #4f7cad; }
.chain-economy    { --accent: #5c7a3b; }
.chain-deck       { --accent: #3f9a96; }
.chain-automation { --accent: #8a6bbf; }
.chain-empty-col  { --accent: #c5793f; }
.chain-parallel   { --accent: #b5547e; }

/* Collapsible category header for the grouped quick-buy list. Carries the
   category accent colour; click to fold a whole category away. */
.quick-cat {
  display: flex; align-items: center; gap: 0.45rem; width: 100%;
  background: none; border: none; border-bottom: 1px solid var(--line);
  cursor: pointer; text-align: left;
  font-family: var(--font-display);
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent, var(--ink-3));
  padding: 0.45rem 0.25rem 0.3rem; margin: 0.5rem 0 0.35rem;
}
.quick-cat:first-of-type { margin-top: 0; }
.quick-cat-chevron { width: 0.9em; font-size: 0.7rem; opacity: 0.75; }
.quick-cat-name { flex: 1; }
.quick-cat-count {
  font-size: 0.64rem; font-weight: 800; color: var(--ink-3);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-pill); padding: 0 6px; line-height: 1.5;
}
.quick-cat:hover { color: var(--ink); }
.quick-cat:hover .quick-cat-name { text-decoration: underline; }

/* A freshly unlocked node lingers with a gold bloom so it's easy to spot after
   it slides in (entrance + reflow are WAAPI in renderQuickBuy). */
.node.node-new { z-index: 2; animation: node-bloom 2.6s ease-out; }
@keyframes node-bloom {
  0%   { box-shadow: 0 0 0 2px var(--gold-bright), 0 0 22px 7px rgba(231, 181, 78, 0.85); }
  55%  { box-shadow: 0 0 0 1px var(--gold), 0 0 14px 3px rgba(231, 181, 78, 0.5); }
  100% { box-shadow: var(--sh-1); }
}
@media (prefers-reduced-motion: reduce) {
  .node.node-new { animation: none; box-shadow: 0 0 0 1px var(--gold), 0 0 12px 2px rgba(231, 181, 78, 0.55); }
}

/* anticipation fill (behind content) */
.buy-progress {
  position: absolute; left: 0; top: 0; bottom: 0;
  background: linear-gradient(90deg, var(--gold-soft), rgba(201, 147, 47, 0.34));
  z-index: 0;
  /* ease-out-back: the fill springs up and overshoots slightly before settling */
  transition: width 480ms cubic-bezier(0.34, 1.56, 0.64, 1);
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .buy-progress { transition: width 200ms ease; }
}
.node-info, .btn-node-buy, .p-info, .btn-p-buy { position: relative; z-index: 1; }

.node.affordable {
  border-color: var(--gold);
  box-shadow: 0 0 0 1px var(--gold), 0 0 14px rgba(201, 147, 47, 0.45);
}
.node.affordable .buy-progress {
  background: linear-gradient(90deg, rgba(201, 147, 47, 0.26), rgba(231, 181, 78, 0.5));
}

.node .node-info { flex: 1; min-width: 0; }
.node .node-label { font-weight: 800; font-size: 0.92rem; color: var(--ink); }
.node .node-meta {
  font-size: 0.74rem; margin-top: 4px;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  color: var(--ink-2);
}
.lvl-tag {
  font-weight: 800; font-size: 0.68rem;
  padding: 1px 6px; border-radius: var(--r-pill);
  background: var(--gold-soft); color: var(--wood-dark);
  line-height: 1.4;
}
.lvl-tag.maxed-tag { background: rgba(92, 122, 59, 0.2); color: #3e5a28; }
.lvl-now { opacity: 0.7; }
.lvl-next { color: var(--wood-dark); font-weight: 700; }
.node.maxed .lvl-next { display: none; }
.node.maxed .node-meta { opacity: 0.75; }
.node.locked .node-meta { opacity: 1; }

.node .lvl-bar { height: 4px; background: rgba(0, 0, 0, 0.08); border-radius: var(--r-pill); margin-top: 5px; overflow: hidden; }
.node .lvl-fill { height: 100%; background: linear-gradient(90deg, var(--wood), var(--gold)); border-radius: var(--r-pill); transition: width 200ms var(--ease); }

.node[data-depth="1"] { margin-left: 0.9rem; border-left: 3px solid var(--line); padding-left: 0.75rem; }
.node[data-depth="2"] { margin-left: 1.8rem; border-left: 3px solid var(--line); padding-left: 0.75rem; }
.node[data-depth="3"] { margin-left: 2.7rem; border-left: 3px solid var(--line); padding-left: 0.75rem; }

.btn-node-buy {
  flex-shrink: 0;
  background: linear-gradient(180deg, #a07c45, var(--wood-dark));
  color: #fff; border: none;
  border-radius: var(--r-pill); padding: 0.32rem 0.72rem;
  font: inherit; font-size: 0.82rem; font-weight: 800; cursor: pointer;
  box-shadow: var(--sh-1);
  transition: filter 0.15s ease, transform 0.12s var(--ease);
}
.btn-node-buy:disabled { opacity: 0.4; cursor: not-allowed; background: #a78f63; }
.btn-node-buy:hover:not(:disabled) { filter: brightness(1.08); }
.btn-node-buy:active:not(:disabled) { transform: translateY(1px); }
.lock-text { font-size: 0.78rem; opacity: 0.65; font-style: italic; }

/* ============================ Prestige block ========================== */

.prestige-block {
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(138, 107, 255, 0.22), transparent 60%),
    linear-gradient(180deg, var(--plum-2), var(--plum));
  color: var(--plum-ink);
  border: 1px solid var(--plum-line);
  border-radius: var(--r-lg);
  padding: 1rem;
  box-shadow: var(--sh-3);
}
/* header doubles as the collapse toggle */
.prestige-head {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 0.6rem;
  background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 0;
}
.prestige-block.collapsed .prestige-head { margin-bottom: 0; }
.prestige-head:hover .prestige-title { color: var(--violet-2); }
.prestige-title { font-family: var(--font-display); font-weight: 600; font-size: 1.05rem; letter-spacing: 0.01em; }
.diamond-count { font-weight: 800; font-size: 1.05rem; }
.prestige-collapsed-status { font-size: 0.8rem; opacity: 0.85; margin-top: 0.4rem; }

.btn-prestige {
  position: relative; overflow: hidden;
  width: 100%;
  background: linear-gradient(135deg, var(--violet), #b06cff);
  color: #fff; border: none; border-radius: var(--r-pill);
  padding: 0.6rem 0.9rem; font: inherit; font-weight: 800; cursor: pointer;
  box-shadow: 0 2px 0 #4d3aa0, var(--sh-2);
  transition: filter 0.15s ease, transform 0.12s var(--ease);
}
/* progress toward the next diamond, behind the label */
.btn-prestige .prestige-fill {
  position: absolute; left: 0; top: 0; bottom: 0; z-index: 0;
  background: rgba(255, 255, 255, 0.26);
  transition: width 320ms cubic-bezier(0.2, 0.9, 0.3, 1);
}
.btn-prestige .prestige-btn-label { position: relative; z-index: 1; }
.btn-prestige:hover:not(:disabled) { filter: brightness(1.1); }
.btn-prestige:active:not(:disabled) { transform: translateY(1px); box-shadow: 0 1px 0 #4d3aa0; }
.btn-prestige:disabled { opacity: 0.6; cursor: not-allowed; }
.prestige-hint { font-size: 0.76rem; opacity: 0.78; margin: 0.5rem 0 0; line-height: 1.4; }

.p-node {
  display: flex; align-items: center; gap: 0.5rem;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--plum-line);
  border-radius: var(--r);
  padding: 0.45rem 0.6rem; margin-top: 0.45rem;
  position: relative; overflow: hidden;
  transition: border-color 0.15s ease, box-shadow 0.2s ease;
}
.p-node.maxed { opacity: 0.72; }
.p-node.affordable {
  border-color: var(--violet-2);
  box-shadow: 0 0 0 1px var(--violet-2), 0 0 14px rgba(176, 108, 255, 0.5);
}
.p-node .buy-progress {
  background: linear-gradient(90deg, rgba(124, 92, 255, 0.2), rgba(176, 108, 255, 0.46));
}
.p-node .p-info { flex: 1; min-width: 0; }
.p-node .p-label { font-weight: 800; font-size: 0.9rem; }
.p-node .p-meta { font-size: 0.73rem; opacity: 0.85; margin-top: 3px; }
.btn-p-buy {
  flex-shrink: 0; background: linear-gradient(180deg, var(--violet-2), var(--violet));
  color: #fff; border: none; border-radius: var(--r-pill);
  padding: 0.3rem 0.65rem; font: inherit; font-weight: 800; font-size: 0.8rem; cursor: pointer;
  transition: filter 0.15s ease, transform 0.12s var(--ease);
}
.btn-p-buy:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-p-buy:hover:not(:disabled) { filter: brightness(1.1); }
.btn-p-buy:active:not(:disabled) { transform: translateY(1px); }

/* ============================ Modal =================================== */

.modal-overlay {
  position: fixed; inset: 0; z-index: 2000;
  background: rgba(28, 20, 10, 0.5);
  backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center;
  padding: 1.5rem;
  animation: overlay-in 160ms ease-out;
}
.modal-overlay[hidden] { display: none; }
@keyframes overlay-in { from { opacity: 0; } to { opacity: 1; } }
.modal {
  position: relative;
  background: var(--paper-3);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-3);
  max-width: 620px; width: 100%;
  max-height: 85vh; overflow: auto;
  padding: 1.75rem 1.9rem 2rem;
  animation: modal-in 200ms var(--ease);
}
@keyframes modal-in { from { opacity: 0; transform: translateY(12px) scale(0.98); } to { opacity: 1; transform: none; } }
.modal-close {
  position: absolute; top: 0.7rem; right: 0.8rem;
  background: transparent; border: none; cursor: pointer;
  font-size: 1.2rem; line-height: 1; color: var(--ink-2); padding: 0.35rem;
  border-radius: var(--r-sm);
}
.modal-close:hover { background: var(--gold-soft); color: var(--ink); }
.modal-body h2 { font-family: var(--font-display); font-weight: 600; margin: 0 0 0.6rem; font-size: 1.5rem; }
.modal-body h3 { font-family: var(--font-display); font-weight: 600; margin: 1.3rem 0 0.4rem; font-size: 1.05rem; color: var(--wood-dark); }
.modal-body p { margin: 0.5rem 0; line-height: 1.55; color: var(--ink-2); }
.modal-body ul { margin: 0.4rem 0; padding-left: 1.25rem; }
.modal-body li { margin: 0.35rem 0; line-height: 1.5; color: var(--ink-2); }
.modal-body strong { color: var(--ink); font-weight: 800; }

/* ============================ Sidebar quick-buy ======================= */

.btn-tree {
  width: 100%;
  font: inherit; font-weight: 800; font-size: 0.95rem; cursor: pointer;
  color: var(--felt-ink);
  background: radial-gradient(120% 100% at 50% 0%, rgba(255,255,255,0.10), transparent 60%),
              linear-gradient(180deg, var(--felt-2), var(--felt));
  border: 1px solid var(--felt-edge);
  border-radius: var(--r);
  padding: 0.6rem 0.9rem;
  box-shadow: var(--sh-2);
  transition: filter 0.15s ease, transform 0.12s var(--ease);
}
.btn-tree:hover { filter: brightness(1.1); }
.btn-tree:active { transform: translateY(1px); }
.quick-empty { font-size: 0.82rem; color: var(--ink-3); margin: 0.25rem 0 0.5rem; line-height: 1.4; }

/* ============================ Tech tree overlay ======================= */

.tt-overlay {
  position: fixed; inset: 0; z-index: 2100;
  background: rgba(20, 30, 24, 0.62);
  backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center;
  padding: clamp(0.5rem, 2vw, 1.5rem);
  animation: overlay-in 160ms ease-out;
}
.tt-overlay[hidden] { display: none; }
.tt-modal {
  display: flex; flex-direction: column;
  width: min(1080px, 96vw);
  max-height: 94vh;
  background:
    radial-gradient(130% 90% at 50% -10%, rgba(255,255,255,0.08), transparent 55%),
    linear-gradient(180deg, var(--felt-2), var(--felt));
  border: 1px solid var(--felt-edge);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-3);
  animation: modal-in 200ms var(--ease);
  overflow: hidden;
}
.tt-head {
  display: flex; align-items: center; gap: 1rem;
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid rgba(0,0,0,0.25);
  color: var(--felt-ink);
}
.tt-title { font-family: var(--font-display); font-weight: 600; font-size: 1.2rem; }
.tt-legend { display: flex; align-items: center; gap: 0.5rem; font-size: 0.78rem; color: var(--felt-ink-2); margin-left: auto; }
.tt-key { display: inline-block; width: 14px; height: 14px; border-radius: 50%; vertical-align: middle; border: 2px solid var(--line); background: var(--paper-3); margin-left: 0.4rem; }
.tt-key.major { width: 18px; height: 18px; }
.tt-key.minor { width: 12px; height: 12px; }
.tt-key.locked { background: #6f624a; border-color: #5a4f3b; }
.tt-head .modal-close { position: static; color: var(--felt-ink); }
.tt-head .modal-close:hover { background: rgba(255,255,255,0.12); }

.tt-body { overflow: auto; padding: clamp(0.75rem, 2vw, 1.5rem); }
.tt-canvas { position: relative; margin: 0 auto; }

/* Lane bands group each chain; name sits in the left gutter. */
.tt-lane {
  position: absolute; left: 0;
  border-radius: 14px;
}
.tt-lane.even { background: rgba(255, 255, 255, 0.045); }
.tt-lane.odd  { background: rgba(0, 0, 0, 0.085); }
.tt-lane::before {
  content: ''; position: absolute; left: 10px; top: 12px; bottom: 12px; width: 3px;
  border-radius: 3px; background: rgba(231, 181, 78, 0.45);
}
.tt-lane-name {
  position: absolute; left: 26px; top: 50%; transform: translateY(-50%);
  width: 92px;
  font-family: var(--font-display); font-weight: 600; font-size: 0.92rem;
  line-height: 1.15; color: var(--felt-ink);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}

.tt-edges { position: absolute; inset: 0; pointer-events: none; overflow: visible; }
.tt-edge { stroke-width: 3; stroke-linecap: round; fill: none; }
.tt-edge.owned  { stroke: rgba(160, 204, 128, 0.95); }
.tt-edge.open   { stroke: rgba(231, 181, 78, 0.72); }
.tt-edge.locked { stroke: rgba(255, 255, 255, 0.13); }

.tt-node {
  position: absolute;
  transform: translate(-50%, -50%);
  display: grid; place-items: center;
  border-radius: 50%;
  cursor: pointer;
  border: 2px solid var(--line);
  background:
    radial-gradient(70% 65% at 50% 30%, #fffefb, transparent 70%),
    linear-gradient(160deg, var(--paper-3), var(--paper-2));
  color: var(--ink);
  box-shadow: var(--sh-2), inset 0 1px 0 rgba(255, 255, 255, 0.7);
  transition: transform 0.12s var(--ease), box-shadow 0.18s ease, border-color 0.18s ease;
  animation: tt-pop 300ms var(--ease) backwards;
}
.tt-node.major { width: 62px; height: 62px; }
.tt-node.minor { width: 42px; height: 42px; }
.tt-node:hover { transform: translate(-50%, -50%) scale(1.1); z-index: 6; box-shadow: var(--sh-3); }
@keyframes tt-pop {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.55); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

.tt-node.owned  { border-color: var(--wood); }
.tt-node.maxed  {
  border-color: #6f9148;
  background: radial-gradient(70% 65% at 50% 30%, #f4f8ea, transparent 70%), linear-gradient(160deg, #eaf1da, #dde9c8);
}
.tt-node.affordable {
  border-color: var(--gold);
  box-shadow: 0 0 0 2px var(--gold), 0 0 20px rgba(231, 181, 78, 0.65), inset 0 1px 0 rgba(255,255,255,0.7);
  animation: tt-pop 300ms var(--ease) backwards, tt-pulse 1.8s ease-in-out infinite 300ms;
}
@keyframes tt-pulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--gold), 0 0 16px rgba(231,181,78,0.5), inset 0 1px 0 rgba(255,255,255,0.7); }
  50%      { box-shadow: 0 0 0 2px var(--gold), 0 0 26px rgba(231,181,78,0.85), inset 0 1px 0 rgba(255,255,255,0.7); }
}
.tt-node.locked {
  width: 42px; height: 42px;
  background: rgba(20, 30, 24, 0.34);
  border-color: rgba(255, 255, 255, 0.16);
  color: rgba(233, 226, 207, 0.7);
  cursor: default;
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.3);
  animation: tt-pop 300ms var(--ease) backwards;
}

/* Central hub node */
.tt-node.centre {
  width: 84px; height: 84px;
  border-color: var(--gold);
  background:
    radial-gradient(70% 65% at 50% 30%, #fff7e4, transparent 70%),
    linear-gradient(160deg, #f6e4bd, #e7c987);
  box-shadow: 0 0 0 2px var(--gold), 0 6px 22px rgba(110, 81, 40, 0.45), inset 0 1px 0 rgba(255,255,255,0.8);
  z-index: 4;
}
.tt-node.centre .tt-ic { font-size: 2.1rem; }
.tt-node.centre.maxed { border-color: #6f9148; }

/* coins-toward-next-level arc ring */
.tt-node:not(.locked):not(.maxed)::before {
  content: '';
  position: absolute; inset: -5px;
  border-radius: 50%;
  background: conic-gradient(var(--gold) var(--fill, 0%), transparent 0);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
  opacity: 0.85; pointer-events: none;
}

.tt-ic { font-size: 1.55rem; line-height: 1; }
.tt-node.minor .tt-ic { font-size: 1.05rem; }
.tt-node.locked .tt-ic { font-size: 1rem; opacity: 0.85; }

.tt-lvl, .tt-cost {
  position: absolute; left: 50%; transform: translateX(-50%);
  font-size: 0.58rem; font-weight: 800; line-height: 1;
  padding: 2px 6px; border-radius: var(--r-pill);
  white-space: nowrap; pointer-events: none;
  box-shadow: 0 1px 2px rgba(0,0,0,0.25);
}
.tt-cost { top: -8px; background: var(--paper-3); color: var(--ink-2); border: 1px solid var(--line); }
.tt-lvl  { bottom: -8px; background: var(--wood-dark); color: #fff; }
.tt-node.maxed .tt-lvl { background: #5c7a3b; }
.tt-node.affordable .tt-cost { background: var(--gold); color: #fff; border-color: var(--gold-bright); }

.tt-tooltip {
  position: fixed; z-index: 2500; max-width: 260px;
  background: rgba(34, 26, 15, 0.97);
  color: var(--paper);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: var(--r);
  padding: 0.6rem 0.75rem;
  box-shadow: var(--sh-3);
  font-size: 0.82rem; line-height: 1.4;
  display: flex; flex-direction: column; gap: 3px;
  pointer-events: none;
}
.tt-tooltip[hidden] { display: none; }
.tt-tooltip b { font-size: 0.92rem; }
.tt-tip-desc { opacity: 0.8; font-size: 0.78rem; }
.tt-tip-now { color: #c9bfa6; }
.tt-tip-next { color: var(--gold-bright); }
.tt-tip-cost { color: #fff; font-weight: 800; margin-top: 2px; }
.tt-tip-lock { color: #e7a; opacity: 0.9; }

/* ============================ Responsive ============================== */

@media (max-width: 880px) {
  .play-area { flex-direction: column; align-items: stretch; gap: 1rem; }
  .felt { align-self: stretch; }
  .side-panel { flex: 1 1 auto; max-height: none; overflow: visible; padding-right: 0; }
  .title { font-size: 1.1rem; }
  /* Stacked below the felt, the panel rides the PAGE scroll (no inner scroll
     box), so a sticky tab bar at top:0 would collide with the sticky topbar and
     float over the board. Let it scroll with the content instead. */
  .panel-tabs { position: static; }
  .panel-tabs::before { display: none; }
}

@media (max-width: 560px) {
  /* Phone: shrink the whole card with one knob so all 7 columns fit the width.
     --card-w / --card-h stay PLAIN px (no calc) for the JS fan/drop math, which
     parseFloats --card-h (see cardHeight in render.js). 45×64 ≈ 70×100 × 0.64. */
  :root { --card-scale: 0.64; --card-w: 45px; --card-h: 64px; }
  .topbar { flex-wrap: wrap; }
  .title { order: -1; flex-basis: 100%; text-align: left; }
  .topbar-actions { justify-content: flex-start; }
  /* Tighter felt + tableau so the seven shrunk columns fit across the row. */
  .felt { padding: clamp(0.75rem, 3vw, 1.25rem); padding-bottom: 1.5rem; }
  .tableau { gap: 5px; }

  /* Keep Towers + Deck + Draw on ONE line: shrink the gaps between the tower
     stacks and between the pile groups so the top row fits a phone width. */
  .foundations { gap: 0.25rem; }
  .top-row { gap: 0.6rem; }
  .stock-waste { gap: 0.6rem; }

  /* Trim the topbar to essentials on a phone. */
  #new-game { display: none; }              /* the felt already has a per-board New Game */
  #reset-all { display: none; }             /* Reset now lives inside the 🐞 menu */
  #debug-toggle .btn-txt { display: none; } /* Debug collapses to just the bug */
  .debug-item.mobile-only { display: block; }

  /* Topbar: compact so the controls don't eat the screen above the board. */
  .topbar { gap: 0.5rem; padding: 0.5rem 0.75rem; }
  .topbar-actions { gap: 0.35rem; width: 100%; }
  .btn-ghost { padding: 0.45rem 0.6rem; font-size: 0.85rem; }

  /* Less chrome around the play area on a small screen; keep the last row of the
     stacked panel clear of the home indicator. */
  .play-area { padding: 0.75rem; padding-bottom: max(0.75rem, env(safe-area-inset-bottom)); }
  .boards { gap: 1rem; }
  .board { gap: 0.8rem; }
  .board-head .coins { font-size: 1rem; padding: 0.2rem 0.7rem 0.2rem 0.55rem; }
  /* Phones: allow the header to wrap (there isn't room for label + bank +
     every action button on one line). */
  .board-head { flex-wrap: wrap; }

  /* Bigger tab hit areas for thumbs. */
  .panel-tab { padding: 0.65rem 0.4rem; font-size: 0.9rem; }

  /* Modal: fill more of the small screen, trim the generous desktop padding. */
  .modal-overlay { padding: 0.75rem; }
  .modal { padding: 1.25rem 1.15rem 1.5rem; max-height: 92vh; border-radius: var(--r-lg); }
  .modal-body h2 { font-size: 1.3rem; }
  .modal-body h3 { font-size: 1rem; }

  /* Tech-tree overlay: edge-to-edge canvas, drop the wide legend. */
  .tt-overlay { padding: 0.4rem; }
  .tt-modal { width: 100vw; max-height: 96vh; }
  .tt-head { padding: 0.6rem 0.7rem; gap: 0.6rem; }
  .tt-title { font-size: 1.05rem; }
  .tt-legend { display: none; }
}

@media (max-width: 400px) {
  /* Compact phones (iPhone SE / mini): shrink a touch more. 39×56 ≈ ×0.56. */
  :root { --card-scale: 0.56; --card-w: 39px; --card-h: 56px; }
  .tableau { gap: 4px; }
}

/* ── Phone held sideways (short viewport): a FIXED, app-like layout so nothing
   ever runs off the bottom — like the desktop web, just bounded to the height.
   The felt + panel sit side by side (use the wide axis), each scrolls inside its
   own box, and the board fans to the felt's REAL height (min-height:0 makes
   fitTableauSpacing measure the box instead of the viewport-floor clamp). Tall
   viewports (tablets/desktop in landscape) are excluded by max-height, so they
   keep the normal layout. This deliberately overrides the ≤880 stacking. ── */
@media (orientation: landscape) and (max-height: 600px) and (pointer: coarse) {
  /* Cards sized for the short height; bigger now that the header is hoisted out,
     so the columns fill the width with smaller gaps under space-between. Tighter
     fan cap (--vis-max-frac) so cards overlap a bit more vertically. */
  :root { --card-scale: 0.62; --card-w: 43px; --card-h: 62px; --vis-max-frac: 0.38; }

  /* Pin the app to the visible viewport; no page scroll. */
  #app { height: 100dvh; min-height: 0; overflow: hidden; }

  /* Side by side again (undo the stacking), filling the available height.
     Pad the sides by the safe-area insets so the notch / rounded corner (on
     whichever side after rotation) can't hide the left column, and clear the
     home indicator at the bottom. */
  .play-area {
    flex: 1; min-height: 0; overflow: hidden;
    flex-direction: row; align-items: stretch;
    justify-content: center; gap: 0.5rem;
    padding: 0.4rem
             max(0.5rem, env(safe-area-inset-right))
             max(0.4rem, env(safe-area-inset-bottom))
             max(0.5rem, env(safe-area-inset-left));
  }
  .felt {
    flex: 1 1 auto; min-width: 0;
    min-height: 0; align-self: stretch;
    overflow: auto;
    padding: 0.6rem; padding-bottom: 0.8rem;
  }
  .side-panel {
    flex: 0 0 38%; max-width: var(--panel-w);
    align-self: stretch; max-height: none; overflow: auto;
    padding-right: 2px;
  }
  /* The panel is its own scroll box again → sticky tabs work (and need their
     opaque backing band back, which the ≤880 rule had switched off). */
  .panel-tabs { position: sticky; }
  .panel-tabs::before { display: block; }

  /* Trim the topbar so the short height goes to the board (same idea as the
     portrait phone trims, which don't apply here because the width is wide). */
  .topbar {
    gap: 0.4rem;
    padding: max(0.3rem, env(safe-area-inset-top))
             max(0.6rem, env(safe-area-inset-right))
             0.3rem
             max(0.6rem, env(safe-area-inset-left));
  }
  .title { font-size: 1rem; }
  #new-game { display: none; }              /* the felt has a per-board New Game */
  #reset-all { display: none; }             /* Reset lives in the 🐞 menu */
  #debug-toggle .btn-txt { display: none; } /* Debug collapses to just the bug */
  .debug-item.mobile-only { display: block; }

  /* Compress the felt internals: drop the decorative section labels and tighten
     every vertical gap so the board fills the height instead of floating with a
     big gap above the tableau. */
  .section-label { display: none; }
  .felt { gap: 0.3rem; }
  .board { gap: 0.3rem; }
  .board-section { gap: 0; }
  .tableau { padding-top: 0; }
  .board-head { margin: 0; }

  /* Hoist the coin bank + New Game out of the felt up here, above the tabs, so the
     felt's header row is reclaimed entirely. (renderBoards moves the bank in.) */
  .panel-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 0.5rem; margin-bottom: 0.5rem;
  }
  .panel-head .coins { font-size: 1.05rem; padding: 0.2rem 0.7rem 0.2rem 0.55rem; }
  .panel-head #panel-new-game { padding: 0.4rem 0.9rem; } /* tighter than the default primary */
  .board-head > span:first-child { display: none; } /* "Game 1" label — redundant */
  /* Higher specificity than the `pointer: coarse` block below (which re-sets
     .btn-new-this to inline-flex) so this actually wins in landscape. */
  .board-actions .btn-new-this { display: none; }   /* New Game now lives in .panel-head */

  /* Anchor the board to BOTH felt edges and spread the columns + pile groups
     across the full width instead of bunching at the left. */
  .tableau { justify-content: space-between; }
  .top-row { justify-content: space-between; gap: 0.5rem; }
}

/* Touch devices: comfortable ≥44px tap targets + no double-tap-zoom delay on
   controls. Gated on a COARSE primary pointer, so a mouse-driven desktop (fine
   pointer) is completely unaffected — the cards themselves keep their size. */
@media (pointer: coarse) {
  .btn-ghost, .btn-primary, .btn-new-this, .btn-undo, .btn-auto, .btn-cascade,
  .panel-tab, .btn-node-buy, .btn-claim, .btn-p-buy, .btn-tree, .claim-toast-go {
    min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
    touch-action: manipulation;
  }
  .modal-close { min-width: 44px; min-height: 44px; touch-action: manipulation; }
}

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

/* ===================== Side-panel tabs (Coins / Feats / Prestige) ===== */
.panel-tabs {
  position: sticky; top: 0; z-index: 5;
  display: flex; gap: 0.3rem;
  padding: 0.25rem; margin: -0.1rem 0 0;
  background: var(--paper-2);
  border: 1px solid var(--line); border-radius: var(--r-pill);
  box-shadow: var(--sh-1);
}
/* Opaque backing band so content scrolling under the sticky pill can't peek
   through its rounded corners or the gap below it. Page-colored, bled out past
   the pill, painted within the pill's stacking context (above the panes). */
.panel-tabs::before {
  content: '';
  position: absolute;
  left: -5px; right: -5px; top: -12px; bottom: -9px;
  background: var(--paper);
  border-radius: var(--r-lg);
  z-index: -1;
  pointer-events: none;
}
.panel-tab {
  position: relative;
  flex: 1 1 0; min-width: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.3rem;
  padding: 0.5rem 0.4rem;
  font-family: var(--font-ui); font-weight: 800; font-size: 0.86rem;
  color: var(--ink-2); background: transparent;
  border: none; border-radius: var(--r-pill); cursor: pointer;
  white-space: nowrap; transition: background 160ms var(--ease), color 160ms var(--ease);
}
.panel-tab:hover { color: var(--ink); background: rgba(110, 81, 40, 0.08); }
.panel-tab.active {
  color: var(--ink); background: var(--paper-3);
  box-shadow: var(--sh-1), inset 0 0 0 1px var(--line);
}
.panel-tab.has-claims, .panel-tab.has-buys { color: var(--gold); }
.panel-tab.pulse { animation: tab-pulse 1.1s ease-in-out 2; }
@keyframes tab-pulse {
  0%, 100% { box-shadow: none; }
  50% { box-shadow: 0 0 0 2px var(--gold-bright), 0 0 12px 2px rgba(231, 181, 78, 0.6); }
}
.tab-badge {
  display: inline-flex; align-items: center; justify-content: center;
  box-sizing: border-box;
  min-width: 1.2rem; height: 1.2rem; padding: 0 0.32rem;
  margin-left: 0.18rem;
  font-size: 0.72rem; font-weight: 900; line-height: 1; text-align: center;
  color: #3a2a0c; background: var(--gold-bright);
  border-radius: var(--r-pill); box-shadow: 0 1px 2px rgba(60,42,18,0.25);
  animation: badge-pop 0.3s var(--ease);
}
/* A CSS display rule otherwise beats the `hidden` attribute — keep it hidden at 0. */
.tab-badge[hidden] { display: none; }
@keyframes badge-pop { from { transform: scale(0.4); } to { transform: scale(1); } }

/* ===================== Feats tab ===================================== */
.feat-section {
  display: flex; justify-content: space-between; align-items: baseline;
  margin: 0.9rem 0 0.45rem; padding-bottom: 0.25rem;
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--font-ui); font-weight: 800; font-size: 0.78rem;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-3);
}
.feat-section:first-of-type { margin-top: 0.4rem; }
.feat-section-count { font-size: 0.72rem; color: var(--ink-3); }

.feat-row {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.55rem 0.65rem; margin-bottom: 0.4rem;
  background: var(--paper-2); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--sh-1);
}
.feat-info { flex: 1; min-width: 0; }
.feat-label { font-family: var(--font-ui); font-weight: 800; font-size: 0.92rem; color: var(--ink); }
.feat-lv {
  display: inline-block; vertical-align: middle;
  margin-left: 0.4rem; padding: 0.05rem 0.42rem;
  font-size: 0.7rem; font-weight: 800; line-height: 1.35;
  color: var(--ink-2); background: rgba(110, 81, 40, 0.13);
  border-radius: var(--r-pill);
}
.feat-desc { font-size: 0.76rem; color: var(--ink-3); margin-top: 1px; line-height: 1.25; }
.feat-bar {
  height: 5px; margin-top: 0.4rem;
  background: rgba(0, 0, 0, 0.08); border-radius: var(--r-pill); overflow: hidden;
}
.feat-fill {
  height: 100%; border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--wood), var(--gold-bright));
  /* springy overshoot as the bar fills toward its target */
  transition: width 560ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Red pips wherever a ♥ or ♦ appears in feat text. */
.suit-red { color: var(--card-red); }

/* Auto-player jammed: a persistent pill + a pulsing New Game button to nudge a redeal. */
.stuck-pill {
  display: inline-flex; align-items: center; gap: 0.25rem;
  padding: 0.2rem 0.55rem;
  font-family: var(--font-ui); font-weight: 800; font-size: 0.74rem;
  color: #7a2e12; background: #fbe2cf;
  border: 1px solid #e0a986; border-radius: var(--r-pill);
  white-space: nowrap;
  animation: stuck-pulse 1.3s ease-in-out infinite;
}
@keyframes stuck-pulse {
  0%, 100% { opacity: 0.75; box-shadow: 0 0 0 0 rgba(231, 181, 78, 0); }
  50% { opacity: 1; box-shadow: 0 0 10px 2px rgba(231, 181, 78, 0.55); }
}
/* Auto-play game tank, folded INTO the ⏸/▶ Auto button as a small count pill:
   how many games it'll still chain before resting. Goes warm + pulses at 0. */
.btn-auto { display: inline-flex; align-items: center; gap: 0.35rem; }
.auto-tank-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.3em; padding: 0 0.32em; height: 1.3em;
  font-family: var(--font-ui); font-weight: 800; font-size: 0.78em;
  font-variant-numeric: tabular-nums;
  color: #fff; background: rgba(0, 0, 0, 0.28);
  border-radius: var(--r-pill);
}
.auto-tank-badge.empty {
  color: #7a2e12; background: #fbe2cf;
  animation: stuck-pulse 1.3s ease-in-out infinite;
}
/* The end-game "Send them all!" cascade button — the star of the moment. */
.btn-cascade {
  padding: 0.45rem 0.8rem;
  font-family: var(--font-ui); font-weight: 900; font-size: 0.86rem;
  color: #3a2a0c; background: linear-gradient(180deg, var(--gold-bright), var(--gold));
  border: none; border-radius: var(--r-pill); cursor: pointer;
  box-shadow: 0 2px 6px rgba(120, 84, 20, 0.4);
  animation: cascade-glow 1.1s ease-in-out infinite;
}
.btn-cascade:hover { filter: brightness(1.08); }
.btn-cascade:active { transform: translateY(1px); }
@keyframes cascade-glow {
  0%, 100% { box-shadow: 0 2px 6px rgba(120, 84, 20, 0.4), 0 0 0 0 rgba(231, 181, 78, 0); }
  50% { box-shadow: 0 2px 6px rgba(120, 84, 20, 0.4), 0 0 14px 3px rgba(231, 181, 78, 0.65); }
}
.btn-new-this.nudge,
.btn-primary.nudge, /* also the topbar / side-panel New Game (dead-game detector) */
.panel-tab.nudge { /* Feats tab: a feat has sat unclaimed for a few minutes */
  animation: nudge-pulse 1.2s ease-in-out infinite;
  border-radius: var(--r-pill);
}
@keyframes nudge-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(231, 181, 78, 0); }
  50% { box-shadow: 0 0 0 3px var(--gold-bright), 0 0 14px 2px rgba(231, 181, 78, 0.6); }
}
.feat-bar.gated .feat-fill { background: linear-gradient(90deg, #9c8a6a, #b8a884); }
.feat-meta {
  display: flex; justify-content: space-between; gap: 0.4rem;
  margin-top: 0.3rem; font-size: 0.74rem; color: var(--ink-3);
}
.feat-lock { color: var(--card-red); font-weight: 700; }
.feat-count { margin-left: auto; font-variant-numeric: tabular-nums; font-weight: 700; }

/* Ready-to-claim: gold-glowing card with the celebratory Claim button. */
.feat-row.feat-ready {
  background: linear-gradient(180deg, #fff6e0, var(--paper-3));
  border-color: var(--gold);
  box-shadow: 0 0 0 1px var(--gold-soft), 0 2px 10px rgba(231, 181, 78, 0.4);
  animation: feat-ready-glow 2.2s ease-in-out infinite;
}
@keyframes feat-ready-glow {
  0%, 100% { box-shadow: 0 0 0 1px var(--gold-soft), 0 2px 10px rgba(231, 181, 78, 0.35); }
  50% { box-shadow: 0 0 0 1px var(--gold), 0 3px 16px rgba(231, 181, 78, 0.6); }
}
.btn-claim {
  flex: 0 0 auto;
  padding: 0.5rem 0.85rem;
  font-family: var(--font-ui); font-weight: 900; font-size: 0.82rem;
  color: #3a2a0c; background: linear-gradient(180deg, var(--gold-bright), var(--gold));
  border: none; border-radius: var(--r-pill); cursor: pointer;
  box-shadow: 0 2px 5px rgba(120, 84, 20, 0.35);
}
.btn-claim:hover { filter: brightness(1.07); }
.btn-claim:active { transform: translateY(1px); }

.feat-row.feat-earned { opacity: 0.62; background: var(--paper-2); }
.feat-row.feat-earned .feat-desc { display: none; }
.feat-check {
  flex: 0 0 auto; width: 1.6rem; height: 1.6rem;
  display: flex; align-items: center; justify-content: center;
  color: #5c7a3b; font-weight: 900; font-size: 1rem;
  background: rgba(92, 122, 59, 0.14); border-radius: var(--r-pill);
}

/* ===================== "New feat ready" toast ======================== */
.claim-toast {
  position: fixed; left: 50%; bottom: calc(1.4rem + env(safe-area-inset-bottom)); transform: translateX(-50%);
  z-index: 60;
  display: flex; align-items: center; gap: 0.7rem;
  padding: 0.7rem 0.85rem 0.7rem 1rem;
  font-family: var(--font-ui); font-weight: 800; font-size: 0.9rem; color: var(--ink);
  background: linear-gradient(180deg, #fff6e0, var(--paper-3));
  border: 1px solid var(--gold); border-radius: var(--r-pill);
  box-shadow: var(--sh-3), 0 0 0 1px var(--gold-soft);
  animation: toast-in 0.4s var(--ease);
}
.claim-toast.out { animation: toast-out 0.45s var(--ease) forwards; }
@keyframes toast-in  { from { opacity: 0; transform: translate(-50%, 18px); } to { opacity: 1; transform: translate(-50%, 0); } }
@keyframes toast-out { to   { opacity: 0; transform: translate(-50%, 18px); } }
.claim-toast-go {
  padding: 0.4rem 0.8rem;
  font-family: var(--font-ui); font-weight: 900; font-size: 0.82rem;
  color: #3a2a0c; background: linear-gradient(180deg, var(--gold-bright), var(--gold));
  border: none; border-radius: var(--r-pill); cursor: pointer;
}
.claim-toast-go:hover { filter: brightness(1.07); }
