/* ============================================================================
   Playit — GLOBAL theme. Only things that repeat on EVERY SITE page live here:
   base/reset, the page scaffold, the arcade background + glitch sprites, and the
   header/brand. Page-specific rules live in that page's own file (e.g.
   landing.css), loaded after this one. The fonts, colour tokens and .btn system
   are one level below, in kit.css — shared with the played game frame (see the
   note under this header), so re-theming means editing THAT one place.
   ============================================================================ */

/* ---- Fonts, colour tokens and the .btn system now live in kit.css ----
   They moved because the played GAME frame needs them too: it is a sandboxed,
   opaque-origin document that can never inherit this stylesheet, so the two
   halves of the product would otherwise drift into look-alike buttons and
   near-miss colours. base.html links kit.css BEFORE this file; the BFF injects
   the same file into every served game page. Add a token or a button variant
   THERE, not here. Everything below is site-only: base/reset, the page
   scaffold, the arcade background, and the header. ---- */

/* ---- Base / reset ---- */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* The `hidden` attribute must always win, even over a class that sets display
   (e.g. a flex row we show/hide from JS). Keeps toggle logic simple and safe. */
[hidden] { display: none !important; }
body {
  min-height: 100vh;
  color: var(--color-text);
  font-family: var(--font-body);
  background-color: var(--color-ink);
  /* soft glow that fades from top-centre down into the ink */
  background-image: radial-gradient(1100px 700px at 50% -10%,
    var(--color-bg-top) 0%, var(--color-panel-raised) 45%, var(--color-ink) 100%);
  background-repeat: no-repeat;
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  image-rendering: pixelated;
}
::selection { background: var(--color-pink); color: var(--color-ink); }

