/* Copyright 2026 G&G Technologies S.r.l. — SPDX-License-Identifier: Apache-2.0 */

/* What this app shapes differently from the shared sheet. The palette, the buttons and the app bar
   come from `_lib/base.css`; nothing here redeclares them.

   Two rules from app/CLAUDE.md that show up in this file rather than in prose:
   headings inside a tool are sans, because nobody reads a toolbar — the serif is kept for the app's
   own name, which is the one moment the app speaks instead of working. And a control is never
   smaller than 44px on touch. */

/* **Niente si seleziona, e su un telefono non è una rifinitura.**

   Il campo è il comando: si tocca in fretta e molte volte di seguito, e una serie di tocchi ravvicinati
   il browser la interpreta come un doppio o triplo clic — cioè come «seleziona». Il risultato è il
   canvas evidenziato in azzurro a metà partita, con la maniglia di selezione sotto il pollice, e da
   lì in poi ogni tocco fa due cose.

   `touch-action: none` sul campo, che c'era già, ferma lo scorrimento e lo zoom: sono un'altra cosa.
   Qui serve la selezione, e serve **su tutto** — la barra in cima e i pannelli si toccano anche
   loro, e un pannello mezzo evidenziato è la stessa scortesia in un posto meno importante.

   Con due eccezioni, e sono eccezioni vere: il campo del nome, dove non poter selezionare vuol dire
   non poter correggere quello che si è scritto; e la tabella dei punteggi, che è l'unica cosa della
   pagina che qualcuno potrebbe voler copiare. */
body {
  -webkit-user-select: none;
  user-select: none;
  /* Il lampo grigio che Chrome su Android disegna sotto ogni tocco. Su un pulsante dice «premuto»;
     su un campo di gioco grande quanto lo schermo è un flash a ogni battito d'ali. */
  -webkit-tap-highlight-color: transparent;
}

.nameform input,
.scores {
  -webkit-user-select: text;
  user-select: text;
}

/* E il menù che iOS apre tenendo premuto su un'immagine — «salva», «copia» — che una canvas si
   prende come se fosse una fotografia. In un gioco in cui si tiene premuto per andare a sinistra,
   comparirebbe di continuo. */
#field {
  -webkit-touch-callout: none;
}

