/* Geometry Wars: Galaxies, remake browser.
   Neon vector aesthetic, built to sit under a full-bleed WebGL canvas.
   No external fonts or assets: the whole site is text files. */

:root {
  --bg: #04060f;
  --ink: #dbeeff;
  --dim: #7f93b5;
  --cyan: #55d8ff;
  --amber: #ffcf4d;
  --magenta: #ff5fd0;
  --green: #58ffa0;
  --danger: #ff5b6e;
  --panel: rgba(6, 12, 26, 0.82);
  --line: rgba(96, 168, 255, 0.28);
  /* Derived tones; theme.js overwrites all of these on :root at boot. */
  --glow-cool: rgba(90, 190, 255, 0.75);
  --glow-warm: rgba(255, 200, 90, 0.70);
  --accent-hi: #8fe6ff;
  --accent-lo: #35b7f0;
  --on-accent: #04121e;
  --surface: rgba(8, 16, 32, 0.58);
  --surface-hi: rgba(30, 70, 130, 0.45);
  --scrim-a: rgba(4, 8, 20, 0.55);
  --scrim-b: rgba(2, 4, 10, 0.90);
  --dim-soft: rgba(127, 147, 181, 0.80);
  --track: rgba(120, 180, 255, 0.22);
  --ship: #ffffff;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

* { box-sizing: border-box; }

/* Nothing whose value resolves from a themed custom property may be transitioned.
   Chromium does not reliably invalidate a transitioned property when the custom property
   behind it is reassigned on :root, so a theme swap left controls painted in the previous
   palette until some unrelated recalc happened. Transitions here are limited to transform
   and width, which never come from a variable. A hard colour cut is correct; a stale one
   is not. */

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--mono);
  /* Nothing here scrolls, zooms, selects, or shows a callout on iOS.
     touch-action is deliberately NOT set to `none` on the body: touch-action intersects down
     the ancestor chain, so blocking it here would also stop the options overlay from
     scrolling on iPhone. The canvas blocks gestures itself instead. */
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-text-size-adjust: 100%;
}

#stage {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;   /* the game owns every gesture over the playfield */
}

/* ============================ HUD ============================ */

.hud {
  position: fixed;
  inset: 0;
  pointer-events: none;
  padding:
    calc(env(safe-area-inset-top, 0px) + 14px)
    calc(env(safe-area-inset-right, 0px) + 16px)
    calc(env(safe-area-inset-bottom, 0px) + 14px)
    calc(env(safe-area-inset-left, 0px) + 16px);
  font-variant-numeric: tabular-nums;
  z-index: 5;
}

.hud > * { position: absolute; }
.hud-tl { top: calc(env(safe-area-inset-top, 0px) + 14px); left: calc(env(safe-area-inset-left, 0px) + 16px); }
.hud-tr { top: calc(env(safe-area-inset-top, 0px) + 14px); right: calc(env(safe-area-inset-right, 0px) + 16px); text-align: right; }
/*
 * --thumb-strip e' la striscia che l'arena lascia libera in fondo su telefono in verticale,
 * scritta da main.js a ogni ridimensionamento. Vale 0 dappertutto altrove, e allora queste
 * due righe sono quelle di sempre.
 *
 * Il pezzo basso dell'HUD sale sopra la striscia. Prima stava esattamente dove si appoggiano
 * i pollici: vite, bombe e livello del cannone in basso a sinistra, il drone in basso a
 * destra, cioe' sotto le due mani. Il drone e' anche un pulsante, e stava sopra allo stick
 * destro: per cambiare modalita' bisognava alzare il pollice che sta mirando.
 */
.hud-bl {
  bottom: calc(env(safe-area-inset-bottom, 0px) + 14px + var(--thumb-strip, 0px));
  left: calc(env(safe-area-inset-left, 0px) + 16px);
}

.score {
  font-size: clamp(26px, 5.4vmin, 52px);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: #fff;
  text-shadow: 0 0 12px var(--glow-cool), 0 0 34px var(--glow-cool);
  line-height: 1;
}

