/* ═══════════════════════════════════════════════════════════════════
   WORKOUTS v2 — design system "Il muro del box" · BASE
   Nero polveroso (texture magnesite del sito) · Anton display · Inter
   Vibe: scoreboard da gara. Un solo accento: viola Iris #8E70D4.
   ─────────────────────────────────────────────────────────────────────
   Quattro file dal 2026-09-11 (piano A7, 13.1), caricati in quest'ordine:
   base.css (questo) → codifiche.css → atleta.css (base_public.html)
   oppure coach.css (base_admin.html).
   Qui sta tutto ciò che vale per ENTRAMBE le viste: font, token (anche
   --rail-off e --dim), reset, layout e testata (anche sul telefono),
   tipografia, bottoni, badge, card, form, flash, toast, tabelle, modale
   note, sheet (guscio), utility, mobile generico, avatar, colore track,
   il kit v2 della sheet di registrazione (chip, seg, celle, flabel,
   hintline, log-tag: lo usano anche il form coach e la scheda utente),
   coach notes, i commenti e la loro sheet, la tendina @, l'interruttore
   .pf-sw, conferma, pagina di errore.
   Una sezione nuova va nel file della sua area, in fondo. ⚠️ A parità di
   specificità vince l'ultima regola caricata: una regola di base che deve
   battere una di area si scrive più specifica, non si sposta (le tre
   compensazioni «13.1» in codifiche.css sono nate così). Dentro ogni file
   le sezioni stanno nell'ordine che avevano nel file unico (git:
   static/css/workouts.css fino al 2026-09-10); lo split è verificato con
   scripts/vetrina/css_diff.py (stili calcolati prima/dopo: zero
   differenze).
   ═══════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════
   WORKOUTS v2 — design system "Il muro del box"
   Nero polveroso (texture magnesite del sito) · Anton display · Inter
   Vibe: scoreboard da gara. Un solo accento: viola Iris #8E70D4.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Font self-hosted ─────────────────────────────────────────────── */
@font-face {
  font-family: 'Anton';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/anton-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/inter-var-latin.woff2') format('woff2');
}

/* ── Token ────────────────────────────────────────────────────────── */
:root {
  color-scheme: dark;

  /* colori — nero con una punta di viola, allineati ai riferimenti grafici
     del kit v2 (fondo #0D0C11, superfici #17161C).
     I due livelli di superficie restano: --surface-2 tiene lo stesso passo
     di prima (+8 su ogni canale) per non appiattire card e piani rialzati. */
  --ink:        #0D0C11;
  --surface:    #17161C;
  --surface-2:  #1F1E24;
  /* allineati ai riferimenti grafici (2026-08-14): il filetto era scivolato
     al 9% contro il 7%, il testo a #f5f4f7 e il grigio attenuato a #9c99a6.
     Valgono i riferimenti: #8C8798 sta a 5.17:1 sulla card e 5.60:1 sulla
     pagina, sopra la soglia AA di 4.5 per il testo piccolo. */
  --line:       rgba(255,255,255,.07);
  --text:       #F2F0F5;
  --muted:      #8C8798;
  --purple:     #8E70D4;
  /* il viola in canali, per le trasparenze: rgba(var(--accent-rgb), .14).
     La faccia DaVinci lo ridefinisce (static/css/tema-dvp.css) e con lui
     cambiano tutte le tinte che ne derivano (2026-09-23). */
  --accent-rgb: 142, 112, 212;
  --purple-hi:  #A886CD;
  --purple-dim: rgba(var(--accent-rgb), .14);
  --purple-line:rgba(var(--accent-rgb), .4);
  /* ui-kit card WOD (2026-08-10): tinte del brand a bassa opacità per gli
     sfondi bottone (MAI hex fisso: la trasparenza li tiene coerenti su
     superfici diverse) + versioni schiarite del viola per testo/icone */
  --brand-light: #BBA9E5;   /* testo/icone sui bottoni primari */
  --brand-mid:   #9B85DD;   /* sottotitolo tipo "EVERY 1:40 X 5" */
  --body-text:   #CFCCD6;   /* corpo descrizione card */
  --btn-tint:        rgba(var(--accent-rgb), .15);
  --btn-tint-hover:  rgba(var(--accent-rgb), .22);
  --btn-tint-active: rgba(var(--accent-rgb), .28);
  --btn-sec-bg:       rgba(255,255,255,.06);
  --btn-sec-bg-hover: rgba(255,255,255,.10);
  --btn-sec-fg:       #C9C6D1;
  /* SELEZIONE (2026-08-14, decisione di Roberta) — un controllo selezionato è
     viola al 22%, il suo hover al 28%. Prima il valore girava in tre
     intensità diverse (20% chip classifica, 22% barre segmentate, 28% hover):
     il 20% su fondo scuro si confondeva col grigio dell'hover, che è proprio
     l'errore che le specifiche mettono in guardia dal fare.
     ⚠️ NON riusare --btn-tint-*: quelli sono lo sfondo di un'AZIONE, questi lo
     stato di un INTERRUTTORE. Stessi numeri oggi, ma cambiano per motivi
     diversi. */
  --sel-tint:       rgba(var(--accent-rgb), .22);
  --sel-tint-hover: rgba(var(--accent-rgb), .28);
  --sel-fg:         #D6C9F2;
  /* versione desaturata per le superfici piene e grandi (bottone primario,
     giorno attivo): il viola pieno a tutta larghezza pesava troppo */
  --purple-mute:    #7B6CA4;
  --purple-mute-hi: #8B7BB6;
  /* ⭐ Le TINTE DELL'ACCENTO che erano scritte a mano nei fogli (2026-09-23,
     le due facce): valori identici a prima, ma ora la faccia DaVinci le
     ridefinisce in un punto (static/css/tema-dvp.css). Un viola nuovo si
     scrive come token, mai come esadecimale in una regola. */
  --accent-testo:      #D6C9F2;   /* testo chiaro su una tinta (io in classifica, hover) */
  --accent-testo-hi:   #E4DBF7;
  --accent-etichetta:  #A996DE;   /* etichette e numeri nell'accento */
  --accent-vivo:       #A97FF5;   /* il timer negli ultimi secondi */
  --accent-lampo:      #262233;   /* il lampo del timer */
  --accent-inchiostro: #1B1030;   /* testo SOPRA l'accento pieno */
  --brand-light-rgb:   187, 169, 229;   /* --brand-light in canali */
  --sheet-cta-bg:       #1B1826;
  --sheet-cta-bg-hover: #221E31;
  /* i GRIGI con la punta di viola, per luminosità (il numero è la L di
     HSL): erano un centinaio di esadecimali sparsi, stessi valori */
  --grigio-93: #EDEBF2;
  --grigio-91: #E8E6ED;
  --grigio-80: #C9C6D1;
  --grigio-66: #A5A0AE;
  --grigio-62: #9C97A6;
  --grigio-51: #7E7989;
  --grigio-44: #6E6979;
  --grigio-35: #57535F;
  --grigio-22: #3A3742;
  /* le tinte delle sezioni (For Time a sezioni, codifiche.css .sez--*):
     la prima è --brand-light, poi a scendere */
  --tinta-sez-b: #A98FE0;
  --tinta-sez-c: #9C8BC7;
  --tinta-sez-d: #9A94A6;
  --ok:   #4ade80;  --ok-dim:   rgba(74,222,128,.14);  --ok-line:   rgba(74,222,128,.35);
  --warn: #fbbf24;  --warn-dim: rgba(251,191,36,.14);  --warn-line: rgba(251,191,36,.35);
  --err:  #fc6868;  --err-dim:  rgba(252,104,104,.14); --err-line:  rgba(252,104,104,.35);

  /* spacing — base 4 */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

  /* type */
  --font: 'Inter', system-ui, sans-serif;
  --font-display: 'Anton', 'Arial Black', sans-serif;
  --fs-xs: 12px; --fs-sm: 13.5px; --fs-base: 15px; --fs-lg: 17px; --fs-xl: 20px;
  --fs-input: 16px;   /* i controlli restano a 16px: niente zoom iOS */
  /* due gradini SOTTO --fs-xs, aggiunti alla scala il 2026-08-14. Non sono
     un'eccezione: le specifiche li prescrivono per occhielli ed etichette
     (10px) e per sottotitoli e righe meta (11px), ed erano le due misure più
     scritte a mano di tutto il file (26 e 18 occorrenze). Restano FUORI dalla
     media query mobile: sono già i più piccoli, rimpicciolirli li renderebbe
     illeggibili. */
  --fs-eyebrow: 10px;
  --fs-meta:    11px;
  /* etichetta delle sezioni coach notes: fuori scala di proposito (è un
     occhiello) e FUORI dalla media query, non deve rimpicciolire */
  --cn-head-fs: 10px;
  --display-sm: 24px;
  --display-lg: clamp(26px, 4.5vw, 36px);
  --display-hero: clamp(34px, 7vw, 56px);

  /* geometria — --r-lg è il raggio delle bottom sheet (20px nei riferimenti
     del kit v2): un gradino nuovo della scala, non un numero sparso */
  --r-sm: 8px; --r-md: 14px; --r-lg: 20px; --r-pill: 999px;
  /* BOTTONI (2026-08-14, decisione di Roberta) — il raggio segue la
     dimensione, due gradini soli. Prima lo stesso bottone d'azione esisteva
     in cinque forme (11px card WOD, 12px massimali, 13px riepilogo score,
     14px sheet e dock, 999px profilo/auth/coach/admin): non si incontravano
     mai tranne che nel profilo, ed è lì che si vedeva.
     La pastiglia NON sparisce dal file: resta su chip, filtri e badge, dove
     la forma tonda distingue un interruttore da un'azione. */
  --r-btn:    12px;          /* bottone in linea, piccolo */
  --r-btn-lg: var(--r-md);   /* bottone grande a tutta larghezza */
  --speed: .15s ease;
  --tap: 44px;
  /* ── Il segno del FUOCO (2026-08-27, scelto con Roberta) ───────────
     Il filo cade SUL bordo del comando (offset negativo), non fuori:
     staccato si vedevano due righe — il bordo del campo e l'anello
     intorno — e lei l'ha bocciato tre volte prima di arrivarci.
     Si cambia QUI per tutta l'app. */
  --fuoco-w: 1.5px;
  --fuoco-c: var(--purple);
  /* altezza della bottom nav, safe-area ESCLUSA. Era scritta a mano come
     72px in quattro punti (padding del main, toast, dock della classifica):
     tre cose che devono muoversi insieme alla nav e che potevano divergere
     in silenzio. La nav non ha un'altezza propria — la fa il contenuto —
     quindi questo resta il numero di riferimento di chi le sta attorno. */
  --nav-h: 72px;
}

/* mobile: scala tipografica più compatta — sullo schermo stretto il testo
   a 15px "spingeva" e si leggeva peggio. --fs-input NON si tocca (sotto i
   16px iOS zooma il campo al focus). */
@media (max-width: 480px) {
  :root {
    --fs-xs: 11.5px; --fs-sm: 12.5px; --fs-base: 14px;
    --fs-lg: 16px; --fs-xl: 18px;
    --display-sm: 22px;
  }
}

/* ── Reset + base ─────────────────────────────────────────────────── */
* { box-sizing: border-box; margin: 0; padding: 0; }
/* gutter stabile: le pagine corte (senza scrollbar) non spostano più
   il contenuto centrato rispetto a quelle lunghe */
html { scroll-behavior: smooth; scrollbar-gutter: stable; }
/* ⚠️ Safari spegne il doppio tocco solo se lo dice l'elemento che HAI
   TOCCATO: metterlo sulla radice o sul body non basta, il tocco cade su
   un titolo o su un div qualsiasi e lo zoom parte lo stesso. Serve
   davvero su tutti (segnalato da Roberta il 2026-08-20, due tentativi
   più leggeri non erano bastati).
   `manipulation` = niente doppio tocco, ma le due dita restano LIBERE:
   chi ci vede poco deve poter ingrandire, e se la pagina finisce zoomata
   è l'unico modo per uscirne. Il doppio tocco vero lo spegne no-zoom.js,
   perché su Safari il CSS da solo non bastava. */
* { touch-action: manipulation; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    /* senza, lo stagger delle card resterebbe a opacity 0 per il delay */
    animation-delay: 0s !important;
  }
  /* gli pseudo-elementi delle View Transitions NON sono coperti dal
     selettore * del documento: si azzerano a parte */
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* ── View Transitions cross-document (Chrome 126+ / Safari 18.2+) ──
   Progressive: dove non supportate si naviga senza animazione (Firefox).
   Default = fade + risalita leggera; con la direzione marcata dal JS
   (toast.js, Navigation API) avanti scivola da destra, indietro da
   sinistra, come un'app nativa. Topbar e bottom nav hanno uno snapshot
   proprio: restano ferme mentre il contenuto transisce. */