main {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* ---------------------------------------------------------------------------------------------
   la seconda barra: i crediti e la pausa
   --------------------------------------------------------------------------------------------- */

/* Magra apposta. Punti, vite e ondata stanno dentro il campo, dove si guarda già: ripeterli qui
   vorrebbe dire due posti in cui leggere lo stesso numero, e quello in alto è sempre quello che
   non si guarda. */
.hudbar {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 6px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
}

.hudbar .spacer { flex: 1 1 auto; }

.hud-item { display: inline-flex; align-items: baseline; gap: 7px; }

.hud-label {
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Cifre tabulari, o il numero balla di lato ogni volta che cambia — e su un contatore che scatta
   cento volte al minuto si legge come tutta la barra che oscilla. */
.hud-item b {
  font-size: 16px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* L'onda o la croce, mai tutte e due. Lo stato sta su un attributo del pulsante invece che su una
   classe cambiata da JavaScript, così il markup dice da solo in che stato è. */
#sound[data-sound="on"] .i-mute { display: none; }

#sound[data-sound="off"] .i-wave { display: none; }

#sound[data-sound="off"] { color: var(--faint); }

/* ---------------------------------------------------------------------------------------------
   il campo, e i pannelli che ci stanno sopra
   --------------------------------------------------------------------------------------------- */

/* The field, and the panels that sit over it. The canvas is never hidden: an arcade cabinet was
   never dark either, and a black rectangle behind a dialog reads as a crash. */
.stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
}

/* The field has a fixed palette — it is a screen inside the app, and a screen has its own colours —
   while everything around it follows the site's two themes. What that costs is a dark rectangle
   sitting in a light page, so the field gets a bezel: a framed screen reads as a screen, an unframed
   one reads as a hole.

   `image-rendering: pixelated` is the whole of the pixel look on this side. The canvas is painted at
   640 x 360 and blown up by a whole multiple; without this the browser would smooth it back into
   the thing it was drawn small to avoid. */
#field {
  grid-area: 1 / 1;
  /* Il campo è il comando, quindi il browser non deve interpretare il dito da sé: senza questa
     riga un tocco trascinato scorre la pagina e uno doppio la ingrandisce, e in tutt'e due i casi
     il gioco perde il dito a metà manovra. */
  touch-action: none;
  width: 100%;
  height: 100%;
  min-height: 46vh;
  display: block;
  image-rendering: pixelated;
  border: 3px solid var(--border-strong);
  border-radius: 6px;
  background: #0b0f1a;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5) inset;
}

.panel {
  grid-area: 1 / 1;
  place-self: center;
  width: min(560px, calc(100% - 2rem));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  text-align: center;
  max-height: calc(100% - 1.5rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.panel.wide { width: min(680px, calc(100% - 2rem)); }

/* **Il pannello di richiamo porta i propri colori**, ed è l'unico che lo fa.

   Tutti gli altri stanno su una `.sheet`, cioè su una superficie che segue il tema: nel tema chiaro
   sono una scheda chiara appoggiata sul campo, e si leggono. Questo no — sta direttamente sul campo,
   che ha una **tavolozza fissa** perché è uno schermo dentro l'app. Prendendo `--text` dal tema, nel
   tema chiaro il titolo diventa inchiostro scuro su un cielo scuro: c'è, e non si vede.
   
   È esattamente il difetto che l'app sorella ha avuto, nello stesso punto e per la stessa ragione, e
   si trova in un modo solo: aprendo il gioco **col tema chiaro già impostato**. Da qui, e non dal
   pulsante premuto dopo. */
.panel.attract { color: #e8ecf5; }

.panel.attract .sub,
.panel.attract .small { color: #aab3c9; }

.panel.attract .title { text-shadow: 0 2px 14px rgba(0, 0, 0, 0.6); }

/* Il gettone e il link alla classifica: verde chiaro fisso, non l'accento del tema. Nel tema chiaro
   `--accent-text` è un verde scuro, giusto su una pagina bianca e illeggibile su questo cielo. */
.panel.attract .coin,
.panel.attract .linkish { color: #6ee7b7; border-color: #34d399; }

.panel.attract .coin { background: rgba(52, 211, 153, 0.12); }

.panel > * { margin: 0; max-width: 100%; }

/* Il contenuto di ogni pannello tranne quello di richiamo sta su una superficie sua.

   La prima versione contava su un velo dipinto sopra il campo dal disegnatore, e funziona nel tema
   scuro e non fa niente in quello chiaro: lì il velo è bianco su un campo bianco, quindi il gioco
   fermo si vede a piena forza e un nemico atterra sul titolo. Una superficie sistema tutti e due i
   temi in un colpo, ed è la forma del sito: pannello, filo di un pixel e i due pixel di accento in
   cima. */
.sheet {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  background: linear-gradient(170deg, var(--panel-2), var(--panel) 60%);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.4rem 1.5rem 1.2rem;
  max-width: 100%;
  width: 100%;
}

.sheet::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 12%;
  right: 12%;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--accent), var(--accent-text));
}

.sheet > * { margin: 0; max-width: 100%; }

/* Serif qui e in nessun altro punto dell'app. La regola di app/CLAUDE.md: il serif dice «testo da
   leggere», e gli unici momenti in cui quest'app parla invece di lavorare sono il suo nome e i suoi
   pannelli. */
.title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(30px, 6vw, 46px);
  letter-spacing: 0.02em;
  margin: 0;
}

.small-title { font-size: clamp(21px, 4vw, 28px); }

.sub { margin: -4px 0 4px; color: var(--muted); }

.lead { margin: 0; font-size: 17px; color: var(--text); font-variant-numeric: tabular-nums; }

.small { font-size: 12.5px; color: var(--faint); line-height: 1.55; }

.kicker {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--accent-text);
}

.kicker b { font-size: 20px; font-variant-numeric: tabular-nums; }

.linkish {
  border: none;
  padding: 2px 0;
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 3px;
  background: none;
  font-size: 13px;
}

.big { font-size: 16px; padding: 11px 26px; }

/* Il punto che separa l'invito a installare dai due comandi accanto. Sta nel CSS e non nel markup
   perché così **compare e sparisce con il pulsante**: un separatore che è un elemento a sé va
   nascosto da qualcuno, e quel qualcuno prima o poi se ne dimentica — lasciando un punto solitario
   in fondo alla riga.

   `pointer-events: none` perché il punto non è un comando: chi lo prende di striscio col pollice non
   deve installare niente. */
#install:not([hidden])::before {
  content: "· ";
  color: var(--faint);
  pointer-events: none;
}