.mult {
  margin-top: 4px;
  font-size: clamp(15px, 2.8vmin, 26px);
  color: var(--amber);
  text-shadow: 0 0 12px var(--glow-warm);
  /* Grows to the right on a bump: scaling from the centre would push it off-screen. */
  transform-origin: left center;
  transition: transform 90ms ease-out;
}
.mult.bump { transform: scale(1.28); }

.best-label { font-size: 10px; letter-spacing: 0.28em; color: var(--dim); }
.best {
  font-size: clamp(14px, 2.4vmin, 22px);
  color: var(--cyan);
  text-shadow: 0 0 10px var(--glow-cool);
}

/*
 * L'annuncio del premio di soglia: compare sopra i pip, sale di poco e sfuma.
 *
 * La riga [hidden] non e' pleonastica. `hidden` e' un display:none dello user agent e perde
 * contro qualunque display esplicito, e qui sotto ce n'e' uno: senza questa riga l'annuncio
 * resterebbe in pagina con l'attributo messo, che e' gia' successo due volte in questo
 * progetto. A vincere e' la specificita' e non l'ordine: `.award[hidden]` ha un selettore di
 * attributo in piu' di `.award`, quindi batte il display:flex ovunque sia scritta. Sta qui
 * sopra solo perche' e' la riga da leggere per prima.
 */
.award[hidden] { display: none; }
.award {
  display: flex;
  gap: 10px;
  margin-bottom: 8px;
  font-size: clamp(13px, 2.1vmin, 19px);
  font-weight: 700;
  letter-spacing: 0.08em;
  line-height: 1;
  white-space: nowrap;
  /* La durata la riscrive js/ui/ui.js da AWARD_MS: questa e' il ripiego, e vale lo stesso. */
  animation: award-rise 1.2s ease-out forwards;
}
/*
 * Ogni pezzo del colore dei pip di cui parla, com'e' gia' per le vite e per le bombe: l'HUD
 * parla la lingua dell'arena, e qui vuol dire che non serve leggere la parola per sapere se
 * e' arrivata una vita o una bomba. Il bianco resta della nave e il magenta della bomba,
 * quindi la regola del bianco e quella dell'oro restano dove sono.
 *
 * Le tasche piene non sono un premio in mano e non prendono in prestito nessuno dei due
 * colori: sono punteggio, e il punteggio nell'HUD e' del colore del testo.
 */
.award b { font-weight: inherit; text-shadow: 0 0 10px currentColor, 0 0 26px currentColor; }
.award .for-life { color: var(--ship); }
.award .for-bomb { color: var(--magenta); }
.award .for-points { color: var(--ink); }

@keyframes award-rise {
  0%   { opacity: 0; transform: translateY(6px); }
  15%  { opacity: 1; transform: translateY(0); }
  70%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-10px); }
}

/*
 * Chi ha chiesto meno movimento tiene la notizia e perde il viaggio: l'annuncio resta fermo e
 * si limita a comparire e sparire. Toglierlo del tutto vorrebbe dire togliere l'informazione a
 * chi ha chiesto solo meno animazione, che e' una cosa diversa.
 */
.reduced-motion .award { animation: award-fade 1.2s steps(1, end) forwards; }
@keyframes award-fade {
  0%   { opacity: 1; }
  85%  { opacity: 1; }
  100% { opacity: 0; }
}

.lives, .bombs { display: flex; gap: 6px; align-items: center; margin-top: 6px; }
.lives i, .bombs i {
  display: block;
  width: clamp(11px, 1.9vmin, 16px);
  aspect-ratio: 1;
  background: currentColor;
  /* Ship and bomb pips drawn as CSS shapes, so there are no image requests. */
  clip-path: polygon(100% 50%, 22% 100%, 42% 50%, 22% 0%);
}
/* currentColor makes the pip glow follow the pip colour, whatever the theme sets. */
/* The life pips are ships, so they are white: the HUD speaks the arena's language. */
.lives { color: var(--ship); filter: drop-shadow(0 0 6px currentColor); }
.bombs { color: var(--magenta); filter: drop-shadow(0 0 6px currentColor); }
.bombs i { clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); }