/* Text for screen readers only — a heading or a label a sighted player doesn't need spelled out. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---- Page scaffold: content sits above the decorative backdrop ---- */
.page {
  position: relative;
  z-index: 40;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.page-main {
  flex: 1 1 auto;
  width: 100%;
  max-width: 1140px;
  margin: 0 auto;
  padding: 18px 22px 90px;
}

/* ---- Arcade backdrop (decorative; never captures clicks) ---- */
.bg-grid {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 44px 44px;
  -webkit-mask-image: radial-gradient(circle at 50% 30%, #000 0%, transparent 78%);
  mask-image: radial-gradient(circle at 50% 30%, #000 0%, transparent 78%);
}
.glow {
  position: fixed;
  z-index: 0;
  pointer-events: none;
  border-radius: 50%;
}
.glow-pink {
  top: -160px; left: -120px;
  width: 520px; height: 520px;
  background: radial-gradient(circle, var(--glow-pink), transparent 68%);
}
.glow-cyan {
  right: -140px; bottom: -200px;
  width: 560px; height: 560px;
  background: radial-gradient(circle, var(--glow-cyan), transparent 68%);
}
.scanlines {
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  mix-blend-mode: multiply;
  background: repeating-linear-gradient(
    rgba(0, 0, 0, 0) 0px, rgba(0, 0, 0, 0) 2px, rgba(0, 0, 0, .16) 3px);
}
.vignette {
  position: fixed;
  inset: 0;
  z-index: 89;
  pointer-events: none;
  background: radial-gradient(ellipse at center, transparent 60%, rgba(0, 0, 0, .45));
}

/* Floating pixel sprites. Each gently drifts (transform, via CSS below). The
   glitch + teleport is driven by JS (static/js/global.js): it adds `.is-glitching`
   for a brief window and jumps left/top to a new
   random spot, then removes it. The float (transform) and glitch (on the inner
   svg) never fight. */
.floating-sprite {
  position: fixed;
  z-index: 2;
  pointer-events: none;
  will-change: transform, left, top;
}
/* The sprite rests at 0.3 opacity; the glitch animation drives its own
   opacity/filter/clip while flashing. */
.floating-sprite svg { display: block; opacity: .3; }
.floating-sprite.is-glitching svg { animation: sprite-glitch .38s steps(2) infinite; }
.floating-sprite-1 { left: 6%;  top: 16%; animation: float-a 7s ease-in-out infinite; }
.floating-sprite-2 { left: 87%; top: 32%; animation: float-b 9s ease-in-out infinite; }
.floating-sprite-3 { left: 12%; top: 78%; animation: float-c 6s ease-in-out infinite; }

/* ---- Brand (logo mark + wordmark), a link home to the landing, in the header
   on every page. It's an <a>, so drop the underline; the wordmark keeps its own
   colour (set below). On hover the mark glows to show it's tappable. ---- */
.brand { display: flex; align-items: center; gap: 12px; text-decoration: none; }
.brand-mark {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  background: var(--color-panel-raised);
  border: 3px solid var(--color-pink);
  box-shadow: 0 4px 0 var(--color-pink-shadow);
  transition: box-shadow .12s;
}
.brand:hover .brand-mark { box-shadow: 0 4px 0 var(--color-pink-shadow), 0 0 12px var(--glow-pink); }
.brand-mark svg { display: block; }
.brand-wordmark {
  font-family: var(--font-display);
  font-size: 15px;
  letter-spacing: 1px;
  color: var(--color-text);
  text-shadow: 2px 2px 0 var(--color-shadow-ink);
  white-space: nowrap;
}
.wordmark-accent { color: var(--color-green); }

/* ---- Coin icon (global partial): shown wherever a coin cost appears. Size is
   set per place that uses it; here we just keep it a tidy inline block. ---- */
.coin-icon { display: block; }

/* ---- Site header ---- */
/* In-flow by default (every page except the landing page, which fixes it — see landing.css —
   for its scroll-snap sections; the IDE/play full-viewport shells already never scroll, so a
   fixed header there would only add complexity for no benefit). */
.site-header {
  position: relative;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 22px;
  border-bottom: 3px solid var(--color-line);
  background: var(--header-glass);
  backdrop-filter: blur(4px);
}
.header-actions { display: flex; align-items: center; gap: 9px; }

/* The desktop primary nav — HOME + BROWSE & PLAY (neither needs an account). TRULY centred via
   absolute positioning on the wrapper (not space-between, which would drift with the width of the
   brand or the account/login controls on either side; `.site-header` is already
   position:relative). Folded into the burger menu below 1080px signed in / 820px signed out — see
   "Mid-size screens" near the end of this file. */
.header-nav {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 24px;
}
/* A small button-pill — same "outline, fills solid on the active page" shape as the gallery's own
   .filter-tab, so the two arcade-tab patterns in the app stay visually the same component.
   --nav-accent is set per item below; currentColor on the icon's SVG fill means the glyph always
   matches (dim outline at rest, dark ink once the fill lights up). */
.header-nav-btn {
  --nav-accent: var(--color-cyan);
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: .5px;
  color: var(--color-text-dim);
  text-decoration: none;
  white-space: nowrap;
  background: var(--color-panel);
  border: 3px solid var(--color-line);
  border-radius: 4px;
  padding: 9px 14px;
  cursor: pointer;
}
.header-nav-btn:hover { color: var(--color-text); border-color: var(--color-line-2); }
.header-nav-btn.is-active {
  color: var(--color-ink);
  background: var(--nav-accent);
  border-color: var(--nav-accent);
}
.header-nav-btn-home { --nav-accent: #ff8ac0; }
.header-nav-btn-browse { --nav-accent: var(--color-cyan); }
.header-nav-icon { display: inline-flex; }
.header-nav-icon svg { display: block; }
/* The divider between HOME and BROWSE & PLAY — same look as the one between the balance badge and
   the account chip. */
.header-nav-sep { width: 3px; height: 34px; background: var(--color-line); }

/* ---- Logged-in header: the account chip + its dropdown (Credits balance, Top Up, Account Info /
   Edit Profile, and LOG OUT). ---- */
.header-account { position: relative; }
.account-chip {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 9px;
  background: var(--color-panel-raised);
  border: 3px solid var(--color-green);
  box-shadow: 0 4px 0 var(--color-green-shadow);
  padding: 7px 11px;
}
.account-avatar {
  width: 26px;
  height: 26px;
  flex: none;
  display: grid;
  place-items: center;
  background: var(--color-green);
  border: 2px solid var(--color-ink);
  /* The person icon (partial/icon/person.html) is fill:currentColor — ink on the green chip. */
  color: var(--color-ink);
}
.account-avatar svg { display: block; }
.account-who { display: flex; flex-direction: column; align-items: flex-start; line-height: 1; }
.account-label {
  font-family: var(--font-body);
  font-size: 12px;
  letter-spacing: 1px;
  color: var(--color-muted-2);
}
.account-name {
  font-family: var(--font-display);
  font-size: 11px;
  color: var(--color-green);
  margin-top: 4px;
  max-width: 96px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.account-caret {
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--color-green);
  margin-left: 2px;
}

/* The dropdown: a small arcade menu that rises in under whatever toggles it. 250px wide so item
   labels sit on one line. Generic — shared by the account chip's dropdown AND
   the mobile burger's panel (partial/header.html + partial/account_menu_items.html), so there's one
   copy of this component instead of two drifting ones. */
.dropdown-menu {
  position: absolute;
  top: calc(100% + 12px);
  right: 0;
  width: 250px;
  z-index: 70;
  background: var(--color-panel);
  border: 3px solid var(--color-green);
  box-shadow: 0 0 0 3px var(--color-ink), 8px 10px 0 rgba(0, 0, 0, .55);
  animation: menu-rise .16s ease both;
}
.dropdown-item-form { margin: 0; }
.dropdown-item {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  box-sizing: border-box;
  cursor: pointer;
  background: transparent;
  border: none;
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: 9px;
  letter-spacing: 1px;
  color: var(--color-text);
  padding: 13px 14px;
}
.dropdown-item-icon { width: 20px; flex: none; display: inline-flex; justify-content: center; }
/* Hover: a dark highlight, and the label takes each item's accent colour. */
.dropdown-item:hover { background: #1a1642; }
.dropdown-item-topup:hover { color: var(--color-gold); }
.dropdown-item-inventory .dropdown-item-icon { color: var(--color-pink); }
.dropdown-item-inventory:hover { color: var(--color-pink); }
.dropdown-item-mygames:hover { color: var(--color-green); }
.dropdown-item-account:hover { color: var(--color-cyan); }
.dropdown-item-danger { color: var(--color-pink-light); }
.dropdown-item-danger:hover { background: #2a1030; color: var(--color-pink); }
/* The solid rule above LOG OUT (distinct from the Credits row's dashed underline). */
.dropdown-sep { height: 2px; background: #2a2758; margin: 2px 0; }

/* The dropdown's rise-in: it slides up a touch and fades in as it opens. */
@keyframes menu-rise {
  from { transform: translateY(10px); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .dropdown-menu { animation: none; }
  .header-balance-coin { animation: none; }
}

/* ---- The burger menu (shown below 1080px signed in, 820px signed out — see the media queries at
   the end of this file).
   Collapses the nav link + whatever the desktop right side shows (account info or login/register)
   into one [data-menu-toggle] group, wired by the SAME header.js as the account chip. ---- */
.header-burger-wrap { position: relative; display: none; }
.header-burger {
  width: 38px;
  height: 38px;
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  cursor: pointer;
  background: var(--color-panel-raised);
  border: 3px solid var(--color-line-2);
}
.header-burger-bar { width: 18px; height: 2px; background: var(--color-text); }

/* ---- Logged-in header: the coin BALANCE badge, sitting left of the account chip. The badge, a
   thin divider, and the chip share one flex row (.header-right). ---- */
.header-right { display: flex; align-items: center; gap: 18px; }
/* The badge is a button (it opens the Top Up overlay — partial/header.html). The negative margin
   cancels the padding, so the tap area grows without shifting the header layout. */
.header-balance {
  display: flex;
  align-items: center;
  gap: 9px;
  background: none;
  border: 0;
  padding: 7px 5px;
  margin: -7px -5px;
  font: inherit;
  cursor: pointer;
}
/* Hovering (or keyboard-focusing) the badge brightens the gold count — a gentle "I'm tappable". */
.header-balance:hover .header-balance-count,
.header-balance:focus-visible .header-balance-count { color: #ffe35a; }
.header-balance:hover .header-balance-label,
.header-balance:focus-visible .header-balance-label { color: var(--color-text); }
/* The coin bobs gently and casts a hard pixel shadow. */
.header-balance-coin {
  display: inline-flex;
  filter: drop-shadow(0 3px 0 rgba(0, 0, 0, .45));
  animation: coin-bob 2.4s ease-in-out infinite;
}
.header-balance-coin .coin-icon { width: 30px; height: 30px; }
.header-balance-text { display: flex; flex-direction: column; align-items: flex-start; line-height: 1; }
.header-balance-label {
  font-family: var(--font-body);
  font-size: 13px;
  letter-spacing: 1px;
  color: var(--color-muted-2);
}
.header-balance-count {
  font-family: var(--font-display);
  font-size: 18px;
  color: var(--color-gold);
  text-shadow: 2px 2px 0 #7a5200;
  margin-top: 4px;
}
/* The thin vertical rule between the balance and the account chip. */
.header-divider { width: 3px; height: 34px; background: var(--color-line); }

/* The Credits balance line at the top of the account dropdown (mirrors the badge). The count is
   pushed to the far right; a dashed rule separates it from the LOG OUT item below. Shared by the
   desktop dropdown and the mobile menu (partial/account_menu_items.html). */
.dropdown-credits {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 14px 14px 13px;
  border-bottom: 2px dashed #3a3670;
}
.dropdown-credits .coin-icon { width: 16px; height: 16px; }
.dropdown-credits-label { font-family: var(--font-body); font-size: 16px; color: var(--color-muted); }

.dropdown-credits-count {
  margin-left: auto;
  font-family: var(--font-display);
  font-size: 13px;
  color: var(--color-gold);
  text-shadow: 1px 1px 0 #7a5200;
}

/* The coin's gentle up-and-down bob. */
@keyframes coin-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3px); }
}

/* ---- Coin-balance counter animation (coins.js) ---- */
/* Any live balance eases its colour so the up/down flash fades in and out. */
.coin-live { transition: color .2s, text-shadow .2s; }
/* While ticking, the number flashes green counting UP / pink counting DOWN, then reverts to gold. */
.coins-up { color: var(--color-green); text-shadow: 2px 2px 0 var(--color-green-shadow); }
.coins-down { color: var(--color-pink); text-shadow: 2px 2px 0 var(--color-pink-shadow); }
/* The header coin gives a quick pop when the balance changes (overrides the resting bob briefly). */
.coins-pop { animation: coin-pop .5s ease; }
@keyframes coin-pop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.35) rotate(-8deg); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .coin-live { transition: none; }
  .coins-pop { animation: none; }
}

/* ---- The arcade filter tab (the gallery's style tabs, My Inventory's kind tabs) ----
   An outlined pill that fills solid in its accent once active. --style-accent is the accent (cyan
   unless the page sets one per tab — the gallery gives each style its own colour). */
.filter-tab {
  --style-accent: var(--color-cyan);
  font-family: var(--font-display);
  font-size: 11px;
  color: var(--color-text-dim);
  background: var(--color-panel);
  border: 3px solid var(--color-line);
  border-radius: 4px;
  padding: 11px 20px;
  cursor: pointer;
}
.filter-tab.is-active {
  color: var(--color-ink);
  background: var(--style-accent);
  border-color: var(--style-accent);
}

/* ---- The icon-only "+" add button (the IDE's ASSETS tab, My Inventory) ----
   A .btn with a colour variant, squarer and roomier than a text button, holding a big pixel "+"
   (partial/icon/plus.html) that centres perfectly via flex — no font-baseline drift. The .btn
   ledge/lift (kit.css) still gives it the arcade feel. Use: class="btn btn-green btn-plus". */
.btn-plus { padding: 8px 16px; }
.btn-plus-icon { display: inline-flex; }
.btn-plus-icon svg { width: 22px; height: 22px; display: block; }

/* ---- The neon meter bar (the wizard's "coins spent" bar, My Inventory's space bar) ----
   A dark well with a pink→gold fill whose width is the --meter-pct custom property the page's JS
   (or template) sets, gently pulsing so it reads as live. */
.meter-bar {
  height: 16px;
  background: var(--color-ink);
  border: 2px solid var(--color-line);
  position: relative;
  overflow: hidden;
}
.meter-bar-fill {
  height: 100%;
  width: var(--meter-pct, 0%);
  background: linear-gradient(90deg, var(--color-pink), var(--color-gold));
  transition: width .4s;
  animation: meterBarGlow 1.6s ease-in-out infinite;
}
@keyframes meterBarGlow {
  0%, 100% { filter: brightness(1); }
  50% { filter: brightness(1.35); }
}
@media (prefers-reduced-motion: reduce) {
  .meter-bar-fill { animation: none; }
}

/* ---- Animations used by the global background sprites ---- */
@keyframes float-a {
  0%, 100% { transform: translateY(0) rotate(-6deg); }
  50%      { transform: translateY(-22px) rotate(6deg); }
}
@keyframes float-b {
  0%, 100% { transform: translateY(0) rotate(8deg); }
  50%      { transform: translateY(-30px) rotate(-8deg); }
}
@keyframes float-c {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-16px); }
}
/* The TITLE glitch — the landing's hero title and the play page's loader marquee share it: a
   rare shake of the word itself (glitch-shake), with a cyan ghost and a magenta ghost tearing
   across it in clipped bands (glitch-cyan / glitch-magenta on ::before / ::after). Global because
   two pages use it; the ghosts' text comes from each page's own rule. */
@keyframes glitch-shake {
  0%, 90%, 100% { transform: translate(0, 0); }
  91% { transform: translate(-3px, 1px); }
  93% { transform: translate(3px, -1px); }
  95% { transform: translate(-2px, 0); }
  96% { transform: translate(2px, 1px); }
  98% { transform: translate(-1px, -1px); }
}
@keyframes glitch-cyan {
  0%, 89%, 100% { opacity: 0; transform: translate(0, 0); clip-path: inset(0 0 0 0); }
  90% { opacity: .85; transform: translate(-4px, 0); clip-path: inset(8% 0 62% 0); }
  93% { opacity: .7;  transform: translate(3px, -2px); clip-path: inset(48% 0 20% 0); }
  96% { opacity: .8;  transform: translate(-2px, 1px); clip-path: inset(72% 0 6% 0); }
  98% { opacity: 0; }
}
@keyframes glitch-magenta {
  0%, 89%, 100% { opacity: 0; transform: translate(0, 0); clip-path: inset(0 0 0 0); }
  90% { opacity: .8;  transform: translate(4px, 0); clip-path: inset(20% 0 50% 0); }
  93% { opacity: .75; transform: translate(-3px, 2px); clip-path: inset(58% 0 10% 0); }
  96% { opacity: .8;  transform: translate(2px, -1px); clip-path: inset(4% 0 78% 0); }
  98% { opacity: 0; }
}
/* The sprite glitch — a fast RGB-tear flicker. JS turns this on (via .is-glitching)
   for a brief window while it teleports the sprite, then off; global.js does the
   random scheduling. */
@keyframes sprite-glitch {
  0%   { opacity: .85; filter: none; clip-path: inset(0 0 0 0); }
  15%  { opacity: .35; filter: hue-rotate(120deg) saturate(3); clip-path: inset(30% 0 24% 0); }
  30%  { opacity: .9;  filter: none; clip-path: inset(0 0 0 0); }
  45%  { opacity: .25; filter: hue-rotate(-140deg) saturate(2); clip-path: inset(8% 0 62% 0); }
  60%  { opacity: .85; filter: none; }
  75%  { opacity: .3;  filter: hue-rotate(80deg); clip-path: inset(56% 0 14% 0); }
  100% { opacity: .7;  filter: none; clip-path: inset(0 0 0 0); }
}
/* Blinking caret — shared by the wizard prompt console placeholder and the chat
   step's question + loading carets (all show a ▊ that
   blinks on/off). Blink via VISIBILITY, not opacity: an opacity animation promotes
   the caret to its own GPU layer, and a caret that also MOVES (the loading status
   line erases + retypes) then leaves a stale "ghost" copy of that layer behind —
   a fixed rectangle the caret's own size/colour. visibility isn't composited, so
   it blinks identically with no ghost. Keep it visibility-based. */
@keyframes blink { 0%, 49% { visibility: visible; } 50%, 100% { visibility: hidden; } }

/* "This control is live right now" pulsing badge — shared by the IDE mic dot, its reconnect pill's
   dot, and the wizard prompt console's own mic dot (two pages now, so the keyframe lives here). */
@keyframes dotPulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.55); opacity: .65; }
}