@view-transition { navigation: auto; }
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; transform: translateY(10px); } }
@keyframes vt-in-fwd { from { opacity: 0; transform: translateX(28px); } }
@keyframes vt-in-back { from { opacity: 0; transform: translateX(-28px); } }
::view-transition-old(root) { animation: vt-out .18s ease both; }
::view-transition-new(root) { animation: vt-in .22s ease both; }
html:active-view-transition-type(fwd) ::view-transition-new(root) {
  animation-name: vt-in-fwd;
}
html:active-view-transition-type(back) ::view-transition-new(root) {
  animation-name: vt-in-back;
}
.topbar { view-transition-name: topbar; }
.bottom-nav { view-transition-name: bottomnav; }

body {
  font-family: var(--font);
  font-size: var(--fs-base);
  color: var(--text);
  background: var(--ink);
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  line-height: 1.6;
  /* ⭐ 2026-08-27: `clip`, non `hidden` — è la cura della bottom nav che
     «balla» su iPhone (segnalata da Bernardo, misurata con /debug/barra:
     380 frame su 2073 con la barra fuori posto, senza alcuno zoom).
     `overflow-x: hidden` NON è combinabile con `overflow-y: visible`, e
     il browser forza l'altro asse ad `auto`: il body diventa così un
     CONTENITORE DI SCROLL, e su WebKit un fixed dentro un body-scroller
     viene ricomposto in ritardo — durante lo scroll scorre via col
     documento e torna a posto quando ci si ferma. `clip` è l'unico
     valore che convive con `visible`: taglia l'overflow orizzontale
     come prima, ma non crea nessuno scroller (verificato: overflow-y
     calcolato passa da `auto` a `visible`). La riga `hidden` resta
     sopra come ripiego per i browser senza clip (Safari < 16). */
  overflow-x: hidden;
  overflow-x: clip;
  /* `contain` e non `none` (2026-08-22, chiesto da Roberta: «o che
     rimbalza di più»): none spegne del tutto il rimbalzo elastico e
     l'arrivo in fondo è secco. `contain` tiene quello che serviva — la
     scorsa non passa a quello che c'è sotto, niente ricarica tirando giù
     dall'alto — e restituisce il rimbalzo. */
  overscroll-behavior-y: contain;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-font-smoothing: antialiased;
}
/* niente texture: i riferimenti del design system posano le card su
   --ink pieno. La polvere di magnesite (static/img/dust.jpg) sgranava
   troppo sulle schermate dell'app e resta solo sul sito. */
body > * { position: relative; z-index: 1; }

a { color: var(--purple-hi); text-decoration: none; }
a:hover { text-decoration: underline; }
::selection { background: var(--purple); color: #fff; }

a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
  outline: var(--fuoco-w) solid var(--fuoco-c);
  outline-offset: calc(-1 * var(--fuoco-w));
}
/* ⚠️ un link DENTRO UN TESTO non ha un riquadro su cui appoggiare il
   filo: il suo segno è la sottolineatura, che è il modo naturale del
   testo e non disegna scatole intorno alle parole. Solo dentro i
   paragrafi: i link travestiti da bottone (.btn, .tl-btn…) stanno
   altrove e tengono il filo. */
:is(p, li, .hint, .rich-text, figcaption) a:focus-visible {
  outline: none;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.icon {
  width: 20px; height: 20px;
  flex: 0 0 auto;
  vertical-align: -4px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon--sm { width: 16px; height: 16px; vertical-align: -3px; }
/* icone PIENE del ui-kit (nav + card WOD): riempimento, niente contorno */
.icon--fill { fill: currentColor; stroke: none; }

/* ── Layout ───────────────────────────────────────────────────────── */
main { flex: 1; padding: var(--s4) 0 var(--s6); }
.container {
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  padding: 0 var(--s4);
}
/* Coach e admin lavorano su tabelle larghe (utenti, griglia settimana):
   1240px costringeva /admin/utenti a scorrere di lato. */
body.admin .container { max-width: 1600px; }
/* ⛔ non esiste più la variante "narrow" per le pagine di scrittura
   (2026-08-18, deciso da Francesco: «tutte larghe come le più larghe» —
   le finestre coach che cambiavano larghezza fra una pagina e l'altra
   stonavano più di un form largo). Il block body_class in base_admin
   resta come hook. */

/* topbar */
header.topbar {
  /* ⚠️ fondo OPACO e niente backdrop-filter (2026-08-21): terza volta
     dopo bottom nav e testata della home. Su iPhone WebKit ricompone in
     ritardo un layer appiccicato col blur, e mentre si scorre in fretta
     TUTTI i livelli fissi della pagina restano indietro — compresa la
     barra in basso, che è quella che si vede «staccarsi». rgba(10,10,11)
     era anche il vecchio nero caldo, non --ink. */
  background: var(--ink);
  min-height: 60px;
  display: flex;
  align-items: center;
  position: sticky;
  top: 0;
  z-index: 100;
  border-bottom: 1px solid var(--line);
}
header.topbar > .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  min-width: 0;
}
.brand { display: flex; align-items: center; min-width: 0; }
.brand img { height: 27px; width: auto; display: block; }
/* ⭐ 2026-08-27 (Roberta): non piu la scritta viola nel carattere del
   logo dopo un filo grigio. Ora e una barretta viola di 3 punti con
   accanto la parola in maiuscolo: la STESSA barra che sta a sinistra
   delle targhette della settimana, quindi la testata parla la lingua
   della griglia e non aggiunge una forma nuova.
   ⚠️ Provate anche la pastiglia piena (come il badge COACH dei commenti)
   e quella vuota: la piena pesava quanto una voce di menu, la vuota su
   fondo nero spariva a schermo piccolo. */
.brand-app {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--body-text);
  margin-left: var(--s2);
  padding-left: var(--s2);
  border-left: 3px solid var(--purple);
  white-space: nowrap;
}
.topbar-nav {
  display: flex;
  gap: var(--s1);
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.topbar-nav a, .topbar-nav .nav-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 40px;
  padding: 0 var(--s3);
  border-radius: var(--r-pill);
  border: none;
  background: none;
  font-family: var(--font);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--muted);
  cursor: pointer;
  transition: color var(--speed), background-color var(--speed);
}
.topbar-nav a:hover, .topbar-nav .nav-btn:hover {
  color: var(--text);
  background: var(--surface-2);
  text-decoration: none;
}
.topbar-nav a.active { color: var(--purple-hi); }
.nav-form { display: inline-flex; }

/* bottom nav (atleti, mobile) */
.bottom-nav {
  display: none;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 100;
  /* ⚠️ fondo OPACO e niente backdrop-filter (2026-08-17). Prima era
     rgba(10,10,11,.92) + blur(14px): su iPhone la nav "svolazzava" durante
     lo scroll con inerzia, lasciando vedere il contenuto scorrere sotto —
     un layer fixed con backdrop-filter WebKit lo ricompone in ritardo, e
     l'8% di trasparenza mostrava comunque la pagina attraverso la barra.
     Il colore è anche l'allineamento ai token: rgba(10,10,11) era il
     vecchio «nero caldo», non l'attuale --ink. */
  background: var(--ink);
  /* ⛔ NIENTE `transform: translateZ(0)` (2026-08-22). C'era dal 17 agosto
     come «rimedio standard ai fixed che ballano su iOS», e faceva il danno
     che doveva curare: dava alla barra uno strato grafico tutto suo, e il
     telefono si ritrovava a ridisegnare a ogni fotogramma la fascia di
     contenuto che ci passa sotto. Scorrendo veloce fino in fondo erano le
     ULTIME CARD a tremare — non la testata, non la barra.
     Provato in A/B sull'iPhone di Roberta, stesso gesto: con lo strato
     trema, senza è calma. Se qualcuno lo rimette, il tremolio torna. */
  border-top: 1px solid var(--line);
  /* ⚠️ Questa imbottitura CAMBIA da sola mentre si scorre, e non è un
     difetto: su iPhone con la barra degli indirizzi in basso, quando
     Safari la ritira nella pastiglia il telefono dichiara «gli ultimi
     34px ora sono coperti» e la zona sicura si apre. Senza, le icone
     finirebbero sotto la pastiglia. Quello che si poteva togliere è lo
     SCATTO: ora la crescita scivola insieme all'animazione di Safari
     (2026-08-21, barra «che si alza» segnalata da due telefoni). */
  padding-bottom: env(safe-area-inset-bottom);
  transition: padding-bottom .18s ease;
}
/* paraurti (2026-08-18): in Safari con la barra indirizzi in basso il
   viewport di layout e quello visibile si disallineano mentre la barra
   si espande/ritira, e sotto la nav si apriva un "buco" col contenuto
   che scorreva dentro. La fascia estende il fondo della nav oltre il
   bordo: nel buco si vede lei, non la pagina. */
.bottom-nav::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 0; right: 0;
  height: 120px;
  background: var(--ink);
}
.bottom-nav-inner {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
}
.bottom-nav a {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 0 8px;
  min-height: var(--tap);
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--muted);
  transition: color var(--speed);
}
.bottom-nav a:hover { text-decoration: none; }
.bottom-nav a.active { color: var(--purple-hi); }
.bottom-nav a:active { color: var(--text); }
.bottom-nav .icon { width: 22px; height: 22px; }

.footer-pub {
  text-align: center;
  padding: var(--s5) var(--s4);
  color: var(--muted);
  font-size: var(--fs-xs);
  border-top: 1px solid var(--line);
}

/* ── Tipografia ───────────────────────────────────────────────────── */
h1.display, h2.display {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  font-size: var(--display-lg);
  line-height: 1.04;
  text-wrap: balance;
  margin: 0 0 var(--s4);
}
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--purple-hi);
}
.muted { color: var(--muted); }
small, .small { font-size: var(--fs-sm); color: var(--muted); }
.empty {
  color: var(--muted);
  text-align: center;
  padding: var(--s5) 0;
}
.empty .icon { width: 28px; height: 28px; opacity: .6; margin-bottom: var(--s2); }
/* PR, categoria senza niente: una riga spenta e basta. Stesso grigio dei
   giorni futuri, e 36px di stacco dai filtri perché non sembri appesa
   alla fila di chip (misura scelta da Roberta il 2026-08-20). */
.pr-vuoto {
  margin: 0;
  padding: 36px 0 8px;
  text-align: center;
  font-size: 13px;
  color: var(--dim);
}
/* ⛔ `.empty--hero`, il watermark col graffito, è STATO TOLTO il
   2026-09-04 (Roberta): lo stato vuoto dell'app è uno solo, il riquadro
   tratteggiato `.tl-empty` (icona, titolo, riga sotto). Il graffito, oltre
   a parlare un'altra lingua, arrivava sempre tagliato — alto 111 punti
   dentro un'imbottitura da 110. Se ricompare da qualche parte, è una
   ricaduta: la regola sta in docs/design-system.md. */

/* flow di testo nei contesti prose */
.prose p, .prose ul, .prose ol { margin-bottom: var(--s3); }
.prose :last-child { margin-bottom: 0; }
.prose li { margin-bottom: var(--s1); margin-left: var(--s5); }

/* rich-text dei coach (output Quill sanitizzato) */
/* le descrizioni importate da BTWB usano &nbsp;: senza questo, su mobile
   la riga non manda a capo e viene tagliata a destra */
.rich-text { overflow-wrap: anywhere; }
.rich-text { font-size: var(--fs-base); line-height: 1.6; }
.rich-text p { margin-bottom: var(--s3); }
.rich-text h2, .rich-text h3 {
  margin: var(--s4) 0 var(--s2);
  line-height: 1.25;
}
.rich-text h2 { font-size: var(--fs-xl); }
.rich-text h3 { font-size: var(--fs-lg); color: var(--purple-hi); }
.rich-text ul, .rich-text ol { margin: 0 0 var(--s3) var(--s5); }
.rich-text li { margin-bottom: var(--s1); }
.rich-text a { text-decoration: underline; }
/* formato "riga grigia" dell'editor (rest / note): stesso stile della
   riga di recupero generata sotto lo schema SxR (.tl-card-sub) */
.rich-text p.ql-rest-on {
  color: var(--muted);
  font-size: var(--fs-sm);
  margin-bottom: var(--s1);
}
.rich-text :last-child { margin-bottom: 0; }