button, input[type="range"] { touch-action: manipulation; }

.icon-btn {
  pointer-events: auto;
  margin-top: 10px;
  min-width: 44px;
  min-height: 44px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0.1em;
  cursor: pointer;
}
.icon-btn:active { background: var(--surface-hi); }

/*
 * La colonna delle schede, in basso a destra. E' lei a portare la posizione, non le schede:
 * l'alleato compare e sparisce, e una colonna che le impila dal basso lo fa senza che nessuno
 * debba sapere quanto e' alta la scheda sotto, che dipende da un font che scala con lo schermo.
 */
.badge-stack {
  right: calc(env(safe-area-inset-right, 0px) + 16px);
  bottom: calc(env(safe-area-inset-bottom, 0px) + 14px + var(--thumb-strip, 0px));
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

.drone-badge {
  pointer-events: auto;
  display: grid;
  grid-template-columns: auto auto;
  gap: 2px 10px;
  align-items: center;
  padding: 8px 12px;
  min-height: 44px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: clamp(11px, 1.8vmin, 14px);
  letter-spacing: 0.1em;
  cursor: pointer;
}
.drone-name { color: var(--green); text-shadow: 0 0 10px currentColor; }
.drone-level { color: var(--dim); font-size: 0.85em; }
.drone-xp {
  grid-column: 1 / -1;
  height: 3px;
  background: var(--track);
  border-radius: 2px;
  overflow: hidden;
}
.drone-xp i { display: block; height: 100%; width: 0%; background: var(--green); box-shadow: 0 0 8px var(--green); transition: width 180ms ease-out; }

/*
 * La scheda dell'alleato: la stessa scatola, piu' piccola, non premibile, e col bordo nel
 * colore della modalita' arrivata, cosi' la scheda e il drone in campo sono la stessa cosa.
 *
 * La riga con display:none non e' ridondante: `hidden` e' un display:none dello user agent, e
 * qualunque display esplicito lo batte, quindi senza di lei .drone-badge la terrebbe a schermo
 * con il suo display:grid.
 *
 * Ma non e' nemmeno l'unica difesa, e non lo e' per un motivo che e' successo davvero: questo
 * foglio di stile e' un file separato dal markup, il sito si carica a mano, e caricato l'HTML
 * e non la CSS la scheda restava a schermo dall'inizio della partita col testo segnaposto
 * dentro, che sembrava un alleato fantasma. Adesso il display lo scrive anche ui.js, cioe' lo
 * stesso codice che decide di mostrarla. Questa riga resta per chi legge il foglio di stile.
 */
.ally-badge {
  pointer-events: none;
  padding: 6px 10px;
  min-height: 0;
  font-size: clamp(10px, 1.6vmin, 12px);
  background: var(--panel);
}
.ally-badge[hidden] { display: none; }
.ally-tag {
  grid-column: 1 / -1;
  font-size: 0.8em;
  letter-spacing: 0.22em;
  opacity: 0.9;
}
/* Si svuota mentre il tempo passa, mentre quella del drone si riempie mentre sale di livello:
   due barre uguali ferme direbbero la stessa cosa, due barre che si muovono al contrario no. */
.ally-time {
  grid-column: 1 / -1;
  height: 3px;
  background: var(--track);
  border-radius: 2px;
  overflow: hidden;
}
.ally-time i { display: block; height: 100%; width: 100%; }

/* The gun's level, in the corner with the lives and the bombs rather than beside the drone
   badge: it belongs with what you have, not with what is flying next to you. Painted in
   --bullet, mirrored from the theme, so the readout and the thing it describes stay the same
   colour on screen even when the palette moves under it. */
.gun {
  display: grid;
  grid-template-columns: auto auto;
  gap: 3px 8px;
  align-items: center;
  justify-content: start;
  margin-top: 8px;
  min-width: 108px;
  font-family: var(--mono);
  font-size: clamp(9px, 1.5vmin, 11px);
  letter-spacing: 0.14em;
  color: var(--dim);
}
.gun-level { color: var(--bullet, var(--amber)); }
.gun-xp {
  grid-column: 1 / -1;
  height: 3px;
  background: var(--track);
  border-radius: 2px;
  overflow: hidden;
}
.gun-xp i { display: block; height: 100%; width: 0%; background: var(--bullet, var(--amber)); box-shadow: 0 0 8px var(--bullet, var(--amber)); transition: width 180ms ease-out; }

/* ============================ Schermate ============================ */

.overlay {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: grid;
  place-items: center;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
  padding:
    calc(env(safe-area-inset-top, 0px) + 20px)
    calc(env(safe-area-inset-right, 0px) + 20px)
    /* Extra room at the foot so the last line never hides under the audio-unlock pill. */
    calc(env(safe-area-inset-bottom, 0px) + 62px)
    calc(env(safe-area-inset-left, 0px) + 20px);
  background: radial-gradient(ellipse at center, var(--scrim-a) 0%, var(--scrim-b) 100%);
  backdrop-filter: blur(3px) saturate(120%);
  -webkit-backdrop-filter: blur(3px) saturate(120%);
}
.overlay[hidden] { display: none; }

.screen {
  width: min(760px, 100%);
  text-align: center;
  animation: fade-in 220ms ease-out;
}
.screen[hidden] { display: none; }

@keyframes fade-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.title-block h1 {
  margin: 0;
  display: flex;
  flex-direction: column;
  line-height: 0.92;
  letter-spacing: 0.12em;
}
.title-block .t1 { font-size: clamp(30px, 8.2vmin, 74px); color: var(--ink); text-shadow: 0 0 16px var(--glow-cool), 0 0 46px var(--glow-cool); }
.title-block .t2 { font-size: clamp(38px, 10.5vmin, 96px); color: #fff; text-shadow: 0 0 18px var(--glow-warm), 0 0 52px var(--glow-warm); }
.title-block h2 {
  margin: 6px 0 0;
  font-size: clamp(16px, 3.6vmin, 32px);
  letter-spacing: 0.5em;
  text-indent: 0.5em;
  color: var(--magenta);
  text-shadow: 0 0 16px currentColor;
}
.tagline { margin: 10px 0 0; font-size: 11px; letter-spacing: 0.32em; color: var(--dim); }

h3 {
  margin: 0 0 18px;
  font-size: clamp(20px, 4.4vmin, 34px);
  letter-spacing: 0.28em;
  color: #fff;
  text-shadow: 0 0 14px var(--glow-cool);
}

/* --- Selettore drone --- */
.drone-picker { margin: 26px 0 8px; }
.picker-label { margin: 0 0 10px; font-size: 11px; letter-spacing: 0.3em; color: var(--dim); }
.drone-options { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.drone-options button {
  flex: 0 1 auto;
  min-height: 44px;
  padding: 10px 14px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--dim);
  font-family: var(--mono);
  font-size: clamp(11px, 2vmin, 14px);
  letter-spacing: 0.14em;
  cursor: pointer;
}
.drone-options button[aria-checked="true"] {
  color: #fff;
  border-color: currentColor;
  background: var(--surface-hi);
  box-shadow: 0 0 18px var(--glow-cool), inset 0 0 14px var(--glow-cool);
}
.drone-desc {
  margin: 12px auto 0;
  max-width: 46ch;
  min-height: 3em;
  font-size: clamp(11px, 2vmin, 13px);
  line-height: 1.6;
  color: var(--dim);
}

/* --- Bottoni --- */
.menu-actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 22px; }

.btn {
  min-height: 48px;
  padding: 12px 26px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: clamp(12px, 2.2vmin, 16px);
  letter-spacing: 0.22em;
  cursor: pointer;
  transition: transform 90ms ease-out;
}
.btn:active { transform: scale(0.97); }
.btn.primary {
  color: var(--on-accent);
  background: linear-gradient(180deg, var(--accent-hi), var(--accent-lo));
  border-color: transparent;
  font-weight: 700;
  box-shadow: 0 0 28px var(--glow-cool);
}
.btn.danger { color: var(--danger); border-color: currentColor; }
.btn.small { min-height: 40px; padding: 8px 16px; letter-spacing: 0.12em; }

.hint { margin-top: 18px; font-size: 11px; letter-spacing: 0.14em; color: var(--dim); line-height: 1.7; }

/* Version chip: the number a bug report needs, and the way into the release notes. */
.version-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  padding: 7px 14px;
  min-height: 36px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--dim);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  cursor: pointer;
}
.version-sep { opacity: 0.45; }
/* Lit until the player has looked at the notes for a version they have not seen. */
.version-chip.has-news { color: var(--ink); border-color: var(--cyan); }
.version-chip.has-news::after {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--cyan);
  box-shadow: 0 0 8px var(--cyan);
}

