*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --font: 'Nunito', system-ui, sans-serif;
  --ink: #3a3350;
  --ink-soft: #6b6383;
  --cream: #fdf6ec;
  --panel: rgba(255, 252, 246, 0.94);
  --gold: #f0c040;
  --gold-dim: #d4a830;
  --green: #5da345;
  --green-soft: #e8f4e0;
  --coral: #e2695a;
  --coral-soft: #fdeae6;
  --lav: #b9a5d8;
  --shadow: 0 10px 30px rgba(58, 51, 80, 0.18);
}

html, body {
  width: 100%; height: 100%;
  overflow: hidden;
  font-family: var(--font);
  color: var(--ink);
  background: #efe3d5;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

button { font-family: var(--font); cursor: pointer; }
button:focus-visible, [tabindex]:focus-visible {
  outline: 4px solid #4a90d9;
  outline-offset: 3px;
  border-radius: 12px;
}

/* ══ Top bar ══ */
.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 10px 16px;
  background: var(--panel);
  border-bottom: 2px solid rgba(58, 51, 80, 0.08);
  backdrop-filter: blur(6px);
}
.topbar-title { display: flex; align-items: center; gap: 10px; min-width: 0; }
.topbar-shop { height: 44px; width: auto; flex-shrink: 0; filter: drop-shadow(0 2px 3px rgba(58, 51, 80, 0.25)); }
.topbar-title-text { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.topbar-title strong { font-size: 17px; font-weight: 900; white-space: nowrap; }
.topbar-title span { font-size: 12px; font-weight: 700; color: var(--ink-soft); white-space: nowrap; }
.topbar-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }

.tb-btn {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 46px; padding: 8px 14px;
  border: 2px solid rgba(58, 51, 80, 0.14);
  border-radius: 14px;
  background: #fff; color: var(--ink);
  font-size: 14px; font-weight: 800;
  transition: transform 0.12s, background 0.15s, border-color 0.15s;
}
.tb-btn:hover { transform: translateY(-1px); border-color: rgba(58, 51, 80, 0.3); }
.tb-btn svg { width: 20px; height: 20px; fill: var(--ink); stroke: var(--ink); flex-shrink: 0; }
.tb-btn.toggle[aria-pressed="false"] { opacity: 0.45; }
.tb-btn.toggle[aria-pressed="false"] span::after { content: " off"; font-weight: 700; }
.tb-btn.quick-exit {
  background: var(--ink); color: #fff; border-color: var(--ink);
}
.tb-btn.quick-exit svg { fill: var(--gold); stroke: none; }
.tb-btn.quick-exit:hover { background: #2a2440; }

/* ══ Stage ══ */
.stage {
  /* Starts below the top bar so nothing of the room hides under it, and the
     room is anchored to the top so the arches and bookcases are never cropped
     on wide, short windows (the floor is what gets trimmed instead). */
  position: fixed; top: var(--topbar-h); left: 0; right: 0; bottom: 0;
  /* Image is set from config.background; this is the fallback tone. */
  background: #efe3d5 center top / cover no-repeat;
  overflow: hidden; /* confetti starts above and falls out below */
}

/* ══ Ambience: studio spotlights, mirror screen, colour wash, bokeh (decorative) ══ */
.ambience {
  position: absolute; inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 2;
}
/* Soft pools of light from the ceiling spots, breathing slowly */
.spot {
  position: absolute;
  top: -12%;
  width: 30vw; height: 70vh;
  background: radial-gradient(ellipse at 50% 0%,
    rgba(255, 244, 214, 0.55), rgba(255, 244, 214, 0.18) 45%, rgba(255, 244, 214, 0) 75%);
  filter: blur(14px);
  mix-blend-mode: screen;
  animation: spotBreathe 12s ease-in-out infinite;
}
.spot-1 { left: 6%;  animation-delay: 0s; }
.spot-2 { left: 35%; width: 30vw; opacity: 0.7; animation-delay: -4s; animation-duration: 15s; }
.spot-3 { right: 6%; animation-delay: -8s; animation-duration: 13s; }
@keyframes spotBreathe {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 0.95; }
}
/* The mirror screen glows gently and shifts between lavender and teal.
   Position and size are pinned to the mirror in the background image by
   layoutAnchors() in game.js (config.anchors). */
.mirror-glow {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 45%,
    rgba(255, 255, 255, 0.55), rgba(205, 190, 235, 0.45) 40%, rgba(160, 220, 210, 0.3) 70%, rgba(160, 220, 210, 0) 100%);
  mix-blend-mode: screen;
  animation: mirrorHue 16s ease-in-out infinite;
  will-change: filter, opacity;
  /* Colour the mirror takes when a card lands (set by the stage wash) */
  --wash: transparent;
}
@keyframes mirrorHue {
  0%, 100% { filter: hue-rotate(0deg) brightness(1); opacity: 0.75; }
  50% { filter: hue-rotate(40deg) brightness(1.1); opacity: 1; }
}
.mirror-ring {
  position: absolute; inset: -3%;
  border-radius: 50%;
  box-shadow: 0 0 40px 10px rgba(255, 236, 190, 0.35), inset 0 0 40px rgba(255, 255, 255, 0.35);
  animation: ringPulse 7s ease-in-out infinite;
}
@keyframes ringPulse {
  0%, 100% { opacity: 0.5; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.015); }
}
/* A slow diagonal light sweep across the glass */
.mirror-sheen {
  position: absolute; inset: 0;
  border-radius: 50%;
  overflow: hidden;
  background: linear-gradient(115deg,
    rgba(255, 255, 255, 0) 30%, rgba(255, 255, 255, 0.5) 46%, rgba(255, 255, 255, 0) 60%);
  background-size: 300% 100%;
  animation: sheenSweep 14s ease-in-out infinite;
}
@keyframes sheenSweep {
  0%, 60% { background-position: 120% 0; }
  100% { background-position: -120% 0; }
}
/* ── Card reveal: ribbons of light spiral inward in the mirror, gather to a
   bright point, and the card materialises from it (.stage.conjure, set by
   game.js for cfg.cardReveal.delay ms) ── */