/* ---- Mid-size screens: fold the header before its parts collide ----
   The centre buttons are pinned to the exact middle, so a wide right side runs into them. Measured
   (2026-10-01): signed in, the coins + account chip overlapped BROWSE & PLAY at every width up to
   1061px; signed out, LOGIN / REGISTER cleared it from 802px. Each folds into the burger menu just
   below its own width — the same menu every page already uses below 560px. */
@media (max-width: 1080px) {
  .site-header:has(.header-right) :is(.header-nav, .header-right) { display: none; }
  .site-header:has(.header-right) .header-burger-wrap { display: block; }
}
@media (max-width: 820px) {
  .site-header:has(.header-actions) :is(.header-nav, .header-actions) { display: none; }
  .site-header:has(.header-actions) .header-burger-wrap { display: block; }
}

/* ---- Small screens: keep the header and hero comfortable ---- */
@media (max-width: 560px) {
  .site-header { padding: 12px 14px; gap: 10px; }
  .brand-wordmark { font-size: 13px; }
  .page-main { padding: 14px 16px 70px; }
  /* Below this width there isn't room for the nav link plus the balance/account chip (or
     login/register) side by side, so both collapse into the burger menu instead. */
  .header-nav, .header-right, .header-actions { display: none; }
  .header-burger-wrap { display: block; }
}