.user-text { overflow-wrap: anywhere; }
.pre-line { white-space: pre-line; }

/* ── Bottoni ──────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: var(--tap);
  padding: 0 var(--s5);
  /* squadrati come tutto il resto: la pastiglia tonda era rimasta solo qui */
  border-radius: var(--r-btn-lg);
  font-family: var(--font);
  font-size: var(--fs-sm);
  font-weight: 600;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--speed), border-color var(--speed),
              color var(--speed), transform var(--speed);
}
.btn:hover { text-decoration: none; }
.btn:active { transform: scale(.97); }
.btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }

/* ⚠️ LA STESSA LINGUA DELL'ATLETA (2026-08-24, scelta di Roberta fra due
   proposte). L'azione che conclude non è più viola PIENO con testo
   bianco: è la velatura viola col filo, cioè il «Salva risultato» che
   l'atleta ha nella sheet (.sheet-cta). Le altre sono neutre, e il
   pericolo lo dice il cestino, non il rosso — come per gli avvisi, dove
   il tipo lo dice l'icona. Il rosso resta al passaggio del mouse, quando
   stai per premere davvero. */
.btn-primary {
  background: var(--btn-tint);
  color: var(--brand-light);
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), .45);
}
.btn-primary:hover { background: var(--btn-tint-hover); color: var(--sel-fg); }
.btn-ghost {
  background: rgba(255, 255, 255, .06);
  border-color: transparent;
  color: var(--grigio-66);
}
.btn-ghost:hover { background: rgba(255, 255, 255, .11); color: var(--text); }
.btn-danger { background: rgba(255, 255, 255, .06); border-color: transparent; color: var(--grigio-66); }
.btn-danger:hover { background: var(--err-dim); color: var(--err); }

.btn--sm { min-height: 36px; padding: 0 var(--s4); font-size: var(--fs-sm); border-radius: var(--r-btn); }
.btn--block { width: 100%; }
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap);
  height: var(--tap);
  flex: 0 0 auto;
  /* quadrato stondato su una velatura, non più pastiglia col filo: è lo
     stile della chiusura nei riferimenti del kit v2 (.x/.close, velatura
     rgba(255,255,255,.06), niente bordo), portato su TUTTI i bottoni
     icona. Il filo resta trasparente così l'hover non sposta il layout. */
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .06);
  border: 1px solid transparent;
  color: var(--grigio-66);
  cursor: pointer;
  transition: color var(--speed), border-color var(--speed), background-color var(--speed);
}
/* il grigio chiaro è l'hover, come sui chip: qui si schiarisce la velatura
   invece di accendere un filo viola, che su un quadrato stondato leggeva
   come «selezionato» */
.btn-icon:hover { color: var(--text); background: rgba(255, 255, 255, .11); text-decoration: none; }
.btn-icon:active { transform: scale(.94); }
.btn-icon--danger:hover { color: var(--err); border-color: var(--err-line); background: var(--err-dim); }
/* disabilitato = segnaposto che tiene la colonna allineata (l'occhio
   dell'impersonazione sulle righe admin). Niente pointer-events: none,
   sennò sparirebbe anche il title che spiega il perché. */
.btn-icon:disabled { opacity: .35; cursor: not-allowed; }
.btn-icon:disabled:hover { color: var(--grigio-66); background: rgba(255, 255, 255, .06); }
.btn-icon:disabled:active { transform: none; }

/* 36px come li vuole Roberta (il riferimento dice 30, troppo piccolo per
   un dito). L'area toccabile resta 44px — il bersaglio che il repo si è
   dato, --tap — allargata oltre il bordo visibile: si vede piccolo, si
   prende lo stesso. */
.btn-icon--sm { position: relative; border-radius: var(--r-btn); }
.btn-icon--sm::after {
  content: '';
  position: absolute;
  inset: calc((36px - var(--tap)) / 2);
}

/* ⚠️ Nelle sheet l'area estesa a destra veniva TAGLIATA: la X sta sul
   bordo destro del corpo, che scorre (overflow) e quindi ritaglia tutto
   quello che sporge fuori — restavano 44px su tre lati e 36 sul quarto.
   È lo stesso difetto annotato sulla PR #5, mai chiuso.
   Qui l'area si allarga solo verso l'INTERNO: 36 + 8 a sinistra = 44 di
   bersaglio, e a destra non sporge niente da tagliare. Non si perde
   nulla: a destra della X c'è il bordo dello schermo, nessuno ci tocca. */
.score-sheet-head .btn-icon--sm::after,
.note-dialog-head .btn-icon--sm::after {
  inset: calc((36px - var(--tap)) / 2) 0 calc((36px - var(--tap)) / 2)
         calc(36px - var(--tap));
}

.actions {
  display: flex;
  gap: var(--s2);
  flex-wrap: wrap;
  align-items: center;
}

/* ── Badge ────────────────────────────────────────────────────────── */
.badge {
  display: inline-block;
  max-width: 100%;
  /* line-height = altezza: il testo uppercase resta centrato nel box
     (+1px sopra per la centratura ottica, niente discendenti) */
  padding: 1px 10px 0;
  line-height: 21px;
  border-radius: var(--r-sm);
  font-size: var(--fs-meta);
  font-weight: 700;
  text-transform: uppercase;
  background: var(--purple-dim);
  color: var(--purple-hi);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
a.badge { transition: background-color var(--speed), color var(--speed); }
a.badge:hover { text-decoration: none; background: rgba(var(--accent-rgb), .26); }
/* 2026-08-27 (Roberta): il viola pieno era l'unico colore acceso della
   pagina e strillava. Lo stesso viola opaco delle chip selezionate. */
.badge--active { background: var(--sel-tint); color: var(--sel-fg); }
/* ...tranne su ADMIN, che deve staccarsi dal COACH: sono pochi e il
   pieno qui è un accento, non un colore di fondo (2026-08-27).
   Il pieno è quello desaturato che usiamo già per le superfici piene
   (bottone primario, giorno attivo): il viola acceso qui strillava. */
.badge--admin { background: var(--purple-mute); color: #fff; }
.badge--ok   { background: var(--ok-dim);   color: var(--ok); }
.badge--warn { background: var(--warn-dim); color: var(--warn); }
.badge--dim  { background: var(--surface-2); color: var(--muted); }

.badge-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  min-width: 0;
}

/* ── Card ─────────────────────────────────────────────────────────── */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s4) var(--s4);
  margin-bottom: var(--s3);
}
.card > h2.section-title:first-child { margin-top: 0; }

h2.section-title {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--purple-hi);
  margin: var(--s5) 0 var(--s2);
}
/* sezioni raggiungibili da un'ancora (#coach/#video/#score dalla card):
   la topbar sticky è 60px, il titolo non ci deve finire sotto */
.anchor { scroll-margin-top: 76px; }

.page-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s3);
  margin-bottom: var(--s4);
}
.page-header h1.display { margin-bottom: 0; }

/* ── Form ─────────────────────────────────────────────────────────── */
input:where([type="text"],[type="password"],[type="email"],[type="url"],
       [type="number"],[type="date"],[type="time"],[type="search"],[type="tel"]),
select, textarea {
  width: 100%;
  min-height: var(--tap);
  padding: 10px var(--s4);
  font-family: var(--font);
  font-size: var(--fs-input);    /* 16px: niente zoom iOS */
  background-color: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  outline: none;
  transition: border-color var(--speed), background-color var(--speed);
}
textarea { min-height: 88px; line-height: 1.5; resize: vertical; }
input:focus, select:focus, textarea:focus { border-color: var(--purple); }
::placeholder { color: var(--muted); opacity: .7; }

select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%239c99a6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  cursor: pointer;
  /* un'opzione più lunga della colonna si clippa sul bordo vivo
     («Codificata — Rounds F»): con l'ellissi almeno si vede che continua */
  text-overflow: ellipsis;
}
option { background: var(--surface-2); color: var(--text); }

/* Safari su iPhone non fa restringere input[type=date] sotto la larghezza
   che si sceglie da sé: width 100% viene ignorato, il campo esce dal foglio
   e si porta dietro in orizzontale tutta la schermata (visto sul modulo del
   massimale). Spegnendo l'aspetto nativo il campo rispetta la larghezza, e
   toccandolo si apre lo stesso il selettore a rotella. */
input[type="date"] {
  appearance: none;
  -webkit-appearance: none;
  max-width: 100%;
  text-align: left;
  padding-right: 42px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='%238C8798'><path d='M7.6 1.8a1.05 1.05 0 0 1 1.05 1.05V6.4a1.05 1.05 0 0 1-2.1 0V2.85A1.05 1.05 0 0 1 7.6 1.8zm8.8 0a1.05 1.05 0 0 1 1.05 1.05V6.4a1.05 1.05 0 0 1-2.1 0V2.85A1.05 1.05 0 0 1 16.4 1.8z'/><path fill-rule='evenodd' d='M3 6.9A2.6 2.6 0 0 1 5.6 4.3h12.8A2.6 2.6 0 0 1 21 6.9v12.9a2.6 2.6 0 0 1-2.6 2.6H5.6A2.6 2.6 0 0 1 3 19.8zM5.1 9.4v1.9h13.8V9.4z'/></svg>");
  background-repeat: no-repeat;
  background-position: right 13px center;
}
/* Il pulsantino del calendario è un pezzo di Chrome che su iPhone non
   esiste: per questo lì l'icona spariva. Adesso il calendario lo
   disegniamo noi qui sopra, uguale su tutti, e quello di Chrome resta al
   suo posto ma invisibile, così sul Mac si continua ad aprire il
   selettore toccando l'icona. */
/* Su iPhone il valore della data sta dentro un suo pseudo-elemento, e
   il text-align del campo non lo tocca: senza questa riga la data resta
   centrata anche se il campo dice sinistra. */
input[type="date"]::-webkit-date-and-time-value {
  text-align: left;
}

input[type="date"]::-webkit-calendar-picker-indicator {
  opacity: 0;
  width: 24px;
  height: 24px;
  margin: 0;
  cursor: pointer;
}

::-webkit-calendar-picker-indicator {
  filter: invert(.75);
  cursor: pointer;
}
input[type="search"]::-webkit-search-cancel-button { filter: invert(.6); }
input[type="checkbox"], input[type="radio"] {
  accent-color: var(--purple);
  width: 18px; height: 18px;
}

.field { margin-bottom: var(--s4); }
.field > label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: var(--s2);
}
.field .hint { margin-top: var(--s1); font-size: var(--fs-xs); color: var(--muted); }
.form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--s3);
  align-items: start;
}
.checkbox-field {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: var(--tap);
  font-size: var(--fs-sm);
  cursor: pointer;
}
.checkbox-field input { width: 18px; flex: 0 0 auto; }
.checkbox-inline { display: inline-flex; margin-right: var(--s3); min-height: 32px; }
.form-actions { margin-top: var(--s5); display: flex; gap: var(--s2); flex-wrap: wrap; }

.search-input { max-width: 380px; }

/* ── Flash ────────────────────────────────────────────────────────── */
.flash {
  padding: var(--s3) var(--s4);
  border-radius: var(--r-sm);
  border: 1px solid;
  margin-bottom: var(--s3);
  font-size: var(--fs-sm);
}
/* ⚠️ Come i toast: niente verde né rosso. Restano su fondo scuro, e solo
   errori e avvertimenti portano il filo lilla. Questi si vedono ancora
   inline sulle pagine di accesso, dove il messaggio deve stare sopra ai
   campi e non può scappare in fondo allo schermo. */
.flash { background: var(--surface-2); border-color: var(--line); color: var(--text); }
.flash-error, .flash-warning { border-color: rgba(var(--brand-light-rgb), .55); }

/* ── Impersonazione: banner admin «stai navigando come X» ──────────────
   Primo elemento del body in entrambe le base. NON sticky di proposito:
   la home a timeline ha già la sua testata sticky a top:0 (e nasconde la
   topbar), le due si sovrapporrebbero. Si esce anche col logout. */
/* 2026-08-28 (Roberta): via il giallo. Non è un avviso, è uno STATO
   dell'app — stai guardando come un altro — e il giallo da noi vuol dire
   «c'è una cosa da sapere» sulle pastiglie. Fondo neutro, il nome in
   grassetto, e «Esci» tenuto a destra sulla stessa riga: da 109 punti di
   altezza a 61, e la frase sta lo stesso su due righe. */
.vis-bar {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  flex-wrap: nowrap;
  padding: var(--s2) var(--s4);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  color: var(--body-text);
  font-size: var(--fs-sm);
}
/* ⚠️ la frase si prende quello che avanza e il bottone non si stringe:
   senza, «Esci» andava a capo sotto la frase */