.version-line {
  margin: 14px 0 0;
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--dim-soft);
}

/* Release notes */
.news-list { display: grid; gap: 12px; text-align: left; }
.news-entry {
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}
.news-entry.current { border-color: var(--cyan); box-shadow: 0 0 18px var(--glow-cool); }
.news-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 10px;
}
.news-version {
  font-size: 15px;
  font-weight: 700;
  color: var(--cyan);
  letter-spacing: 0.08em;
}
.news-title { font-size: 12px; letter-spacing: 0.14em; color: var(--ink); }
.news-date { margin-left: auto; font-size: 10px; letter-spacing: 0.14em; color: var(--dim-soft); }
/* The paragraph that says what a release is, for an entry that has no "since last time". */
.news-body {
  margin: 0 0 4px;
  font-size: 11px;
  line-height: 1.75;
  color: var(--dim-soft);
  text-wrap: pretty;
}
.news-kind {
  margin: 10px 0 4px;
  font-size: 10px;
  letter-spacing: 0.22em;
  color: var(--dim);
}
.news-entry ul { margin: 0; padding-left: 18px; }
.news-entry li { font-size: 12px; line-height: 1.75; color: var(--dim); }
.news-entry li b { color: var(--ink); }

.offline-note {
  margin: 10px 0 0;
  font-size: 11px;
  letter-spacing: 0.12em;
  line-height: 1.6;
  color: var(--green);
}
.offline-note[hidden] { display: none; }