/* L'unica riga di questa app che parla di iPhone. Non ha un pulsante da premere — installare passa
   da Condividi — quindi è una frase, e si chiude toccandola. */
#installHint { cursor: pointer; }

.choose { display: flex; flex-wrap: wrap; gap: 0.6rem; justify-content: center; }

/* ---------------------------------------------------------------------------------------------
   l ' a n n u n c i o   d i   o n d a t a
   --------------------------------------------------------------------------------------------- */

/* Il tipo di ondata esisteva da tre fasi e non lo sapeva nessuno: le regole cambiavano — nessun
   nemico in volo, un premio per chi sopravvive, due giocatori che non devono toccarsi — e in campo
   non c'era niente che lo dicesse.

   Sta sopra il canvas e non dentro, perché è testo: dipingerlo nei pixel vorrebbe dire una terza
   lingua da tenere allineata dentro un'immagine. In alto e non al centro, perché al centro
   coprirebbe il punto in cui si sta guardando nel momento in cui l'ondata comincia. */
.herald {
  grid-area: 1 / 1;
  place-self: start center;
  /* Sotto il soffitto e sotto la barra delle vite, non sopra: in cima al campo ci sono già le
     teste dei cavalieri e il numero dell'ondata dipinti nei pixel, e un riquadro appoggiato lì
     copre l'unica informazione che si guarda mentre si comincia. */
  margin-top: clamp(52px, 15vh, 130px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 22px;
  text-align: center;
  pointer-events: none;
  background: color-mix(in srgb, var(--panel) 95%, transparent);
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.45);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  animation: herald-in 0.35s ease-out both;
}

.herald-wave {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
}

.herald-kind {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(19px, 3.4vw, 26px);
  color: var(--accent-text);
}

.herald-kind:empty { display: none; }

.herald-note { font-size: 12.5px; color: var(--muted); }

.herald-note:empty { display: none; }

/* Il premio incassato usa lo stesso riquadro con l'accento pieno: è la stessa voce che annuncia
   l'ondata, e alla fine dice com'è andata. */
.herald[data-kind="bonus"] { border-color: var(--accent); }

.herald[data-kind="bonus"] .herald-kind { color: var(--accent-text); }

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

/* ---------------------------------------------------------------------------------------------
   il gettone
   --------------------------------------------------------------------------------------------- */

/* L'unico comando della schermata di apertura, e l'idea stessa dell'app. Grande, contornato
   nell'accento, e lampeggiante — il lampeggio è il cabinato che cita sé stesso, ed è l'unica
   animazione dell'app che non sia il gioco. */
.coin {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 16px;
  padding: 13px 26px;
  border: 1px solid var(--accent);
  color: var(--accent-text);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  animation: blink 1.6s steps(1, end) infinite;
}