.vis-bar > form, .vis-bar > .btn { flex: none; }
/* ⚠️ 2026-08-28: era un inline-flex, quindi l'icona, «Stai impersonando»,
   il nome e il resto della frase diventavano quattro BLOCCHI affiancati,
   ognuno che andava a capo per conto suo: sul telefono la frase si
   spezzava in colonne. È una frase: deve scorrere come tale, con
   l'icona dentro il testo. */
.vis-bar-txt { display: block; flex: 1; min-width: 0; }
.vis-bar-txt b { color: var(--text); font-weight: 700; }
.vis-bar-txt .icon { vertical-align: -3px; margin-right: var(--s2); color: var(--muted); }
.vis-bar .btn { color: var(--btn-sec-fg); }

/* ── Toast snackbar (mobile): i flash ri-emessi da toast.js sopra la
   bottom nav; su desktop la region serve solo ai toast generati da JS ── */
#toast-region {
  position: fixed;
  left: var(--s4);
  right: var(--s4);
  bottom: calc(var(--s4) + env(safe-area-inset-bottom));
  z-index: 110;               /* sopra la bottom nav (100) */
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  pointer-events: none;
}
/* ⚠️ con una sheet aperta toast.js sposta la region DENTRO il <dialog>
   (sennò il messaggio è velato dal backdrop e per giunta inerte): lì il
   suo z-index compete con i figli della sheet, che stanno più in alto.
   Resta `position: fixed` — e adesso funziona davvero, perché lo
   scivolamento d'apertura è passato al guscio interno. */
dialog > #toast-region { z-index: 1000; }
/* con la bottom nav (mobile autenticato) i toast salgono sopra di lei */
body:has(.bottom-nav) #toast-region {
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--s3));
}
@media (min-width: 640px) {
  #toast-region { left: auto; right: var(--s5); bottom: var(--s5); width: 360px; }
}
.toast {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--text);
  font-size: var(--fs-sm);
  box-shadow: 0 8px 30px rgba(0, 0, 0, .45);
  pointer-events: auto;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .22s ease, transform .22s ease;
}
.toast--on { opacity: 1; transform: translateY(0); }
/* ⚠️ Gli avvisi non hanno più colori di stato: niente verde per «fatto»
   né rosso per «errore» (deciso con Roberta il 2026-08-21). Il tipo lo
   dice l'ICONA a sinistra, e solo quelli che chiedono attenzione — gli
   errori e gli avvertimenti — portano il filo lilla. Il verde e il rosso
   su fondo nero gridavano più del messaggio, ed erano l'unico punto del
   sito con colori semaforici. */
.toast-msg { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.toast-ico { width: 18px; height: 18px; flex: none; color: var(--muted); }
.toast--success .toast-ico { color: var(--brand-light); }
.toast--warning, .toast--error { border-color: rgba(var(--brand-light-rgb), .55); }
.toast--warning .toast-ico, .toast--error .toast-ico { color: var(--brand-light); }
.toast-action {
  flex: 0 0 auto;
  font-weight: 700;
  color: var(--purple-hi);
  white-space: nowrap;
}
.toast-close {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border: 0;
  background: none;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

/* ── Tabelle ──────────────────────────────────────────────────────── */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 calc(-1 * var(--s5));
  padding: 0 var(--s5);
}
.data-table { width: 100%; border-collapse: collapse; }
.data-table th, .data-table td {
  padding: var(--s3);
  text-align: left;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm);
  vertical-align: middle;
}
.data-table th {
  font-size: var(--fs-meta);
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
  white-space: nowrap;
}
/* header con grafia esatta (es. "SxR"): niente uppercase automatico */
.data-table th.th-keepcase { text-transform: none; }
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr:hover { background: rgba(255,255,255,.025); }
.row-actions { display: flex; gap: var(--s2); align-items: center; }
.nowrap { white-space: nowrap; }

/* nuovi token della spec */
:root {
  --rail-off: #242229;
  --dim: #4E4A56;
}

/* ── Modale note (score) ──────────────────────────────────────────── */
/* padding 0 sul dialog + contenuto in .note-dialog-inner: così un click
   "sul dialog" è per forza sul backdrop e notes_modal.js può chiudere */
.note-dialog {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 0;
  max-width: min(420px, 90vw);
  margin: auto;
}
.note-dialog::backdrop { background: rgba(0, 0, 0, .6); }

/* Apertura/chiusura animate dei dialog (note + score sheet): slide-up
   leggero + dissolvenza, backdrop in fade. Progressive: senza
   @starting-style/allow-discrete l'apertura resta secca come prima.
   prefers-reduced-motion: coperto dal blocco globale in testa al file. */
/* ⚠️ Lo scivolamento sta sul GUSCIO INTERNO, non sul dialog. Un elemento
   che si sposta diventa il riferimento dei figli con position:fixed, e
   dentro la sheet ci finisce la region dei toast: con `translate` sul
   dialog l'avviso si ancorava ai bordi della SHEET invece che dello
   schermo, e cambiava posto da telefono a telefono (Roberta, 2026-08-21).
   Sul dialog resta la sola opacità, che non crea riferimenti. */
dialog.note-dialog, dialog.score-sheet {
  opacity: 0;
  transition: opacity .2s ease,
              overlay .25s ease allow-discrete, display .25s ease allow-discrete;
}
dialog.note-dialog[open], dialog.score-sheet[open] { opacity: 1; }
@starting-style {
  dialog.note-dialog[open], dialog.score-sheet[open] { opacity: 0; }
}
.note-dialog > *, .score-sheet > * { translate: 0 16px; transition: translate .25s ease; }
.note-dialog[open] > *, .score-sheet[open] > * { translate: 0 0; }
@starting-style {
  .note-dialog[open] > *, .score-sheet[open] > * { translate: 0 16px; }
}
dialog.note-dialog::backdrop, dialog.score-sheet::backdrop {
  opacity: 0;
  transition: opacity .25s ease,
              overlay .25s ease allow-discrete, display .25s ease allow-discrete;
}
dialog.note-dialog[open]::backdrop, dialog.score-sheet[open]::backdrop { opacity: 1; }
@starting-style {
  dialog.note-dialog[open]::backdrop, dialog.score-sheet[open]::backdrop { opacity: 0; }
}

/* ── Bottom sheet log score (home) ────────────────────────────────── */
.score-sheet {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 0;
  /* ⭐ 2026-08-28 (Roberta): 720 come la colonna delle pagine, non piu
     560. Con la colonna a 480 una finestrella da 560 era piu larga della
     pagina; ora sarebbe piu STRETTA di quello che c'e sotto, e il testo
     dentro andrebbe a capo prima di quello della card da cui l'hai
     aperta. Una misura sola per tutte le sheet, comprese quelle del coach
     (la scheda dell'utente in Utenti l'ha guardata a 720 e va bene). */
  width: min(720px, calc(100vw - 2 * var(--s4)));
  margin: auto;
  max-height: 85dvh;
  /* ⚠️ Lo scroll sta sul GUSCIO INTERNO, non qui (2026-08-29, segnalato
     da Francesco: aprendo «Nome e cognome» compariva per un istante una
     barra di scroll che poi spariva). Il contenuto interno entra
     traslato di 16px verso il BASSO, e con l'overflow su questo elemento
     quei 16px erano contenuto che deborda: il browser mostrava la barra
     per tutta la durata dell'animazione. Spostando lo scroll sull'inner
     — che è proprio l'elemento traslato — la sua traslazione non genera
     overflow dentro sé stesso. `clip` e non `hidden`: non crea un
     contenitore di scroll (stessa ragione del body, 2026-08-27). */
  overflow: clip;
}
/* 13/18 sopra e sotto sono i valori del riferimento (specifica-log.md §1,
   `.sheet{padding:13px 16px 18px}`): fuori dalla scala base-4 di proposito,
   la testata della sheet respira meno del piede */
.score-sheet-inner {
  padding: 13px var(--s4) 18px;
  /* il limite arriva dal guscio (85dvh, 88 su telefono): `inherit` lo
     segue da solo, comprese le ridefinizioni nella media query */
  max-height: inherit;
  overflow-y: auto;
}
/* ⚠️ 2026-08-27 (Roberta): aprendo la scheda si vedeva ogni tanto un filo
   viola tutto intorno alla finestrella. È il guscio: porta tabindex="-1"
   per togliere il fuoco alla X, e apriamo con un click che parte dal
   codice — così il browser tratta il fuoco come se fosse arrivato da
   tastiera e ci disegna attorno l'anello. Qui il guscio non è un
   comando: intorno deve esserci solo il suo riquadro grigio. */
/* vale per tutti i gusci: le quattro sheet e le due finestrelle-nota.
   I comandi DENTRO tengono il loro filo del fuoco, ci mancherebbe. */
.score-sheet:focus,
.score-sheet:focus-visible,
.score-sheet-inner:focus,
.score-sheet-inner:focus-visible,
.note-dialog:focus,
.note-dialog:focus-visible,
.note-dialog-inner:focus,
.note-dialog-inner:focus-visible { outline: none; }
.score-sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s3);
}
.score-sheet-title {
  font-family: var(--font);
  /* --fs-xl vale 18px sotto i 480px, cioè esattamente la misura dei
     riferimenti alla larghezza per cui sono disegnati; sopra sale a 20px,
     restando dentro la scala invece di inchiodare un 18px fisso */
  font-size: var(--fs-xl);
  /* 700 come nei riferimenti: nella sheet il titolo è il soggetto della
     schermata, non una voce di elenco */
  font-weight: 700;
  /* .02em fra le lettere e 6px d'aria sotto l'occhiello: entrambi nel
     riferimento (`.ttl{margin-top:6px}`), nessuno
     dei due c'era */
  margin-top: 6px;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}
.sheet-errors { display: flex; flex-direction: column; gap: var(--s2); margin-bottom: var(--s3); }
/* titolo di sezione dentro le sheet (es. "Video" nelle Coach notes) */
.sheet-section-title {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--purple-hi);
  margin: var(--s4) 0 var(--s2);
}

/* note del form score in accordion chiusi di default (coach 2026-08-11):
   con Scaled la pubblica si apre da sola (score_form.js). Round 2: non
   più <details> ma button + .clp, così l'apertura è animata */
/* ⚠️ Il guscio (fondo, raggio, spaziature) è quello del kit v2: .note-box.
   Qui c'è solo il comportamento accordion, che il kit aveva tolto e il
   coach ha voluto indietro (2026-08-14). */
.note-acc-head {
  display: flex;
  align-items: center;
  gap: var(--s2);
  width: 100%;
  background: none;
  border: 0;
  padding: 0;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
/* l'etichetta dentro il bottone non deve avere il margine che ha quando
   sta sopra un campo sempre aperto: da chiusa la scatola resta bassa */
.note-acc-head .nlab { margin-bottom: 0; }
.note-acc-head::after {
  content: '›';
  margin-left: auto;
  font-size: 18px;
  line-height: 1;
  color: var(--muted);
  transition: rotate var(--speed);
}
.note-acc.is-open .note-acc-head::after { rotate: 90deg; }
.note-acc-head:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
.note-acc-body { padding-top: 8px; }
/* ⭐ QUANDO l'hai fatto (0059): il valore sta nell'intestazione, così la
   data si legge senza aprire — la riga si apre solo per cambiarla.
   ⚠️ Il `margin-left: auto` della freccia da solo spartirebbe lo spazio
   in due (due margini auto se lo dividono in parti uguali): con un
   valore accanto, la freccia lo cede e resta appiccicata al testo. */
.nquando {
  margin-left: auto;
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--text);
}
.note-acc-head:has(.nquando)::after { margin-left: 0; }
.note-acc-body input[type=date] { width: 100%; }