/* Legal notice. Deliberately quiet but always present and readable, never a hover tooltip
   or a collapsed panel, since the point is that it is visible without looking for it. */
.legal {
  max-width: 62ch;
  margin: 22px auto 0;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  font-size: 10px;
  line-height: 1.75;
  letter-spacing: 0.04em;
  color: var(--dim-soft);
  /* Left-aligned: it is a paragraph, and centred ragged text is harder to read at 10px. */
  text-align: left;
  text-wrap: pretty;
}

/* --- Opzioni --- */
/* --- Theme cards ---------------------------------------------------------
   Each card is painted in the palette it is offering, not in the one currently applied:
   choosing a theme should be looking at it, not reading its name. The variables come from
   the theme's own css block, set inline by the picker. */
.screen-note {
  margin: 6px auto 0;
  max-width: 46ch;
  font-size: clamp(11px, 2vmin, 13px);
  line-height: 1.6;
  color: var(--dim);
}

.theme-cards {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: center;
  margin-top: 18px;
}

.theme-card {
  flex: 1 1 190px;
  max-width: 260px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px 16px 16px;
  border-radius: 14px;
  border: 1px solid var(--card-line, var(--line));
  background: var(--card-bg, var(--surface));
  color: var(--card-ink, var(--ink));
  font-family: var(--mono);
  text-align: left;
  cursor: pointer;
  transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
}

.theme-swatches { display: flex; gap: 6px; }

.theme-swatch {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  /* No border: a ring would read as a sixth colour, and the first swatch is the ship. */
  box-shadow: 0 0 8px currentColor;
}

.theme-card-name { font-size: clamp(13px, 2.4vmin, 16px); letter-spacing: 0.18em; }