.coin:hover { background: var(--accent-soft); border-color: var(--accent); }

.coin-mark { display: inline-flex; }

@keyframes blink { 0%, 62% { opacity: 1; } 63%, 100% { opacity: 0.45; } }

/* Chi ha chiesto meno movimento ha chiesto meno di esattamente questo. Il gioco non viene
   rallentato: quello sarebbe cambiare le regole, che non è ciò che la preferenza vuol dire. */
@media (prefers-reduced-motion: reduce) {
  .coin { animation: none; }
  .herald { animation: none; }
}

/* ---------------------------------------------------------------------------------------------
   come si gioca, il nome, la tabella
   --------------------------------------------------------------------------------------------- */

.how {
  text-align: left;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-2);
  padding: 14px 16px;
  width: 100%;
}

.how h2 {
  font-size: 12px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 8px;
  font-weight: 500;
}

.how h2 + ul { margin-top: 0; }

.how ul { list-style: none; margin: 0 0 10px; padding: 0; display: grid; gap: 7px; }

/* La regola del gioco, sopra l'elenco delle sue conseguenze. Nel colore del testo e non in quello
   attenuato: è l'unica riga del pannello che va letta per forza. */
.how .rule { font-size: 13.5px; color: var(--text); line-height: 1.5; margin: 0 0 10px; }

/* Il quadratino del sito invece del pallino del browser. */
.how li {
  position: relative;
  padding-left: 16px;
  font-size: 13.5px;
  color: var(--muted);
  line-height: 1.5;
}

.how li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 7px;
  width: 6px;
  height: 6px;
  background: linear-gradient(135deg, var(--accent), var(--accent-text));
}

.nameform {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
}

.nameform label {
  font-size: 12px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--faint);
}

.nameform input {
  font: inherit;
  font-size: 16px;              /* sotto i 16px, iOS ingrandisce la pagina quando il campo prende il fuoco */
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  width: 190px;
}

.scores {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  text-align: left;
}

.scores th {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  font-weight: 500;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
}

.scores td { padding: 6px 8px; border-bottom: 1px solid var(--border); color: var(--muted); }

.scores .pos { width: 40px; color: var(--faint); font-variant-numeric: tabular-nums; }

.scores .who { color: var(--text); overflow-wrap: anywhere; }

/* Il segno che quella riga è stata fatta in due. Una sigla e non un colore: due punteggi fatti in
   condizioni diverse devono distinguersi anche per chi i colori non li separa. */
.scores .who small {
  color: var(--faint);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  margin-left: 6px;
}

.scores .pts { text-align: right; font-variant-numeric: tabular-nums; width: 74px; }

.scores .when { text-align: right; color: var(--faint); white-space: nowrap; }

.totals {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  justify-content: center;
  font-size: 12.5px;
  color: var(--faint);
}

.totals b { color: var(--text); font-variant-numeric: tabular-nums; }

.io { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }

/* ---------------------------------------------------------------------------------------------
   i tasti, cambiati
   --------------------------------------------------------------------------------------------- */

.keymap { display: grid; gap: 14px; width: 100%; }

.keyset { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; }

.keyset h3 {
  font-size: 12px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--faint);
  font-weight: 500;
  margin: 0 0 8px;
}

.keyrow {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 0;
  text-align: left;
}

.keyrow span { flex: 1 1 auto; font-size: 13.5px; color: var(--muted); }

/* Il pulsante è il tasto: si clicca e si preme quello nuovo. Monospazio, perché quello che c'è
   scritto dentro è un codice di tastiera e non una parola — e in tondo «KeyW» e «Key W» si
   confondono. Quarantaquattro pixel di altezza, come ogni comando dell'app. */
.keycap {
  min-width: 118px;
  min-height: 44px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--text);
}

.keycap[data-listening="1"] {
  border-color: var(--accent);
  color: var(--accent-text);
  background: var(--accent-soft);
}