/* The glow blends with `screen`, so the ribbons use saturated colour rather
   than white (white would vanish against the pale glass). */
.swirl {
  position: absolute; inset: 2%;
  border-radius: 50%;
  opacity: 0;
  background: conic-gradient(from 0deg,
    rgba(95, 211, 95, 0) 0 40%, rgba(95, 211, 95, 1) 62%, rgba(240, 176, 64, 1) 80%, rgba(240, 176, 64, 0) 92%);
  -webkit-mask: radial-gradient(circle, transparent 56%, #000 60%, #000 76%, transparent 80%);
  mask: radial-gradient(circle, transparent 56%, #000 60%, #000 76%, transparent 80%);
  filter: blur(1px) drop-shadow(0 0 12px rgba(95, 211, 95, 0.9));
  will-change: transform, opacity;
}
.swirl-b {
  inset: 12%;
  background: conic-gradient(from 160deg,
    rgba(155, 127, 214, 0) 0 36%, rgba(155, 127, 214, 1) 60%, rgba(61, 189, 176, 1) 80%, rgba(61, 189, 176, 0) 92%);
  -webkit-mask: radial-gradient(circle, transparent 48%, #000 53%, #000 72%, transparent 77%);
  mask: radial-gradient(circle, transparent 48%, #000 53%, #000 72%, transparent 77%);
  filter: blur(1px) drop-shadow(0 0 12px rgba(155, 127, 214, 0.9));
}
.swirl-c {
  inset: 22%;
  background: conic-gradient(from 280deg,
    rgba(240, 176, 64, 0) 0 42%, rgba(240, 176, 64, 1) 64%, rgba(95, 211, 95, 1) 82%, rgba(95, 211, 95, 0) 94%);
  -webkit-mask: radial-gradient(circle, transparent 40%, #000 46%, #000 68%, transparent 74%);
  mask: radial-gradient(circle, transparent 40%, #000 46%, #000 68%, transparent 74%);
  filter: blur(1px) drop-shadow(0 0 12px rgba(240, 176, 64, 0.9));
}
.swirl-core {
  position: absolute; left: 50%; top: 50%;
  width: 34%; height: 34%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, 1), rgba(142, 230, 138, 0.8) 35%, rgba(142, 230, 138, 0) 70%);
  transform: translate(-50%, -50%) scale(0);
  opacity: 0;
  will-change: transform, opacity;
}
.stage.conjure .swirl-a { animation: swirlIn 0.85s cubic-bezier(0.45, 0, 0.3, 1) forwards; }
.stage.conjure .swirl-b { animation: swirlInRev 0.85s 0.05s cubic-bezier(0.45, 0, 0.3, 1) forwards; }
.stage.conjure .swirl-c { animation: swirlIn 0.85s 0.1s cubic-bezier(0.45, 0, 0.3, 1) forwards; }
.stage.conjure .swirl-core { animation: swirlCore 0.85s ease-in forwards; }
.stage.conjure .mirror-glow { animation: mirrorConjure 0.85s ease-in; }
@keyframes swirlIn {
  0%   { transform: rotate(0deg) scale(1.2); opacity: 0; }
  20%  { opacity: 1; }
  100% { transform: rotate(560deg) scale(0.3); opacity: 0; }
}
@keyframes swirlInRev {
  0%   { transform: rotate(0deg) scale(1.25); opacity: 0; }
  20%  { opacity: 1; }
  100% { transform: rotate(-500deg) scale(0.25); opacity: 0; }
}
@keyframes swirlCore {
  0%   { transform: translate(-50%, -50%) scale(0); opacity: 0; }
  60%  { transform: translate(-50%, -50%) scale(0.6); opacity: 0.7; }
  85%  { transform: translate(-50%, -50%) scale(1.6); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(2.4); opacity: 0; }
}
/* The glass dims a little so the ribbons stand out, then flares as they meet */
@keyframes mirrorConjure {
  0%   { filter: brightness(0.9) saturate(1.2); opacity: 0.8; }
  60%  { filter: brightness(0.95) saturate(1.3); opacity: 0.85; }
  85%  { filter: brightness(1.6) saturate(1); opacity: 1; }
  100% { filter: brightness(1) saturate(1); opacity: 0.85; }
}

/* Full-room colour wash: the stage goes softly green or coral when a card lands */
.wash-layer {
  position: absolute; inset: 0;
  background: var(--wash, transparent);
  opacity: 0;
  mix-blend-mode: soft-light;
}
.stage.wash .wash-layer { animation: washIn 1.5s ease-out; }
.stage.wash .mirror-glow {
  background: radial-gradient(circle at 50% 45%,
    rgba(255, 255, 255, 0.75), var(--wash) 45%, rgba(255, 255, 255, 0) 100%);
  animation: mirrorFlash 1.5s ease-out;
}
@keyframes washIn {
  0% { opacity: 0; }
  25% { opacity: 0.3; }
  100% { opacity: 0; }
}
@keyframes mirrorFlash {
  0% { opacity: 1; filter: brightness(1.6); }
  100% { opacity: 0.8; filter: brightness(1); }
}
/* Soft out-of-focus orbs of coloured light drifting slowly upward */
.orb {
  position: absolute;
  left: var(--ox); top: var(--oy);
  width: 26px; height: 26px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--oc), rgba(255, 255, 255, 0) 70%);
  filter: blur(2px);
  animation: orbFloat var(--os) var(--od) ease-in-out infinite;
  opacity: 0;
  will-change: transform, opacity;
}
@keyframes orbFloat {
  0%   { transform: translate(0, 0) scale(0.6); opacity: 0; }
  20%  { opacity: 0.9; }
  50%  { transform: translate(22px, -40px) scale(1.1); opacity: 0.6; }
  80%  { opacity: 0.8; }
  100% { transform: translate(-14px, -90px) scale(0.5); opacity: 0; }
}
.stage::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgba(30, 24, 48, 0.10) 0%, rgba(30, 24, 48, 0) 22%, rgba(30, 24, 48, 0) 55%, rgba(30, 24, 48, 0.28) 100%);
}