.theme-card-blurb {
  font-size: clamp(10px, 1.9vmin, 12px);
  line-height: 1.55;
  opacity: 0.72;
  letter-spacing: 0.04em;
}

.theme-card[aria-checked="true"] { border-color: currentColor; }

.rows { display: grid; gap: 12px; text-align: left; }
.row {
  display: grid;
  grid-template-columns: minmax(120px, 1fr) minmax(0, 1.6fr) auto;
  gap: 12px;
  align-items: center;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}
/* `hidden` is a UA style of display:none, and any explicit display beats it. The row sets
   display:grid, so without this line hiding one does nothing at all: the attribute is set, the
   element stays on screen, and every test that walks the screen keeps passing. */
.row[hidden] { display: none; }
.row label { font-size: clamp(11px, 2vmin, 13px); letter-spacing: 0.12em; color: var(--dim); }
/* A button sitting straight in a row is a grid item, and a grid item stretches: the theme
   row's button filled the whole column, which put its centre far to the right of every other
   control on the screen. Pressing down from the language row then scored it worse than the
   row below and skipped it entirely. It sizes to its label now, in the same column as the
   first button of every other row. */
.row > .btn { justify-self: start; }
/* A row whose explanation wraps under the control instead of squeezing beside it. */
.row-wide .row-note {
  grid-column: 1 / -1;
  margin: 2px 0 0;
  font-size: 11px;
  line-height: 1.6;
  color: var(--dim-soft);
}
.row output { min-width: 3.5ch; text-align: right; font-size: 12px; color: var(--cyan); }

.seg { display: flex; gap: 4px; flex-wrap: wrap; }
.seg button {
  flex: 1 1 auto;
  min-height: 40px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--dim);
  font-family: var(--mono);
  font-size: clamp(10px, 1.8vmin, 12px);
  letter-spacing: 0.08em;
  cursor: pointer;
}
.seg button[aria-checked="true"] {
  color: var(--on-accent);
  background: var(--cyan);
  border-color: transparent;
  font-weight: 700;
}

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 28px;
  background: transparent;
  cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background: var(--track);
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px;
  height: 20px;
  margin-top: -8px;
  border-radius: 50%;
  background: var(--cyan);
  box-shadow: 0 0 12px var(--glow-cool);
}
input[type="range"]::-moz-range-track { height: 4px; border-radius: 2px; background: var(--track); }
input[type="range"]::-moz-range-thumb { width: 20px; height: 20px; border: none; border-radius: 50%; background: var(--cyan); }

/* --- Comandi --- */
.help-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); text-align: left; }
.help-card { padding: 14px 16px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); }
.help-card h4 { margin: 0 0 10px; font-size: 12px; letter-spacing: 0.2em; color: var(--cyan); }
.help-card ul { margin: 0; padding-left: 18px; }
.help-card li { font-size: 12px; line-height: 1.9; color: var(--dim); }
.help-card b { color: var(--ink); font-weight: 700; }
.help-card .note { margin: 10px 0 0; font-size: 11px; line-height: 1.6; color: var(--dim-soft); }

/* --- Pausa e fine partita --- */
.pause-stats, .stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
  margin: 18px 0 4px;
}
.stat {
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}
.stat b { display: block; font-size: clamp(16px, 3.2vmin, 24px); color: #fff; }
.stat span { font-size: 10px; letter-spacing: 0.2em; color: var(--dim); }

.go-title { color: var(--danger); text-shadow: 0 0 18px currentColor; }
.final-score {
  font-size: clamp(44px, 12vmin, 96px);
  font-weight: 700;
  color: #fff;
  line-height: 1;
  text-shadow: 0 0 20px var(--glow-cool), 0 0 60px var(--glow-cool);
  font-variant-numeric: tabular-nums;
}
.final-tag { margin-top: 8px; font-size: 12px; letter-spacing: 0.22em; color: var(--amber); min-height: 1.4em; }

/* --- Condivisione --- */
.share-box {
  margin-top: 16px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  text-align: left;
}
.share-box[hidden] { display: none; }
.share-status { margin: 0 0 10px; font-size: 12px; letter-spacing: 0.06em; color: var(--amber); }
.share-text {
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.7;
}
.share-privacy { margin: 10px 0 0; font-size: 11px; line-height: 1.6; color: var(--dim-soft); }

.error-text { font-size: 13px; line-height: 1.8; color: var(--dim); max-width: 46ch; margin: 0 auto; }

.tap-hint {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 22px);
  transform: translateX(-50%);
  z-index: 20;
  padding: 10px 18px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel);
  font-size: 11px;
  letter-spacing: 0.18em;
  color: var(--dim);
  pointer-events: none;
}
.tap-hint[hidden] { display: none; }