/* il backdrop di showModal non blocca lo scroll della pagina su iOS */
body:has(dialog.score-sheet[open]) { overflow: hidden; }
/* su mobile è una vera bottom sheet: ancorata in basso, sale dal fondo */
@media (max-width: 639px) {
  .score-sheet {
    width: 100vw;
    max-width: 100vw;
    margin: auto 0 0;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    border-bottom: 0;
    max-height: 88dvh;
  }
  .score-sheet-inner {
    padding-bottom: calc(18px + env(safe-area-inset-bottom));
  }
  /* ⭐ 2026-08-28 (Roberta): lo scivolamento vero, con la sua durata.
     Prima il guscio saltava in posizione senza transizione e l'unico
     movimento erano i 16 punti del contenuto: si vedeva un fade con uno
     scatto dentro, non una sheet che sale. Curva morbida in uscita
     (parte svelta, si posa piano), 320ms come le sheet di sistema. */
  dialog.score-sheet {
    translate: 0 100%;
    transition: translate .32s cubic-bezier(.32, .72, 0, 1),
                opacity .18s ease,
                overlay .32s ease allow-discrete,
                display .32s ease allow-discrete;
  }
  dialog.score-sheet[open] { translate: 0 0; }
  @starting-style {
    dialog.score-sheet[open] { translate: 0 100%; }
  }
  /* ⭐ 2026-08-28 (Roberta): qui il contenuto NON fa anche la sua mossa da
     16 punti. Il guscio sta gia scivolando su da fondo schermo: i due
     movimenti insieme si leggono come un rimbalzo — «viene su e poi
     ritorna un po' giu». Se n'e accorta sulla conferma e poi anche su
     Coach notes. Da computer i 16 punti restano: li il guscio non scivola
     e quella e tutta l'animazione che c'e. */
  .score-sheet > *, .score-sheet[open] > * { translate: none; transition: none; }
}

.note-dialog-inner { padding: var(--s4); }
.note-dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s3);
}
.note-dialog-body {
  margin: 0;
  white-space: pre-line;
  color: var(--muted);
}

/* ── Utility ──────────────────────────────────────────────────────── */
/* Collapse animato (round 2, 2026-08-11): wrapper .clp + figlio .clp-inner.
   grid-template-rows 0fr→1fr è l'unico modo di animare height:auto senza
   misurare in JS. ⚠️ MAI [hidden] sul wrapper (il display:none !important
   qui sotto ucciderebbe la transizione) e MAI margini esterni sul
   contenuto: vanno DENTRO .clp-inner (overflow hidden li contiene).
   visibility con delay = i contenuti chiusi non sono focusabili da tab. */
.clp {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  visibility: hidden;
  transition: grid-template-rows .28s ease, opacity .2s ease,
              visibility 0s linear .28s;
}
.clp.is-open {
  grid-template-rows: 1fr;
  opacity: 1;
  visibility: visible;
  transition: grid-template-rows .28s ease, opacity .25s ease .05s,
              visibility 0s;
}
.clp > .clp-inner { overflow: hidden; min-height: 0; }
/* ⚠️ La tendina della ricerca movimento (lift_search.js) vive DENTRO il
   collapse del modificatore Scaled, e il clip qui sopra la tagliava: le
   voci in basso finivano sotto le righe Quando/Note della sheet, non
   cliccabili (2026-09-01). A tendina aperta il JS rilascia il clip con
   questa classe — l'animazione del collapse a quel punto è già finita —
   e lo rimette alla chiusura. */
.clp > .clp-inner.has-sugg { overflow: visible; }

[hidden] { display: none !important; }
.mt-2 { margin-top: var(--s2); }
.mt-3 { margin-top: var(--s3); }
.mb-0 { margin-bottom: 0; }

/* ── Mobile ───────────────────────────────────────────────────────── */
@media (max-width: 639px) {
  main { padding-top: var(--s4); }
  .card { padding: var(--s4); }
  .table-scroll { margin: 0 calc(-1 * var(--s4)); padding: 0 var(--s4); }
  .board { padding: var(--s2) var(--s4); }
  .board-row--me {
    margin: 0 calc(-1 * var(--s4));
    padding-left: calc(var(--s4) - 3px);
    padding-right: var(--s4);
  }

  /* atleti: via la nav in alto, dentro la bottom nav; il logotipo
     resta solo in mezzo all'header */
  body.public .topbar-nav { display: none; }
  body.public header.topbar > .container { justify-content: center; }
  body.public .bottom-nav { display: block; }
  body.public main { padding-bottom: calc(var(--nav-h) + env(safe-area-inset-bottom)); }
  /* il footer lascia il posto alla bottom nav — ma solo per chi è
     dentro: da login/registrazione è l'unica via all'informativa */
  body.public .footer-pub { display: none; }
  body.public.guest .footer-pub { display: block; }
  body.public.guest main { padding-bottom: var(--s5); }

  .board-score { font-size: var(--fs-lg); }
  .day-heading { top: 56px; }
}

.btn-icon--sm { width: 36px; height: 36px; }

/* ══ v2.1 — AVATAR ═════════════════════════════════════════════════── */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  flex: 0 0 auto;
  border-radius: 50%;
  overflow: hidden;
  background: var(--purple-dim);
  color: var(--purple-hi);
  text-decoration: none;
}
.avatar:hover { text-decoration: none; }
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar-initials {
  font-size: 13px;
  font-weight: 700;
  /* line-height 1: con l'interlinea ereditata (1.55) le maiuscole, che
     vivono sopra la baseline, finivano un filo alte.
     ⛔ Qui c'era un margin-right: -.02em che annullava lo spazio dopo
     l'ultima lettera del letter-spacing: via con le lettere spaziate
     (2026-09-08). */
  line-height: 1;
  /* ⚠️ E scendono di un decimo del corpo. `line-height: 1` centra la
     SCATOLA della riga, ma le maiuscole non riempiono la scatola: stanno
     sopra la linea di base e sotto restano vuote. L'inchiostro finiva
     0,10em sopra il centro del cerchio — misurato su tre misure diverse:
     0,8px sulle foto della classifica, 3,5px su quella grande del
     profilo (segnalato da Roberta il 2026-08-19, «su tutto il sito»).
     In em e non in px, così vale per tutte le misure di avatar.
     Con transform e non con margin: non tocca il layout, e le iniziali
     non hanno discendenti da tenere in conto.
     ⚠️ .05 e NON il valore che pareggia i due spazi, che sarebbe .12.
     Scelto da Roberta col cursore, e la differenza è il punto: dentro un
     cerchio le maiuscole vanno un filo SOPRA il centro geometrico, o
     l'occhio le vede sedute. Misurando i due spazi si arriva a .12 e le
     lettere sembrano basse — provato, e bocciato guardandolo.
     ⛔ Non «correggere» questo numero con una misura: non è un errore,
     è centratura ottica. Se serve rivederlo, si rifà il cursore. */
  transform: translateY(.05em);
}
.avatar--xl { width: 72px; height: 72px; }
.avatar--xl .avatar-initials { font-size: 24px; }

.board-name-link { color: var(--text); font-weight: 600; }
.board-name-link:hover { color: var(--purple-hi); text-decoration: none; }

.athlete-head {
  display: flex;
  align-items: center;
  gap: var(--s4);
  margin-bottom: var(--s4);
}
.athlete-head--sm { gap: var(--s3); margin-bottom: 0; }
.athlete-head-name { font-size: var(--display-sm); margin: 0; }
/* il p sotto il nome eredita il margine UA 1em 0 e, con l'avatar
   centrato, spingeva il nome in alto: reset scoped, MAI globale su p */
.athlete-head p { margin: var(--s1) 0 0; }
.athlete-head-pr { margin-left: auto; }
/* .score-row* e .score-combo* rimossi il 2026-08-17: vivevano solo per
   il profilo atleta, che ora è la stessa timeline dello Storico
   (athlete/_tl_node.html, own=False). */

/* ══ v1.1b — COLORE TRACK + CATALOGO MOVIMENTI ═════════════════════ */
/* accento per-track via --tc (tracks.color, admin/tracks) — discreto:
   il colore si mescola col grigio per non fare "arcobaleno" */
.badge--track {
  color: color-mix(in srgb, var(--tc, var(--muted)) 72%, var(--muted));
  border-color: color-mix(in srgb, var(--tc, currentColor) 32%, transparent);
  background: color-mix(in srgb, var(--tc, currentColor) 9%, transparent);
}

/* input color nativo, in tinta coi form */
input[type="color"].color-input {
  width: 44px;
  height: 32px;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  cursor: pointer;
}

/* ══ v1.3 — SHEET DI REGISTRAZIONE (kit grafico v2, 2026-08-12) ══════
   Scritta sui riferimenti "log score" e "log record" del kit v2.
   Ossatura UNICA per score e record:
   maniglia · occhiello categoria + titolo + chiusura · filetto ·
   [selettore] · etichetta · campi · riga di contesto · note · CTA.
   Cambia SOLO la riga dei campi (specifica-log.md §1).
   Mappa classi spec → produzione (prefissi sulle collisioni):
   .field→.sheet-field · .result/.tags/.tag/.actions→.log-* ·
   .note→.note-box; 1:1 .chip .mini .mbtn .flabel .fnote .two .cell
   .csub .hintline .mc .bigcheck .cta→.sheet-cta */

/* maniglia: primo elemento dell'ossatura (specifica-log.md §1). Solo sotto
   i 640px, dove la sheet sale davvero dal fondo e la lineetta racconta che
   si può trascinare; sopra è una finestra centrata e non vorrebbe dire niente */
.sheet-grab { display: none; }
@media (max-width: 639px) {
  .sheet-grab {
    display: block;
    width: 36px;
    height: 4px;
    border-radius: 2px;
    background: rgba(255, 255, 255, .16);
    margin: 0 auto 15px;
  }
}

/* testata della sheet: occhiello di categoria + titolo del lavoro */
.sheet-eyebrow {
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
}
.score-sheet-title { line-height: 1.15; }
.sheet-hr { height: 1px; background: rgba(255, 255, 255, .07); margin: 15px 0; }

/* chip: selezione = VIOLA in tutta l'app, il grigio chiaro è l'hover */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 0;
  border-radius: 999px;
  padding: 7px 14px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  color: var(--grigio-62);
  background: rgba(255, 255, 255, .05);
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease;
}
.chip:hover { background: rgba(255, 255, 255, .10); color: var(--grigio-91); }
.chip.on { background: var(--sel-tint); color: var(--sel-fg); }
.chip.on:hover { background: var(--sel-tint-hover); color: var(--accent-testo-hi); }
.chip:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
.chips { display: flex; gap: 7px; margin-top: 15px; }
/* i radio veri restano la verità del form: nascosti ma focusabili */
.chips input[type="radio"],
.chips input[type="checkbox"] {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
/* chip a CHECKBOX (track assegnati in /admin/utenti, 2026-08-17): lo
   stato acceso lo dà :checked via :has, senza JS — la classe .on resta
   ai chip pilotati da script (score form, filtri board) */
.chips--wrap { flex-wrap: wrap; margin-top: 0; }
.chip:has(input[type="checkbox"]:checked) {
  background: var(--sel-tint);
  color: var(--sel-fg);
}
.chips label.chip { cursor: pointer; }
.chips label.chip:focus-within { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }

/* Il riquadro a due della sheet: è il .tm-seg del timer (stessa cornice,
   stessa velatura viola sulla metà scelta) portato nel log dello score.
   Rx/Scaled erano due pastiglie tonde, sole in tutta l'app a esserlo.
   Alto 41px: sotto ai campi come peso, sopra alla barra Tempo/Cap che è
   la stessa cosa in piccolo (misure scelte da Roberta il 2026-08-21). */
.seg {
  display: flex;
  gap: 4px;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  margin-top: 15px;
}
.seg-b {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 9px;
  padding: 8px;
  background: none;
  color: var(--muted);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  /* la riga di testo va inchiodata: col 1.6 del body la label cresceva di
     6px e il riquadro tornava alto come i campi */
  line-height: 1.15;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}
.seg-b:hover { color: var(--grigio-80); }
.seg-b.on { background: var(--sel-tint); color: var(--sel-fg); }
/* Tempo/Cap: lo stesso riquadro in piccolo, appoggiato a destra
   dell'etichetta del campo. Non va a capo: dentro c'è anche il cap. */
.seg--mini {
  flex: none;
  margin-top: 0;
  gap: 3px;
  padding: 3px;
  border-radius: var(--r-sm);
}
.seg--mini .seg-b {
  padding: 5px 10px;
  border-radius: 6px;
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  text-transform: uppercase;
  white-space: nowrap;
}
/* i radio veri restano la verità del form: nascosti ma selezionabili.
   Il fuoco lo prende l'input, l'anello va portato sulla label. */
.seg input[type="radio"] {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
.seg-b:has(input:focus-visible) { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }

/* riga etichetta del campo (+ nota di servizio a destra) */
.frow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 16px 0 8px;
  gap: 10px;
}
.frow--tight { margin-top: 0; }
.flabel {
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  color: var(--grigio-51);
  text-transform: uppercase;
}
/* ⚠️ nessuno la usa al momento: la specifica §7 la riserva alle note che
   portano un DATO reale («1 round = 20 reps»), e quel dato l'app non ce
   l'ha ancora. Si tiene per quando ci sarà, non si riempie di spiegazioni. */
.fnote { font-size: var(--fs-eyebrow); color: var(--grigio-35); }

/* barra segmentata: Time/Cap, 1RM…5RM, distanze — stesso componente */
.mini {
  display: flex;
  gap: 3px;
  background: rgba(255, 255, 255, .05);
  padding: 3px;
  border-radius: 9px;
}
.mbtn {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  font-family: inherit;
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--grigio-51);
  background: none;
  padding: 7px 0;
  border-radius: 6px;
  cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: background-color .15s ease, color .15s ease;
}
.mbtn:hover { color: var(--grigio-80); }
.mbtn.on { background: var(--sel-tint); color: var(--sel-fg); }
/* i radio veri restano la verità del form ma non si vedono (nel
   riferimento gli .mbtn sono <button>: qui sono label+radio, sennò il
   pallino di sistema comparirebbe accanto all'etichetta). Il fuoco lo
   prende l'input, non la label: l'outline va portato su di lei. */