/* Privacy meter */
:root { --topbar-h: 68px; }
.meter {
  /* Above the bins/bookcases (11) so it is never hidden behind them on narrow windows */
  position: absolute; top: 14px; left: 50%; transform: translateX(-50%); z-index: 14;
  display: flex; align-items: center; gap: 12px;
  padding: 10px 18px; border-radius: 18px;
  background: var(--panel); box-shadow: var(--shadow);
}
.meter-label { font-size: 14px; font-weight: 900; color: var(--ink-soft); }
.meter-locks { display: flex; gap: 8px; }
.meter-lock { width: 30px; height: 30px; position: relative; }
.meter-lock svg { width: 100%; height: 100%; }
.meter-lock .lock-body { fill: #ded5ea; }
.meter-lock .lock-shackle { fill: none; stroke: #ded5ea; stroke-width: 2.6; }
.meter-lock.locked .lock-body { fill: var(--gold); }
.meter-lock.locked .lock-shackle { stroke: var(--gold-dim); }
.meter-lock.locked { animation: lockPop 0.5s ease; }
@keyframes lockPop {
  0% { transform: scale(1); }
  45% { transform: scale(1.45) rotate(-6deg); }
  100% { transform: scale(1); }
}

/* Progress dots */
.progress {
  position: absolute; top: 72px; left: 50%; transform: translateX(-50%); z-index: 14;
  display: flex; gap: 7px;
}
.progress i {
  width: 11px; height: 11px; border-radius: 50%;
  background: rgba(255, 252, 246, 0.75);
  border: 2px solid rgba(58, 51, 80, 0.25);
}
.progress i.done { background: var(--green); border-color: var(--green); }
.progress i.now { background: var(--gold); border-color: var(--gold-dim); transform: scale(1.25); }
.progress i.skipped { background: var(--lav); border-color: var(--lav); }

/* ══ Card ══ */
.card-zone {
  position: absolute; top: 46%; left: 50%; transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  z-index: 12;
}
.game-card {
  position: relative;
  width: 260px;
  background: #fff;
  border-radius: 26px;
  border: 3px solid rgba(58, 51, 80, 0.1);
  box-shadow: var(--shadow);
  padding: 16px 16px 18px;
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  animation: cardFloat 3.2s ease-in-out infinite;
  transition: box-shadow 0.2s;
  will-change: transform;
}
.game-card:active { cursor: grabbing; }
.game-card.dragging {
  animation: none;
  transition: none;
  box-shadow: 0 24px 48px rgba(58, 51, 80, 0.3);
  z-index: 30;
}
.game-card.entering { animation: cardEnter 0.55s cubic-bezier(0.34, 1.56, 0.64, 1), cardFloat 3.2s 0.55s ease-in-out infinite; pointer-events: none; }
.game-card.flying { animation: none; transition: transform 0.55s cubic-bezier(0.5, 0, 0.75, 0.6), opacity 0.55s ease; pointer-events: none; }
.game-card.returning { animation: none; transition: transform 0.5s cubic-bezier(0.34, 1.3, 0.64, 1); }
/* Float via transform (GPU-composited); margin/top would jitter. */
@keyframes cardFloat {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-9px); }
}
@keyframes cardEnter {
  0% { transform: scale(0.3) translateY(-120px); opacity: 0; }
  100% { transform: scale(1) translateY(0); opacity: 1; }
}
.card-art {
  width: 100%; aspect-ratio: 1;
  border-radius: 18px; overflow: hidden;
  background: var(--cream);
}
.card-art img { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }
.card-label {
  margin-top: 12px;
  font-size: 21px; font-weight: 900; line-height: 1.2;
  text-align: center;
  min-height: 50px;
  display: flex; align-items: center; justify-content: center;
}
.card-speak {
  position: absolute; top: -14px; right: -14px;
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--gold); border: 3px solid #fff;
  box-shadow: 0 4px 10px rgba(58, 51, 80, 0.25);
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.15s;
}
.card-speak:hover { transform: scale(1.12); }
.card-speak svg { width: 22px; height: 22px; fill: var(--ink); stroke: var(--ink); }
.card-hint {
  font-size: 14px; font-weight: 800; color: #fff;
  background: rgba(58, 51, 80, 0.55);
  padding: 6px 16px; border-radius: 999px;
  pointer-events: none;
}
/* Skip appears only on cards the config marks as sensitive */
.card-skip { background: var(--panel); border-color: var(--lav); color: var(--ink); }
.card-skip[hidden] { display: none; }

/* ══ Baskets ══ */
.basket {
  position: absolute; bottom: 3.5vh; z-index: 11;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: none; border: none;
  padding: 14px;
  border-radius: 30px;
  transition: transform 0.18s ease, background 0.18s ease;
}
#basketLeft { left: 5vw; }
#basketRight { right: 5vw; }
.basket img {
  width: clamp(130px, 17vw, 200px);
  filter: drop-shadow(0 12px 14px rgba(58, 51, 80, 0.4));
  pointer-events: none;
  /* Only transform is transitioned; animating filter causes jittery repaints. */
  transition: transform 0.18s ease;
}
.basket:hover img, .basket:focus-visible img, .basket.armed img {
  filter: drop-shadow(0 12px 14px rgba(58, 51, 80, 0.4))
          drop-shadow(0 0 18px rgba(255, 232, 150, 0.95));
}
.basket-label {
  font-size: clamp(15px, 1.6vw, 19px); font-weight: 900; color: #fff;
  padding: 8px 20px; border-radius: 999px;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.18);
  margin-top: -8px;
  background: var(--ink); /* real colour is set from config.bins[].color */
}
.basket:hover img, .basket.armed img { transform: translateY(-6px) scale(1.06); }
.basket.armed { background: rgba(255, 252, 246, 0.35); }
.basket.armed::after {
  content: ""; position: absolute; inset: 0;
  border: 4px dashed rgba(255, 252, 246, 0.95);
  border-radius: 30px; pointer-events: none;
  animation: armedPulse 1s ease-in-out infinite;
}
@keyframes armedPulse {
  0%, 100% { opacity: 0.65; }
  50% { opacity: 1; }
}
.basket.received img { animation: basketBounce 0.5s ease; }
.basket-body { position: relative; display: block; line-height: 0; }