/* Controller confirmation. Parked at the very bottom, under the legal notice rather than over
   it, and lifted above the tap hint only when that one is showing, since on a phone with a
   Bluetooth pad both can be true at once. Never interactive, so it takes no pointer events and
   can safely overlap the arena. */
.pad-toast {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 16px);
  transform: translateX(-50%);
  z-index: 21;
  max-width: min(92vw, 58ch);   /* wide enough that a pad name stays on one line */
  padding: 10px 18px;
  border-radius: 999px;
  border: 1px solid var(--cyan);
  background: var(--panel);
  box-shadow: 0 0 24px var(--glow-cool);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.10em;
  line-height: 1.5;
  color: var(--ink);
  text-align: center;
  text-wrap: balance;
  pointer-events: none;
  animation: pad-toast-in 200ms ease-out;
}
.pad-toast.gone {
  border-color: var(--line);
  box-shadow: none;
  color: var(--dim);
}
.pad-toast.stacked { bottom: calc(env(safe-area-inset-bottom, 0px) + 66px); }
/* The graphics note is a state, not an event: it sits above the transient toasts, stays until
   the context comes back, and is tinted so it does not read as good news. */
.pad-toast.warn {
  bottom: calc(env(safe-area-inset-bottom, 0px) + 76px);
  border-color: var(--amber);
  box-shadow: 0 0 24px var(--glow-warm);
  color: var(--ink);
}
.pad-toast[hidden] { display: none; }
@keyframes pad-toast-in { from { opacity: 0; transform: translate(-50%, 10px); } to { opacity: 1; transform: translate(-50%, 0); } }

/* The live line on the Comandi screen, with a status dot in front of it: a colour that
   changes under your thumb is read faster than a sentence that changes. Green once the
   browser can actually see the pad. */
.pad-state {
  margin: 10px 0 0;
  padding-left: 16px;
  position: relative;
  font-size: 11px;
  line-height: 1.6;
  letter-spacing: 0.06em;
  color: var(--dim);
}
.pad-state::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--dim-soft);
}
.pad-state.found { color: var(--green); }
.pad-state.found::before { background: var(--green); box-shadow: 0 0 8px var(--green); }

/* ======================= Il controllo che stai puntando =======================

   Three ways to point at a control and they have to look the same: the mouse, the keyboard,
   and a controller. The third needs a class of its own, because :focus-visible is a heuristic
   about the last interaction the *browser* knows about and a gamepad is invisible to it: focus
   moved from script after a mouse click does not match it, which is precisely the pause menu.
   js/main.js hangs .navfocus on whatever it moves to.

   These blocks live at the end of the file on purpose. Every filled state below
   (.btn.primary, .btn.danger, [aria-checked="true"]) has the same specificity as its own
   highlight, so source order is what decides, and this being last is what makes the highlight
   win. The previous arrangement had it first, which is why PLAY and RESUME lit up for nobody:
   the rule was there, it just lost every time. */

.btn:hover, .btn:focus-visible, .btn.navfocus,
.seg button:hover, .seg button:focus-visible, .seg button.navfocus,
.drone-options button:hover, .drone-options button:focus-visible, .drone-options button.navfocus,
.icon-btn:hover, .icon-btn:focus-visible, .icon-btn.navfocus {
  color: #fff;
  border-color: var(--cyan);
  box-shadow: 0 0 22px var(--glow-cool);
  outline: none;
}