.mini input[type="radio"] {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
.mbtn:has(input:focus-visible) { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }

/* campo principale: box col filo viola, numero grande, unità a destra */
.sheet-field {
  display: flex;
  align-items: center;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(var(--accent-rgb), .40);
  border-radius: 12px;
  padding: 8px 13px;
}
.sheet-field input {
  /* la regola globale dei campi impone min-height 44px (il bersaglio
     per il dito): dentro i componenti del kit gonfia la scatola ben
     oltre il riferimento, quindi qui si azzera */
  min-height: 0;
  flex: 1;
  min-width: 0;
  background: none;
  border: 0;
  outline: none;
  color: var(--text);
  font-family: inherit;
  font-size: 22px;
  font-weight: 700;
  padding: 2px 0;
  /* 16px minimo su iOS non serve: 22px è già sopra la soglia di zoom */
}
.sheet-field input::-webkit-outer-spin-button,
.sheet-field input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.sheet-field input[type=number] { -moz-appearance: textfield; appearance: textfield; }
.sheet-unit { font-size: 12px; font-weight: 500; color: var(--muted); flex: none; }

/* due celle affiancate: MIN/SEC e ROUNDS/REPS. Il bordo trasparente
   evita che il layout salti quando arriva il focus. */
.two { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.cell {
  background: rgba(255, 255, 255, .05);
  border: 1px solid transparent;
  border-radius: 12px;
  padding: 8px 0;
  text-align: center;
}
.cell:focus-within { border-color: rgba(var(--accent-rgb), .40); }
.cell input {
  /* senza questo eredita il padding 10/16 della regola globale dei
     campi e la cella cresce di 20px in altezza */
  padding: 0;
  /* la regola globale dei campi impone min-height 44px (il bersaglio
     per il dito): dentro i componenti del kit gonfia la scatola ben
     oltre il riferimento, quindi qui si azzera */
  min-height: 0;
  width: 100%;
  background: none;
  border: 0;
  outline: none;
  color: var(--text);
  font-family: inherit;
  font-size: 20px;
  font-weight: 700;
  text-align: center;
}
.cell input::-webkit-outer-spin-button,
.cell input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.cell input[type=number] { -moz-appearance: textfield; appearance: textfield; }
.csub {
  font-size: 9px;
  font-weight: 600;
  color: var(--grigio-44);
  margin-top: 4px;
}

/* riga di contesto: il tuo 1RM, il tuo migliore, il cap del WOD */
.hintline {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-meta);
  color: var(--muted);
  margin-top: 9px;
}
.hintline b { color: var(--grigio-91); font-weight: 600; }
.hintline .icon { width: 14px; height: 14px; color: var(--grigio-44); flex: none; }

/* mini-card di una serie (pesi per serie): la descrizione sta DENTRO la
   serie, perché le serie possono essere diverse fra loro */
.mc {
  background: rgba(255, 255, 255, .04);
  border-radius: 12px;
  padding: 8px 13px;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.mc-mid { flex: 1; min-width: 0; }
.mc-top { display: flex; align-items: center; gap: 8px; }
.mc-n { font-size: var(--fs-eyebrow); font-weight: 700; color: var(--grigio-44); }
.mc-pct { font-size: var(--fs-meta); font-weight: 700; color: var(--brand-light); }
.mc-d { font-size: 12px; color: var(--body-text); line-height: 1.4; margin-top: 4px; }
/* ⭐ Minuti e secondi degli intervalli (2026-08-28): due caselle strette
   coi due punti in mezzo, dentro la stessa pastiglia `.mc-in` che prima
   conteneva il campo unico «m:ss». Le cifre sono tabulari e la larghezza
   è fissa in `ch`, così i due punti non ballano mentre si scrive. */
.mc-duo { display: inline-flex; align-items: baseline; gap: 2px; }
.mc-duo input {
  width: 2.4ch;
  padding: 0;
  min-height: 0;
  background: none;
  border: 0;
  outline: none;
  text-align: center;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  font-size: var(--fs-input);
  font-weight: 600;
}
/* ⭐ 2026-08-28 (Roberta): MIN e SEC vivono qui dentro, piccoli come le
   etichette del riquadro grande del For Time e centrati come le cifre che
   prenderanno il loro posto. Essendo il segnaposto, spariscono da soli
   appena si scrive: nessuna etichetta da spegnere a mano.
   ⚠️ La casella si allarga a 3.4ch — deve tenere sia «MIN» a 9 punti sia
   tre cifre a 16 — e la regola sta sotto .mc-in, che ha la stessa forza e
   viene dopo: senza il genitore vincerebbe lei coi suoi 40px. */
.mc-in .mc-duo input { width: 3.4ch; }
.mc-duo input::placeholder {
  color: var(--grigio-44);
  font-size: 9px;
  font-weight: 600;
}
.mc-duo input::-webkit-outer-spin-button,
.mc-duo input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.mc-duo input[type=number] { -moz-appearance: textfield; appearance: textfield; }
.mc-duo-sep { color: var(--muted); font-weight: 600; }

.mc-in {
  flex: none;
  background: rgba(255, 255, 255, .07);
  border-radius: 9px;
  padding: 6px 10px;
  min-width: 62px;
  display: flex;
  align-items: baseline;
  justify-content: center;
}
.mc-in input {
  /* la regola globale dei campi impone min-height 44px (il bersaglio
     per il dito): dentro i componenti del kit gonfia la scatola ben
     oltre il riferimento, quindi qui si azzera */
  min-height: 0;
  width: 40px;
  /* padding 0 obbligatorio: la regola globale degli input ne mette 32px
     orizzontali e dentro i 40px non resterebbe spazio per le cifre */
  padding: 0;
  background: none;
  border: 0;
  outline: none;
  color: var(--text);
  font-family: inherit;
  font-size: 17px;
  font-weight: 700;
  text-align: center;
}
.mc-in input::-webkit-outer-spin-button,
.mc-in input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.mc-in input[type=number] { -moz-appearance: textfield; appearance: textfield; }
.mc-u { font-size: var(--fs-eyebrow); color: var(--grigio-44); font-weight: 500; margin-left: 2px; }
/* più caselle sulla stessa riga: i pick di uno stesso movimento
   («10 reps» «7,5 kg» del Rear Delt Fly, 2026-09-02), strette fra loro */
.mc-ins { flex: none; display: flex; gap: 6px; }
/* i due tasti della riga serie al log dei sets_load: la × che la
   toglie (2026-08-25) e la freccia «copia in giù» (2026-09-04). Dal
   2026-09-04 sera sono glifi NUDI e viola, senza il quadrato del kit
   (Francesco: «questi quadratoni non mi piacciono»); la freccia sta a
   SINISTRA del peso, così l'ultima riga, che non ce l'ha, tiene la
   colonna dei kg allineata. L'area toccabile resta 44 via ::after,
   come .btn-icon--sm. Il margine negativo della × compensa in parte
   il padding della card verso le righe del riepilogo. */
.mc-tool {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--brand-light);
  cursor: pointer;
  transition: color var(--speed);
}
.mc-tool::after { content: ''; position: absolute; inset: -10px; }
.mc-tool:hover { color: var(--text); }
.mc-tool:active { transform: scale(.9); }
.mc-tool .icon { width: 14px; height: 14px; stroke-width: 2.2; }
.mc > [data-set-del] { margin-right: -6px; }
.mc > [data-set-copy] { margin-right: -4px; }
.mc-ro { flex: none; min-width: 62px; text-align: right; font-variant-numeric: tabular-nums; }
.mc-ro b { font-size: 17px; font-weight: 700; }
.mc-ro span { font-size: var(--fs-eyebrow); color: var(--grigio-44); font-weight: 500; margin-left: 2px; }

/* solo completamento */
/* «solo completamento»: la stessa cella dei minuti e dei secondi, con la
   spunta al posto del numero. ⛔ Qui c'era .bigcheck, un riquadro con la
   spunta a sinistra e il testo di fianco: era l'unico pezzo della sheet
   in un'altra lingua (Roberta, 2026-08-25). */
.cell--fatto { grid-column: 1 / -1;   /* da sola prende tutta la riga */
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 4px; cursor: pointer; }
.cell--fatto .icon { width: 26px; height: 26px; color: var(--brand-light); }
.cell--fatto .csub { margin-top: 0; }

/* nota: il textarea ha padding e margin del browser, azzerati perché il
   testo si allinei con l'etichetta sopra */
.note-box {
  background: rgba(255, 255, 255, .04);
  border-radius: 12px;
  padding: 12px 13px;
  margin-top: 15px;
}
.note-box textarea {
  width: 100%;
  display: block;
  background: none;
  border: 0;
  outline: none;
  resize: none;
  padding: 0;
  margin: 0;
  color: var(--body-text);
  font-family: inherit;
  /* il riferimento dice 12px, ma qui vince la regola del progetto:
     --fs-input non si tocca mai (16px = niente zoom iOS al focus) */
  font-size: var(--fs-input);
  line-height: 1.55;
}
/* Le due note in UN blocco: erano due riquadri con 15px d'aria in mezzo
   e sembravano staccate (Roberta, 2026-08-21). Il .note-box perde fondo e
   raggio suoi e diventa una riga di questo. */
.notes { margin-top: 15px; background: rgba(255, 255, 255, .04); border-radius: 12px; }
.notes .note-box { margin-top: 0; background: none; border-radius: 0; padding: 11px 13px; }
.notes .note-box + .note-box { border-top: 1px solid rgba(255, 255, 255, .06); }
/* il segnaposto è un SUGGERIMENTO, non contenuto: cala a --fs-sm, la
   misura che ha già quello dei commenti (Roberta, 2026-08-21: «unifichiamoli»).
   ⚠️ Il textarea resta a --fs-input e non si tocca: la regola dei 16px
   riguarda il testo DIGITATO, l'unico che iOS misura per decidere se
   ingrandire la pagina al focus. Il segnaposto sparisce appena si scrive. */
.note-box textarea::placeholder { color: var(--grigio-35); font-size: var(--fs-sm); }
.nlab {
  font-size: 9px;
  font-weight: 700;
  color: var(--grigio-44);
  margin-bottom: 5px;
  /* NOTA (FACOLTATIVA) come nel riferimento, e come tutte le altre
     etichette della sheet: la trasformazione sta qui e non nel testo
     perché le note sono DUE e i due template le scrivono in modi diversi */
  text-transform: uppercase;
}
.ntxt { font-size: 12px; color: var(--body-text); line-height: 1.55; white-space: pre-line; }
.ncap { display: flex; align-items: center; gap: 6px; font-size: var(--fs-eyebrow); color: var(--grigio-44); margin-top: 8px; }
.ncap .icon { width: 13px; height: 13px; flex: none; }

/* CTA principale: MAI viola pieno — fondo scuro, filo viola, testo lilla */
.sheet-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: var(--r-btn-lg);
  padding: 14px 0;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--brand-light);
  background: var(--sheet-cta-bg);
  border: 0;
  width: 100%;
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(var(--accent-rgb), .45);
  margin-top: 15px;   /* 15, non --s4: valore del riferimento */
  transition: background-color .15s ease, color .15s ease;
}
.sheet-cta:hover { background: var(--sheet-cta-bg-hover); color: var(--accent-testo); }
.sheet-cta:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
.sheet-cta .icon { width: 18px; height: 18px; }