/* ---- Arcade select ------------------------------------------------------
   The site's ONE dropdown form control (the wallet's withdraw modal) — reuse it, don't author a
   second. A real <select> underneath, so keyboard, screen readers and the native phone wheel all
   work; only the skin is ours. Metrics match .auth-input (auth.css) so it lines up with the other
   fields, and the 48px min-height clears the 44px tap-target floor.

   `appearance: none` strips the OS chrome, then a CSS-drawn caret is painted in the padding on the
   right. The caret is a background gradient rather than a pseudo-element, because a <select> can't
   host children — the extra right padding is what keeps the text off it. */
.arcade-select { display: block; }
.arcade-select-label {
  display: block;
  font-family: var(--font-display);
  font-size: 8px;
  letter-spacing: 1px;
  color: var(--color-faint);
  margin: 0 0 8px;
}
.arcade-select-input {
  width: 100%;
  box-sizing: border-box;
  min-height: 48px;
  appearance: none;
  -webkit-appearance: none;
  background-color: var(--color-ink);
  /* the caret: two 2px bars meeting in a V, drawn 18px in from the right edge */
  background-image:
    linear-gradient(45deg, transparent 50%, var(--color-text-dim) 50%),
    linear-gradient(135deg, var(--color-text-dim) 50%, transparent 50%);
  background-position: right 22px center, right 16px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  border: 2px solid var(--color-line-2);
  outline: none;
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 20px;
  line-height: 1.2;
  padding: 12px 42px 12px 12px;
  cursor: pointer;
}
.arcade-select-input:focus { border-color: var(--color-cyan); }
/* The popped-open list is drawn by the OS, which ignores nearly everything above — set the option
   colours explicitly so a light-themed browser doesn't render dark text on our dark panel. */