/* ══ Shelving mode: bookcases stand in the alcoves, signs baked into the art ══ */
/* Position and size are set per-alcove by layoutShelves() in game.js. */
.stage.shelving .basket img { height: var(--shelf-h, clamp(240px, 40vh, 420px)); width: auto; }
/* With bookcases up in the alcoves the meter moves out of their way, to the
   bottom-left above the sideboard; the progress dots stay top-centre. */
.stage.shelving .meter {
  top: auto; bottom: 16px; left: 16px; transform: none;
  flex-direction: column; align-items: flex-start; gap: 8px;
  padding: 10px 14px 12px;
}
.stage.shelving .meter-locks { display: grid; grid-template-columns: repeat(5, 32px); gap: 6px; }
.stage.shelving .meter-lock { width: 32px; height: 32px; }
.stage.shelving .progress { top: 14px; }
@media (max-width: 800px) {
  /* Narrow: keep clear of the helper's speech bubble */
  .stage.shelving .meter { bottom: auto; top: 12px; left: 12px; }
}
/* The sign is baked into the bookcase artwork (make-cabinet-signs.ps1), so the
   text label is kept for assistive tech only. */
.stage.shelving .basket-label {
  position: absolute; width: 1px; height: 1px; margin: 0; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  background: none !important; box-shadow: none;
}
/* Hover/bounce move the whole body so the spines travel with the bookcase */
.stage.shelving .basket-body { transition: transform 0.18s ease; transform-origin: bottom center; }
.stage.shelving .basket:hover img, .stage.shelving .basket.armed img,
.stage.shelving .basket:focus-visible img, .stage.shelving .basket.received img { transform: none; animation: none; }
.stage.shelving .basket:hover .basket-body, .stage.shelving .basket.armed .basket-body { transform: translateY(-6px) scale(1.03); }
.stage.shelving .basket.received .basket-body { animation: basketBounce 0.5s ease; }
/* A copy of the room clipped to whatever stands in front of the bookcases
   (e.g. the armchair), so the shelves sit behind it. Clip set by layoutShelves(). */