/* stato "già registrato": riepilogo, tag, nota, azioni */
.log-result {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: rgba(var(--accent-rgb), .12);
  border-radius: 14px;
  padding: 14px 16px;
  margin-top: 16px;
}
.log-rlabel { font-size: var(--fs-eyebrow); font-weight: 600; color: var(--accent-etichetta); }
.log-rval { font-size: 30px; font-weight: 700; line-height: 1; }
.log-rval span { font-size: 13px; font-weight: 500; color: var(--grigio-62); margin-left: 3px; }
/* La posizione porta in classifica: è il dato che ne parla, quindi fa
   da collegamento e si porta dietro un chevron. Niente fondo e niente
   pastiglia — dentro il riquadro viola sarebbe una macchia — e ⚠️ MAI la
   sottolineatura, che qui il tema mette su ogni <a> (Roberta, 2026-08-21). */
.log-rside {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  text-align: right; color: inherit; -webkit-tap-highlight-color: transparent;
}
.log-rside, .log-rside:hover, .log-rside:active { text-decoration: none; }
.log-rgo { width: 15px; height: 15px; flex: none; color: var(--brand-light); }
/* posizione in classifica e delta: numeri che si aggiornano → tabulari */
.log-rpos { display: block; font-size: 18px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.log-rposl { display: block; font-size: var(--fs-eyebrow); color: var(--grigio-62); margin-top: 4px; }
/* il delta sul record precedente è BIANCO, mai verde/rosso: sui tempi
   migliorare significa scendere e il colore mentirebbe */
.log-rdelta { font-size: 15px; font-weight: 700; line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; }
.log-tags { display: flex; gap: 6px; margin-top: 12px; flex-wrap: wrap; }
.log-tag {
  font-size: 9px;
  font-weight: 700;
  padding: 4px 8px;
  border-radius: 6px;
  color: var(--grigio-66);
  background: rgba(255, 255, 255, .06);
}
.log-tag--pr {
  color: var(--accent-inchiostro);
  background: var(--brand-light);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.log-tag--pr .icon { width: 11px; height: 11px; }
/* la pastiglia col giorno di esecuzione (0059): compare solo quando il
   lavoro è stato fatto in un giorno diverso da quello programmato */
.log-tag:has(.icon) { display: inline-flex; align-items: center; gap: 4px; }
.log-tag .icon { width: 11px; height: 11px; }
.log-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 15px; }
.log-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  border: 0;
  border-radius: 13px;
  padding: 13px 0;
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}
.log-btn .icon { width: 17px; height: 17px; }
.log-btn--edit { background: rgba(var(--accent-rgb), .15); color: var(--brand-light); }
.log-btn--edit:hover { background: rgba(var(--accent-rgb), .24); color: var(--accent-testo); }
.log-btn--del { background: rgba(255, 255, 255, .06); color: var(--grigio-66); }
.log-btn--del:hover { background: rgba(255, 255, 255, .11); color: var(--grigio-91); }
.log-btn:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
.donebox {
  display: flex;
  align-items: center;
  gap: 13px;
  background: rgba(var(--accent-rgb), .12);
  border-radius: 14px;
  padding: 15px 16px;
  margin-top: 16px;
}
.donebox-b {
  width: 34px; height: 34px;
  border-radius: 11px;
  background: rgba(var(--accent-rgb), .30);
  color: var(--accent-testo);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.donebox-t { font-size: 15px; font-weight: 700; }
.field-date input { width: 100%; }

/* ── Coach notes: le sezioni (kit v2, dentro l'editor dal 2026-08-14) ─ */
.cn-text { font-size: 13px; color: var(--body-text); line-height: 1.7; }
/* la fascia video non si appoggia al testo che la precede: nel
   riferimento c'è aria, come tra una sezione e l'altra */

/* Descrizioni standard dei movimenti (0040): in coda alle istruzioni sui
   WOD a serie, pescate dal catalogo. Titoletto sulle misure delle
   etichette sezione ma col colore della CATEGORIA (--cat inline dal
   template); il testo è semplice, gli a-capo della textarea li rende
   pre-line — niente HTML, niente |safe. */
.cn-movements { margin-top: 16px; }
.cn-mv-name {
  font-size: var(--cn-head-fs);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--cat, var(--brand-light));
  margin: 18px 0 7px;
}
.cn-movements .cn-mv-name:first-child { margin-top: 0; }
.cn-mv-desc {
  font-size: 13px;
  color: var(--body-text);
  line-height: 1.7;
  white-space: pre-line;
  margin: 0;
}

/* Le tre sezioni sono righe del rich-text (<p class="ql-cn-*">): stesse
   misure dei vecchi .cn-block-head, ma valgono in LETTURA e dentro
   l'editor, così il coach vede subito quello che vedrà l'atleta.
   L'etichetta è testo vero nel documento (sopravvive a nh3, si cerca, la
   legge uno screen reader); dal CSS arriva solo l'icona. */
.rich-text p[class*="ql-cn-"],
.quill-holder.ql-snow .ql-editor p[class*="ql-cn-"] {
  font-size: var(--cn-head-fs);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--brand-light);
  margin: 18px 0 7px;
}
.rich-text > p[class*="ql-cn-"]:first-child,
.quill-holder.ql-snow .ql-editor > p[class*="ql-cn-"]:first-child { margin-top: 0; }
/* etichetta cancellata ma formato rimasto: niente icona orfana */
p[class*="ql-cn-"]:empty { display: none; }
/* mask + currentColor invece di background-image: il colore resta in un
   posto solo (quello del <p>) e l'icona segue hover e stato attivo senza
   una seconda copia del data-URI */
.rich-text p[class*="ql-cn-"]::before,
.quill-holder.ql-snow .ql-editor p[class*="ql-cn-"]::before {
  content: '';
  display: inline-block;
  width: 16px;
  height: 16px;
  vertical-align: -3px;
  margin-right: 7px;
  background: currentColor;
  -webkit-mask: var(--cn-ic) center / 16px no-repeat;
          mask: var(--cn-ic) center / 16px no-repeat;
}
/* gli stessi tre disegni di templates/_icons.html (target, focus,
   trending-down): se cambiano lì, vanno cambiati anche qui */
p.ql-cn-goal, .ql-cn[value="goal"] {
  --cn-ic: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16z'/><path d='M12 7a5 5 0 1 0 0 10 5 5 0 0 0 0-10zm0 8a3 3 0 1 1 0-6 3 3 0 0 1 0 6z'/><circle cx='12' cy='12' r='1.6'/></svg>");
}
p.ql-cn-movement, .ql-cn[value="movement"] {
  --cn-ic: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8zM5 15H3v4a2 2 0 0 0 2 2h4v-2H5v-4zM5 5h4V3H5a2 2 0 0 0-2 2v4h2V5zm14-2h-4v2h4v4h2V5a2 2 0 0 0-2-2zm0 16h-4v2h4a2 2 0 0 0 2-2v-4h-2v4z'/></svg>");
}
p.ql-cn-scaling, .ql-cn[value="scaling"] {
  --cn-ic: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M16 18l2.29-2.29-4.88-4.88-4 4L2 7.41 3.41 6l6 6 4-4 6.3 6.29L22 12v6z'/></svg>");
}
/* fascia video del kit: icona play piena e titolo, niente chevron.
   Il play NON ha la pastiglia viola piena: nel riferimento è la sola
   icona in lilla su fondo trasparente. Il disco pesava quanto il titolo
   e spostava l'occhio sul pulsante invece che sul nome del movimento;
   per lo stesso motivo è sparita la miniatura di YouTube, che dentro un
   cerchio da 38px non si capiva cosa fosse (tolta dal markup, non
   nascosta: da nascosta il browser la scaricava lo stesso). */
.video-row .video-row-play {
  width: 30px;
  height: 30px;
  background: none;
  border-radius: 0;
  overflow: visible;
}
.video-row .video-row-play .icon { width: 30px; height: 30px; color: var(--brand-light); }

.lb-exp > .clp-inner { padding: 0; }
/* ⚠️ l'imbottitura sta sul guscio INTERNO: sul .clp-inner non collassa
   mai (min-height:0 azzera il contenuto, i padding restano) e ogni riga
   chiusa lasciava 16px di striscia morta sotto di sé */
.lb-exp-in { padding: 12px 0 14px 24px; }
.cmt { display: flex; gap: 9px; margin-top: 12px; }
/* ⚠️ il PRIMO non prende il margine: si sommava ai 12px della tendina e
   i commenti partivano 24px sotto il bordo, mentre serie e fist bump
   partono a 12 — le tre sezioni sembravano disallineate fra loro
   (segnalato da Roberta il 2026-08-19) */
.lb-exp-in .cmt:first-child { margin-top: 0; }
/* e senza commenti la barra di scrittura eredita lo stesso salto.
   ⚠️ NON `:empty`: il contenitore contiene gli a capo lasciati dal
   template, quindi vuoto non lo è mai — serve guardare i commenti veri.
   ⚠️ Vale SOLO dentro la riga di classifica: nella sheet del WOD, senza
   commenti, c'è la tessera tratteggiata e la barra ci finiva incollata
   (segnalato da Roberta il 2026-08-20) */
.lb-exp-in .lb-comments:not(:has(.cmt)) + .lb-write { margin-top: 0; }
.cmt-av {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .10);
  color: var(--grigio-80);
  font-size: 8px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  overflow: hidden;
}
.cmt-av img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cmt-av .avatar-initials { font-size: 8px; font-weight: 600; }
.cmt-main { flex: 1; min-width: 0; }
.cmt-head { display: flex; align-items: center; gap: 6px; }
.cmt-name { font-size: var(--fs-meta); font-weight: 600; color: var(--grigio-80); }
.cmt-coach {
  font-size: 8px;
  font-weight: 700;
  color: var(--brand-light);
  background: rgba(var(--accent-rgb), .15);
  padding: 2px 5px;
  border-radius: 4px;
}
/* ⭐ 2026-08-28 (Roberta): con la funzione «rispondi» (0052) i commenti
   degli altri hanno freccia + cestino e i propri solo il cestino, e la
   colonna a destra ballava.
   ⚠️ Provate tre strade. L'orario NON può stare in mezzo o in fondo alla
   parte destra: quella scritta cambia larghezza da sola («2h», «17m», e
   dopo una settimana la data), quindi trascina sempre qualcosa — o si
   stacca il cestino, o il blocco non arriva al bordo come il bottone di
   invio della barra di scrittura.
   Scelta di Roberta: l'orario sta col NOME, a sinistra, e a destra
   restano solo le due icone. Così a destra non c'è più niente che cambia
   larghezza e la colonna sta ferma da sola, senza spazi riservati. */
.cmt-time {
  font-size: var(--fs-eyebrow);
  color: var(--grigio-35);
  margin-left: 2px;   /* + il gap 6 della riga = 8 dal nome */
  font-variant-numeric: tabular-nums;
}
/* le due icone sul bordo destro: l'auto va sulla PRIMA del gruppo, e nei
   propri commenti (senza freccia) la prima è il cestino */
.cmt-reply-btn { margin-left: auto; }
.cmt-head:not(:has(.cmt-reply-btn)) .cmt-del { margin-left: auto; }
/* Nota PRIVATA dello score in classifica (2026-08-25): la vede SOLO lo
   staff. Il riquadro tratteggiato segnala al coach che i soci questa
   riga non la vedono; l'etichetta col lucchetto fa il resto. Grafica
   prima stesura. */
.cmt--private {
  padding: 8px 10px;
  border: 1px dashed rgba(255, 255, 255, .16);
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .03);
}
.cmt-priv {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 8px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--muted);
  background: rgba(255, 255, 255, .08);
  padding: 2px 5px;
  border-radius: 4px;
}
.cmt-priv .icon { width: 9px; height: 9px; }
.cmt-text { font-size: 12px; color: var(--body-text); line-height: 1.55; margin-top: 3px; white-space: pre-line; overflow-wrap: anywhere; }
.cmt-del { display: flex; }
.cmt-del-btn {
  background: none;
  border: 0;
  /* ⭐ 2026-08-28 (Roberta): 8 e non 4, che da telefono freccia e cestino
     si toccavano. Sta a SINISTRA apposta: allarga il passo fra le due
     icone senza spostare il bordo destro, che resta in colonna col
     bottone di invio. */
  padding: 0 0 0 8px;
  color: var(--grigio-35);
  cursor: pointer;
  display: flex;
}
.cmt-del-btn:hover { color: var(--err); }
/* la form è solo la riga: il guscio è passato al campo, così l'invio può
   uscire dal box ed essere un bottone vero invece di una spunta appoggiata
   dentro al testo */