.arcade-select-input option { background: var(--color-panel); color: var(--color-text); }
/* Inside the green account-card modals (GAME PLAN), focus follows that card's accent, exactly as
   .auth-input already does there. */
.account-card .arcade-select-input:focus { border-color: var(--color-green); }

/* Where the browser can, take over the POPPED-OPEN list too (Chrome/Edge, newer Safari — the
   customizable select). Skinned as the site's ONE menu, .dropdown-menu above: panel, green frame,
   ink outline + hard shadow, the same rise-in. A ::picker() pseudo-element can't carry that class,
   so its look is restated here — keep the two in step. A browser without base-select skips this
   whole block and keeps the OS popup (the closed box is arcade-styled either way). */
@supports (appearance: base-select) {
  .arcade-select-input,
  .arcade-select-input::picker(select) { appearance: base-select; }
  /* base-select's own style rounds the corners — the arcade is square, everywhere. */
  .arcade-select-input,
  .arcade-select-input::picker(select),
  .arcade-select-input option { border-radius: 0; }
  /* base-select brings its own caret glyph — the closed box already paints ours. */
  .arcade-select-input::picker-icon { display: none; }
  .arcade-select-input::picker(select) {
    margin-top: 12px; /* the breathing room .dropdown-menu keeps under its toggle */
    padding: 0;
    background: var(--color-panel);
    border: 3px solid var(--color-green);
    box-shadow: 0 0 0 3px var(--color-ink), 8px 10px 0 rgba(0, 0, 0, .55);
    animation: menu-rise .16s ease both;
  }
  /* Each level as a row: the SAME type the closed box shows (options inherit the select's own
     font, so the list reads exactly like the control that opened it), dark hover, and the same
     48px height the closed box has — roomy, never squeezed. */
  .arcade-select-input option {
    display: flex;
    align-items: center;
    gap: 11px;
    min-height: 48px;
    box-sizing: border-box;
    padding: 12px 14px;
    cursor: pointer;
  }
  .arcade-select-input option:hover,
  .arcade-select-input option:focus { background: #1a1642; }
  /* The level the game has right now: green, tick and all (the tick is base-select's own). */
  .arcade-select-input option:checked { color: var(--color-green); }
  .arcade-select-input option::checkmark { color: var(--color-green); }
  @media (prefers-reduced-motion: reduce) {
    .arcade-select-input::picker(select) { animation: none; }
  }
}

/* ---- the tooltip — the site's ONE tooltip component (.ide-tip) ----
   A small hint panel skinned like .dropdown-menu (panel + green frame + ink outline + hard
   drop). It sits hidden, absolutely positioned beside its trigger, opening UPWARD by default.
   The usual anchor is the .ide-dock-slot below (an icon-only button with its hint as the next
   sibling — the IDE dock and tab bar, the wizard chat's START OVER, the asset cards' buttons), or
   the "?" chip (.tip-help), which a tap can pin open. pointer-events:none so it never steals the
   hover. */
.ide-tip {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 0;
  width: 260px;
  z-index: 70;
  padding: 10px 12px;
  background: var(--color-panel);
  border: 3px solid var(--color-green);
  box-shadow: 0 0 0 3px var(--color-ink), 6px 8px 0 rgba(0, 0, 0, .55);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.35;
  color: var(--color-text-dim);
  white-space: normal;
  text-align: left;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity .12s, transform .12s, visibility 0s .12s;
}
/* line 1: the hint's name in arcade caps; the rest is the plain-words explanation */
.ide-tip-name {
  display: block;
  margin-bottom: 6px;
  font-family: var(--font-display);
  font-size: 8px;
  letter-spacing: 1px;
  color: var(--color-text);
}
/* The slot: an icon-only button with its hint as the next sibling, so plain CSS shows the hint on
   hover / keyboard focus — no JS. Shared by the IDE dock + tab bar, the wizard chat header and the
   asset cards' small buttons. */
.ide-dock-slot { position: relative; display: inline-flex; }
/* The same tip opening DOWNWARD, right-aligned — for buttons on a bar at the top of a panel
   (the IDE GAME tab's view toggle, the wizard chat's START OVER), which hug the bar's right edge. */
.ide-tip-below {
  bottom: auto;
  top: calc(100% + 10px);
  left: auto;
  right: 0;
  transform: translateY(-6px);
}
/* shown when the slot's button is hovered or keyboard-focused — after a short pause, so a cursor
   passing through doesn't flash it */
.ide-dock-slot > button:hover + .ide-tip,
.ide-dock-slot > button:focus-visible + .ide-tip {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: .25s;
}
/* The "?" chip — the explain-this button beside a label (the Wallet's "on hold", My Inventory's
   "what fits"): a tiny ink-framed cyan square, cursor: help. Its tip is the .ide-tip right AFTER it; hover or
   keyboard focus shows it, and a TAP pins it (global.js toggles .is-open) — the only door touch
   users have, since hover-only tips are display:none under (hover: none). */
.tip-help {
  cursor: help;
  flex: none;
  padding: 5px 8px;
  font-family: var(--font-display);
  font-size: 9px;
  color: var(--color-ink);
  background: var(--color-cyan);
  border: 2px solid var(--color-ink);
}
.tip-help:hover { background: var(--color-cyan-light, #8ff0ff); }
.tip-help:hover + .ide-tip,
.tip-help:focus-visible + .ide-tip {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: .25s;
}
/* touch has no hover — hover-only tips hide there; a "?" chip's pinned one still shows (only a
   chip's: other tips use .is-open for their own show rules, e.g. the IDE rail's name hint) */
@media (hover: none) { .ide-tip { display: none; } }
.tip-help + .ide-tip.is-open {
  display: block;
  opacity: 1;
  visibility: visible;
  transform: none;
}
@media (prefers-reduced-motion: reduce) { .ide-tip { transition: none; } }