.version-chip:hover, .version-chip:focus-visible, .version-chip.navfocus {
  color: var(--ink);
  border-color: var(--cyan);
  box-shadow: 0 0 18px var(--glow-cool);
  outline: none;
}

/* A control already filled with the accent has no colour left to change, so it is ringed
   instead: a gap in the page background, then the accent again. Reads as a halo at a glance
   and survives any theme, since both colours come from the palette. */
.btn.primary:hover, .btn.primary:focus-visible, .btn.primary.navfocus,
.seg button[aria-checked="true"]:hover,
.seg button[aria-checked="true"]:focus-visible,
.seg button[aria-checked="true"].navfocus {
  color: var(--on-accent);
  box-shadow: 0 0 30px var(--glow-cool), 0 0 0 2px var(--bg), 0 0 0 4px var(--accent-hi);
}

/* Destructive actions keep their own colour: going red-to-cyan on hover would read as the
   button changing meaning. */
.btn.danger:hover, .btn.danger:focus-visible, .btn.danger.navfocus {
  color: var(--danger);
  border-color: currentColor;
  box-shadow: 0 0 22px currentColor;
}

/* The drone buttons carry their mode colour as an inline style, which outranks any rule here,
   so their highlight is built out of currentColor and stays on-mode. */
.drone-options button:hover, .drone-options button:focus-visible, .drone-options button.navfocus {
  border-color: currentColor;
  box-shadow: 0 0 20px currentColor;
}
.drone-options button[aria-checked="true"]:hover,
.drone-options button[aria-checked="true"]:focus-visible,
.drone-options button[aria-checked="true"].navfocus {
  box-shadow: inset 0 0 14px var(--glow-cool), 0 0 0 2px var(--bg), 0 0 0 4px currentColor;
}

/* The cards carry their own palette inline, so like the drone buttons their highlight is
   built out of what is already on them rather than out of the active theme's variables. */
.theme-card:hover, .theme-card:focus-visible, .theme-card.navfocus {
  transform: translateY(-2px);
  border-color: currentColor;
  box-shadow: 0 0 24px var(--card-line, var(--line));
}
.theme-card[aria-checked="true"] {
  box-shadow: inset 0 0 0 1px currentColor;
}
.theme-card[aria-checked="true"]:hover,
.theme-card[aria-checked="true"]:focus-visible,
.theme-card[aria-checked="true"].navfocus {
  box-shadow: inset 0 0 0 1px currentColor, 0 0 26px var(--card-line, var(--line));
}

/* A row whose control cannot do anything on this browser: still usable, because the choice is
   about the next controller as much as this one, but no longer claiming to be in charge. */
.row.unsupported label, .row.unsupported .seg button { opacity: 0.55; }

/* Sliders get a ring rather than a fill: there is no border to light up. */
input[type="range"]:focus-visible, input[type="range"].navfocus {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
  border-radius: 8px;
}

/* Landscape phones are short: tighten the vertical rhythm so menus still fit. */
@media (max-height: 460px) {
  .legal { margin-top: 14px; padding-top: 10px; font-size: 9px; line-height: 1.6; }
  .drone-picker { margin: 14px 0 4px; }
  .drone-desc { min-height: 0; }
  .menu-actions { margin-top: 14px; }
  .title-block h2 { margin-top: 2px; }
  .tagline { display: none; }
}

/*
 * Guidato dalla classe, non dalla media query.
 *
 * La media query da sola non basta piu': nelle Opzioni c'e' una scelta a tre stati, e chi
 * mette "Pieni" avendo il movimento ridotto acceso a livello di sistema deve ottenere il
 * gioco pieno anche qui. La classe la mette main.js con la preferenza gia' risolta, e in
 * modalita' Auto la risolve leggendo la stessa media query.
 */
html.reduced-motion .screen { animation: none; }
html.reduced-motion .pad-toast { animation: none; }
html.reduced-motion .mult { transition: none; }