.foreground {
  position: absolute; inset: 0; z-index: 11;
  background: inherit; pointer-events: none;
}
/* Cameo: a character peeks in from the right edge (config.cameo) */
.cameo {
  /* A full figure leaning in from the edge, tipped over so his upper body
     angles down into the room and his hips sit on the screen edge - legs stay
     off-stage. He slides in along his own body line. --cameo-hip is how far
     down the sprite his hips are (pivot); config.cameo.side = "left" flips him. */
  --cameo-h: clamp(360px, 92vh, 900px);
  --cameo-hip: 0.40;   /* belt line, fraction of sprite height (all poses share one crop) */
  --cameo-hipx: 0.62;  /* belt buckle, fraction of sprite width */
  --cameo-tilt: -30deg;
  position: absolute; right: 0; top: calc(72% - var(--cameo-h) * var(--cameo-hip));
  z-index: 12; pointer-events: none;
  height: var(--cameo-h);
  transform-origin: calc(var(--cameo-hipx) * 100%) calc(var(--cameo-hip) * 100%);
  /* out: hips on the edge, tipped over, pushed off-stage along his body */
  transform: translateX(calc((1 - var(--cameo-hipx)) * 100%)) rotate(var(--cameo-tilt)) translateY(80%);
  opacity: 0;
  /* An unhurried lean in and back out */
  transition: transform 1.3s cubic-bezier(0.25, 0.8, 0.3, 1), opacity 0.5s ease;
}
.cameo.in { transform: translateX(calc((1 - var(--cameo-hipx)) * 100%)) rotate(var(--cameo-tilt)); opacity: 1; }
/* Left edge: the sprite is mirrored, so the hips sit at (1 - hipx) across */
.cameo.left {
  right: auto; left: 0;
  transform-origin: calc((1 - var(--cameo-hipx)) * 100%) calc(var(--cameo-hip) * 100%);
  transform: translateX(calc((var(--cameo-hipx) - 1) * 100%)) rotate(calc(-1 * var(--cameo-tilt))) translateY(80%);
}
.cameo.left.in { transform: translateX(calc((var(--cameo-hipx) - 1) * 100%)) rotate(calc(-1 * var(--cameo-tilt))); }
.cameo.left img { transform: scaleX(-1); }
.cameo img {
  display: block; height: 100%; width: auto;
  filter: drop-shadow(-6px 10px 12px rgba(40, 30, 20, 0.3));
}
@media (max-width: 800px) { .cameo { --cameo-h: clamp(260px, 70vh, 520px); } }
/* Filed books: one spine per book, in rows over the shelf compartments */
.spines { position: absolute; inset: 0; pointer-events: none; }
.shelf-row {
  position: absolute; display: flex; align-items: flex-end; gap: 2%;
}
.spine {
  position: relative;
  flex: 0 1 14%; height: var(--h, 90%);
  background:
    linear-gradient(90deg, rgba(0, 0, 0, 0.28), rgba(0, 0, 0, 0) 30%, rgba(255, 255, 255, 0.14) 55%, rgba(0, 0, 0, 0.22)),
    var(--spine);
  border-radius: 2px 2px 1px 1px;
  /* side shading plus a shadow cast onto the shelf board it stands on */
  box-shadow: 1px 0 2px rgba(0, 0, 0, 0.35), 0 3px 4px rgba(0, 0, 0, 0.35);
  transform-origin: bottom;
  animation: spineIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.spine::before, .spine::after {
  content: ""; position: absolute; left: 18%; right: 18%; height: 2px;
  background: rgba(240, 192, 64, 0.85);
}
.spine::before { top: 14%; }
.spine::after { bottom: 14%; }
@keyframes spineIn {
  0% { transform: scaleY(0.1); opacity: 0; }
  100% { transform: scaleY(1); opacity: 1; }
}
@keyframes basketBounce {
  0% { transform: scale(1); }
  35% { transform: scale(1.14) translateY(-8px); }
  70% { transform: scale(0.97); }
  100% { transform: scale(1); }
}

/* ══ Sage ══ */
.sage {
  position: absolute; bottom: 3.5vh; left: 50%; transform: translateX(-50%);
  z-index: 13;
  display: flex; align-items: flex-end; gap: 12px;
  max-width: min(520px, 44vw);
}
.sage-face {
  width: 92px; height: 92px; border-radius: 50%;
  border: 4px solid #fff; object-fit: cover;
  box-shadow: var(--shadow);
  flex-shrink: 0;
}
.sage-bubble {
  position: relative;
  background: var(--panel);
  border-radius: 20px 20px 20px 6px;
  padding: 14px 18px;
  box-shadow: var(--shadow);
  min-width: 220px;
}
.sage-bubble p { font-size: 16px; font-weight: 800; line-height: 1.45; }
.sage-bubble.tip-good { border: 3px solid var(--green); }
.sage-bubble.tip-gentle { border: 3px solid var(--gold); }
.sage-bubble.tip-note { border: 3px solid var(--lav); }
.sage-bubble .btn { margin-top: 10px; }
.sage-bubble.pop { animation: bubblePop 0.35s ease; }
@keyframes bubblePop {
  0% { transform: scale(0.85); opacity: 0.4; }
  100% { transform: scale(1); opacity: 1; }
}

/* ══ Demo hand ══ */
.demo-hand {
  position: fixed; z-index: 60; width: 64px; height: 64px;
  pointer-events: none;
  /* Moved with transform (GPU-composited), never top/left, to stay smooth. */
  will-change: transform;
  filter: drop-shadow(0 6px 10px rgba(58, 51, 80, 0.35));
}

/* ══ Overlays & panels ══ */
.overlay[hidden] { display: none; }
.overlay {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  padding: 84px 16px 24px;
  background: rgba(42, 34, 64, 0.45);
  backdrop-filter: blur(5px);
  overflow-y: auto;
}
.panel {
  background: var(--panel);
  border-radius: 28px;
  box-shadow: 0 24px 64px rgba(30, 24, 48, 0.4);
  padding: 34px 38px;
  width: min(560px, 94vw);
  text-align: center;
  margin: auto;
}
.panel h1 { font-size: clamp(28px, 4vw, 40px); font-weight: 900; line-height: 1.1; margin-bottom: 4px; }
.panel h2 { font-size: 30px; font-weight: 900; margin-bottom: 8px; }
.panel-shop {
  font-size: 13px; font-weight: 900; text-transform: uppercase;
  letter-spacing: 1.5px; color: var(--lav); margin-bottom: 6px;
}
.entry-sage {
  width: 130px; height: 130px; border-radius: 50%;
  border: 5px solid var(--gold); object-fit: cover;
  margin: 18px auto 14px; display: block;
  box-shadow: var(--shadow);
}
.entry-welcome { font-size: 18px; font-weight: 700; line-height: 1.55; margin-bottom: 12px; }
.entry-note {
  font-size: 15px; font-weight: 800; color: var(--ink-soft);
  background: var(--green-soft); border-radius: 12px;
  padding: 10px 14px; margin-bottom: 22px;
}
.entry-quick-note { margin-top: 18px; font-size: 13px; font-weight: 700; color: var(--ink-soft); }
.pause-text { font-size: 17px; font-weight: 700; color: var(--ink-soft); margin-bottom: 22px; }

.panel-buttons { display: flex; flex-direction: column; gap: 10px; align-items: stretch; }

.btn {
  border: none; border-radius: 16px;
  background: #fff; color: var(--ink);
  border: 2px solid rgba(58, 51, 80, 0.16);
  font-weight: 900;
  transition: transform 0.12s, box-shadow 0.12s;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(1px); }
.btn-big { font-size: 19px; padding: 15px 26px; min-height: 58px; }
.btn-small { font-size: 15px; padding: 8px 18px; min-height: 42px; }
.btn-primary {
  background: var(--gold); border-color: var(--gold);
  box-shadow: 0 5px 0 var(--gold-dim);
}
.btn-primary:hover { box-shadow: 0 7px 0 var(--gold-dim), 0 8px 18px rgba(58, 51, 80, 0.2); }
.btn-primary:active { box-shadow: 0 2px 0 var(--gold-dim); }

/* ══ Completion ══ */
.done-panel h2 { margin-top: 14px; }
.badge {
  width: 148px; height: 148px; margin: 0 auto;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 38%, #fff8e2, #ffe9a8);
  border: 6px solid var(--gold);
  box-shadow: 0 0 0 6px rgba(240, 192, 64, 0.3), var(--shadow);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 16px; overflow: hidden;
  animation: badgeSpin 0.9s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes badgeSpin {
  0% { transform: scale(0.2) rotate(-180deg); opacity: 0; }
  100% { transform: scale(1) rotate(0); opacity: 1; }
}
.badge img { width: 62px; height: 62px; border-radius: 50%; object-fit: cover; }
.badge span {
  font-size: 12px; font-weight: 900; color: var(--gold-dim);
  text-transform: uppercase; letter-spacing: 0.5px;
  text-align: center; line-height: 1.15; max-width: 104px;
}
.done-text { font-size: 18px; font-weight: 700; line-height: 1.5; margin: 10px 0 22px; }

.help-box {
  margin-top: 24px; text-align: left;
  background: var(--cream); border-radius: 16px; padding: 16px 20px;
}
.help-title { font-size: 14px; font-weight: 900; margin-bottom: 10px; }
.help-box ul { list-style: none; }
.help-box li {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 7px 0; font-size: 15px; font-weight: 700;
  border-bottom: 1px solid rgba(58, 51, 80, 0.08);
}
.help-box li:last-child { border-bottom: none; }
.help-box li span:last-child { color: var(--ink-soft); text-align: right; }

/* ══ Sparkles ══ */
.spark {
  position: fixed; z-index: 90; pointer-events: none;
  width: 12px; height: 12px;
  clip-path: polygon(50% 0%, 63% 37%, 100% 50%, 63% 63%, 50% 100%, 37% 63%, 0% 50%, 37% 37%);
  animation: sparkFly 0.9s ease-out forwards;
}
@keyframes sparkFly {
  0% { transform: translate(0, 0) scale(1) rotate(0deg); opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(0.1) rotate(180deg); opacity: 0; }
}

/* ══ Studio theme (config.theme = "studio", Ref 61) ══ */
/* Signal lamps: a halo behind each lamp head and a pool of light on the floor.
   Colour comes from config.bins[].glow (set as --glow by game.js). */
.basket-glow { display: none; }
.basket.has-glow .basket-glow {
  display: block;
  position: absolute; z-index: -1;
  left: 50%; top: 4%;
  width: 150%; aspect-ratio: 1;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(circle, #ffffff 0%, var(--glow) 22%, transparent 62%);
  mix-blend-mode: screen;
  opacity: 0.5;
  filter: blur(10px);
  transition: opacity 0.3s ease, transform 0.3s ease;
  animation: lampIdle 4s ease-in-out infinite;
}
.basket.has-glow .basket-glow::after {
  /* faint coloured light pooling on the floor around the base (no white
     centre - it read as a pale smudge under the stand) */
  content: ""; position: absolute;
  left: 50%; bottom: -36%;
  width: 90%; height: 26%;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(ellipse, var(--glow) 0%, transparent 65%);
  opacity: 0.45;
}
@keyframes lampIdle {
  0%, 100% { opacity: 0.45; }
  50% { opacity: 0.62; }
}
.basket.has-glow:hover .basket-glow,
.basket.has-glow:focus-visible .basket-glow,
.basket.has-glow.armed .basket-glow { opacity: 0.95; animation: none; transform: translateX(-50%) scale(1.1); }
.basket.has-glow.received .basket-glow { animation: lampFlare 1.1s ease-out; }
@keyframes lampFlare {
  0% { opacity: 1; transform: translateX(-50%) scale(1.45); filter: blur(6px); }
  100% { opacity: 0.5; transform: translateX(-50%) scale(1); filter: blur(10px); }
}
.theme-studio .basket img { width: clamp(150px, 19vw, 230px); }
.theme-studio .basket:hover img, .theme-studio .basket.armed img {
  filter: drop-shadow(0 12px 14px rgba(58, 51, 80, 0.4)) drop-shadow(0 0 22px var(--glow, #ffe896));
}
/* ── Basketball hoops (config.hoop) ──
   A live SVG net hangs from the rim (positioned by game.js from the rim
   geometry). When a card drops through, it stretches and sways. */
.hoop-net {
  position: absolute;
  overflow: visible;
  pointer-events: none;
  transform-origin: 50% 0;
  filter: drop-shadow(0 2px 2px rgba(58, 51, 80, 0.35));
  will-change: transform;
}
.hoop-net .net-mesh {
  fill: none; stroke: #fffaf0; stroke-width: 2.4;
  stroke-linecap: round; stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.hoop-net .net-loop {
  fill: none; stroke: #fffaf0; stroke-width: 2.6;
  vector-effect: non-scaling-stroke;
}
.stage.hoops .basket:hover .hoop-net, .stage.hoops .basket.armed .hoop-net { animation: netSway 1.2s ease-in-out infinite; }
.stage.hoops .basket .hoop-net.swish { animation: netSwish 0.8s cubic-bezier(0.25, 0.8, 0.3, 1); }
@keyframes netSwish {
  0%   { transform: scale(1, 1); }
  28%  { transform: scale(0.9, 1.32) skewX(0deg); }
  50%  { transform: scale(1.04, 0.96) skewX(6deg); }
  70%  { transform: scale(0.98, 1.06) skewX(-4deg); }
  85%  { transform: scale(1.01, 0.99) skewX(2deg); }
  100% { transform: scale(1, 1) skewX(0deg); }
}
@keyframes netSway {
  0%, 100% { transform: skewX(0deg); }
  50% { transform: skewX(3deg); }
}
/* Backboard lights (config.hoop.board): a ring of bulbs around the board and
   a light layer over it, in the bin's `light` colour (--light, set by
   game.js). Dim at rest with a slow idle twinkle; a card dropping through
   adds .lit - the bulbs chase twice round the board, the whole board lights
   up, then it all settles back. */
.board-lights {
  position: absolute;
  overflow: visible;
  pointer-events: none;
  z-index: 1;
}
.board-lights .board-glow {
  fill: var(--light, #fff);
  opacity: 0;
  mix-blend-mode: screen;
}
.board-lights .bulb {
  opacity: 0.32;
  animation: bulbIdle 3.2s calc(var(--i, 0) * -0.27s) ease-in-out infinite;
}
.board-lights .bulb-glass {
  fill: var(--light, #fff);
  stroke: rgba(255, 255, 255, 0.6);
  stroke-width: 0.7;
  vector-effect: non-scaling-stroke;
}
.board-lights .bulb-shine { fill: #fff; opacity: 0.75; }
@keyframes bulbIdle {
  0%, 100% { opacity: 0.28; }
  50% { opacity: 0.46; }
}
.stage.hoops .basket:hover .board-lights .bulb,
.stage.hoops .basket.armed .board-lights .bulb { opacity: 0.7; animation: none; }
.stage.hoops .basket:hover .board-lights .board-glow,
.stage.hoops .basket.armed .board-lights .board-glow { opacity: 0.16; transition: opacity 0.25s ease; }
.board-lights.lit {
  filter: drop-shadow(0 0 6px var(--light, #fff));
  animation: boardHalo 2s ease-out forwards;
}
.board-lights.lit .board-glow {
  animation: boardBlaze 2s ease-out forwards;
}
.board-lights.lit .bulb {
  animation:
    bulbChase 0.55s calc(var(--i, 0) * 0.55s / 24) linear 2,
    bulbBlaze 0.9s 1.1s ease-out forwards;
}
.board-lights.lit .bulb-glass {
  animation:
    bulbSwell 0.55s calc(var(--i, 0) * 0.55s / 24) linear 2,
    bulbSwellHold 0.9s 1.1s ease-out forwards;
}
@keyframes bulbChase {
  0% { opacity: 1; }
  22% { opacity: 1; }
  60% { opacity: 0.3; }
  100% { opacity: 0.3; }
}
@keyframes bulbBlaze {
  0% { opacity: 1; }
  35% { opacity: 1; }
  100% { opacity: 0.32; }
}
/* Lit bulbs flash white-hot, then settle back to their colour. */
@keyframes bulbSwell {
  0% { r: 3.3; fill: #fff; }
  22% { r: 3; fill: #fff; }
  60%, 100% { r: 2.3; fill: var(--light, #fff); }
}
@keyframes bulbSwellHold {
  0% { r: 3.3; fill: #fff; }
  35% { r: 3.1; fill: #fffbe8; }
  100% { r: 2.3; fill: var(--light, #fff); }
}
@keyframes boardBlaze {
  0% { opacity: 0.08; }
  50% { opacity: 0.16; }
  58% { opacity: 0.5; }
  72% { opacity: 0.4; }
  100% { opacity: 0; }
}
@keyframes boardHalo {
  0%, 50% { filter: drop-shadow(0 0 3px var(--light, #fff)); }
  60% { filter: drop-shadow(0 0 12px var(--light, #fff)); }
  100% { filter: drop-shadow(0 0 0 transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .board-lights .bulb { animation: none; }
  .board-lights.lit .bulb { animation: bulbBlaze 1.6s ease-out forwards; }
  .board-lights.lit { animation: none; }
}
/* Hovering/arming lifts the hoop; the net lifts with its image (same body),
   so keep the image lift modest or the net parts from the rim. */
.stage.hoops .basket:hover img, .stage.hoops .basket.armed img { transform: none; }
.stage.hoops .basket-body { transition: transform 0.18s ease; transform-origin: bottom center; }
.stage.hoops .basket:hover .basket-body, .stage.hoops .basket.armed .basket-body { transform: translateY(-6px) scale(1.04); }
.stage.hoops .basket.received img { animation: none; }
.stage.hoops .basket.received .basket-body { animation: hoopNudge 0.5s ease; }
@keyframes hoopNudge {
  0% { transform: translateY(0); }
  30% { transform: translateY(3px) scale(0.99); }
  60% { transform: translateY(-2px); }
  100% { transform: translateY(0); }
}

/* Hoops: the label is printed flat onto the sign hanging from the post (box
   set by game.js from config.hoop.plaque) - no pill, no shadow, ink colour
   from config.bins[].ink. Font size is set by game.js from the hoop width. */
.stage.hoops .basket-label.on-plaque {
  position: absolute; margin: 0; padding: 0 3%;
  transform: none;
  display: flex; align-items: center; justify-content: center; text-align: center;
  box-sizing: border-box;
  background: none; border: none; box-shadow: none; border-radius: 0;
  white-space: normal; line-height: 0.98;
  font-weight: 900; letter-spacing: 0.01em;
  font-size: 14px;            /* overridden per hoop width by game.js */
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.55); /* pressed into the sign */
  pointer-events: none;
}
.stage.hoops .basket img { width: clamp(215px, 27vw, 330px); }
.theme-studio .basket-label {
  position: absolute; left: 50%; top: 56%;
  transform: translateX(-50%);
  margin: 0; white-space: nowrap;
  font-size: clamp(14px, 1.4vw, 17px);
  padding: 7px 16px;
  border: 2px solid rgba(255, 255, 255, 0.85);
}
.theme-studio .basket { padding-bottom: 10px; }

/* The behaviour card reads like a pane of the mirror screen: cool glass tint,
   a lavender rim and a soft light sweep across the picture. */
.theme-studio .game-card {
  background: linear-gradient(165deg, #ffffff 0%, #f8f4ff 60%, #eef9f3 100%);
  border-color: rgba(185, 165, 216, 0.55);
  box-shadow: var(--shadow), 0 0 0 7px rgba(255, 255, 255, 0.3), 0 0 46px rgba(205, 190, 235, 0.55);
}
.theme-studio .card-art { position: relative; background: #fbf4e6; }
.theme-studio .card-art::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(115deg,
    rgba(255, 255, 255, 0) 35%, rgba(255, 255, 255, 0.55) 48%, rgba(255, 255, 255, 0) 60%);
  background-size: 300% 100%;
  animation: sheenSweep 9s -2s ease-in-out infinite;
}
.theme-studio .card-label { font-size: 19px; }
/* The card materialises out of the gathered light instead of dropping in */
.theme-studio .game-card.entering {
  animation: cardMaterialise 0.6s cubic-bezier(0.2, 0.9, 0.3, 1.15), cardFloat 3.2s 0.6s ease-in-out infinite;
}
@keyframes cardMaterialise {
  0%   { transform: scale(0.2); opacity: 0; filter: blur(10px) brightness(2.2); }
  55%  { opacity: 1; filter: blur(2px) brightness(1.5); }
  100% { transform: scale(1); opacity: 1; filter: blur(0) brightness(1); }
}
.theme-studio .card-speak { background: #8ee68a; }
/* The card zone is pinned to the mirror's centre (config.anchors). Only the
   card sits in the centred box; the hint and Skip hang below it so they do
   not pull the card down off the mirror. */
.theme-studio .card-zone { gap: 0; }
.theme-studio .card-hint {
  position: absolute; top: calc(100% + 14px); left: 50%;
  transform: translateX(-50%); white-space: nowrap;
}
.theme-studio .card-skip {
  position: absolute; top: calc(100% + 56px); left: 50%;
  transform: translateX(-50%); white-space: nowrap;
}
.theme-studio .card-skip:hover { transform: translate(-50%, -2px); }
.theme-studio .card-skip:active { transform: translate(-50%, 1px); }

/* Meter: each sorted card turns a light green */
.theme-studio .meter-lock .lock-shackle { fill: none; stroke: #d8d0e6; stroke-width: 2; }
.theme-studio .meter-lock .lock-body { fill: #e6e0f0; }
.theme-studio .meter-lock.locked .lock-body { fill: #5fd35f; }
.theme-studio .meter-lock.locked .lock-shackle { stroke: #3f9a3a; }
.theme-studio .meter-lock.locked svg { filter: drop-shadow(0 0 5px rgba(95, 211, 95, 0.8)); }

/* ── Celebration: confetti and streamers from the ceiling (bins[].celebrate) ── */
/* Two layers per piece: the outer span falls at a steady rate and drifts
   sideways (linear, so nothing stalls mid-air); the inner element tumbles,
   flutters or twists on its own clock, which is what makes it read as paper. */
.confetti, .streamer {
  position: absolute; top: -30px; z-index: 13;
  pointer-events: none;
  will-change: transform, opacity;
  perspective: 120px;
  transform-style: preserve-3d;
  animation: pieceFall var(--dur, 3s) var(--delay, 0s) linear forwards;
  opacity: 0;
}
@keyframes pieceFall {
  0%   { transform: translate(0, 0) scale(var(--scale, 1)); opacity: 0; }
  5%   { opacity: 1; }
  50%  { transform: translate(calc(var(--drift) * 0.6), 52vh) scale(var(--scale, 1)); }
  93%  { opacity: 1; }
  100% { transform: translate(var(--drift), 104vh) scale(var(--scale, 1)); opacity: 0; }
}
/* Confetti: a small paper piece. The <i> tumbles about a tilted axis, so it
   goes edge-on (thin) and face-on (wide) each turn, while zig-zagging. The
   back face is a darker shade of the same colour. */
.confetti > i {
  display: block;
  width: 11px; height: 15px;
  border-radius: 2px;
  background: var(--c);
  background-image: linear-gradient(135deg, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0) 55%, rgba(0, 0, 0, 0.12));
  box-shadow: 0 1px 1px rgba(58, 51, 80, 0.12);
  transform-origin: center;
  animation: confettiTumble var(--flip, 0.9s) ease-in-out infinite;
}
.confetti-round > i { width: 11px; height: 11px; border-radius: 50%; }
.confetti-strip > i { width: 6px; height: 20px; border-radius: 3px; }
@keyframes confettiTumble {
  0%   { transform: rotate(var(--tilt)) translateX(calc(var(--amp) * -1)) rotateX(0deg)   rotateY(-15deg); filter: brightness(1.05); }
  25%  { transform: rotate(var(--tilt)) translateX(0)                      rotateX(90deg)  rotateY(0deg);   filter: brightness(0.8); }
  50%  { transform: rotate(var(--tilt)) translateX(var(--amp))             rotateX(180deg) rotateY(15deg);  filter: brightness(0.9); }
  75%  { transform: rotate(var(--tilt)) translateX(0)                      rotateX(270deg) rotateY(0deg);   filter: brightness(0.78); }
  100% { transform: rotate(var(--tilt)) translateX(calc(var(--amp) * -1)) rotateX(360deg) rotateY(-15deg); filter: brightness(1.05); }
}
/* Streamer: a wavy ribbon (SVG S-curve) hanging from its top. It twists
   about its length so the face catches light then goes thin, and swings
   like a pendulum from the top. */
.streamer { top: -170px; }
.streamer .ribbon {
  display: block;
  width: 20px; height: 150px;
  overflow: visible;
  transform-origin: 50% 0;
  filter: drop-shadow(0 2px 2px rgba(58, 51, 80, 0.18));
  animation: ribbonTwist var(--twist, 1.2s) ease-in-out infinite;
}
@keyframes ribbonTwist {
  0%   { transform: rotate(calc(var(--swing) * -1)) rotateY(-70deg) scaleY(1);    filter: brightness(1.1) drop-shadow(0 2px 2px rgba(58, 51, 80, 0.18)); }
  50%  { transform: rotate(var(--swing))            rotateY(70deg)  scaleY(0.94); filter: brightness(0.82) drop-shadow(0 2px 2px rgba(58, 51, 80, 0.18)); }
  100% { transform: rotate(calc(var(--swing) * -1)) rotateY(-70deg) scaleY(1);    filter: brightness(1.1) drop-shadow(0 2px 2px rgba(58, 51, 80, 0.18)); }
}

/* Heart-shaped sparkles for the Respect lamp (config.bins[].sparkShape) */
.spark.spark-heart {
  width: 15px; height: 14px;
  clip-path: path("M7.5 14C2.5 10 0 7.2 0 4.3 0 1.9 1.9 0 4.3 0 5.6 0 6.8.7 7.5 1.8 8.2.7 9.4 0 10.7 0 13.1 0 15 1.9 15 4.3 15 7.2 12.5 10 7.5 14Z");
}

/* Entry and finish panels pick up the studio palette */
.theme-studio .panel-shop { color: #7a9a5c; }
.theme-studio .entry-sage { border-color: #8ee68a; }
.theme-studio .entry-note { background: #eef5ff; }

/* ══ Responsive ══ */
@media (max-width: 900px) {
  .tb-btn span { display: none; }
  .tb-btn.quick-exit span { display: inline; }
  .game-card { width: 190px; }
  .card-label { font-size: 18px; min-height: 44px; }
  .sage { max-width: 60vw; }
  .sage-face { width: 70px; height: 70px; }
  .sage-bubble p { font-size: 14px; }
}
@media (max-width: 640px) {
  .meter { padding: 8px 12px; }
  .meter-lock { width: 24px; height: 24px; }
  .progress { top: 62px; }
  .card-zone { top: 42%; }
  .basket { bottom: 2vh; padding: 8px; }
  #basketLeft { left: 1vw; }
  #basketRight { right: 1vw; }
  .sage { position: absolute; bottom: 2vh; max-width: 46vw; }
  .sage-face { display: none; }
  .theme-studio .basket img { width: 124px; }
  .theme-studio .basket-label { font-size: 13px; padding: 5px 12px; }
  .stage.hoops .basket img { width: 175px; }
}

/* ══ Reduced motion ══ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