.lb-write {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-top: 13px;
}
.lb-write-field {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 9px;
  /* l'ancora della tendina dei tag @ (.mn-sugg, 0052) */
  position: relative;
  background: rgba(255, 255, 255, .05);
  /* niente filo: solo il fondo, come nel riferimento grafico */
  border: 0;
  /* la pastiglia è uscita dai campi (decisione di Roberta, 2026-08-14):
     resta su chip, filtri e badge, dove dice «si accende e si spegne».
     Questo è un campo di testo e prende il raggio dei campi */
  border-radius: var(--r-btn);
  /* ⚠️ niente margine interno sopra e sotto: i campi hanno già 44px minimi
     di loro (la misura del bersaglio da toccare), e altri 9+9 portavano la
     riga a 64px contro i 38 del bottone d'invio. Così la riga è alta 44
     esatti, quanto il bottone accanto */
  padding: 0 13px;
}
.lb-write-field .icon { width: 16px; height: 16px; color: var(--grigio-44); flex: none; }
.lb-write input {
  flex: 1;
  min-width: 0;
  background: none;
  border: 0;
  outline: none;
  color: var(--text);
  font-family: inherit;
  /* --fs-input non si tocca mai: 16px = niente zoom iOS al focus */
  font-size: var(--fs-input);
  padding: 0;
}
/* il segnaposto è un SUGGERIMENTO, non contenuto: a 16px pesava più dei
   commenti veri, che sono 12px. Scende a --fs-sm, a metà strada.
   ⚠️ Il campo resta a --fs-input e non si tocca: la regola dei 16px
   riguarda il testo DIGITATO, che è quello che iOS misura per decidere se
   ingrandire la pagina al focus. Il segnaposto sparisce appena si scrive.
   ⚠️ Il selettore è sul pseudo-elemento e non su "input" anche perché
   check_conventions.py cerca la parola "input" nel selettore e lo
   segnalerebbe come campo sotto i 16px: è un falso positivo, ma il
   controllo non sa distinguere il segnaposto dal testo scritto. */
.lb-write-field ::placeholder { color: var(--grigio-35); font-size: var(--fs-sm); }
/* bottone d'invio: tinta viola come le azioni in card, non una spunta
   grigia dentro al campo. Quadrato stondato alla misura del bersaglio,
   la stessa del campo accanto */
.lb-write-send {
  flex: none;
  width: var(--tap);
  height: var(--tap);
  border: 0;
  border-radius: var(--r-btn);
  background: var(--btn-tint);
  color: var(--brand-light);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color var(--speed);
}
.lb-write-send:hover { background: var(--btn-tint-hover); }
.lb-write-send:active { background: var(--btn-tint-active); }
.lb-write-send .icon { width: 17px; height: 17px; }

/* tendina dei suggerimenti @ (mentions.js): gemella di .rft-sugg ma
   ancorata SOPRA il campo — il form di scrittura è l'ultimo elemento
   della sheet e della tendina di classifica, verso il basso verrebbe
   tagliata dallo scroll container */
.mn-sugg {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  z-index: 30;
  min-width: min(240px, 100%);
  max-width: 100%;
  display: flex;
  flex-direction: column;
  max-height: 240px;
  overflow-y: auto;
  padding: var(--s1);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
  /* appesa al DOM a ogni apertura: l'ingresso morbido riparte da solo */
  animation: pop-in .15s ease;
}
.mn-sugg-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
/* la fotina riusa la veste degli avatar dei commenti (.cmt-av): qui
   serve solo il flex none, il cerchio arriva da quella regola */
.mn-sugg-av { flex: none; }
.mn-sugg-nome {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mn-sugg-item:hover, .mn-sugg-item.is-act { background: rgba(255, 255, 255, .08); }
/* il picker dell'atleta del Personal Trainer (athlete_picker.js, 0065):
   stessa tendina, ma sotto il campo — nel form coach e nella settimana
   sotto c'è spazio. */
.ath-field { position: relative; }
.ath-field .mn-sugg--sotto { top: calc(100% + 6px); bottom: auto; }

/* i due vuoti: stessa tessera tratteggiata del giorno senza programmazione */
.lb-empty {
  margin: 4px 2px 0;
  border: 1px dashed rgba(255, 255, 255, .13);
  border-radius: 14px;
  padding: 26px 18px;
  text-align: center;
}
.lb-empty-icon { width: 30px; height: 30px; color: var(--grigio-22); }
.lb-empty-title { font-size: 14px; font-weight: 600; color: var(--grigio-80); margin-top: 11px; }
/* 2026-08-28: l'invito non è una didascalia, è la spiegazione di cosa
   serve quella sezione — più chiaro e un filo più grande */
.lb-empty-sub { font-size: var(--fs-sm); color: var(--body-text); margin-top: 5px; line-height: 1.5; }
.lb-goto {
  background: none;
  border: 0;
  padding: 0;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--brand-light);
  cursor: pointer;
}
/* Interruttore: la casella vera resta sotto e continua a stare dentro il
   form, così senza JS la pagina funziona ancora col suo bottone Salva. */
.pf-sw { position: relative; flex: none; width: 44px; height: 26px; }
.pf-sw input {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.pf-sw span {
  display: block;
  width: 100%; height: 100%;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .10);
  transition: background var(--speed);
  pointer-events: none;
}
.pf-sw span::after {
  content: '';
  position: absolute;
  top: 3px; left: 3px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--muted);
  transition: transform var(--speed), background var(--speed);
}
.pf-sw input:checked ~ span { background: var(--purple); }
.pf-sw input:checked ~ span::after { transform: translateX(18px); background: #fff; }
.pf-sw input:focus-visible ~ span { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
.pf-sw input:disabled { cursor: default; }
.pf-sw input:disabled ~ span { opacity: .5; }
/* ── Niente anello viola sul touch (2026-08-25) ─────────────────────
   Su telefono l'anello del fuoco compare al TOCCO e resta acceso finché
   non tocchi altrove: sui chip e sul riquadro a due lo accendono le
   caselle nascoste dentro le label, e ci si ritrova la riga viola
   attorno al bottone appena premuto («la solita riga viola orribile»,
   Roberta). Lì dentro non serve a nessuno: non si naviga col tabulatore.
   ⚠️ Resta intero su mouse e tastiera, dove è l'unico modo per sapere
   dove sei se non usi il mouse. E NON tocca il bordo viola dei campi di
   testo mentre ci scrivi, che è un'altra cosa (border-color).
   ⚠️ `!important` voluto: gli anelli sono scritti in una trentina di
   regole sparse per il file, e qui vanno spenti tutti insieme. */
@media (pointer: coarse) {
  *:focus-visible,
  .chips label.chip:focus-within,
  .seg-b:has(input:focus-visible),
  .mbtn:has(input:focus-visible),
  .auth-ck input:focus-visible ~ .auth-ck-box,
  .pf-sw input:focus-visible ~ span {
    outline: none !important;
  }
}
/* ── La conferma (2026-08-28, con Roberta) ────────────────────────────
   Vive nel guscio delle sheet: qui sotto c'è solo quello che le è
   proprio, cioè la riga di spiegazione e i due bottoni in colonna —
   il primo è il verbo dell'azione, il secondo è sempre «Annulla». */
.conf-txt {
  margin: 8px 0 0;
  font-size: var(--fs-sm);
  color: var(--body-text);
  line-height: 1.5;
}
.conf-azioni { display: grid; gap: var(--s2); margin-top: var(--s4); }
.conf-azioni .btn { justify-content: center; }


/* ── Pagina di errore (2026-08-28, con Roberta) ───────────────────────
   404 / 403 / 500 vestite come uno STATO VUOTO: stesso riquadro
   tratteggiato di «Nessuna sessione registrata», così chi la incontra
   riconosce il modo di dire «qui non c'è niente» invece di trovarsi
   davanti una schermata mai vista. */
.err-box {
  border: 1px dashed rgba(255, 255, 255, .18);
  border-radius: var(--r-md);
  padding: 26px 18px;
  text-align: center;
  margin-bottom: var(--s5);
}
.err-cod {
  font-family: var(--font-display);
  font-size: 34px;
  color: var(--muted);
  margin-bottom: 10px;
}
/* maiuscolo nel carattere del testo, non in quello dei titoli: al codice
   sopra deve restare la scena (provate tutte e due con Roberta) */
.err-tit {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  text-transform: uppercase;
}
.err-txt {
  margin: 6px 0 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  line-height: 1.5;
}

/* ── La testata del coach sotto i 900: il menu (13.1 bis, 2026-09-11) ──
   Storia: il 27/08 sotto i 760 il logo prendeva la sua riga e le voci
   una riga che scorreva di lato; l'11/09, guardando la testata a 830,
   Francesco ha bocciato sia quella sia le voci a capo: «menu hamburger
   quando non ci stanno». Sotto i 900 le voci spariscono e accanto al
   logo compare il bottone del menu; le voci si aprono in colonna sotto
   la testata (topbar_menu.js apre e chiude, anche con Esc e col tocco
   fuori). Sopra i 900 il bottone non esiste. */
.topbar-menu-btn { display: none; }
.topbar-menu-btn .icon--chiudi { display: none; }
@media (max-width: 900px) {
  header.topbar { min-height: 0; }
  header.topbar > .container {
    flex-wrap: wrap;
    padding-top: var(--s2);
    padding-bottom: var(--s2);
    gap: var(--s2);
  }
  .brand { flex: 1 1 auto; }
  .topbar-menu-btn { display: inline-flex; margin-left: auto; }
  header.topbar.is-open .topbar-menu-btn .icon--menu { display: none; }
  header.topbar.is-open .topbar-menu-btn .icon--chiudi { display: block; }
  .topbar-nav { display: none; }
  /* aperto: un pannello in SOVRIMPRESSIONE appeso a destra sotto il
     bottone (Francesco, 11/09), non una riga che spinge giù la pagina.
     La testata è sticky, quindi è lei il riferimento dell'absolute. */
  header.topbar.is-open .topbar-nav {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    position: absolute;
    top: calc(100% + 4px);
    right: var(--s4);
    min-width: 220px;
    padding: 6px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
    z-index: 101;
  }
  .topbar-nav a, .topbar-nav .nav-btn { min-height: 44px; width: 100%; }
  .nav-form { display: flex; }
}

/* ── Il guscio iOS: il sito fuori dalla barra di stato (2026-09-16) ──
   Dentro l'app degli store la WebView di Capacitor copre TUTTO lo
   schermo, tacca e orologio compresi, e il sito (che come PWA su iPhone
   usa la barra di stato «black», cioè NON ci va sotto) finiva con
   l'orologio sopra il logo (Roberta, build 2 di TestFlight). Su Android
   lo stesso problema si è risolto nel guscio (MainActivity tiene la
   WebView dentro le barre e dentro la pagina env(...) vale zero); su
   iPhone si fa qui, perché il CSS l'app lo prende al volo senza una
   build: il server mette `app app-ios` sul body quando lo user agent è
   quello del guscio (services/app_shell.py), e la pagina si abbassa di
   env(safe-area-inset-top) — che vale qualcosa solo con viewport-fit=cover
   e dentro un contesto senza barre, quindi fuori dall'app resta zero.
   Il fondo dietro l'orologio è il nero del body. Il basso è già a posto
   ovunque (env(safe-area-inset-bottom) sulla nav, sui toast e sul dock).
   Gli elementi appiccicati o fissi IN ALTO devono scendere della stessa
   misura, sennò restano sotto l'orologio: sono elencati qui, uno per
   uno; un elemento nuovo con top fisso va aggiunto. */
body.app-ios { padding-top: env(safe-area-inset-top); }
body.app-ios header.topbar,
body.app-ios .home-head { top: env(safe-area-inset-top); }
body.app-ios .day-heading { top: calc(60px + env(safe-area-inset-top)); }
body.app-ios .foto-big-x { top: calc(14px + env(safe-area-inset-top)); }
/* ⭐ La FASCIA dell'orologio è coperta (2026-09-23, Francesco su iPhone,
   profilo e classifica). Il padding del body sposta la pagina solo
   finché non si scorre: poi il contenuto sale e passa sotto l'orologio,
   perché fra il bordo dello schermo e la topbar appiccicata non c'era
   niente di opaco, e nelle pagine senza topbar (la classifica) il
   titolo ci finiva sopra intero. Una striscia fissa del fondo della
   pagina copre quella fascia su ogni pagina, sopra topbar e nav (100),
   sotto i toast (110). Le sheet e i dialog stanno nel top layer e si
   arrangiano da sé (il timer a schermo intero ha il suo padding). */
body.app-ios::before {
  content: '';
  position: fixed;
  top: 0; left: 0; right: 0;
  height: env(safe-area-inset-top);
  background: var(--ink);
  z-index: 105;
  pointer-events: none;
}