/* ---------------------------------------------------------------------------------------------
   a tutto schermo
   --------------------------------------------------------------------------------------------- */

/* **Due meccanismi in uno, e servono tutt'e due.**
   L'API `requestFullscreen` toglie la cornice del browser; questo attributo toglie la barra dell'app
   e il piede, che il browser non sa che ci sono. Dove l'API non esiste — su iPhone non c'è, e non è
   un caso di nicchia: è metà dei telefoni — resta comunque questo, e il campo guadagna lo spazio di
   due barre, che su uno schermo alto quattrocento pixel è un terzo di tutto.

   Sono attributi su `<html>`, non classi: lo stato si legge dall'ispettore senza aprire il codice. */
:root[data-full="1"] header,
:root[data-full="1"] .foot { display: none; }

/* `vh` prima e `dvh` dopo, e non è ridondanza: su iOS `vh` conta la barra del browser come se non
   ci fosse, quindi da solo lascia il fondo del campo sotto il bordo dello schermo. `dvh` misura
   quello che si vede davvero — ma non lo conoscono le versioni di Safari su cui questo meccanismo è
   l'**unico** che funziona, perché lì l'API del tutto schermo non esiste. Chi capisce la seconda
   riga la usa, gli altri restano sulla prima. */
:root[data-full="1"] main { height: 100vh; height: 100dvh; }

/* La cornice del campo sparisce con la pagina intorno: incornicia uno schermo dentro una pagina, e
   a tutto schermo la pagina non c'è più. */
:root[data-full="1"] #field {
  border: 0;
  border-radius: 0;
  min-height: 100vh;
  min-height: 100dvh;
  box-shadow: none;
}

/* L'uscita: nella griglia dello stage come l'annuncio, così non serve posizionarla in assoluto.
   Quarantaquattro pixel, come ogni comando dell'app, e appena visibile — deve trovarsi quando la si
   cerca e sparire quando non la si cerca. */
.full-exit {
  grid-area: 1 / 1;
  place-self: start end;
  margin: 10px calc(10px + env(safe-area-inset-right)) 0 0;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: color-mix(in srgb, var(--panel) 70%, transparent);
  color: var(--muted);
}

.full-exit:hover { color: var(--accent-text); border-color: var(--accent); }

/* ---------------------------------------------------------------------------------------------
   il piede, e gli schermi stretti
   --------------------------------------------------------------------------------------------- */

.foot {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 0 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.foot .spacer { flex: 1 1 auto; }

@media (max-width: 620px) {
  .hudbar { gap: 12px; padding: 5px 12px; }
  .sheet { padding: 1.1rem 1rem 1rem; }
  .scores .when, .scores th.when { display: none; }
  .keyrow { flex-wrap: wrap; }
}

/* **Un telefono in orizzontale**, che è come questo gioco va tenuto e quindi il caso normale e non
   quello limite. Lì l'altezza è tutto: su uno schermo alto quattrocento pixel, il `min-height: 46vh`
   del campo vale centottantaquattro pixel, e le due barre più il piede si prendono il resto.

   Quindi il minimo sparisce — al campo basta lo spazio che avanza, e ce n'è di più — e tutto quello
   che sta intorno si stringe. È il modo di guadagnare uno schermo senza chiedere niente a nessuno,
   e il pulsante del tutto schermo resta per quando anche questo non basta. */
@media (orientation: landscape) and (max-height: 560px) {
  #field { min-height: 0; }
  .appbar { padding-top: 4px; padding-bottom: 4px; }
  .hudbar { padding: 2px 12px; }
  .foot { padding-top: 0.3rem; font-size: 0.78rem; }
  .panel { gap: 0.35rem; }
  .sheet { padding: 0.8rem 1rem 0.7rem; gap: 0.4rem; }
  .title { font-size: clamp(24px, 5vw, 34px); }
  .small-title { font-size: clamp(18px, 3.4vw, 22px); }
}
