:root {
  /* ============================================================
     TOKEN — unico punto di definizione di colore, spaziatura, ombre,
     raggi e durate (sessione "interfaccia: aspetto e fluidità").

     Il colore porta già significato altrove nell'app (barre=layer,
     puntini=stato, pastiglie=canale): la cornice (tela, colonna atleti,
     barra superiore, pannelli, pulsanti secondari) resta perciò quasi
     incolore, grigi appena tinti di blu. UN SOLO colore d'accento
     (--accent), usato SOLO per l'azione primaria e per il fuoco da
     tastiera — scelto lontano da tutti i colori semantici sotto (nessun
     layer, canale, stato o pagamento in questa app è verde-acqua/indaco).
     --brand resta il colore personalizzabile dall'agenzia (tenants.colore,
     impostato via JS in app.js — invariato lato funzionale) ma il suo uso
     visivo in questa sessione si restringe all'identità di marca pura,
     mai ad azioni o stati. ============================================ */

  /* -- cornice: tela, superfici, testo -- */
  --bg: #eef1f6;
  --surface-2: #e6eaf1;
  --card: #ffffff;
  --text: #1b2130;
  --muted: #64748b;
  --border: #e2e6ee;
  --border-strong: #cfd6e2;
  --danger: #dc2626;

  /* -- unico accento: azione primaria + fuoco tastiera -- */
  --accent: #0f766e;
  --accent-hover: #0b5c56;
  --accent-contrast: #ffffff;
  --accent-soft: rgba(15, 118, 110, .09);
  --focus-ring: 0 0 0 3px rgba(15, 118, 110, .32);

  /* -- fondo evidenziazione voci di menu (hover + fuoco) --
     Sessione "email di benvenuto, hover dei menu, pannello agenda", blocco
     2b: terza volta che l'hover risultava invisibile — causa vera trovata
     leggendo i token, non indovinata: var(--bg) è #eef1f6, un grigio
     quasi bianco appena percettibile sopra --card (#ffffff), e su
     .layer-tab (menu principale, sotto) il cambio era da un pastello
     colorato per-layer (--layer-*-bg, altrettanto chiaro) a un altro
     pastello quasi identico in luminosità — un cambio di tinta, non di
     contrasto, invisibile a colpo d'occhio. Ora un velo di accento
     traslucido: cambia SEMPRE hue e luminosità in modo netto, sopra
     qualunque sfondo chiaro sottostante (bianco o pastello per-layer).
     Unico punto di definizione: cambiarlo qui aggiorna tutti i dropdown
     E il menu principale (che condivide questo stesso token, vedi
     .layer-tab più sotto — non la classe .menu-item, forma diversa, ma
     lo stesso "linguaggio" di evidenziazione). */
  --menu-hover-bg: rgba(15, 118, 110, .16);

  /* -- identità di marca dell'agenzia (tenants.colore), non un'azione -- */
  --brand: #2563eb;

  /* -- raggi -- */
  --radius-sm: 6px;
  --radius: 9px;
  --radius-lg: 12px;

  /* -- ombre: profondità a tre livelli, tela / superficie / sollevato -- */
  --shadow-xs: 0 1px 2px rgba(15, 23, 42, .05);
  --shadow-sm: 0 1px 3px rgba(15, 23, 42, .08), 0 1px 2px rgba(15, 23, 42, .04);
  --shadow-md: 0 6px 16px rgba(15, 23, 42, .10), 0 2px 4px rgba(15, 23, 42, .05);
  --shadow-lg: 0 16px 32px rgba(15, 23, 42, .14), 0 4px 10px rgba(15, 23, 42, .07);

  /* -- tipografia: quattro dimensioni in tutto -- */
  --fs-xs: 11px;
  --fs-sm: 13px;
  --fs-md: 15px;
  --fs-lg: 20px;

  /* -- animazione: 120-200ms, mai oltre 250ms; solo transform/opacity -- */
  --dur-fast: 120ms;
  --dur-base: 160ms;
  --dur-slow: 200ms;
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --ease-in: cubic-bezier(.7, 0, .84, 0);

  /* Sistema visivo — tre canali, tre significati (mai mescolati):
     colore barra = layer (o, per il social, il primo canale scelto),
     colore/forma punto = flag, testo = atleta. Unico punto di definizione,
     usato SIA dal calendario SIA dalle linguette in alto (era un bug: non
     corrispondevano). Un nuovo layer futuro aggiunge solo una coppia
     --layer-X / --layer-X-bg qui. */
  --layer-social: #2563eb;
  --layer-social-bg: #e8f0fe;
  --layer-race: #15803d;
  --layer-race-bg: #e7f6ec;
  /* Blocco 2 (sessione "riquadri delle categorie..., sfondi per layer
     nella vista a elenco"): sfondo tenue di riga nella vista a elenco,
     derivato dal colore SOLIDO del layer con opacità bassa su bianco —
     mai un colore scritto a mano nelle righe stesse (list-row-* sotto
     leggono solo queste variabili).
     Sessione "correzione sfondi vista a elenco": le regole CSS a
     riposo/hover erano già corrette (nessuna regola successiva le
     sovrascriveva), il valore all'8-9% era stato scambiato per "non
     applicato" — qui alzato a 15-16/27-28% per essere più visibile a
     riposo.
     Sessione "sui colori sfondo e hover..." (dopo aver visto il
     risultato dal vivo): quei valori più alti erano in realtà troppo
     marcati — tornati agli originali di Blocco 2 (8-9% a riposo, 15-16%
     in hover), che andavano già bene. La struttura resta quella
     corretta nella sessione precedente (colore SEMPRE presente a
     riposo, più intenso in hover, mai il contrario) — solo l'intensità
     torna quella di partenza. Contrasto verificato a mano (luminanza
     relativa) sul layer più critico (--layer-race, luminanza pura più
     bassa): 8% → ~13:1, 15% → ~11:1, sempre ben oltre la soglia 4.5:1
     richiesta. */
  --list-row-social-bg: color-mix(in srgb, var(--layer-social) 8%, white);
  --list-row-social-bg-hover: color-mix(in srgb, var(--layer-social) 15%, white);
  --list-row-race-bg: color-mix(in srgb, var(--layer-race) 8%, white);
  --list-row-race-bg-hover: color-mix(in srgb, var(--layer-race) 15%, white);
  --list-row-agenda-bg: color-mix(in srgb, var(--layer-agenda) 9%, white);
  --list-row-agenda-bg-hover: color-mix(in srgb, var(--layer-agenda) 16%, white);
  /* Blocco 2 ("agenda unificata..."): 'appointment' e 'deadline' si
     fondono in un unico layer 'agenda', colore ARANCIONE — una scadenza
     dentro questo layer NON usa questo colore (resta indicata dal
     triangolo per urgenza, --deadline-* sotto), solo le voci agenda
     normali disegnate come barra. */
  --layer-agenda: #ea580c;
  --layer-agenda-bg: #fef1e7;

  /* Scadenze (sessione "layer scadenze"): non un colore di layer fisso
     come sopra, ma un colore per URGENZA — un indicatore, non una barra,
     vedi calendar.js buildDeadlineMarker(). */
  --deadline-overdue: #dc2626;
  --deadline-soon: #f87171;
  --deadline-upcoming: #d97706;
  --deadline-far: #9ca3af;

  /* Blocco 6b: disponibilità dell'atleta — verde/ambra/rosso, sempre
     accompagnati dal testo nel title/tooltip, mai solo colore. */
  --availability-available: #16a34a;
  --availability-limited: #d97706;
  --availability-unavailable: #dc2626;

  /* Sessione "stati semplificati": scala di significato per i flag
     (tbc/confermato/annullato), condivisa da tutti i layer. "fatto" è
     stato eliminato nella sessione "rifiniture di interfaccia" (blocco 1)
     insieme al colore che gli era dedicato. */
  --st-tbc: #9ca3af;       /* da confermare */
  --st-confirmed: #2563eb; /* confermato, non ancora concluso */
  --st-cancelled: #dc2626; /* annullato */

  /* Blocco 3a ("social: icone, non colori"): i colori di marca dei canali
     social sono ELIMINATI di proposito, non solo inutilizzati — un canale
     si riconosce dalla sua icona (SVG monocromatico, calendar.js), mai
     più da un colore. */

  /* Stato economico (gare e appuntamenti): dimensione separata dai flag,
     palette propria per non sovrapporsi al significato dei 4 flag sopra. */
  --pay-pending: #d97706;
  --pay-requested: #2563eb;
  --pay-collected: #16a34a;

  /* Schede di scelta tipo registrazione: colori definiti qui una volta sola.
     Sfondo blu scuro fisso su tutti gli stati; bordo arancione = selezionato. */
  --reg-card-bg: #1b3f6b;
  --reg-card-border-active: #f97316;
}

* { box-sizing: border-box; }

/* Blocco 6 (sessione "correzioni interfaccia..."): su telefono
   l'interfaccia deve stare FERMA in orizzontale — l'unico elemento che può
   scorrere lateralmente è la griglia del calendario (.calendar-area,
   overflow:auto propria, vedi sotto), mai la pagina intera. overflow-x qui
   sul contenitore principale come rete di sicurezza: anche se qualcosa
   dentro sfora la larghezza per un bug futuro, la pagina non guadagna
   comunque uno scorrimento orizzontale proprio. */
html {
  overflow-x: hidden;
}
body {
  margin: 0;
  overflow-x: hidden;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums; /* date, orari, conteggi non "ballano" fra le celle */
  background: var(--bg);
  color: var(--text);
}

button, input, select, textarea { font: inherit; color: inherit; }

a { color: var(--accent); }

/* Fuoco da tastiera visibile e coerente ovunque (6): un solo stile, un solo
   colore (l'accento), mai l'outline di default del browser che varia da
   motore a motore. Il mouse non lo vede mai (:focus-visible), la tastiera
   sempre. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
:focus:not(:focus-visible) { outline: none; }

/* Animazioni: solo transform/opacity, 120-200ms, mai oltre 250ms — vedi i
   singoli componenti sotto. Chi chiede meno movimento lo ottiene davvero:
   tutto si riduce a scatti istantanei, le regole restano (si può sempre
   riattivare cambiando preferenza), non vengono rimosse. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- pagine auth ---------- */

.auth-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 16px;
}

@media (prefers-color-scheme: dark) {
  .auth-page {
    --bg: #14161a; --card: #1e2128; --text: #e8eaed; --border: #33373f; --muted: #9aa0aa;
  }
}

.auth-card {
  background: var(--card);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  padding: 32px;
  max-width: 380px;
  width: 100%;
  box-shadow: var(--shadow-sm);
  text-align: center;
}

.brand-name {
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--brand);
  margin: 0 0 8px;
}

.auth-card h2 { margin: 0 0 16px; font-size: var(--fs-lg); }
.auth-hint { color: var(--muted); font-size: var(--fs-md); margin-top: -8px; }

.auth-card form { display: flex; flex-direction: column; gap: 14px; text-align: left; }
.auth-card form .row { display: flex; gap: 10px; }
.auth-card form .row > * { flex: 1; min-width: 0; }
/* :not(.consent-label) esclude le etichette consenso che NON devono essere
   flex-column: .auth-card label ha specificità 0,1,1 e batte .consent-label
   (0,1,0), perciò il fix è qui — restringere il selettore, mai !important. */
.auth-card label:not(.consent-label) { display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-sm); color: var(--muted); }
.auth-card input {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: var(--fs-md);
  background: var(--card);
  color: var(--text);
  transition: border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.auth-card input:focus-visible { border-color: var(--accent); box-shadow: var(--focus-ring); outline: none; }
/* :not(.register-type-card) perché le schede agenzia/atleta sono <button>
   dentro .auth-card ma hanno sfondo e bordo propri — senza questa esclusione
   background:var(--accent) (specificità 0,1,1) batte background:var(--reg-card-bg)
   (0,1,0) e le schede restano verdi invece che blu scuro. */
.auth-card button:not(.register-type-card) {
  position: relative;
  margin-top: 4px;
  padding: 11px;
  border: none;
  border-radius: 8px;
  background: var(--accent);
  color: var(--accent-contrast);
  font-weight: 600;
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.auth-card button:not(.register-type-card):hover { opacity: .92; }
.auth-card button:not(.register-type-card):active { transform: scale(.98); }

.form-error { color: var(--danger); font-size: var(--fs-sm); margin: 0; }
.auth-alt { margin-top: 18px; font-size: var(--fs-md); text-align: center; color: var(--muted); }

.lang-switch { margin-top: 14px; display: flex; justify-content: center; gap: 6px; }
.lang-btn {
  padding: 4px 12px; border-radius: 999px; border: 1px solid var(--border);
  font-size: var(--fs-xs); font-weight: 600; text-decoration: none; color: var(--muted);
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.lang-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); }

.legal-links { margin-top: 12px; text-align: center; font-size: var(--fs-xs); color: var(--muted); }
.legal-links a { color: var(--muted); }
/* Blocco 8: consensi in form auth */
.consent-row { display: flex; align-items: flex-start; gap: 8px; font-size: var(--fs-sm); }
.consent-row input[type="checkbox"] { flex-shrink: 0; margin-top: 3px; accent-color: var(--accent); width: 16px; height: 16px; }
/* display:block annulla il display:flex ereditato da .auth-card label —
   senza questa riga ogni frammento di testo e ogni <a> diventano figli
   flex impilati in colonna, spezzando la frase su quattro righe separate.
   flex:1 min-width:0 fa sì che il testo occupi lo spazio residuo della
   riga (dopo la casella) senza fuoriuscire dal contenitore. */
.consent-label { display: block; flex: 1; min-width: 0; color: var(--text); font-size: var(--fs-sm); cursor: pointer; }
.consent-label a { color: var(--accent); text-decoration: underline; }
/* Blocco 8: stato consensi in profilo */
.consent-status-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: var(--fs-md); }
.consent-status-row:last-child { border-bottom: none; }
.consent-ok { color: var(--success, #16a34a); font-weight: 700; }
.consent-missing { color: var(--muted); }
.consent-links { margin-left: 6px; font-size: var(--fs-xs); color: var(--muted); }
.consent-links a { color: var(--accent); }

.partner-logo-top {
  display: block; height: 30px; width: auto; margin: 0 auto 16px;
  content: url('img/logo-webathletics-nero.png');
}
@media (prefers-color-scheme: dark) {
  .partner-logo-top { content: url('img/logo-webathletics-bianco.png'); }
}

/* ---------- caricamento iniziale dell'app (5a) ---------- */
/* Mostrato solo se bootstrap.get supera 300ms (ritardo deciso in app.js):
   un loader che lampeggia su un caricamento istantaneo è peggio di
   nessun loader. */
.app-loader {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg);
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur-slow) var(--ease-out), visibility 0s linear var(--dur-slow);
}
.app-loader.visible { opacity: 1; visibility: visible; transition: opacity var(--dur-slow) var(--ease-out); }
.app-loader-word {
  font-size: var(--fs-lg); font-weight: 600; color: var(--text); text-align: center;
  margin-bottom: 16px; letter-spacing: -.01em;
}
.app-loader-track { display: flex; gap: 5px; width: 168px; height: 6px; }
.app-loader-track span {
  flex: 1; border-radius: 3px; transform-origin: left; transform: scaleX(.15);
  animation: loader-bar 1.2s var(--ease-out) infinite;
}
.app-loader-track span:nth-child(1) { background: var(--layer-social); animation-delay: 0ms; }
.app-loader-track span:nth-child(2) { background: var(--layer-race); animation-delay: 140ms; }
.app-loader-track span:nth-child(3) { background: var(--layer-agenda); animation-delay: 280ms; }
@keyframes loader-bar {
  0%, 100% { transform: scaleX(.15); opacity: .55; }
  50% { transform: scaleX(1); opacity: 1; }
}

/* ---------- scheletri di caricamento (5b) ---------- */
.skeleton {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--border) 37%, var(--surface-2) 63%);
  background-size: 400% 100%;
  animation: skeleton-pulse 1.4s ease-in-out infinite;
  border-radius: var(--radius-sm);
}
@keyframes skeleton-pulse {
  0% { background-position: 100% 0; }
  100% { background-position: 0 0; }
}
.skeleton-bar { height: 16px; margin-bottom: 4px; }
.skeleton-row { height: 14px; margin: 8px 4px; }

/* ---------- shell app ---------- */

.app-shell { display: flex; flex-direction: column; height: 100vh; overflow-x: hidden; }

/* #body-host è il fratello di #calendar-header (vedi commento sotto) —
   deve essere lui stesso, non .app-body al suo interno, a ricevere
   flex:1 dal genitore .app-shell: senza display:flex qui, il flex:1 su
   .app-body poco sotto non avrebbe alcun contenitore flex da riempire e
   il calendario non occuperebbe l'altezza residua della pagina. */
#body-host { flex: 1; display: flex; min-height: 0; min-width: 0; }

/* Sessione "ristrutturazione dell'intestazione...": #calendar-header e
   #body-host (poco sotto, .app-body) sono FRATELLI dentro .app-shell —
   mai uno dentro l'altro (blocco 3). L'intestazione stessa non scorre mai
   in nessuna direzione: solo altezza propria, overflow-x:hidden come
   rete di sicurezza oltre alla struttura stessa. .header-desktop e
   .header-mobile non convivono mai nello stesso momento (sceglie
   isMobileHeaderWidth() in app.js, un solo albero costruito alla volta,
   mai le due strutture mescolate via CSS) — qui sotto vivono quindi le
   regole COMUNI a entrambe (le tre righe, i pezzi di contenuto riusati
   identici) più, più sotto, quelle specifiche di ciascuna. */
.calendar-header { flex-shrink: 0; overflow-x: hidden; background: var(--card); border-bottom: 1px solid var(--border); }
.header-row {
  display: flex; align-items: center; gap: 14px; padding: 8px 16px; flex-wrap: wrap;
}
.header-row + .header-row { border-top: 1px solid var(--border); }
.header-row-1 { justify-content: space-between; }
.header-row-1-left, .header-row-1-right { display: flex; align-items: center; gap: 14px; min-width: 0; }
.header-row-2 { flex-wrap: wrap; }
/* Blocco 3b (sessione "rifiniture ai filtri..."): -1px su padding e
   spazi della riga 2 mobile — SOLO qui, mai sul desktop, che non ha
   questo problema di larghezza (.header-desktop non tocca queste
   regole, il selettore è scoped a .header-mobile). Pochi pixel, ma sono
   quelli che mancavano perché la riga non vada mai a capo a 360px con
   tutti e tre i layer attivi (blocco 3d). */
.header-mobile .header-row-2 { padding: 7px 15px; gap: 13px; }
.header-mobile .header-row-2 .layer-tabs { gap: 5px; }
.header-mobile .header-row-2 .layer-tab { padding: 4px 11px; }
/* Blocco 4 (sessione "correzioni mobile..."): riga 3, la sola riga
   dell'intestazione che scorre DA SOLA invece di andare a capo — i
   controlli temporali (frecce, "Oggi", mese, anno, in vista settimana
   anche la tendina della settimana) non si riducono bene a icone come le
   pastiglie delle altre righe, e non devono mai occupare due righe. Qui
   .header-row-3 stessa (niente più flex-wrap ereditato da .header-row)
   resta l'ANTENATO fermo — position:relative, niente overflow proprio —
   su cui vivono le sfumature ai bordi; .calendar-nav-scroll, unico
   figlio (buildCalendarNavRow() in app.js), è il vero contenitore che
   scorre, con overscroll-behavior-x:contain per non "far scorrere" anche
   la pagina dietro una volta a fine corsa (telefono, swipe). */
.header-row-3 { position: relative; padding: 0; flex-wrap: nowrap; }
.calendar-nav-scroll {
  width: 100%; min-width: 0;
  overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
  padding: 8px 16px;
}
.header-row-3::before, .header-row-3::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 28px; pointer-events: none;
  opacity: 0; transition: opacity var(--dur-fast) var(--ease-out); z-index: 2;
}
.header-row-3::before { left: 0; background: linear-gradient(to right, var(--card), transparent); }
.header-row-3::after { right: 0; background: linear-gradient(to left, var(--card), transparent); }
.header-row-3.has-fade-left::before { opacity: 1; }
.header-row-3.has-fade-right::after { opacity: 1; }

.brand {
  font-weight: 600; color: var(--text); text-decoration: none; cursor: pointer;
  display: flex; align-items: center; gap: 8px; font-size: var(--fs-md); flex-shrink: 0;
}
.brand img { height: 24px; border-radius: var(--radius-sm); flex-shrink: 0; }
/* Distinto da .brand-name (login.php e le altre pagine pubbliche: il
   grande titolo "AthlonFlow", stile tutt'altro — stesso nome per puro
   caso, mai state la stessa cosa). */
.header-brand-name { font-size: var(--fs-md); font-weight: 600; }
.header-user-name { font-size: var(--fs-sm); color: var(--muted); flex-shrink: 0; }

.layer-tabs { display: flex; gap: 6px; flex-shrink: 0; flex-wrap: wrap; }
.layer-tab {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid var(--tab-color, var(--border));
  background: var(--tab-color-bg, #fff);
  color: var(--tab-color, var(--text));
  cursor: pointer;
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
  transition: background 150ms var(--ease-out), color 150ms var(--ease-out);
}
.layer-tab.active { background: var(--tab-color, var(--accent)); color: #fff; }
/* Blocco 3 (sessione "liste Brevo non assegnate, selettore del tipo nel
   pannello, icone dei layer"): "colore pieno quando accesa, attenuato
   quando spenta" — il testo/bordo della linguetta è già nel colore pieno
   del layer anche da spenta (color sopra), niente di nuovo lì; per
   l'icona l'attenuazione è un'opacità ridotta sulla STESSA tinta
   (--tab-color), non un grigio generico: resta riconoscibile di quale
   layer si tratta anche spenta. */
.layer-tab-icon { width: 14px; height: 14px; display: block; flex-shrink: 0; color: var(--tab-color); opacity: .55; }
.layer-tab.active .layer-tab-icon { opacity: 1; color: #fff; }
/* L'SVG di layerIconMarkup() porta 24x24 come ATTRIBUTI HTML (rete di
   sicurezza minima per iOS Safari, CLAUDE.md sez. 7) — senza questa
   regola resta 24x24 anche qui, trabocca dallo span 14x14 e si sovrappone
   all'etichetta accanto: stesso pattern già in uso per ogni altra icona
   condivisa fra più contesti (.channel-icon svg poco sopra in questo
   file), mai solo il contenitore. */
.layer-tab-icon svg { display: block; width: 14px; height: 14px; flex-shrink: 0; }
/* 2a: prima non c'era NESSUNA regola :hover per .layer-tab (verificato —
   solo .active era definito). Non .active, non .menu-item (è una pillola,
   non una riga di elenco): stesso --menu-hover-bg e stesso pattern hover/
   focus-visible delle voci di menu, per coerenza visiva "un solo fondo di
   evidenziazione in tutta l'app" pur restando una regola a sé. */
@media (hover: hover) {
  .layer-tab:not(.active):hover { background: var(--menu-hover-bg); }
}
.layer-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Blocco 1 (sessione "correzioni mobile..."): freccia dei sottofiltri,
   SOLO su mobile e SOLO su un layer attivo che ne ha (buildLayerTabsEl
   con expandable:true) — mai pressione lunga, invisibile e non scoperta
   da nessuno (testo di specifica). .layer-tab-wrap tiene insieme corpo
   e freccia come una sola pastiglia visiva, due bersagli di tocco reali:
   toccare il corpo accende/spegne il layer, toccare la freccia espande. */
.layer-tab-wrap { display: inline-flex; align-items: stretch; }
.layer-tab-split { border-top-right-radius: 0; border-bottom-right-radius: 0; border-right: none; position: relative; }
.layer-tab-arrow {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 30px; padding: 0 8px;
  border: 1px solid var(--tab-color, var(--border));
  border-top-right-radius: 999px; border-bottom-right-radius: 999px;
  background: var(--tab-color-bg, #fff);
  color: var(--tab-color, var(--text));
  cursor: pointer;
}
.layer-tab-arrow::after {
  content: '';
  width: 6px; height: 6px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--dur-fast) var(--ease-out);
}
.layer-tab-arrow.open::after { transform: rotate(225deg); }
/* Contatore "sottofiltri ristretti" (blocco 1: "così non si dimenticano
   accesi") — esiste solo quando l'utente ha DAVVERO tolto almeno
   un'opzione, mai quando tutte sono selezionate (equivale a "nessun
   filtro", updateMobileLayerBadge() in app.js). Sempre su un tab attivo
   (sfondo colorato pieno): bolla chiara per restare leggibile lì sopra. */
.layer-tab-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 15px; height: 15px; margin-left: 5px; padding: 0 3px;
  border-radius: 999px; background: rgba(255, 255, 255, .92); color: var(--tab-color, var(--text));
  font-size: 10px; font-weight: 700; vertical-align: middle;
}

.view-switch { display: flex; gap: 4px; flex-shrink: 0; }
.view-switch button {
  padding: 5px 12px;
  border: 1px solid var(--border);
  background: #fff;
  cursor: pointer;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.view-switch button.active { background: var(--text); color: #fff; border-color: var(--text); }

/* Blocco 6 ("correzione service worker..."): cerchietto con le iniziali.
   Blocco 1b (sessione "ristrutturazione dell'intestazione..."): il
   pannello non è più "position:absolute dentro .user-menu" — vive nel
   body SOLO mentre è aperto, position:fixed con le coordinate calcolate
   in JS (positionPanel() in buildUserMenu()), quindi qui sotto niente
   più "top/right" relativi al genitore: erano loro, insieme a un
   overflow-x:hidden su un antenato, a farlo ritagliare silenziosamente. */
.user-menu { position: relative; flex-shrink: 0; }
.user-menu-avatar {
  position: relative; width: 32px; height: 32px; border-radius: 50%; border: none;
  background: var(--accent); color: var(--accent-contrast); font-size: var(--fs-xs); font-weight: 700;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.user-menu-badge {
  position: absolute; top: -3px; right: -3px; min-width: 16px; height: 16px; padding: 0 3px;
  border-radius: 999px; background: var(--danger); color: #fff; font-size: 10px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; border: 2px solid var(--card);
}
.user-menu-panel {
  position: fixed; min-width: 200px; background: var(--card);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-lg);
  padding: 6px; display: none; flex-direction: column; gap: 2px; z-index: 200;
}
.user-menu-panel.open { display: flex; }
/* Blocco 1 (sessione "Brevo che non sincronizza..."): display:block
   mancante — stesso difetto strutturale già trovato altrove nel file
   (regola ora in CLAUDE.md sez. 7). */
.user-menu-panel svg { display: block; flex-shrink: 0; width: 15px; height: 15px; color: var(--muted); }

/* ── Voce di menu condivisa: UNA classe, .menu-item, usata da ogni elenco
   a tendina dell'app (menu utente in alto, menu "i" della dashboard, menu
   rapido del puntino disponibilità, elenco scadenze multiple dello stesso
   giorno). Il menu principale in alto (.layer-tab, sopra) è una barra di
   pillole sempre visibili, non un elenco a tendina: stessa "lingua" di
   hover/fuoco (stesso --menu-hover-bg, stesso pattern hover/focus-visible)
   ma la sua regola resta separata perché la forma è diversa (pillola, non
   riga a tutta larghezza) — vedi .layer-tab:hover più sopra.
   @media (hover:hover) evita lo stato "incollato" al tocco su telefono;
   :active dà riscontro visibile sul tocco. :focus-visible usa un outline
   coerente col tema (mai box-shadow su elementi già con border-radius). */
.menu-item {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: var(--radius-sm);
  font-size: var(--fs-sm); color: var(--text); text-decoration: none; background: none; border: none;
  cursor: pointer; text-align: left; width: 100%; white-space: nowrap;
  transition: background 150ms var(--ease-out);
}
@media (hover: hover) {
  .menu-item:hover { background: var(--menu-hover-bg); }
}
@media (hover: none) {
  .menu-item:active { background: var(--menu-hover-bg); }
}
.menu-item:focus-visible {
  background: var(--menu-hover-bg);
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.menu-item.active { background: var(--menu-hover-bg); font-weight: 600; }
/* Sessione "catena dei pallini rossi": secondo anello, sulla voce
   "Vai alla dashboard" — stesso linguaggio visivo di .user-menu-badge,
   qui inline invece che in overlay (la voce di menu non è un cerchio). */
.user-menu-item-badge {
  margin-left: auto; min-width: 18px; height: 18px; padding: 0 5px; flex-shrink: 0;
  border-radius: 999px; background: var(--danger); color: #fff; font-size: 11px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}

/* Blocco "vista multi-agenzia": selettore agenzia per manager/admin con
   più di una membership. */
.tenant-switcher {
  padding: 4px 8px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: var(--fs-sm); background: #fff; cursor: pointer; flex-shrink: 0;
}

/* min-width:0 su tutta la catena flex fra .app-shell e .calendar-area:
   senza questo, la larghezza intrinseca minima della griglia (blocco 6b
   più sotto, minmax(100px,...) su 7 colonne) si propaga verso l'alto
   attraverso ogni antenato flex e forza .app-body — quindi la pagina
   intera, intestazione compresa — più largo dello schermo, anche se
   .calendar-area ha già il proprio overflow-x:auto (blocco 3, sessione
   "ristrutturazione dell'intestazione..."). */
.app-body { flex: 1; display: flex; min-height: 0; min-width: 0; }

.sidebar {
  width: 216px;
  flex-shrink: 0;
  background: var(--card);
  border-right: 1px solid var(--border);
  padding: 14px 12px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
.sidebar::-webkit-scrollbar { width: 6px; }
.sidebar::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; }
.sidebar::-webkit-scrollbar-track { background: transparent; }

.sidebar h3 { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .02em; color: var(--muted); margin: 0; }
.sidebar-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.manage-athletes-link {
  display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-xs); color: var(--muted);
  text-decoration: none; white-space: nowrap; cursor: pointer;
}
.manage-athletes-link:hover { color: var(--accent); }
.athlete-row {
  display: flex; align-items: center; gap: 8px; padding: 5px 4px; border-radius: var(--radius-sm); cursor: pointer;
  font-size: var(--fs-md); transition: background var(--dur-fast) var(--ease-out);
}
.athlete-row:hover { background: var(--bg); }

/* Blocco 7 ("correzione service worker..."): interruttore a levetta
   compatto per la colonna atleti — stessi colori/stati del toggle
   standard (calendar.js buildToggle / .toggle in questo file), ma un
   track più piccolo e SENZA il gap riservato al testo: qui il nome è già
   una colonna a sé della riga, la levetta non deve allargarla né rubarle
   spazio. */
.athlete-toggle { display: inline-flex; align-items: center; flex-shrink: 0; cursor: pointer; }
.athlete-toggle-input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: -1px; }
.athlete-toggle-track {
  position: relative; flex-shrink: 0; width: 28px; height: 16px; border-radius: 8px;
  background: var(--border-strong); transition: background-color 150ms var(--ease-out);
}
.athlete-toggle-thumb {
  position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 2px rgba(15, 23, 42, .3); transition: transform 150ms var(--ease-out);
}
.athlete-toggle-input:checked + .athlete-toggle-track { background: var(--accent); }
.athlete-toggle-input:checked + .athlete-toggle-track .athlete-toggle-thumb { transform: translateX(12px); }
/* Terzo stato di "Tutti gli atleti" (alcuni selezionati, non tutti): pallino
   a metà corsa, stesso colore acceso ma più tenue — mai indistinguibile
   dai due stati pieni. */
.athlete-toggle-input:indeterminate + .athlete-toggle-track { background: var(--accent); opacity: .5; }
.athlete-toggle-input:indeterminate + .athlete-toggle-track .athlete-toggle-thumb { transform: translateX(6px); }
.athlete-toggle-input:focus-visible + .athlete-toggle-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.athlete-row-name {
  min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: inherit; text-decoration: none;
}
a.athlete-row-name:hover { color: var(--accent); text-decoration: underline; }
/* Blocco "vista multi-agenzia": intestazione di gruppo quando gli atleti
   vengono da agenzie diverse (2b), ed etichetta agenzia accanto al nome
   (2a) — flex-shrink:0 perché il nome sopra si tronca per primo, mai
   l'etichetta che dice DI CHI è quell'atleta. */
.athlete-group-header {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .02em; color: var(--muted);
  margin: 12px 0 4px; padding: 0 4px;
}
.athlete-group-header:first-child { margin-top: 4px; }
.athlete-row-tenant {
  flex-shrink: 0; font-size: var(--fs-xs); color: var(--muted); background: var(--bg);
  border-radius: 999px; padding: 1px 7px;
}
/* Blocco 6: ruolo del professionista/club su questo atleta */
.athlete-row-access-role {
  flex-shrink: 0; font-size: var(--fs-xs); color: var(--accent); opacity: .8;
  white-space: nowrap;
}
/* Identificativo visivo dell'atleta: iniziali su sfondo neutro, non un
   colore (1a — con cento atleti un colore non distingue nulla). */
.athlete-initials {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 22px; height: 22px; border-radius: 50%; background: var(--bg); border: 1px solid var(--border);
  font-size: var(--fs-xs); font-weight: 700; color: var(--muted); letter-spacing: -.02em;
}
/* Blocco 4b: scheda agenzia, icona valigetta invece delle iniziali. */
.athlete-initials-agency { background: var(--accent); border-color: var(--accent); color: #fff; }
.athlete-initials-agency svg { width: 13px; height: 13px; display: block; flex-shrink: 0; }
/* Atleta con foto: immagine circolare, stessa dimensione delle iniziali. */
.athlete-initials-photo { object-fit: cover; padding: 0; }
/* Sessione "azioni richieste, inviti in sospeso, contatori, novità e
   visto", blocco 3: UN solo componente per ogni pallino con numero
   dell'app — titoli di sezione (rosso, --danger) e sottovoci (arancione
   scuro, stesso #9a3412 già usato come testo di avviso altrove in
   questo foglio) — usato qui per la pillola "Azioni richieste" (blocco 1)
   e per i conteggi della scheda dashboard poco più sotto. Contrasto del
   testo bianco verificato (calcolo WCAG): 4.83:1 su --danger (#dc2626),
   7.31:1 su #9a3412 — entrambi sopra la soglia 4.5:1 per testo normale. */
.count-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px;
  font-size: var(--fs-xs); font-weight: 700; color: #fff; line-height: 1;
  flex-shrink: 0;
}
.count-badge-section { background: var(--danger); }
.count-badge-sub { background: #9a3412; }

/* Avviso testuale generico (es. "troppi atleti selezionati", nav.js) —
   NON la pillola azioni richieste (.action-pill, sotto): stile condiviso
   ma scopo diverso, rimasto distinto apposta. */
.pending-badge {
  margin-top: 14px;
  padding: 7px 10px;
  background: #fff7ed;
  border: 1px solid #fdba74;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  color: #9a3412;
}

/* Blocco 1: pillola "Azioni richieste" al posto del vecchio avviso
   testuale — pallino .count-badge-section sull'angolo, stesso conteggio
   condiviso di dashboardActionCard/menu utente (mai un numero proprio). */
.action-pill {
  position: relative;
  margin-top: 14px;
  padding: 7px 16px 7px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: #fff;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  transition: border-color 150ms var(--ease-out), background 150ms var(--ease-out);
}
@media (hover: hover) {
  .action-pill:hover { border-color: var(--danger); background: #fef2f2; }
}
.action-pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.action-pill-corner {
  position: absolute; top: -8px; right: -8px;
  border: 2px solid var(--card);
}

/* Blocco 1c: evidenziazione breve dopo lo scorrimento automatico — stesso
   principio di .settings-section.section-highlight (impostazioni.php),
   qui generico così lo riusa anche la sezione Novità (blocco 4). */
.flash-highlight {
  transition: box-shadow 400ms var(--ease-out);
  box-shadow: var(--shadow-xs), 0 0 0 3px var(--accent-soft);
}

/* Blocco 7c: stesso trattamento informativo di .pending-badge, ma un blu
   neutro — non è un "problema" da risolvere, solo un chiarimento. */
.dual-space-notice {
  margin: 8px 0 0; padding: 7px 10px;
  background: #eff6ff; border: 1px solid #bfdbfe; border-radius: var(--radius-sm);
  color: #1e40af;
}

.calendar-main { flex: 1; display: flex; flex-direction: column; min-height: 0; min-width: 0; }
/* Blocco 5: CONTENITORE 3 — la griglia scorre qui, da sola, senza
   spostare le due righe sopra (che vivono in tutt'altri contenitori
   adesso, mai più annidati dentro questo). overscroll-behavior-x:contain
   impedisce che arrivare a un bordo dello scroll orizzontale "trabocchi"
   nello scroll della pagina dietro (irrilevante su desktop, reale su
   telefono con lo swipe). */
/* Blocco 3 (sessione "correzioni mobile..."): padding inferiore extra —
   56px di altezza del pulsante "+" (.fab) + 28px di distanza dal fondo +
   20px di margine, così l'ultima riga della griglia (mese, settimana o
   la tabella dell'elenco: .calendar-area è l'UNICO contenitore che
   scorre, tutte e tre le viste) resta leggibile a fine scorrimento anche
   col pulsante sopra di essa. Se .fab cambia dimensione o posizione,
   questo valore va aggiornato insieme. */
.calendar-area { flex: 1; overflow-x: auto; overflow-y: auto; overscroll-behavior-x: contain; padding: 14px 14px 104px; position: relative; }

/* Blocco 5: .calendar-nav non è più una barra a sé (bordo/sfondo/padding
   propri) — vive dentro #calendar-nav-slot, a sua volta dentro
   .filters-row (CONTENITORE 2), che già fornisce bordo/sfondo/padding una
   volta sola per l'intera riga. flex-wrap:nowrap: qui deve restare in
   riga, è la riga stessa che scorre, non i suoi contenuti che vanno a capo. */
.calendar-nav {
  display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; flex-shrink: 0;
}
.calendar-nav button, .calendar-nav select {
  padding: 5px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: #fff;
  cursor: pointer; font-size: var(--fs-sm); white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.calendar-nav button:hover { border-color: var(--border-strong); background: var(--bg); }

/* Blocco 3a: vista elenco — intervallo esplicito invece della
   navigazione mese/settimana, tabella ordinabile con scroll orizzontale
   proprio (mai la pagina intera, vedi CLAUDE.md). */
.list-nav-field { display: flex; align-items: center; gap: 6px; font-size: var(--fs-sm); color: var(--muted); }
.list-nav-field input { padding: 4px 8px; border: 1px solid var(--border); border-radius: var(--radius-sm); }
/* Blocco 5 ("filtri, campi base..."): niente più un overflow-x proprio
   qui — .calendar-area (CONTENITORE 3) è ora l'UNICO contenitore che
   scorre in orizzontale per tutte e tre le viste, mai due scroll
   annidati per la stessa griglia. */
.list-view-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.list-view-table th, .list-view-table td { text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--border); white-space: nowrap; }
.list-view-table th { color: var(--muted); font-weight: 600; cursor: pointer; user-select: none; }
.list-view-table th:hover { color: var(--text); }
.list-view-table tbody tr:not(.list-row-busy) { cursor: pointer; }
.list-view-table tbody tr:not(.list-row-busy):hover { background: var(--bg); }
.list-row-busy { color: var(--muted); font-style: italic; }

/* Blocco 2 (sessione "riquadri delle categorie..., sfondi per layer
   nella vista a elenco"): sfondo di riga secondo il layer dell'item
   (item.type — calendar.js, buildListRows). Sul <tr>, non sui <td>:
   con border-collapse copre l'intera riga bordo a bordo, senza spazi
   bianchi fra le celle.
   Blocco 1 (sessione "correzione sfondi vista a elenco"), punto 1c:
   selettori completamente qualificati (non più la classe nuda) così
   la specificità di chi vince A RIPOSO e chi vince IN HOVER è ovvia
   dal selettore stesso, non un effetto collaterale dell'ordine nel
   foglio:
   - A RIPOSO vince ".list-view-table tbody tr.list-row-<layer>"
     (2 classi + 2 elementi = specificità 0,2,2): l'UNICA regola che
     tocca il background di quel <tr> in assenza di :hover — verificato
     leggendo tutto il file, nessun'altra regola successiva o più
     specifica lo riporta al bianco.
   - IN HOVER vince ".list-view-table tbody tr.list-row-<layer>:not
     (.list-row-busy):hover" (4 classi + 2 elementi = specificità
     0,4,2): batte sia la regola a riposo sopra SIA la vecchia regola
     generica ":not(.list-row-busy):hover { background: var(--bg) }"
     due righe più sopra (quella resta 0,3,2, un gradino sotto) — non
     più per un caso di ordine nel foglio, ma perché ha oggettivamente
     più classi nel selettore. */
.list-view-table tbody tr.list-row-social { background: var(--list-row-social-bg); }
.list-view-table tbody tr.list-row-race { background: var(--list-row-race-bg); }
.list-view-table tbody tr.list-row-agenda { background: var(--list-row-agenda-bg); }
.list-view-table tbody tr.list-row-social:not(.list-row-busy):hover { background: var(--list-row-social-bg-hover); }
.list-view-table tbody tr.list-row-race:not(.list-row-busy):hover { background: var(--list-row-race-bg-hover); }
.list-view-table tbody tr.list-row-agenda:not(.list-row-busy):hover { background: var(--list-row-agenda-bg-hover); }
/* Annullato: sfondo di layer invariato, solo testo barrato e attenuato
   (come .chip-cancelled nel calendario) — mai opacity sull'intera riga,
   altrimenti sbiadirebbe anche lo sfondo colorato appena aggiunto. */
.list-row-cancelled td { color: var(--muted); text-decoration: line-through; }

/* Sessione "lettura prima della modifica su mobile", blocco 3: la riga
   toccata su mobile non apre più subito la modifica — si srotola in
   linea con lo stesso contenuto della scheda a scomparsa
   (buildReadDetail, panel.js), una sola riga alla volta (app.js:
   onListRowTap rimuove ogni .list-row-expanded esistente prima di
   aprirne una nuova). white-space:normal: .list-view-table td sopra
   impone nowrap a tutta la tabella (le altre colonne restano su una
   riga), qui va resettato perché testo lungo, badge e immagini vadano a
   capo come nella scheda. */
.list-row-expanded td {
  white-space: normal; background: var(--bg); padding: 16px 12px 12px;
  border-bottom: 1px solid var(--border); position: relative; cursor: default;
}
.list-row-expanded td .read-detail { padding-right: 40px; }
.list-row-expanded .list-row-edit-btn { position: absolute; top: 8px; right: 8px; }
.is-expanded-source { background: var(--surface-2, var(--bg)); }
/* Animazione breve (blocco 3), rispetta prefers-reduced-motion insieme a
   ogni altra transizione/animazione dell'app (regola globale in cima a
   questo file — animation-duration forzata a 0.01ms). Un'altezza di riga
   <tr> non si anima in modo affidabile in puro CSS: qui basta un breve
   dissolvenza/scorrimento del contenuto, non della riga stessa. */
.list-row-expanded td > * { animation: list-row-expand-in var(--dur-slow) var(--ease-out); }
@keyframes list-row-expand-in {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: translateY(0); }
}
.list-view-empty { padding: 24px 16px; text-align: center; }
.list-pager { display: flex; align-items: center; justify-content: center; gap: 12px; padding: 12px; font-size: var(--fs-sm); color: var(--muted); }

.athlete-search {
  width: 100%; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: var(--fs-sm); margin-bottom: 8px; transition: border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.athlete-search:focus-visible { border-color: var(--accent); box-shadow: var(--focus-ring); outline: none; }

.empty-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: 56px 20px; text-align: center; color: var(--muted);
}
.empty-state svg { display: block; color: var(--border-strong); flex-shrink: 0; }
.empty-state button {
  padding: 10px 20px; border: none; border-radius: var(--radius-sm); background: var(--accent); color: var(--accent-contrast);
  font-weight: 600; cursor: pointer; transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.empty-state button:hover { opacity: .92; }
.empty-state button:active { transform: scale(.98); }
.empty-state-inline { padding: 20px; }

/* ---------- fisarmonica (gestione atleti) ---------- */
/* Grid-rows 0fr↔1fr: anima l'apertura senza mai toccare height/margin
   (proprietà vietate, causano scatti su griglie dense) — vedi DECISIONI.md
   per il limite noto (la chiusura della riga atleta nella lista resta
   istantanea, l'architettura ricostruisce l'elenco a ogni clic). */
.accordion-header {
  width: 100%; text-align: left; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg); cursor: pointer; font-size: var(--fs-md); font-weight: 600; margin-bottom: 8px;
  transition: background var(--dur-fast) var(--ease-out);
}
.accordion-header:hover { background: var(--surface-2); }
.accordion-body {
  display: grid;
  grid-template-rows: 0fr;
  border-bottom: 1px solid var(--border);
  margin-bottom: 8px;
  transition: grid-template-rows var(--dur-slow) var(--ease-out);
}
.accordion-body.open { grid-template-rows: 1fr; }
/* L'attributo [hidden] da solo non basterebbe: una regola d'autore con
   `display` (quella sopra) vince SEMPRE su [hidden] del foglio dello user
   agent, a prescindere dalla specificità — senza questa riga l'elemento
   collassato (0fr, altezza visiva zero) resterebbe comunque raggiungibile
   con Tab. */
.accordion-body[hidden] { display: none; }
.accordion-item:last-child .accordion-body { border-bottom: none; }
.accordion-body > * { overflow: hidden; min-height: 0; padding: 10px 4px 16px; }

.athlete-list-row {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 6px; border: none;
  background: none; cursor: pointer; font-size: var(--fs-md); text-align: left; border-radius: var(--radius-sm);
  transition: background var(--dur-fast) var(--ease-out);
}
.athlete-list-row:hover { background: var(--bg); }
.athlete-list-name { font-weight: 600; min-width: 140px; }
.athlete-list-discipline { color: var(--muted); flex: 1; }
.athlete-list-status { font-size: var(--fs-xs); color: var(--muted); background: var(--bg); padding: 2px 8px; border-radius: 999px; }

.form-hint { color: var(--muted); font-size: var(--fs-xs); margin: 2px 0 0; }

/* ---------- immagini nel pannello (A2) ---------- */

.media-cell { position: relative; width: 84px; }
.media-cell .media-thumb { width: 84px; height: 84px; }
.media-cell-controls {
  position: absolute; bottom: 2px; left: 2px; right: 2px; display: flex; justify-content: space-between;
  opacity: 0; transition: opacity var(--dur-base) var(--ease-out);
}
.media-cell:hover .media-cell-controls, .media-cell:focus-within .media-cell-controls { opacity: 1; }
.media-cell-controls button {
  width: 22px; height: 22px; border-radius: 50%; border: none; background: rgba(0,0,0,.6); color: #fff;
  font-size: var(--fs-sm); line-height: 22px; padding: 0; cursor: pointer;
}
.media-cell-controls button:disabled { opacity: .3; cursor: default; }

/* ---------- allegati Google Drive (B4/B5/B6) ---------- */

/* Blocco 6c ("correzioni interfaccia..."): riga propria per il pulsante
   Drive, a piena larghezza — prima condivideva una .row col campo file,
   che su telefono usciva a destra oltre il bordo del pannello (un
   <input type="file"> nativo ha una larghezza minima che il browser
   impone da solo). flex-wrap perché resta pronta a impilare più di un
   pulsante, se in futuro ce ne fosse più di uno qui. */
.drive-pick-row { display: flex; flex-wrap: wrap; gap: 8px; width: 100%; margin-top: 8px; }
.drive-pick-row button { flex: 1 1 auto; min-width: 0; }
/* Un <input type="file"> non eredita la larghezza dal contenitore come un
   testo: senza questa riga poteva restare più stretto (o più largo, coi
   nomi dei file scelti) del pannello, mai a piena larghezza come gli
   altri campi. */
.attachments-file-input { width: 100%; max-width: 100%; }

.media-cell.drive-cell { width: 140px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 6px; }
.drive-cell .media-thumb { width: 100%; height: 70px; object-fit: contain; background: #fff; border-radius: 4px; }
.drive-file-name { font-size: var(--fs-xs); font-weight: 600; margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.drive-file-meta { font-size: var(--fs-xs); color: var(--muted); }
.drive-file-link { display: block; font-size: var(--fs-xs); margin-top: 2px; }
.drive-share-warning {
  margin-top: 4px; padding: 4px 6px; background: #fff7ed; border: 1px solid #fdba74; border-radius: var(--radius-sm); font-size: var(--fs-xs); color: #9a3412;
}
.drive-share-warning button {
  display: block; margin-top: 3px; padding: 3px 6px; border: none; border-radius: 4px; background: #d97706; color: #fff; font-size: var(--fs-xs); cursor: pointer;
}
.publish-drive-links { display: flex; flex-direction: column; gap: 4px; margin-top: 10px; }
.publish-drive-links a { font-size: var(--fs-sm); }

/* ---------- overlay condivisi: pannello e dialogo (entrata/uscita animate) ---------- */
/* .open aggiunta via rAF subito dopo l'inserimento nel DOM, rimossa prima
   di rimuovere l'elemento (con un breve ritardo pari alla durata della
   transizione) — vedi wireClosableOverlay in panel.js. Solo transform e
   opacity, mai lo scorrimento reale del pannello via left/right. */
.panel-overlay, .dialog-overlay {
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-out);
}
.panel-overlay.open, .dialog-overlay.open { opacity: 1; }

.dialog-overlay {
  position: fixed; inset: 0; background: rgba(15, 23, 42, .38); display: flex; align-items: center; justify-content: center; z-index: 60;
}
.dialog-box {
  background: var(--card); border-radius: var(--radius-lg); padding: 24px; width: min(340px, 90%);
  box-shadow: var(--shadow-lg);
  transform: scale(.97) translateY(4px);
  transition: transform var(--dur-slow) var(--ease-out);
}
.dialog-overlay.open .dialog-box { transform: scale(1) translateY(0); }
.dialog-box form { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; }
.dialog-box label:not(.consent-label) { display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-sm); color: var(--muted); }
.dialog-box input, .dialog-box select { padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); }
/* Blocco 7: intestazione dialog con titolo + X */
.dialog-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.dialog-header h3 { margin: 0; }
.dialog-close-btn {
  background: none; border: none; cursor: pointer; font-size: 1.4rem; line-height: 1;
  color: var(--muted); padding: 0 4px; border-radius: var(--radius-sm);
}
.dialog-close-btn:hover { color: var(--text); }

/* Pulsante X fisso sopra il Google Picker (e sopra la sua schermata di
   accesso). z-index 2147483647 = MAX_INT, garantisce che sia sempre sopra
   qualsiasi overlay Google inietti nella pagina. */
.picker-close-btn {
  position: fixed; top: 16px; right: 16px; z-index: 2147483647;
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--card); border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-md); cursor: pointer;
  font-size: 1.5rem; line-height: 1; color: var(--text);
  display: flex; align-items: center; justify-content: center;
}
.picker-close-btn:hover { background: var(--surface-2); }

/* Blocco 5: selettore ora personalizzato (dropdown a 96 voci, filtro
   mentre si digita). Posizionato come .disciplines-options: esce dal
   flusso verso il basso senza spostare il contenuto circostante. */
.time-picker { position: relative; }
.time-picker input[type="text"] { width: 100%; }
.time-picker-dropdown {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 200;
  max-height: 200px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card); box-shadow: var(--shadow-md); margin-top: 2px;
}
.time-picker-option {
  display: block; width: 100%; text-align: left;
  padding: 6px 10px; border: none; background: none;
  cursor: pointer; font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
}
.time-picker-option:hover, .time-picker-option.current { background: var(--bg); }
.time-picker-option.current { font-weight: 600; }

/* Blocco 4 (sessione "filtri, campi base..."): pannello a scomparsa dal
   basso per la scelta atleti su telefono — stesso principio di
   apertura/chiusura animata di .dialog-overlay sopra (solo opacity sul
   fondo, mai lo scroll reale), ma con lo scivolamento verticale invece
   dello zoom, coerente con "a scomparsa dal basso" del testo di
   specifica. */
.sheet-overlay {
  position: fixed; inset: 0; background: rgba(15, 23, 42, .38);
  display: flex; align-items: flex-end; justify-content: center; z-index: 70;
  opacity: 0; transition: opacity var(--dur-slow) var(--ease-out);
}
.sheet-overlay.open { opacity: 1; }
.athlete-sheet {
  background: var(--card); width: 100%; max-width: 480px; max-height: 78vh;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0; padding: 16px;
  box-shadow: var(--shadow-lg); display: flex; flex-direction: column; gap: 8px;
  transform: translateY(100%); transition: transform var(--dur-slow) var(--ease-out);
}
.sheet-overlay.open .athlete-sheet { transform: translateY(0); }

/* Sessione "lettura prima della modifica su mobile": scheda di sola
   lettura, mese/settimana — stesso principio di .athlete-sheet sopra
   (apertura/chiusura animata, scivolamento verticale), ma con un'altezza
   propria che si anima fra due stati (metà schermo / a tutto schermo,
   .expanded) invece di adattarsi al contenuto — height, non max-height:
   senza un'altezza esplicita il contenuto più corto di 55vh non
   riempirebbe la scheda, rendendo "trascina per espandere" un gesto senza
   nulla da vedere finché non tocca contenuto vero. .dragging spegne la
   transizione SOLO mentre il dito la tiene (app.js — non qui,
   wireReadSheetDrag in panel.js): durante il trascinamento l'altezza deve
   seguire il dito 1:1, senza ritardo; al rilascio la transizione torna,
   ed è lei ad animare lo scatto verso lo stato più vicino. */
.read-sheet {
  background: var(--card); width: 100%; max-width: 640px;
  height: 55vh; min-height: 220px;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column;
  transform: translateY(100%);
  transition: transform var(--dur-slow) var(--ease-out), height var(--dur-slow) var(--ease-out);
}
.sheet-overlay.open .read-sheet { transform: translateY(0); }
.read-sheet.expanded { height: 94vh; }
.read-sheet.dragging { transition: none; }

.read-sheet-handle-row {
  display: flex; justify-content: center; flex-shrink: 0;
  padding: 8px 0 4px; cursor: grab; touch-action: none;
}
.read-sheet-handle-row:active { cursor: grabbing; }
.read-sheet-handle { width: 36px; height: 4px; border-radius: 999px; background: var(--border-strong); }

.read-sheet-header { display: flex; align-items: center; gap: 4px; padding: 0 12px 6px; flex-shrink: 0; }
.read-sheet-header-spacer { flex: 1; }
.read-sheet-close {
  border: none; background: none; font-size: 22px; line-height: 1; color: var(--muted);
  cursor: pointer; padding: 4px 10px; border-radius: var(--radius-sm);
}
.read-sheet-close:hover { background: var(--bg); color: var(--text); }
.read-sheet-edit {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border: none; border-radius: 50%;
  background: none; color: var(--accent); cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}
.read-sheet-edit:hover, .read-sheet-edit:active { background: var(--accent-soft, var(--bg)); }
.read-sheet-edit svg { width: 18px; height: 18px; display: block; flex-shrink: 0; }
/* Sessione "icona atleti su mobile, causa reale": su touch (hover:none,
   stesso criterio di C9 più sotto) icona e bersaglio di tocco crescono al
   minimo di specifica (20px/44px) — su desktop (mouse, :hover attivo)
   resta com'era. */
@media (hover: none) {
  .read-sheet-edit { width: 44px; height: 44px; }
  .read-sheet-edit svg { width: 20px; height: 20px; }
}

.read-sheet-body { flex: 1; min-height: 0; overflow-y: auto; padding: 0 16px 16px; }

/* Blocco 2 (sessione "icona atleti su mobile..."): justify-content da
   .athlete-row (display:flex, condivisa) a "space-between" — SOLO due
   figli diretti qui (.athlete-sheet-all-label e, se presente, il
   collegamento gestione atleti), mai tre sparpagliati: toggle+testo sono
   raccolti in un unico contenitore apposta (vedi app.js). */
.athlete-sheet-all-row {
  flex-shrink: 0; font-weight: 600; padding-bottom: 8px; margin-bottom: 2px;
  border-bottom: 1px solid var(--border);
  justify-content: space-between;
}
.athlete-sheet-all-label { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
/* Sola icona in questo contesto compatto (mai il testo "Gestisci atleti"
   del gemello desktop: affiancato a "Tutti gli atleti" sulla stessa riga
   non ci starebbe mai a 360px senza andare a capo, testo di specifica) —
   area di tocco un po' più generosa del solo carattere, comunque piccola
   e discreta come il resto della riga. */
.mobile-manage-athletes-link {
  flex-shrink: 0; width: 28px; height: 28px; justify-content: center;
  border-radius: 50%; font-size: var(--fs-md);
}
.mobile-manage-athletes-link:active { background: var(--bg); }
.athlete-sheet-list { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.athlete-sheet-footer { flex-shrink: 0; padding-top: 10px; border-top: 1px solid var(--border); }
.athlete-sheet-footer button { width: 100%; }

/* ---------- notifiche (C4) ---------- */

#toast-host { position: fixed; right: 20px; bottom: 20px; display: flex; flex-direction: column; gap: 8px; z-index: 100; }
.toast {
  padding: 10px 16px; border-radius: var(--radius-sm); color: #fff; font-size: var(--fs-sm); box-shadow: var(--shadow-md);
  background: #374151;
  opacity: 0; transform: translateY(8px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
.toast.toast-in { opacity: 1; transform: translateY(0); }
.toast-success { background: #16a34a; }
.toast-error { background: #dc2626; }
.toast-warning { background: #d97706; }
/* Stessa specificità di .toast.toast-in (mai una in meno: altrimenti la
   dissolvenza in uscita non vince sulla classe di entrata, che JS non
   rimuove mai) e dopo di lei nel foglio, così a parità vince l'uscita. */
.toast.toast-out { opacity: 0; transform: translateY(4px); }

/* Blocco 4 (sessione "correzioni card vocale, pulsanti del calendario,
   selezione del soggetto"): .floating-btn è il componente condiviso dai
   due pulsanti flottanti del calendario ("+" e microfono, 4c) — stessa
   dimensione/forma/ombra/centraggio/comportamento "nascosto quando un
   pannello è aperto" (blocco 2, body.has-open-overlay sotto) in UN solo
   posto. Prima di questa sessione .fab e .voice-fab avevano ognuno la
   propria dimensione e posizione scritte a mano, con valori diversi fra
   loro (right 28/20px, bottom 28/90px — quest'ultimo per stare sopra
   #toast-host, mai per allinearsi a .fab): risultato, non erano né sulla
   stessa riga né alla stessa distanza dal bordo (4a). Ora solo il right
   di ciascuno resta specifico (per stare uno accanto all'altro, mai
   sovrapposti), bottom/dimensione/z-index sono UN valore solo qui.
   z-index molto alto (9500, appena sopra .tour-resume-bar a 9000, il
   valore "sempre sopra" più alto già in uso per la UI normale dell'app
   — 2147483647 resta riservato solo a .picker-close-btn, un caso a sé,
   overlay di Google): "sopra ogni altra cosa" del calendario/dashboard,
   non sopra un vero overlay Google iniettato nella pagina. */
.floating-btn {
  position: fixed; bottom: 28px; z-index: 9500;
  width: 56px; height: 56px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--accent-contrast); border: none;
  box-shadow: var(--shadow-lg); cursor: pointer;
  transition: background 150ms var(--ease-out), transform 150ms var(--ease-out), opacity 150ms var(--ease-out);
}
@media (hover: hover) {
  .floating-btn:hover { transform: scale(1.05); }
}
/* Blocco 2 (stessa sessione): "un solo punto che governa la visibilità
   dei flottanti in base allo stato 'pannello aperto'" —
   updateFloatingButtonsVisibility() in panel.js è l'UNICO punto che
   aggiunge/toglie questa classe sul <body>, richiamato da openOverlay()/
   closeOverlay() (a loro volta l'unico punto che ogni pannello/dialogo/
   scheda usa per aprirsi e chiudersi, vedi lì): niente selettori
   ripetuti per ogni tipo di overlay, un solo interruttore. Dissolvenza
   invece di display:none — stessa transizione già in .floating-btn,
   mai uno scatto secco. */
body.has-open-overlay .floating-btn { opacity: 0; pointer-events: none; transform: scale(.7); }

.fab { right: 28px; }
/* 28px (right di .fab) + 56px (larghezza) + 16px (spazio fra i due, 4a). */
.voice-fab { right: 100px; }
/* Blocco 3 (sessione "correzioni card vocale..."): stesso bug/stessa
   causa di .panel-tour-btn svg sopra — display:block e flex-shrink:0
   mancanti, l'unica differenza reale con ogni altra icona del file. */
.voice-fab svg { width: 26px; height: 26px; display: block; flex-shrink: 0; }
.fab svg { width: 26px; height: 26px; display: block; flex-shrink: 0; }
/* 4b: "il pulsante pulsa in rosso" durante la registrazione — un anello
   che si espande e svanisce, non un semplice cambio di colore statico:
   deve leggersi a colpo d'occhio che sta REGISTRANDO, non solo che è
   "attivo". */
.voice-fab.recording { background: var(--danger); animation: voice-fab-pulse 1.2s ease-in-out infinite; }
@keyframes voice-fab-pulse {
  0%, 100% { box-shadow: var(--shadow-lg), 0 0 0 0 rgba(220, 38, 38, .5); }
  50% { box-shadow: var(--shadow-lg), 0 0 0 14px rgba(220, 38, 38, 0); }
}
/* In attesa del servizio (4c): stesso indicatore rotante già in uso per
   i bottoni "in corso" del pannello (button.is-loading, più sotto in
   questo file) — icona nascosta, un anello al centro. */
.voice-fab.processing { pointer-events: none; }
.voice-fab.processing svg { visibility: hidden; }
.voice-fab.processing::after {
  content: ''; position: absolute; left: 50%; top: 50%; width: 20px; height: 20px; margin: -10px 0 0 -10px;
  border-radius: 50%; border: 2px solid rgba(255, 255, 255, .45); border-top-color: #fff;
  animation: btn-spin 650ms linear infinite;
}

/* Card di riepilogo (4c): sopra la riga dei due pulsanti flottanti,
   allineata al bordo esterno di .fab — "Ho capito: …" prima, poi il
   riepilogo con Apri/Modifica/Annulla (o un errore al posto del
   riepilogo, 4d). bottom ricalcolato nel blocco 4 (sessione "correzioni
   card vocale..."): 28px (bottom di .floating-btn) + 56px (altezza) +
   16px di distacco dal pulsante = 100px — prima il microfono stava a
   bottom:90px (sopra #toast-host, non allineato a .fab): 160px era
   calcolato su quella quota, ora obsoleta (4a: i due pulsanti sono
   sulla stessa riga). */
.voice-result-card {
  position: fixed; right: 28px; bottom: 100px; z-index: 9500;
  max-width: min(320px, calc(100vw - 40px));
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); padding: 14px 16px;
  opacity: 0; transform: translateY(8px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
.voice-result-card.visible { opacity: 1; transform: translateY(0); }
.voice-result-transcript { margin: 0; font-size: var(--fs-sm); color: var(--muted); font-style: italic; }
.voice-result-error { margin: 0; font-size: var(--fs-sm); color: var(--danger); font-weight: 600; }
/* Sessione "contratto 2.2": unsupported_intent — un suggerimento, mai un
   errore rosso (--danger): stesso peso visivo di .voice-result-error,
   colore --accent invece. */
.voice-result-suggestion { margin: 0; font-size: var(--fs-sm); color: var(--accent); font-weight: 600; }

/* ---------- schermata di conferma vocale (sessione "conferma prima
   dell'inserimento vocale, data sbagliata al salvataggio", blocco 3) ----------
   Sostituisce .voice-result-summary/-date-hint/-actions (rimosse: la card
   piccola non mostra più l'esito riuscito, solo transcript/errore/
   suggerimento prima che una bozza esista — vedi voice.js). A schermo
   pieno su telefono/app (3a) — nessuna media query "display-mode", una
   sola soglia di LARGHEZZA (640px), stessa filosofia di ogni altro
   breakpoint mobile/desktop del progetto (767px altrove: qui più stretta
   apposta, il contenuto di questa schermata è più verticale/stretto di
   un pannello normale, la finestra centrata desktop resta leggibile fino
   a un po' più giù). Overlay/apertura-chiusura animata: STESSO
   .dialog-overlay/.dialog-box (sopra in questo file) — solo una classe
   modificatrice per le differenze di formato, mai una seconda coppia di
   regole open/transform duplicate. */
.voice-confirm-overlay { z-index: 9600; }
.voice-confirm-box {
  width: min(480px, 92%);
  max-height: 90vh;
  display: flex; flex-direction: column; gap: 14px;
  overflow-y: auto;
  text-align: left;
}
@media (max-width: 640px) {
  .voice-confirm-overlay { align-items: stretch; justify-content: stretch; }
  .voice-confirm-box { width: 100%; max-height: none; height: 100%; border-radius: 0; padding: 24px 20px; }
}
.voice-confirm-row { font-size: var(--fs-lg); line-height: 1.3; }
.voice-confirm-row-type {
  display: flex; align-items: center; gap: 10px;
  font-size: var(--fs-md); font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
  color: var(--tile-color);
}
.voice-confirm-type-icon { width: 22px; height: 22px; display: block; flex-shrink: 0; }
.voice-confirm-type-icon svg { display: block; width: 22px; height: 22px; }
.voice-confirm-row-athlete { display: flex; align-items: center; gap: 10px; font-weight: 600; }
.voice-confirm-row-athlete .athlete-initials { width: 40px; height: 40px; font-size: var(--fs-md); flex-shrink: 0; }
.voice-confirm-row-category, .voice-confirm-row-channels { display: flex; align-items: center; gap: 8px; font-size: var(--fs-md); color: var(--muted); }
.voice-confirm-row-title { font-weight: 700; font-size: 1.4em; }
.voice-confirm-row-place { color: var(--muted); }
.voice-confirm-row-description { font-size: var(--fs-sm); color: var(--muted); }
/* 3c: un campo obbligatorio mancante — riga col nome del campo + "?"
   evidenziato, mai lo stesso stile "neutro" delle righe compilate: deve
   saltare all'occhio SUBITO che manca qualcosa da correggere. */
.voice-confirm-row-missing {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  color: var(--danger); font-weight: 600;
  background: color-mix(in srgb, var(--danger) 8%, transparent);
  border: 1px dashed var(--danger); border-radius: var(--radius-sm);
  padding: 6px 10px;
}
.voice-confirm-missing-mark { font-size: 1.3em; font-weight: 800; }
.voice-confirm-transcript { margin: 4px 0 0; font-size: var(--fs-xs); color: var(--muted); font-style: italic; }
.voice-confirm-banner {
  font-size: var(--fs-sm); padding: 10px 12px; border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
}
.voice-confirm-banner-error { background: color-mix(in srgb, var(--danger) 10%, transparent); color: var(--danger); font-weight: 600; }
/* Stesso ambra di --deadline-upcoming/.toast-warning altrove nel foglio
   (nessuna variabile --warning generica esiste nel progetto, ognuna di
   quelle è nominata per il proprio contesto) — sfondo pieno + testo
   bianco, mai color-mix qui: a differenza dell'errore sopra questo NON è
   un banner discreto, deve fermare l'occhio (3e, "NON chiudere in
   silenzio"). */
.voice-confirm-banner-warning { background: #d97706; color: #fff; font-weight: 600; }
/* 3d: tre bottoni grandi, a tutta larghezza su telefono, in colonna —
   raggiungibili col pollice in fondo allo schermo pieno (margin-top:auto
   li spinge in basso quando il riepilogo sopra non riempie tutta
   l'altezza). Su desktop restano comunque a tutta larghezza del box
   (mai affiancati): sono TRE azioni distinte con pesi diversi (primaria/
   due secondarie), non una riga di pari dignità. */
.voice-confirm-actions { display: flex; flex-direction: column; gap: 10px; margin-top: auto; padding-top: 8px; }
.voice-confirm-actions button { width: 100%; min-height: 48px; font-size: var(--fs-md); font-weight: 600; }
/* CAUSA TROVATA testando dal vivo (3e, banner di discrepanza — Conferma/
   Ridetta si nascondono con l'attributo [hidden]): `button.primary,
   button.secondary { display:inline-flex }` (più sopra in questo file)
   ha specificità (0,1,1), più alta di quella nativa di [hidden] (0,1,0) —
   vince lei, il bottone resta visibile nonostante l'attributo. Difetto
   preesistente e generale (qualunque button.primary/secondary nascosto
   con [hidden] in tutto il progetto ne sarebbe vittima, non solo qui),
   ma corretto solo qui per restare nel perimetro di questa sessione —
   stesso principio già in uso altrove nel foglio per lo stesso identico
   conflitto (vedi .accordion-body[hidden]/.sc-edit-form:not([hidden])/
   .app-recovery:not([hidden]) più sopra). Selettore a due classi+attributo
   (0,2,0): vince su (0,1,1) senza dover toccare la regola generale. */
.voice-confirm-actions button[hidden] { display: none; }
/* 3c: Conferma disattivato (campo obbligatorio mancante) deve SEMBRARE
   disattivato — nessuno stile :disabled generico esiste per
   button.primary in questo foglio (verificato con grep), quindi qui a sé. */
.voice-confirm-btn-confirm:disabled { opacity: .45; cursor: not-allowed; }
.voice-confirm-edit-link { text-align: center; font-size: var(--fs-sm); color: var(--muted); text-decoration: underline; }
.voice-confirm-saved { text-align: center; font-size: var(--fs-lg); font-weight: 700; color: var(--accent); padding: 40px 0; margin: 0; }

.day-num { cursor: pointer; }
.day-num:hover { text-decoration: underline; }

/* Blocco 3 (sessione "correzioni mobile..."): il padding inferiore di
   .calendar-area, poco più sotto, tiene conto dell'altezza/posizione dei
   pulsanti flottanti (56px + 28px di distanza dal fondo, .floating-btn
   più sopra) così l'ultima riga della griglia resta leggibile a fine
   scorrimento anche con un pulsante sopra di essa — se .floating-btn
   cambia dimensione o bottom, quel valore va aggiornato insieme (vedi
   il commento lì). z-index/dimensione/posizione di .fab vivono ora in
   .floating-btn, condivisa col microfono (blocco 4 di questa sessione).
*/

/* ---------- vista mese ---------- */

/* Blocco 6b: 44px minimo per colonna (indicazione della sessione) — sotto
   quella soglia il numero del giorno e i chip diventano illeggibili.
   .calendar-area (overflow:auto, poco sotto in questo file) mostra lo
   scorrimento orizzontale da sola quando il contenuto supera la
   larghezza disponibile, senza bisogno di altro qui: mai più uno
   schiacciamento infinito con colonne 1fr senza un pavimento. */
.month-grid { display: flex; flex-direction: column; gap: 6px; }
.month-headers { display: grid; grid-template-columns: repeat(7, minmax(44px, 1fr)); background: var(--card); }
.month-head { font-size: var(--fs-xs); color: var(--muted); text-transform: uppercase; text-align: center; padding-bottom: 4px; }

/* Settimana del mese: le barre multi-giorno (position:absolute, sopra)
   condividono lo stesso riquadro delle celle giorno (sotto), che riservano
   spazio in cima con un padding-top calcolato in JS in base al numero di
   "corsie" occupate quella settimana — vedi calendar.js, il punto "dove si
   rompe più facilmente" secondo la richiesta che ha aperto questa sessione. */
.month-week { position: relative; }
/* Sessione "quattro correzioni", blocco 2: griglia vera, non più
   percentuali — vedi il commento su barGridColumn() in calendar.js per il
   perché (il difetto reale, su mobile, era un disallineamento fra la
   larghezza "assegnata" a .month-week-days e quella davvero occupata dai
   suoi binari quando la griglia celle trabocca il proprio contenitore).
   grid-template-columns impostato per contesto qui sotto (.month-week/
   .week-days-wrap), SEMPRE lo stesso valore della griglia celle
   corrispondente — un solo posto a doverli tenere in sincrono, non più
   un $gapPx passato a mano da calendar.js. grid-auto-rows/row-gap =
   BAR_LANE_HEIGHT (22px barra + 2px, calendar.js): ogni corsia è una riga
   reale della griglia (grid-row, assegnato in JS), mai un top in pixel. */
.bars-overlay {
  position: absolute; left: 0; right: 0; top: 0; pointer-events: none; z-index: 2;
  display: grid;
  grid-auto-rows: 22px;
  row-gap: 2px;
}
/* column-gap qui SOTTO ripete apposta il gap della griglia celle
   corrispondente (.month-week-days ha gap:6px = row+column insieme,
   .week-cells-grid nessun gap) — dimenticarlo qui riporta ESATTAMENTE
   l'errore-per-colonna della sessione precedente (colonne più strette di
   quelle vere, un binario che si scosta dal bordo cella crescendo con la
   colonna): verificato dal vivo, è il difetto trovato scrivendo questa
   stessa regola la prima volta in questa sessione, prima di aggiungere
   column-gap. */
.month-week .bars-overlay { grid-template-columns: repeat(7, minmax(44px, 1fr)); column-gap: 6px; }
.week-days-wrap .bars-overlay { grid-template-columns: repeat(7, minmax(80px, 1fr)); }
.month-week-days { display: grid; grid-template-columns: repeat(7, minmax(44px, 1fr)); gap: 6px; position: relative; z-index: 1; }

.month-cell {
  position: relative;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  min-height: 88px;
  padding: 5px;
  font-size: var(--fs-xs);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.month-cell.other-month { opacity: .45; }
.month-cell .day-num { font-weight: 600; margin-bottom: 3px; }
/* Oggi: evidenziato ma non colorato (6) — solo tono di sfondo e peso del
   numero, mai un colore d'accento decorativo. */
.month-cell.is-today { background: var(--surface-2); }
.month-cell.is-today .day-num { font-weight: 700; }
/* Weekend: in atletica è quando si gareggia — leggermente distinto. */
.month-cell.is-weekend { background: #f5f3fb; }
.month-cell.is-weekend.is-today { background: var(--surface-2); }
/* Blocco 1 ("correzioni interfaccia..."): giorni passati del mese
   corrente — solo lo sfondo cambia, MAI opacity (a differenza di
   .other-month sopra): gli item dentro devono restare leggibili come
   quelli di un giorno futuro, solo la cella si riconosce come "passata".
   Dopo .is-weekend nell'ordine di cascata così vince a parità di
   specificità sulle celle weekend passate. */
.month-cell.is-past { background: var(--bg); }
.month-cell.is-past.is-weekend { background: var(--bg); }
.month-cell.drop-target {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 2px var(--accent);
}
.month-more-btn {
  display: block; width: 100%; text-align: left; padding: 1px 4px; border: none; background: none;
  color: var(--muted); font-size: var(--fs-xs); font-weight: 600; cursor: pointer; border-radius: 4px;
}
.month-more-btn:hover { background: var(--bg); color: var(--text); }

/* Chip: SOLO tre canali visivi — barra=layer o canale (tenue+bordo saturo),
   punto=flag (colore+forma), testo=atleta o titolo secondo la vista. Mai
   colore-su-colore: lo sfondo resta tenue apposta perché il pallino di
   stato deve "notarsi meno" del previsto, non il contrario (1c). Il colore
   vero e proprio arriva da --chip-color/--chip-bg impostati in JS
   (itemColorVars in calendar.js): layer per gare/appuntamenti, primo
   canale scelto per i post social. */
.chip {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 3px 6px;
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: var(--fs-xs);
  margin-bottom: 3px;
  cursor: grab;
  background: var(--chip-bg);
  border-left: 4px solid var(--chip-color);
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.chip:hover { transform: scale(1.01); box-shadow: var(--shadow-sm); position: relative; z-index: 3; }
.chip:active { cursor: grabbing; }
.chip.dragging { transform: scale(1.03) rotate(1deg); box-shadow: var(--shadow-lg); opacity: .92; }
.chip-label { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Blocco 5: barra "Impegnato" — un item redatto lato server (items.php,
   professionista senza accesso al layer/sottotipo), occupa il tempo
   dell'atleta ma il dettaglio resta nascosto. Grigio neutro apposta,
   nessun colore di layer/canale (quel dato non arriva nemmeno al
   client): non trascinabile (niente draggable in JS) né cliccabile
   (nessun cursor a manina, nessun effetto hover di "cosa aprirei"). */
.busy-bar {
  cursor: default;
  background: var(--surface-2);
  border-left: 4px solid var(--border);
  color: var(--muted);
  font-style: italic;
}
.busy-bar:hover, .busy-bar.month-bar:hover { transform: none; box-shadow: none; }

/* Blocco 6a: gara proposta da un allenatore, non ancora confermata dal
   manager — bordo tratteggiato invece del pieno, resta comunque colorata
   per layer come ogni altra gara (non è "Impegnato": chi la vede ha
   pieno accesso al dettaglio, è solo in attesa di conferma). */
.chip-coach-proposal { border-left-style: dashed; outline: 1px dashed var(--chip-color); outline-offset: -1px; }

/* Comparsa scaglionata al primo caricamento della vista (4) — mai al
   ridisegno dopo un filtro o una navigazione, che restano istantanei (lo
   decide app.js passando isFirstRender solo la prima volta). */
.chip-enter, .bar-enter { animation: item-enter var(--dur-slow) var(--ease-out) both; }
@keyframes item-enter {
  from { opacity: 0; transform: translateY(3px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Barre multi-giorno (mese e settimana): stessa identità visiva del chip,
   posizionate come elementi di griglia dentro .bars-overlay (grid-column/
   grid-row assegnati in JS, calendar.js) — mai più position:absolute,
   che le avrebbe tolte dal flusso della griglia. Altezza 22px (punto 2:
   "barre alte 22-26px"), non più 16 — vedi BAR_LANE_HEIGHT in
   calendar.js, tenuto in sincrono con questo valore. */
.month-bar {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 22px;
  padding: 0 6px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs);
  color: var(--text);
  background: var(--chip-bg);
  border-left: 4px solid var(--chip-color);
  cursor: grab;
  overflow: hidden;
  white-space: nowrap;
  box-sizing: border-box;
  /* .bars-overlay ha pointer-events:none (per non bloccare i click sulle
     celle sotto dove non c'è nessuna barra): la singola barra li deve
     riattivare esplicitamente, altrimenti il click ci passa attraverso e
     arriva alla cella giorno sottostante (apre "nuovo item" invece di
     modificare l'evento multi-giorno). */
  pointer-events: auto;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.month-bar:hover { transform: scale(1.01); box-shadow: var(--shadow-sm); z-index: 3; }
.month-bar:active { cursor: grabbing; }
.month-bar.dragging { transform: scale(1.03) rotate(1deg); box-shadow: var(--shadow-lg); opacity: .92; }
.bar-continuation { flex-shrink: 0; font-size: var(--fs-xs); color: var(--chip-color); font-weight: 700; }

/* ---------- tooltip ricco su chip/barra (punto 2b) ---------- */
/* position:fixed + coordinate calcolate in JS (positionItemTooltip in
   calendar.js): l'elemento sorgente può stare dentro un contenitore con
   overflow:auto (.calendar-area), quindi absolute rispetto a un antenato
   scrollabile lo taglierebbe. pointer-events:none: il tooltip non deve
   mai intercettare il mouse, altrimenti un mouseleave sull'elemento sotto
   lo farebbe sparire e riapparire in un lampo mentre il cursore lo attraversa. */
.item-tooltip {
  position: fixed; z-index: 500; pointer-events: none;
  background: var(--card); color: var(--text); border: 1px solid var(--border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-md);
  padding: 8px 10px; max-width: 260px; font-size: var(--fs-xs); line-height: 1.4;
}
.item-tooltip-title { font-weight: 700; font-size: var(--fs-sm); margin-bottom: 3px; }
.item-tooltip-row { color: var(--muted); }
.item-tooltip-row:first-of-type { color: var(--text); }
.item-tooltip-updated { font-size: 10px; margin-top: 4px; opacity: .8; }

/* ---------- scadenze: indicatore distinto, mai una barra (1b) ---------- */
/* Triangolo nell'angolo della cella, colorato per URGENZA (non per layer):
   rosso scaduta/entro 7gg, ambra entro 30gg, grigio oltre. Un solo
   triangolo per cella (il più urgente); se ce n'è più di una, un numerino
   sovrapposto le conta tutte — clic apre l'elenco (deadline-quick-list) se
   sono più di una, altrimenti l'item direttamente. */
.deadline-corner {
  position: absolute; top: 0; right: 0; width: 0; height: 0;
  border-top: 14px solid var(--deadline-color, var(--deadline-far));
  border-left: 14px solid transparent;
  cursor: pointer; z-index: 4;
  transition: transform var(--dur-fast) var(--ease-out);
}
.deadline-corner:hover { transform: scale(1.15); transform-origin: top right; }
.deadline-corner-count {
  position: absolute; top: 0; right: 0; width: 14px; height: 14px;
  font-size: 8px; font-weight: 700; color: #fff; text-align: center; line-height: 14px;
  pointer-events: none;
}
.deadline-quick-list {
  position: fixed; background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); z-index: 90; min-width: 220px; max-width: 280px;
  opacity: 0; transform: scale(.96) translateY(-2px);
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.deadline-quick-list.open { opacity: 1; transform: scale(1) translateY(0); }
/* Aspetto + hover/fuoco della voce: .menu-item (regola condivisa, sopra). */
.deadline-quick-list .dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--deadline-color); }

/* Badge di stato scadenza (scheda atleta, dashboard) — stesso principio
   colore+testo dei pallini di flag, mai solo colore. */
.deadline-badge {
  display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px; border-radius: 999px;
  font-size: var(--fs-xs); font-weight: 600; background: var(--bg); color: var(--text);
}
.deadline-badge .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--deadline-color); }

.athlete-deadlines h3 { font-size: var(--fs-sm); margin: 0 0 8px; color: var(--muted); }
.athlete-deadline-row {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 6px 0; border-bottom: 1px solid var(--border);
  font-size: var(--fs-sm);
}
.athlete-deadline-row:last-child { border-bottom: none; }

.wa-refresh-section h3 { font-size: var(--fs-sm); margin: 0 0 8px; color: var(--muted); }

/* Blocco 3 — sezione "Staff" nella scheda atleta: figure professionali
   collegate, con stato account e rimozione accesso per riga. */
.athlete-staff-section h3 { font-size: var(--fs-sm); margin: 0 0 8px; color: var(--muted); }
.athlete-staff-row {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 0; border-bottom: 1px solid var(--border);
  font-size: var(--fs-sm);
}
.athlete-staff-row:last-child { border-bottom: none; }
.athlete-staff-row .form-hint { margin: 2px 0 0; }

/* Sezione cambio email di accesso (blocco 2 sessione "cambio email atleta"). */
.athlete-change-email {
  border-top: 1px solid var(--border);
  margin-top: 14px;
  padding-top: 14px;
}
.athlete-change-email .form-section-title {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--muted);
  margin: 0 0 6px;
}
.athlete-change-email .change-email-input {
  width: 100%;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  margin-bottom: 8px;
  box-sizing: border-box;
}
.athlete-change-email button.danger { margin-top: 4px; }

/* Punto 5: form modifica dati atleta in profilo.php */
.discipline-checkboxes { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 12px; }
.discipline-check { display: flex; align-items: center; gap: 4px; font-size: var(--fs-sm);
  background: var(--bg); border: 1px solid var(--border); border-radius: 999px;
  padding: 2px 10px 2px 6px; cursor: pointer; white-space: nowrap; }
.discipline-check input { margin: 0; cursor: pointer; }
.discipline-check:has(input:checked) { background: color-mix(in srgb, var(--accent) 10%, #fff);
  border-color: var(--accent); color: var(--accent); }
.social-input-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.social-label { min-width: 80px; font-size: var(--fs-sm); font-weight: 600; color: var(--muted); text-transform: capitalize; }
.social-input-row input { flex: 1; padding: 5px 8px; font-size: var(--fs-sm); }

/* Blocco 4a/4d: sezione "Link pubblico" nella scheda atleta. */
.public-link-section h3 { font-size: var(--fs-sm); margin: 0 0 8px; color: var(--muted); }
.public-link-url-row { display: flex; gap: 8px; }
.public-link-url-row input { flex: 1; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: var(--fs-sm); background: var(--bg); }

/* Selettore multiplo con ricerca per le discipline (3a): pastiglie
   rimovibili per quelle già scelte, un elenco filtrato mentre si digita —
   niente tendina con oltre trenta voci. */
.disciplines-picker input[type="text"] {
  width: 100%; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: var(--fs-sm); margin-top: 6px;
}
.disciplines-selected { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.disciplines-selected:empty { display: none; }
.discipline-pill {
  display: inline-flex; align-items: center; gap: 4px; padding: 3px 6px 3px 10px;
  border-radius: 999px; background: var(--bg); border: 1px solid var(--border); font-size: var(--fs-xs);
}
.discipline-pill button {
  border: none; background: none; cursor: pointer; font-size: var(--fs-sm); line-height: 1;
  color: var(--muted); padding: 0 2px;
}
.discipline-pill button:hover { color: var(--danger); }
.disciplines-options {
  margin-top: 4px; max-height: 160px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card);
}
.disciplines-options button {
  display: block; width: 100%; text-align: left; padding: 6px 10px; border: none; background: none;
  cursor: pointer; font-size: var(--fs-sm);
}
.disciplines-options button:hover { background: var(--bg); }
.disciplines-no-match { padding: 6px 10px; font-size: var(--fs-sm); color: var(--muted); }

/* ---------- flag: "TBC"/annullato (sessione "rifiniture di interfaccia",
   blocco 1c) — niente più puntini tbc/confermato/fatto: l'etichetta "TBC"
   (.tbc-badge sotto) basta da sola per le proposte, "fatto" è sparito.
   Resta solo il segnale "annullato", non più un pallino ma la barra
   intera: testo barrato e opacità ridotta, altrimenti indistinguibile da
   un impegno valido. ---------- */
.chip-cancelled { opacity: .55; }
.chip-cancelled .chip-label { text-decoration: line-through; }

/* Titolo barrato nel pannello di dettaglio / read-detail per item annullati */
.item-cancelled { text-decoration: line-through; opacity: .7; }

.tbc-badge {
  flex-shrink: 0; font-size: var(--fs-xs); font-weight: 700; letter-spacing: .02em; color: var(--st-tbc);
  border: 1px solid currentColor; border-radius: 3px; padding: 0 3px; line-height: 1.3;
}

/* ---------- icone canale (social) e categoria (agenda) sulla barra ---------- */
/* Blocco 3a/3b ("social: icone, non colori"): niente più un colore di
   marca per canale — le icone (SVG inline, calendar.js) ereditano il
   colore del TESTO circostante via currentColor, mai un colore proprio:
   la barra resta comunque colorata dal solo layer (--layer-social). */
.channel-icons { display: inline-flex; gap: 3px; flex-shrink: 0; align-items: center; }
.channel-icon { display: inline-flex; width: 11px; height: 11px; flex-shrink: 0; }
/* Sessione "icona atleti su mobile, causa reale": niente più width/height
   100% ereditati dal contenitore — su Safari iOS quella catena si rompe
   facilmente dentro un flex. Dimensione in px direttamente sull'svg,
   ripetuta esplicitamente per ogni contesto che la varia (sotto), mai più
   percentuale. */
.channel-icon svg { display: block; width: 11px; height: 11px; flex-shrink: 0; }
/* Sessione "correzione icone categorie agenda": SVG, non più emoji —
   font-size non serve più (dimensione decisa da .channel-icon). */
.subtype-icon { flex-shrink: 0; }
/* Colore esplicito, MAI ereditato dal contesto (chip, cella di tabella,
   anteprima nel pannello…) — coerente con l'arancione del layer agenda
   ovunque l'icona compaia da sola. Dentro una pastiglia filtro fa
   eccezione apposta: lì il colore deve seguire lo stato acceso/spento
   della pastiglia (.filter-pill, var(--pill-color)), esattamente come i
   canali social — non staticamente arancione anche a pastiglia spenta o
   attiva (bianco su sfondo pieno). */
.agenda-category-icon { color: var(--layer-agenda); }
.filter-pill-icon .agenda-category-icon { color: inherit; }
/* Sessione "sostituzione delle icone delle categorie di agenda", 2a:
   16px è la dimensione di default ovunque l'icona categoria compare
   FUORI dal riquadro del pannello (32px) e dalla pastiglia filtro
   (13px) — calendario (chip), vista a elenco (colonna categoria),
   scheda di dettaglio. Selettore a due classi (.agenda-category-icon
   E .channel-icon, non solo .channel-icon) apposta: così NON tocca le
   icone canale social, che restano a 11px di default, e resta più
   specifico (0,2,0/0,2,1) del generico .channel-icon(/svg) sopra
   (0,1,0/0,1,1) — vince sempre, non per un caso di ordine nel foglio. */
.agenda-category-icon.channel-icon {
  width: 16px; height: 16px;
  display: inline-flex; align-items: center; justify-content: center;
}
.agenda-category-icon.channel-icon svg { width: 16px; height: 16px; }

/* Sessione "correzione icone categorie agenda": icona + testo nella
   colonna categoria della vista elenco (calendar.js, col "sub"). */
.list-sub-cell { display: inline-flex; align-items: center; gap: 6px; }

/* Blocco 5c (sessione "... ritocchi"): gruppo di bottoni icona per la
   categoria agenda nel pannello crea/modifica — sostituisce la tendina
   nativa (non poteva contenere un <svg> vero nelle <option>).
   Blocco 3b/3c (sessione "email di benvenuto, hover dei menu, pannello
   agenda"): non più i piccoli .filter-pill/.filter-pill-icon della barra
   filtri (icona 13px, nessuna etichetta, si doveva indovinare/leggere il
   title al passaggio del mouse) — quattro riquadri affiancati, icona più
   del doppio più grande ED etichetta sempre visibile sotto: la scelta si
   legge, non si indovina. 4 in riga se lo spazio basta, altrimenti 2 per
   riga (telefono) — grid con colonne minime invece di un breakpoint
   fisso, si adatta da sé alla larghezza reale del pannello.
   Blocco 3a (sessione "selettore del tipo (terzo tentativo)..."): rinominate
   da `.agenda-category-picker`/`.agenda-category-tile*` a `.tile-picker`/
   `.tile-picker-item*` — lo stesso componente (buildTilePicker, panel.js)
   ora serve ANCHE il selettore canali social nel pannello post, mai due
   implementazioni visive dello stesso pattern. */
.tile-picker {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(74px, 1fr));
  gap: 8px;
}
.tile-picker-item {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  min-height: 84px;
  padding: 14px 6px;
  border: 2px solid var(--border);
  border-radius: var(--radius);
  background: #fff;
  cursor: pointer;
  color: var(--muted);
  transition: border-color 150ms var(--ease-out), background 150ms var(--ease-out), color 150ms var(--ease-out);
}
/* Blocco 1 (sessione "riquadri delle categorie..."): causa reale del
   difetto — .channel-icon (usata altrove per le icone piccole 11px in
   linea) resta un riquadro di layout 11x11px anche qui: solo l'<svg>
   interno veniva ingrandito, mai il suo contenitore .channel-icon. L'SVG
   26px deborda quindi da un riquadro di layout 11px (overflow visibile
   di default), flexbox calcola lo spazio dell'etichetta sottostante in
   base al riquadro piccolo e l'etichetta finisce sovrapposta all'icona
   che deborda. Fix: dare a .channel-icon stesso, qui dentro, la
   dimensione reale (32px) e centrare l'svg al suo interno — così la
   colonna flessibile del tile conosce l'ingombro vero dell'icona.
   Selettore a tre classi (.tile-picker .tile-picker-item .channel-icon,
   specificità 0,3,0/0,3,1) apposta, non solo due: vince sempre sul
   default 16px di .agenda-category-icon.channel-icon (0,2,0/0,2,1) più
   sopra, non per un caso di ordine nel foglio. Selettore generico
   (.channel-icon, non .agenda-category-icon.channel-icon): dentro questo
   componente condiviso l'icona può essere quella di una categoria agenda
   O quella di un canale social (buildChannelIconEl, calendar.js) — stessa
   dimensione per entrambe, il punto centrale del blocco 3a. */
.tile-picker .tile-picker-item .channel-icon {
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
}
.tile-picker .tile-picker-item .channel-icon svg { width: 32px; height: 32px; }
/* Dentro il riquadro l'icona segue lo stato del riquadro (grigio spento,
   colorato acceso) — a differenza di .agenda-category-icon altrove
   (chip, elenco), sempre arancione a prescindere dal contesto. Non serve
   un equivalente per i canali social: senza classe .agenda-category-icon
   non hanno un colore proprio da annullare, seguono currentColor di
   default (vedi commento su .channel-icon in cima al file). */
.tile-picker-item .agenda-category-icon { color: inherit; }
/* overflow-wrap: "Comunicazione"/"Communication" sono una parola sola,
   più larga della colonna minima (74px) su schermi stretti — senza
   questo la riga di testo deborda dal riquadro invece di andare a capo
   (la traccia della griglia ha un minimo fisso in px, non si allarga
   per accoglierla). */
.tile-picker-item-label {
  font-size: var(--fs-xs); font-weight: 600; text-align: center; line-height: 1.2;
  overflow-wrap: break-word; max-width: 100%;
}
@media (hover: hover) {
  .tile-picker-item:hover { border-color: var(--pill-color, var(--accent)); }
}
/* 3c: stato selezionato — bordo pieno + fondo tinto + testo/icona colorati,
   non una leggera variazione di tono: bordo 2px già presente, qui cambia
   colore E riempimento insieme, sempre riconoscibile a colpo d'occhio. */
.tile-picker-item.active {
  border-color: var(--pill-color, var(--accent));
  background: var(--accent-soft);
  color: var(--pill-color, var(--accent));
}
.tile-picker-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Blocco 2c (sessione "selettore del tipo (terzo tentativo)..."): canale
   già scelto su un post salvato, ma nel frattempo tolto dalla scheda
   dell'atleta — bordo tratteggiato invece che pieno, in ENTRAMBI gli stati
   (spento/acceso): l'indicazione "non è più nella scheda" (spiegata per
   esteso nel title, social.channel_stale) deve restare visibile anche da
   selezionato, non solo prima che l'utente lo tocchi. */
.tile-picker-item-stale { border-style: dashed; }

/* Blocco 3c: piccola etichetta colorata per la categoria social — colore
   PROPRIO della categoria (rubrica configurabile), indipendente dal
   colore di layer del social, che le icone canale sopra non toccano più. */
.social-category-badge {
  flex-shrink: 0; font-size: 9px; font-weight: 700; color: var(--social-category-color, var(--muted));
  border: 1px solid var(--social-category-color, var(--border)); border-radius: 3px; padding: 0 3px; line-height: 1.4;
}

/* Sessione "ristrutturazione dell'intestazione...": #filter-pills-row
   (sottofiltri, riga 2 del solo desktop — .header-desktop) e
   #calendar-nav-slot (riga 3, entrambe le strutture) vivono ora dentro
   .header-row, che fornisce già bordo/sfondo/padding una volta per
   l'intera riga e non scorre mai (blocco 3: solo .calendar-area scorre
   in orizzontale). */
.filter-pills-row { display: flex; gap: 14px; flex-wrap: wrap; }
/* Blocco 4/2 (sessione "ristrutturazione..."): controllo scelta atleti,
   presente in DOM SOLO dentro .header-mobile (buildMobileAthletePicker(),
   mai costruito dalla struttura desktop) — niente più toggle a media
   query per mostrarlo/nasconderlo: la sua esistenza nel DOM è già decisa
   da isMobileHeaderWidth() in app.js, qui basta lo stile.
   Blocco 3 (sessione "rifiniture ai filtri..."): non più un interruttore
   con etichetta di testo ("Tutti gli atleti" non ci stava mai sulla
   stessa riga delle pastiglie layer, finiva sempre a capo) — un bottone
   icona, stessa famiglia visiva di .install-topbar-btn (cerchio
   trasparente a riposo, un tocco apre il pannello atleti). */
.athlete-picker {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 32px; height: 32px; border: none; border-radius: 50%;
  background: none; color: var(--muted); cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.athlete-picker:active { background: var(--bg); color: var(--text); }
/* Sessione "icona atleti su mobile...": color:inherit non basta su iOS
   Safari — stesso identico bug, stessa causa, stessa cura già trovata per
   .install-topbar-btn qualche sessione fa (icona invisibile pur toccabile,
   mai riprodotto nel simulatore desktop): il colore va dichiarato
   ESPLICITO anche sull'svg, non solo ereditato dal bottone.
   Sessione "icona atleti su mobile, causa reale": quel fix NON bastava —
   la causa vera è che l'svg (athletePickerIconMarkup, calendar.js) non
   portava width/height come ATTRIBUTI HTML, solo da qui in CSS: dentro un
   contenitore flex Safari può ridurlo a dimensione nulla comunque.
   Aggiunti gli attributi nel markup, più flex-shrink:0 qui (l'svg stesso
   è un item del bottone flex, non solo il bottone lo è del suo). */
.athlete-picker svg { display: block; width: 19px; height: 19px; color: var(--muted); flex-shrink: 0; }
.athlete-picker:active svg { color: var(--text); }
/* Numerino quando la selezione non è "tutti" (blocco 3a) — stesso
   linguaggio visivo di .user-menu-badge (angolo in alto a destra), ma
   colore neutro: non è un avviso, solo un'informazione. */
.athlete-picker-count {
  position: absolute; top: -2px; right: -2px; min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: 999px; background: var(--accent); color: var(--accent-contrast);
  font-size: 10px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  border: 2px solid var(--card);
}
/* Blocco 3c: separa l'icona atleti (scope "chi vedo") dalle pastiglie
   layer (scope "cosa vedo") — controlli di tipo diverso, mai la stessa
   fila indistinta di pastiglie. */
.row2-divider { width: 1px; align-self: stretch; margin: 2px 2px; background: var(--border); flex-shrink: 0; }
.pill-group { display: flex; gap: 6px; flex-wrap: nowrap; }
.filter-pill {
  padding: 3px 10px; border-radius: 999px; border: 1px solid var(--pill-color, var(--border));
  background: #fff; color: var(--pill-color, var(--muted)); font-size: var(--fs-xs); font-weight: 700; cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.filter-pill.active { background: var(--pill-color, var(--accent)); color: #fff; border-color: var(--pill-color, var(--accent)); }

/* Blocco 3a/3b: pillola canale social — solo l'icona (monocromatica,
   currentColor), niente più testo/colore di marca; il nome pieno resta
   nel title (hover/screen reader). */
.filter-pill-icon { display: inline-flex; align-items: center; justify-content: center; padding: 5px 9px; }
.filter-pill-icon .channel-icon { width: 13px; height: 13px; }
.filter-pill-icon .channel-icon svg { width: 13px; height: 13px; }
/* Sessione "sostituzione delle icone delle categorie di agenda": qui
   dentro le pastiglie filtro compaiono SIA icone canale social (solo
   .channel-icon, 13px dalle due regole sopra, invariate) SIA l'icona
   categoria agenda (.channel-icon E .agenda-category-icon insieme) —
   da quando esiste il default 16px altrove (.agenda-category-icon.
   channel-icon, stessa specificità 0,2,0/0,2,1 di queste due regole)
   serve una regola più specifica per restare a 13px anche qui, non
   più un pareggio deciso dall'ordine nel foglio. */
.filter-pill-icon .agenda-category-icon.channel-icon { width: 13px; height: 13px; }
.filter-pill-icon .agenda-category-icon.channel-icon svg { width: 13px; height: 13px; }

/* Blocco 1 (sessione "correzioni mobile..."): fila sottofiltri mobile,
   aperta dalla freccia su un tab layer (.layer-tab-arrow, più sopra) —
   flex-basis:100% dentro .header-row-2 (già flex-wrap:wrap) la forza a
   capo SOTTO la riga dei layer, senza una quarta riga fissa a sé.
   Scorre in orizzontale DA SOLA se le pillole non ci stanno (.pill-group
   dentro ha già flex-wrap:nowrap) — min-width:0 impedisce che la sua
   larghezza intrinseca spinga .header-row-2, e quindi l'intestazione
   intera, più larga dello schermo (stesso principio del blocco 3 della
   sessione precedente). */
.mobile-subfilter-row {
  flex: 1 1 100%; width: 100%; min-width: 0;
  overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
  padding-top: 6px;
}

/* ---------- stato economico (gare e appuntamenti): dimensione separata (2b) ---------- */
.payment-badge {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 14px; height: 14px; border-radius: 50%; font-size: var(--fs-xs); font-weight: 700; color: #fff;
}
.payment-badge.pay-pending { background: var(--pay-pending); }
.payment-badge.pay-requested { background: var(--pay-requested); }
.payment-badge.pay-collected { background: var(--pay-collected); }

/* ---------- vista settimana swimlane ---------- */

/* Blocco 6b (sessione "correzioni interfaccia..."): i giorni non devono
   schiacciarsi oltre una larghezza leggibile (minmax sotto). Blocco 5
   ("filtri, campi base..."): tolto l'overflow-x proprio di qui — con un
   .week-shell scrollabile ANNIDATO dentro .calendar-area, anch'esso
   scrollabile, lo scorrimento orizzontale finiva ambiguamente sull'uno o
   sull'altro a seconda di dove iniziava il gesto (specie touch). Un solo
   contenitore che scorre in orizzontale per tutte le viste, sempre
   .calendar-area (CONTENITORE 3) — qui resta solo l'occorrere naturale
   della larghezza intrinseca (160px + colonne minime) a spingere quello
   scroll. */
.week-shell { display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.week-header-row { display: flex; }
.week-corner { width: 160px; flex-shrink: 0; background: #fafbfc; }
/* Blocco 2 (sessione "correzioni mobile..."): .week-head vive ora dentro
   .week-cells-grid (stessa griglia delle celle, calendar.js) invece che
   in una riga flex a sé — niente più flex:1, la larghezza di colonna la
   decide solo grid-template-columns su .week-cells-grid qui sotto, un
   solo posto, mai due calcoli separati che potevano disallinearsi. */
.week-head { background: #fafbfc; font-size: var(--fs-xs); text-align: center; padding: 6px 2px; font-weight: 600; border-left: 1px solid var(--border); }
.week-head.is-weekend { background: #f5f3fb; }
.week-athlete-row { display: flex; border-top: 1px solid var(--border); }
.week-athlete-label { width: 160px; flex-shrink: 0; display: flex; align-items: center; gap: 6px; font-size: var(--fs-sm); font-weight: 600; padding: 8px; background: #fafbfc; }
.week-athlete-label span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.week-days-wrap { position: relative; flex: 1; }
.week-cells-grid { display: grid; grid-template-columns: repeat(7, minmax(80px, 1fr)); position: relative; z-index: 1; }
.week-cell {
  position: relative;
  background: var(--card); min-height: 68px; padding: 4px; border-left: 1px solid var(--border);
  transition: background var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.week-cell.is-today { background: var(--surface-2); }
.week-cell.is-weekend { background: #f5f3fb; }
.week-cell.is-weekend.is-today { background: var(--surface-2); }
.week-cell.drop-target {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 2px var(--accent);
}

/* ---------- disponibilità atleta (blocco 6b) ---------- */
.availability-dot {
  flex-shrink: 0; width: 9px; height: 9px; border-radius: 50%;
  background: var(--availability-color); margin-left: 4px;
}
.availability-dot.is-editable { cursor: pointer; }
.availability-quick-menu {
  position: fixed; background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); z-index: 90; min-width: 220px; padding: 10px;
  transform-origin: top left;
  opacity: 0; transform: scale(.96) translateY(-2px);
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.availability-quick-menu.open { opacity: 1; transform: scale(1) translateY(0); }
/* Aspetto + hover/fuoco/stato corrente della voce: .menu-item (sopra). */
.availability-quick-menu input, .availability-quick-menu textarea {
  width: 100%; margin-top: 6px; padding: 5px 8px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); font-size: var(--fs-sm); box-sizing: border-box;
}

/* Blocco 3b: popover "Esporta XLSX", stesso pattern di
   .availability-quick-menu — un riquadro flottante ancorato al bottone. */
.export-menu {
  position: fixed; background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); z-index: 90; min-width: 240px; padding: 12px;
  transform-origin: top left;
  opacity: 0; transform: scale(.96) translateY(-2px);
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.export-menu.open { opacity: 1; transform: scale(1) translateY(0); }
.export-menu-title { font-weight: 600; margin-bottom: 4px; }
.export-menu .list-nav-field { margin-top: 8px; }
.export-menu .list-nav-field input { flex: 1; }

/* ---------- pannello creazione/modifica ---------- */

.panel-overlay {
  position: fixed; inset: 0; background: rgba(15, 23, 42, .38);
  display: flex; justify-content: flex-end; z-index: 50;
}
.panel {
  width: min(420px, 100%);
  background: var(--card);
  height: 100%;
  overflow-y: auto;
  padding: 20px;
  box-shadow: var(--shadow-lg);
  transform: translateX(16px);
  transition: transform var(--dur-slow) var(--ease-out);
}
.panel-overlay.open .panel { transform: translateX(0); }
.panel h2 { margin-top: 0; font-size: var(--fs-lg); }
/* Riga intestazione pannello: titolo + bottone "?" tour contestuale. */
.panel-header-row { display: flex; align-items: center; gap: 8px; }
.panel-header-row h2 { margin: 0; flex: 1; }
/* Stesso bottone nell'intestazione di fisarmonica (Aggiungi atleta). */
.accordion-header-row { display: flex; align-items: stretch; }
.accordion-header-row .accordion-header { flex: 1; border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
/* Bottone "i" per avviare il tour contestuale del pannello. Sessione
   "contratto 2.2...", blocco 3: tolto il contenitore circolare (border +
   border-radius:50%) — la nuova icona (tourIconMarkup(), panel.js) ha già
   il proprio cerchio nel path, un secondo cerchio disegnato dal bottone
   attorno era ridondante. Stessi width/height/flex di prima: stessa area
   cliccabile, stesso allineamento in ogni punto dov'è usato, solo senza
   il bordo visibile attorno. */
.panel-tour-btn {
  flex-shrink: 0;
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none;
  background: none;
  color: var(--muted);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out);
}
/* Blocco 3 (sessione "correzioni card vocale, pulsanti del calendario,
   selezione del soggetto"): CAUSA TROVATA dell'icona invisibile in
   iOS/Safari installato — mancavano display:block e flex-shrink:0,
   presenti su OGNI ALTRA regola svg di questo file (.channel-icon svg,
   .athlete-picker svg, .read-sheet-edit svg, .install-topbar-btn svg,
   ...): un SVG inline resta un elemento di livello INLINE per
   default, con una riga di base/altezza di riga che Safari calcola in
   modo diverso da Chrome dentro un contenitore flex — width/height CSS
   da soli non bastavano. display:block lo toglie dal flusso di testo
   (niente baseline/line-height a interferire con il centraggio flex del
   bottone), flex-shrink:0 impedisce che il flex del bottone lo comprima
   sotto la sua dimensione esplicita. */
.panel-tour-btn svg { width: 14px; height: 14px; display: block; flex-shrink: 0; }
.panel-tour-btn:hover { color: var(--accent); }
.panel-close { float: right; border: none; background: none; font-size: 20px; cursor: pointer; color: var(--muted); transition: color var(--dur-fast) var(--ease-out); }
.panel-close:hover { color: var(--text); }
.panel form { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; }
.panel label { display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-sm); color: var(--muted); }
.panel input, .panel select, .panel textarea {
  padding: 9px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: var(--fs-md);
  transition: border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.panel input:focus-visible, .panel select:focus-visible, .panel textarea:focus-visible {
  border-color: var(--accent); box-shadow: var(--focus-ring); outline: none;
}
.panel textarea { min-height: 80px; }
.panel .row { display: flex; gap: 10px; }
.panel .row > * { flex: 1; min-width: 0; }

/* ---------- interruttore a scorrimento (sessione "rifiniture di
   interfaccia", blocco 3) — sostituisce ogni casella di spunta
   dell'applicazione TRANNE nelle liste a selezione multipla (colonna
   atleti, canali, discipline: lì restano caselle, un interruttore in
   elenco è confuso e occupa troppo). Un vero <input type="checkbox">
   sotto, solo reso visivamente invisibile (opacity, mai display:none):
   resta navigabile da tastiera (Tab, Spazio) e dai lettori di schermo,
   l'etichetta è nello stesso <label> quindi cliccabile anch'essa senza
   bisogno di JS — tutta l'interattività è nativa del browser. */
.toggle { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; }
.toggle-input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: -1px; }
.toggle-track {
  position: relative; flex-shrink: 0; width: 38px; height: 22px; border-radius: 11px;
  background: var(--border-strong); transition: background-color 150ms var(--ease-out);
}
.toggle-thumb {
  position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 2px rgba(15, 23, 42, .3);
  transition: transform 150ms var(--ease-out);
}
/* Acceso: posizione del pallino E colore di sfondo cambiano insieme —
   mai il solo colore, riconoscibile anche senza percezione cromatica. */
.toggle-input:checked + .toggle-track { background: var(--accent); }
.toggle-input:checked + .toggle-track .toggle-thumb { transform: translateX(16px); }
.toggle-input:focus-visible + .toggle-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.toggle-input:disabled + .toggle-track { opacity: .5; cursor: not-allowed; }
.toggle:has(.toggle-input:disabled) { cursor: not-allowed; }
.toggle--warn .toggle-input:checked + .toggle-track { background: #dc2626; }
.toggle--warn .toggle-input:focus-visible + .toggle-track { outline-color: #dc2626; }
.toggle-text { font-size: var(--fs-sm); color: var(--text); }

.btn-label { display: inline-block; }

/* Blocco 9 ("rifiniture di interfaccia"): fallback generico per
   .primary/.secondary FUORI da .panel/.settings-page/.settings-section
   (es. il pulsante "Esporta EXCEL" in barra superiore) — senza, un
   pulsante con solo class="secondary" in quei contesti restava un
   controllo nativo del browser senza alcuno stile, esattamente il "non
   un collegamento nudo" che il blocco chiedeva di correggere. Bassa
   specificità (una sola classe): le regole scoped sopra continuano a
   vincere dove già si applicano, questa copre solo il resto. */
button.primary, button.secondary {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 14px; border-radius: var(--radius-sm); font-weight: 600; font-size: var(--fs-sm);
  cursor: pointer; transition: background var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
button.primary { border: none; background: var(--accent); color: var(--accent-contrast); }
button.primary:hover { opacity: .92; }
button.secondary { border: 1px solid var(--border); background: #fff; color: var(--text); }
button.secondary:hover { background: var(--bg); border-color: var(--border-strong); }

.panel button.primary, .settings-page button.primary {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 10px; border: none; border-radius: var(--radius-sm); background: var(--accent); color: var(--accent-contrast);
  font-weight: 600; cursor: pointer; position: relative;
  transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.panel button.primary:hover, .settings-page button.primary:hover { opacity: .92; }
.panel button.primary:active, .settings-page button.primary:active { transform: scale(.98); }
.panel button.secondary {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: #fff; cursor: pointer;
  position: relative; transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.panel button.secondary:hover { background: var(--bg); border-color: var(--border-strong); }

/* Pulsante in corso (5d): stessa dimensione, l'etichetta si nasconde
   (visibility, non display: lo spazio resta) e un piccolo indicatore
   ruota al centro — mai un ridimensionamento del pulsante. */
button.is-loading { pointer-events: none; }
button.is-loading .btn-label { visibility: hidden; }
button.is-loading::after {
  content: ''; position: absolute; left: 50%; top: 50%; width: 14px; height: 14px; margin: -7px 0 0 -7px;
  border-radius: 50%; border: 2px solid rgba(255, 255, 255, .45); border-top-color: #fff;
  animation: btn-spin 650ms linear infinite;
}
button.secondary.is-loading::after { border-color: var(--border-strong); border-top-color: var(--text); }
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* Sessione "selettore del tipo (terzo tentativo)...": ANNULLA la sessione
   precedente ("quattro correzioni", riga+icona a sinistra) — di nuovo tre
   riquadri impilati (colonna, non più affiancati, invariato da lì), ma
   ORA icona SOPRA il testo, non più a fianco, entrambi centrati sia in
   orizzontale che in verticale nel riquadro. Ogni riquadro a tutta
   LARGHEZZA, i tre insieme dividono l'ALTEZZA del contenitore in parti
   uguali (flex:1 sull'asse verticale, invariato). */
.type-choice { display: flex; flex-direction: column; gap: 10px; }
/* Blocco 2a (sessione precedente): sfondo = STESSE variabili delle righe
   della vista a elenco (--list-row-{type}-bg/-bg-hover in ui.css, mai una
   palette a sé) — lo stato selezionato riusa la variante "-hover", già
   "leggermente più intensa" per costruzione, non serve una terza
   intensità. --tile-color/-bg/-bg-hover impostate per tipo da
   buildTypeTileGroup() (panel.js) con lo stesso pattern di --tab-color
   altrove in questo file (panel.js, layerBadge). Icona/testo impilati e
   centrati (colonna): a differenza della sessione precedente (riga, testo
   a sinistra), qui il testo di sessione chiede esplicitamente "icona
   sopra, testo sotto, entrambi centrati" — verificato dal vivo che
   nessuna etichetta va mai a capo alla larghezza minima del pannello (le
   tre parole più lunghe, "Post social"/"Social post", restano su una riga
   sola anche a 360px, il riquadro è largo quanto l'intero pannello). */
.type-tile {
  flex: 1 1 0; min-height: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  width: 100%;
  border: 2px solid transparent;
  border-radius: var(--radius);
  background: var(--tile-bg);
  cursor: pointer;
  font: inherit;
  color: var(--text);
  padding: 14px 16px;
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
/* Icona tre volte più grande della versione a riga (30px → 90px) — testo di
   sessione esplicito ("tre volte più grande di quella attuale"). */
.type-tile-icon { width: 90px; height: 90px; display: block; flex-shrink: 0; color: var(--tile-color); }
/* Stessa correzione di .layer-tab-icon svg qui sopra: senza questa regola
   l'SVG di layerIconMarkup() resta al suo 24x24 nativo invece del 90px
   del riquadro (regola CLAUDE.md sez. 7: width/height dell'SVG come
   attributi HTML uguali al CSS, mai solo CSS). */
.type-tile-icon svg { display: block; width: 90px; height: 90px; flex-shrink: 0; }
.type-tile-label { font-size: var(--fs-lg); font-weight: 600; text-align: center; }
/* Blocco 2d: non selezionato = sfondo leggero, bordo TRASPARENTE dello
   STESSO spessore (2px, mai 0 — altrimenti il testo "salterebbe" di 2px
   passando allo stato selezionato). Fuoco/hover visibili con un bordo a
   mezza intensità (color-mix sulla stessa --tile-color, non una quarta
   variabile) senza sembrare già "selezionato" (bordo pieno, .active). */
.type-tile:hover, .type-tile:focus-visible {
  background: var(--tile-bg-active);
  border-color: color-mix(in srgb, var(--tile-color) 45%, transparent);
  outline: none;
}
.type-tile.active {
  background: var(--tile-bg-active);
  border-color: var(--tile-color);
}
/* Blocco 2c: i riquadri occupano l'intera altezza del contenitore che li
   ospita (.type-choice, non il pannello intero — il titolo sopra resta
   alla sua altezza naturale) — .panel diventa colonna flessibile SOLO in
   questa schermata (classe aggiunta da renderTypeChoice(), mai su
   .panel in generale: il resto del pannello — form di creazione/modifica —
   non deve cambiare comportamento). Dentro un contenitore flex 'float'
   sugli elementi figli non ha alcun effetto (lo standard lo azzera per
   gli elementi flex): .panel-close, normalmente float:right, finirebbe
   in cima come riga a sé invece che nell'angolo — corretto SOLO qui con
   position:absolute, scoperto testando questa schermata dal vivo, non
   toccando .panel-close per ogni altro pannello (create/modifica), dove
   il float esistente resta invariato. */
.panel.panel-type-choice { display: flex; flex-direction: column; position: relative; }
.panel.panel-type-choice .panel-close { position: absolute; top: 20px; right: 20px; float: none; }
.panel.panel-type-choice .type-choice { flex: 1; }

/* Blocco 7a, rifatto nella sessione "correzione service worker...",
   blocco 3: scelta agenzia/atleta singolo in registrazione — classe
   dedicata (mai .type-choice, pensata per un contesto diverso: la
   combinazione con l'id di qui rompeva il layout, una scheda restava
   bianca e sovrapposta). Impilate su telefono, affiancate da qui in su;
   ogni scheda porta titolo + descrizione, mai solo un'etichetta. */
.register-type-choice { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; margin-bottom: 20px; }
.register-type-card {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 6px; width: 100%; padding: 16px;
  background: var(--reg-card-bg); color: #fff;
  /* Bordo sempre 2px — trasparente quando non selezionato, arancione quando sì:
     stessa larghezza evita il layout shift al cambio di selezione. */
  border: 2px solid rgba(255,255,255,.18); border-radius: var(--radius);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.register-type-card:hover { border-color: rgba(255,255,255,.5); }
.register-type-card:focus-visible { outline: 3px solid var(--reg-card-border-active); outline-offset: 2px; }
/* Blocco 1 (sessione "Brevo che non sincronizza..."): mancava
   display:block (il markup, register.php, ora porta anche width/height
   32 come attributi HTML — vedi lì). */
.register-type-icon { display: block; width: 32px; height: 32px; color: #fff; margin-bottom: 2px; flex-shrink: 0; }
.register-type-card-title { font-size: var(--fs-md); font-weight: 600; color: #fff; }
.register-type-card-desc { font-size: var(--fs-sm); color: rgba(255,255,255,.78); }
/* Selezionato: bordo arancione — sfondo resta blu scuro, nessun layout shift */
.register-type-card.active { border-color: var(--reg-card-border-active); }
.register-type-card.active:hover { border-color: var(--reg-card-border-active); }
@media (min-width: 480px) {
  .register-type-choice { flex-direction: row; }
  .register-type-card { flex: 1; }
}

.status-badge {
  display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: 999px;
  font-size: var(--fs-xs); font-weight: 600; background: var(--bg);
}
.status-badge-tbc { color: var(--st-tbc); }
.status-badge-confirmed { color: var(--st-confirmed); }
.status-badge-cancelled { color: var(--st-cancelled); }

/* Sessione "lettura prima della modifica su mobile": contenuto della
   scheda di sola lettura (buildReadDetail, panel.js) — riusato identico
   dallo srotolamento in linea della vista elenco. */
.read-detail-title { margin: 0 0 4px; font-size: var(--fs-lg); }
.read-detail-meta { margin: 0 0 10px; color: var(--muted); font-size: var(--fs-sm); }
.read-detail-badges { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.read-detail-layer-badge {
  padding: 3px 10px; border-radius: 999px; font-size: var(--fs-xs); font-weight: 700;
  background: var(--tab-color-bg, var(--bg)); color: var(--tab-color, var(--text));
  border: 1px solid var(--tab-color, var(--border));
}
.read-detail-category-badge {
  display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px 3px 8px;
  border-radius: 999px; font-size: var(--fs-xs); font-weight: 700;
  border: 1px solid var(--border); color: var(--text);
}
.read-detail-category-badge .channel-icon { color: inherit; }
.read-detail-text { white-space: pre-wrap; margin: 0 0 14px; }
.read-detail-gallery { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.read-detail-gallery img { width: 84px; height: 84px; object-fit: cover; border-radius: var(--radius-sm); }
.read-detail-channels { display: flex; gap: 10px; margin-bottom: 14px; }
.read-detail-channels .channel-icon { width: 16px; height: 16px; color: var(--muted); }
.read-detail-channels .channel-icon svg { width: 16px; height: 16px; }
.read-detail-drive-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.read-detail-drive-file {
  display: flex; align-items: center; gap: 8px; padding: 6px 10px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  text-decoration: none; color: var(--text); font-size: var(--fs-sm);
}
.read-detail-drive-file:hover { background: var(--bg); }
.read-detail-drive-icon { width: 18px; height: 18px; }
.read-detail-validity { margin: 0 0 14px; font-size: var(--fs-sm); }
.read-detail-validity p { margin: 0 0 4px; }
.read-detail-blocca-gare { color: var(--danger); font-weight: 600; }
.media-thumb { width: 72px; height: 72px; object-fit: cover; border-radius: var(--radius-sm); margin-right: 6px; }
.media-list { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }

/* 2d: sezione avvisi nel pannello item, chiusa di default (<details> nativo). */
/* Blocco 4 ("correzione service worker..."): campi essenziali in cima al
   form, il resto sotto "Opzioni avanzate" richiudibile. Sostituisce
   .alert-section (i suoi campi ora vivono dentro .advanced-body, niente
   più un <details> annidato dentro l'altro). Sessione "correzioni
   interfaccia...", blocco 2a: tolta l'evidenziazione colorata (sfondo +
   bordo d'accento) — con il resto già nascosto sotto "Opzioni avanzate"
   non serviva più distinguere visivamente questi campi, restava solo un
   riquadro senza motivo. .field-essential resta come contenitore neutro,
   stesso ordine/spaziatura di prima. */
.field-essential { display: flex; flex-direction: column; gap: 12px; }
.advanced-section { margin-top: 4px; border-top: 1px solid var(--border); padding-top: 12px; }
.advanced-section > summary {
  cursor: pointer; font-size: var(--fs-sm); font-weight: 600; color: var(--muted); padding: 4px 0;
  list-style: none; display: flex; align-items: center; gap: 6px;
}
.advanced-section > summary::-webkit-details-marker { display: none; }
.advanced-section > summary::before { content: '▸'; font-size: 10px; transition: transform var(--dur-fast) var(--ease-out); }
.advanced-section[open] > summary::before { transform: rotate(90deg); }
.advanced-section > .advanced-body { display: flex; flex-direction: column; gap: 12px; margin-top: 10px; }
.advanced-body h3 { margin: 4px 0 0; font-size: var(--fs-sm); color: var(--muted); }

/* Sessione "pannello agenda": selezione rapida durata evento — stessa forma
   dei .filter-pill, colore neutro (nessun --pill-color per questa serie). */
.duration-picker { display: flex; flex-wrap: wrap; gap: 6px; }
.duration-pill {
  padding: 4px 11px; border-radius: 999px; border: 1px solid var(--border);
  background: #fff; color: var(--muted); font-size: var(--fs-xs); font-weight: 600; cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.duration-pill.active { background: var(--accent); color: #fff; border-color: var(--accent); }
.duration-other-fields { margin-top: 6px; width: 100%; }

/* Blocco 2b/2c ("correzioni interfaccia..."): nome dell'atleta ben
   visibile in cima al pannello in modifica, e Salva/Elimina fianco a
   fianco in fondo al posto del vecchio menu "Altro ⋯" (.menu-more/
   .menu-more-list rimosse: nessun altro le usa più). Elimina resta un
   pulsante piccolo e distinto (bordo/testo rosso, mai pieno come Salva),
   con un gap ampio così non capita di premerlo per sbaglio. */
.panel-athlete-name { font-weight: 700; font-size: var(--fs-md); color: var(--text); margin: 4px 0 12px; }
.panel-actions-row { display: flex; align-items: center; gap: 20px; }
.panel-actions-row .primary { flex: 1; }
.panel button.danger {
  flex-shrink: 0; padding: 10px 14px; border: 1px solid #fecaca; border-radius: var(--radius-sm);
  background: #fff; color: var(--danger); font-weight: 600; cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}
.panel button.danger:hover { background: #fef2f2; }

/* Blocco 5: commenti in fondo al pannello item. */
.comments-section h3 { font-size: var(--fs-sm); margin: 0 0 8px; color: var(--muted); }
.comment-row { padding: 8px 0; border-bottom: 1px solid var(--border); position: relative; }
.comment-row:last-child { border-bottom: none; }
.comment-meta { font-size: var(--fs-xs); color: var(--muted); margin-bottom: 2px; }
.comment-body { margin: 0; font-size: var(--fs-sm); white-space: pre-wrap; word-break: break-word; }
.comment-deleted p { margin: 0; font-size: var(--fs-sm); color: var(--muted); font-style: italic; }
.comment-delete {
  border: none; background: none; color: var(--muted); font-size: var(--fs-xs); cursor: pointer;
  padding: 0; margin-top: 2px; text-decoration: underline;
}
.comment-delete:hover { color: var(--danger); }
.comment-form { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.comment-form textarea { min-height: 60px; padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: var(--fs-sm); resize: vertical; }
.comment-form button { align-self: flex-end; }

/* ---------- vista atleta mobile ---------- */

.mobile-shell { max-width: 480px; margin: 0 auto; padding: 12px 12px 90px; }
.mobile-header { display: flex; justify-content: space-between; align-items: center; padding: 8px 4px 16px; }
.mobile-brand { display: flex; align-items: center; gap: 8px; }
.mobile-brand img { height: 22px; border-radius: var(--radius-sm); }
.mobile-section-title { font-size: var(--fs-sm); text-transform: uppercase; color: var(--muted); margin: 18px 0 8px; }
.mobile-card {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px; margin-bottom: 10px;
  transition: box-shadow var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.mobile-card:active { transform: scale(.99); }
.mobile-card img.cover { width: 100%; border-radius: var(--radius-sm); margin-bottom: 8px; max-height: 180px; object-fit: cover; }
.mobile-card .title { font-weight: 600; margin-bottom: 4px; }
.mobile-card .meta { font-size: var(--fs-sm); color: var(--muted); }
.mobile-actions { display: flex; gap: 8px; margin-top: 10px; }
.mobile-actions button {
  flex: 1; padding: 9px; border-radius: var(--radius-sm); border: 1px solid var(--border); background: #fff; cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.mobile-actions button:active { transform: scale(.97); }
.mobile-actions button.approve { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }

/* Sessione "ristrutturazione dell'intestazione...": .sidebar è sostituita
   su telefono da .athlete-picker (riga 2 di .header-mobile, blocco 4) —
   allineato a 767px, lo stesso punto di rottura usato in app.js
   (isMobileHeaderWidth(), matchMedia('(max-width: 767px)')) per evitare
   un intervallo in cui le due strutture non concordano. */
@media (max-width: 767px) {
  .sidebar { display: none; }
}

/* Blocco 2c (sessione "ristrutturazione dell'intestazione..."): se la
   riga 1 mobile (icona + selettore vista + menu utente) non ci sta a
   360px, si riduce — padding e font più compatti — mai uno scorrimento:
   flex-wrap resta comunque l'ultima rete di sicurezza (.header-row, più
   sopra), ma non deve mai servire davvero. Scoperto solo dentro
   .header-mobile: il desktop ha spazio a sufficienza e non deve
   restringersi. */
@media (max-width: 400px) {
  .header-mobile .view-switch button { padding: 5px 8px; font-size: var(--fs-xs); }
  .header-mobile .header-row-1-right { gap: 6px; }
}

/* Sessione "quattro correzioni", blocco 3: ANNULLA la sessione precedente
   (vedi DECISIONI.md), che faceva dipendere l'icona da quanto testo
   c'entrava a 360px — regola più semplice: su telefono e nell'app
   installata SOLO testo, mai l'icona; su desktop icona E testo, sempre.
   Un unico punto di soglia — 767px, la STESSA larghezza già usata in
   TUTTO il resto del layout mobile (isMobileHeaderWidth() in app.js,
   matchMedia('(max-width: 767px)'); .sidebar sopra usa lo stesso valore
   apposta, "per evitare un intervallo in cui le due strutture non
   concordano") — non una soglia nuova scelta per questo caso, mai una
   regola CSS a sé. Un telefono e un'app installata SU telefono sono
   entrambi, per costruzione, sotto questa soglia: non serve un controllo
   separato su display-mode:standalone, la larghezza da sola basta. */
@media (max-width: 767px) {
  .layer-tab-icon { display: none; }
}

/* Blocco 6 (sessione "filtri, campi base..."): vista mese leggibile su
   telefono. Con l'intero mese ancora costretto nella larghezza dello
   schermo (44px minimo di prima, mai raggiunto su un telefono reale) le
   celle finivano troppo strette per distinguere un item dall'altro.
   100px minimo per colonna: la griglia diventa più larga dello schermo e
   scorre in orizzontale dentro .calendar-area (CONTENITORE 3, blocco 5),
   mai la pagina intera. Su desktop nulla cambia: fuori da questa media
   query resta il minmax(44px,...) di prima, che su schermi larghi non
   scatta mai — il mese resta interamente contenuto come oggi. */
@media (max-width: 720px) {
  .month-headers, .month-week-days { grid-template-columns: repeat(7, minmax(100px, 1fr)); }
  /* Sessione "quattro correzioni", blocco 2: .bars-overlay deve restare
     sincronizzata con QUESTA regola — è esattamente il disallineamento
     con questa soglia (mai applicata all'overlay, prima di questa
     sessione) la causa del difetto su mobile. */
  .month-week .bars-overlay { grid-template-columns: repeat(7, minmax(100px, 1fr)); }
  /* L'intestazione dei giorni scorre SOLIDALE alla griglia (è un
     elemento normale nel flusso orizzontale, si sposta insieme al resto
     quando .calendar-area scorre) ma resta fissa verticalmente:
     position:sticky rispetto al proprio antenato scrollabile
     (.calendar-area) — un secondo asse indipendente dal primo, sticky
     riguarda solo l'alto/basso, mai la posizione orizzontale. */
  .month-headers { position: sticky; top: 0; z-index: 5; }
}

/* C9: pannello e vista atleta usabili da telefono — target di tocco più
   grandi, niente affordance legate solo a :hover (che su touch non scatta
   mai). Zone cliccabili di almeno 44px (6) anche quando l'elemento
   disegnato è più piccolo: il pallino di stato resta visivamente 12px ma
   la sua area di tocco cresce con un padding trasparente. */
@media (hover: none) {
  .media-cell-controls { opacity: 1; }
}
@media (max-width: 480px) {
  .panel { padding: 16px; }
  .panel input, .panel select, .panel textarea, .panel button,
  .mobile-actions button, .auth-card input, .auth-card button {
    min-height: 44px;
  }
  .status-dot { padding: 16px; margin: -16px; background-clip: content-box; }
  .type-choice button { padding: 20px 10px; }
  .floating-btn { bottom: 16px; }
  .fab { right: 16px; }
  .voice-fab { right: 88px; } /* 16 + 56 + 16, stessa logica del desktop */
  .voice-result-card { right: 16px; bottom: 88px; }
}

/* ---------- pagina profilo+impostazioni (blocco 8, "rifiniture di
   interfaccia e semplificazioni" — fonde le vecchie profilo.php e
   impostazioni.php) ---------- */

/* 8d: ~720px, centrata — un modulo a tutta larghezza su un monitor
   grande è illeggibile. Spaziatura generosa fra le sezioni (32px, non
   più 16): sono schede distinte, non un unico form lungo. Su telefono
   restano semplicemente impilate a piena larghezza (nessuna regola in
   più necessaria: sono già div in colonna). */
.settings-page { max-width: 720px; margin: 0 auto; padding: 24px 16px 60px; }
.settings-back { font-size: var(--fs-sm); color: var(--muted); text-decoration: none; }
.settings-back:hover { color: var(--accent); }
.settings-page h1 { margin: 12px 0 24px; font-size: var(--fs-lg); }
.settings-section {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: 20px; margin-bottom: 32px; box-shadow: var(--shadow-xs);
  transition: box-shadow var(--dur-slow) var(--ease-out), border-color var(--dur-slow) var(--ease-out);
}
.settings-section.section-highlight {
  border-color: var(--accent); box-shadow: var(--shadow-xs), 0 0 0 3px var(--accent-soft);
}
.settings-section h2 { margin: 0 0 14px; font-size: var(--fs-lg); }
.settings-flash { padding: 10px 14px; border-radius: var(--radius-sm); background: var(--bg); }
.settings-flash-success { background: #ecfdf5; color: #065f46; }
.settings-flash-error { background: #fef2f2; color: #991b1b; }
.settings-tabs { display: flex; gap: 0; margin-bottom: 24px; border-bottom: 1px solid var(--border); }
.settings-tab { padding: 8px 16px; font-size: var(--fs-sm); font-weight: 500; color: var(--muted); text-decoration: none; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.settings-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.settings-tab:hover { color: var(--text); }

/* Sessione "affidabilità degli aggiornamenti PWA": riquadro di avviso per
   azioni a doppia conferma tutta server-side (superadmin.php, modalità
   emergenza) — stessi colori di .settings-flash-error, un riquadro invece
   di una riga sola perché qui dentro ci sta anche il form di conferma. */
.warning-box {
  background: #fef2f2; border: 1px solid #fecaca; border-radius: var(--radius-sm);
  padding: 14px; margin-top: 12px;
}
.warning-box p { margin: 0 0 12px; color: #991b1b; font-weight: 600; }
.warning-box form { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* 8d: etichette SOPRA i campi (mai a fianco), testo di aiuto in grigio
   sotto (.form-hint, già definita altrove) — la stessa struttura di
   .panel, qui applicata a un form server-rendered invece che costruito
   via createElement. Esclude .toggle: quell'etichetta è a fianco del
   proprio interruttore per definizione (3), non sopra un campo. */
.settings-section label:not(.toggle) {
  display: block; font-size: var(--fs-sm); font-weight: 600; color: var(--text); margin: 16px 0 4px;
}
.settings-section label:not(.toggle):first-of-type { margin-top: 0; }
.settings-section input[type="text"], .settings-section input[type="email"],
.settings-section input[type="password"], .settings-section input[type="time"],
.settings-section input[type="date"], .settings-section select {
  width: 100%; padding: 9px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: var(--fs-md); box-sizing: border-box; background: #fff;
  transition: border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.settings-section input:disabled { background: var(--bg); color: var(--muted); }
.settings-section input:focus-visible, .settings-section select:focus-visible {
  border-color: var(--accent); box-shadow: var(--focus-ring); outline: none;
}
.settings-section button.primary, .settings-section button.secondary { margin-top: 16px; }
.settings-section .form-hint { margin-top: 4px; }

/* 8d: riscontro visibile al salvataggio, un pulsante per sezione — questi
   paragrafi (id "*-result") sono già .form-hint, solo un filo più
   marcati perché sono la CONFERMA, non un suggerimento passivo. */
.settings-section p.form-hint[id$="-result"] { font-weight: 600; color: var(--accent); margin-top: 8px; }

/* Righe di elenco dentro una sezione (sessioni attive, "chi vede i miei
   dati") — hairline fra loro, stesso pattern della dashboard (blocco 4):
   sono già dentro una scheda bianca, una cornice propria sarebbe una
   scatola dentro la scatola. */
.settings-list-row {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 0; border-bottom: 1px solid var(--border);
}

/* Rubriche categorie social: elenco verticale, una per riga.
   Riga: [pallino] [nome] [matita] [cestino] — sempre visibili senza
   modalità globale. Clic matita → modulo inline sotto quella riga. */
.sc-list { display: flex; flex-direction: column; margin: 8px 0 4px; }
.sc-row { display: flex; flex-direction: column; border-bottom: 1px solid var(--border); }
.sc-row:last-child { border-bottom: none; }
.sc-view-row { display: flex; align-items: center; gap: 8px; padding: 8px 0; }
.sc-swatch { width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; border: 1px solid rgba(0,0,0,.15); }
.sc-name { flex: 1; font-size: var(--fs-sm); font-weight: 500; min-width: 0; }
.sc-row-btns { display: flex; gap: 2px; flex-shrink: 0; }
.sc-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: var(--radius-sm); border: none;
  background: none; cursor: pointer; color: var(--muted);
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
/* Blocco 1 (sessione "Brevo che non sincronizza..."): nessuna regola
   dedicata per l'svg qui dentro — si affidava SOLO agli attributi HTML
   (width/height sul markup), senza display:block/flex-shrink:0. */
.sc-icon-btn svg { display: block; flex-shrink: 0; }
.sc-icon-btn:hover { background: var(--border); color: var(--text); }
.sc-icon-btn-danger:hover { background: rgba(220,38,38,.1); color: var(--danger); }
/* display non va nella regola base: .sc-edit-form { display: flex }
   avrebbe specificità 0,0,1,0 — identica a [hidden]{ display:none } del
   browser — e l'ultima dichiarata vince, rendendo il form sempre visibile.
   Soluzione: dichiarare display solo quando l'elemento NON è nascosto. */
.sc-edit-form {
  flex-direction: column; gap: 8px;
  padding: 10px 0 14px; border-top: 1px dashed var(--border);
}
.sc-edit-form:not([hidden]) { display: flex; }
.sc-edit-form-row { display: flex; gap: 8px; align-items: center; }
.sc-edit-nome { flex: 1; min-width: 0; }
.sc-edit-color { width: 40px; height: 38px; padding: 2px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: #fff; cursor: pointer; }
.sc-edit-form-btns { display: flex; gap: 8px; }
.sc-edit-form-btns button { margin-top: 0 !important; }
@media (pointer: coarse) {
  .sc-icon-btn { width: 44px; height: 44px; }
}
.social-category-add-row { display: flex; gap: 8px; align-items: center; margin-top: 12px; }
.social-category-add-row input[type="text"] { flex: 1; width: auto; }
.social-category-add-row input[type="color"] { width: 40px; height: 38px; padding: 2px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: #fff; cursor: pointer; }
.social-category-add-row button { margin-top: 0 !important; }
.settings-list-row:last-child { border-bottom: none; }
.settings-list-row .form-hint { margin: 2px 0 0; }

/* Blocco 3: contenitore per un interruttore montato via JS
   (mountToggle()/buildToggle()) — nessuno stile proprio, serve solo come
   ancora nel DOM lato PHP prima che il JS lo popoli. */
.toggle-field { margin: 16px 0; }
.toggle-field:first-child { margin-top: 0; }

/* Blocco 7: logo agenzia, anteprima + pulsanti affiancati. */
.logo-upload-row { display: flex; align-items: center; gap: 14px; }
.logo-preview {
  width: 64px; height: 64px; object-fit: contain; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--bg); padding: 4px;
}

/* Blocco 3d: pannello superadmin, un elenco di sola lettura — tabella più
   larga della colonna impostazioni, con scroll orizzontale proprio se lo
   schermo è stretto (mai la pagina intera, vedi CLAUDE.md). */
.superadmin-page { max-width: 1000px; }
.table-scroll { overflow-x: auto; }
.superadmin-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.superadmin-table th, .superadmin-table td { text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--border); white-space: nowrap; }
.superadmin-table th { color: var(--muted); font-weight: 600; }
/* Blocco 2b (sessione "... pannello di controllo ..."): agenzia inattiva
   da 30+ giorni — leggero sfondo, mai il solo colore a segnalarlo (il
   testo "inattiva da 30+ giorni" in .superadmin.inactive_30d resta
   comunque presente accanto alla data). */
.superadmin-row-inactive { background: #fef2f2; }

/* Blocco 2a/2c (sessione "... pannello di controllo ..."): registro
   attività/errori — pagina senza JS come il resto di superadmin.php, i
   filtri sono un form GET classico. */
.log-tabs { display: flex; gap: 8px; margin-bottom: 16px; }
.log-tab-inactive {
  display: inline-block; padding: 10px 18px; border-radius: var(--radius-sm); border: 1px solid var(--border);
  color: var(--text); text-decoration: none; font-weight: 600;
}
.log-tab-inactive:hover { background: var(--bg); }
.log-filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 16px; }
.log-filters select, .log-filters input {
  padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: var(--fs-sm);
}
.primary-link {
  display: inline-block; padding: 10px 18px; border-radius: var(--radius-sm); background: var(--accent);
  color: var(--accent-contrast); text-decoration: none; font-weight: 600;
  transition: opacity var(--dur-fast) var(--ease-out);
}
.primary-link:hover { opacity: .92; }

.emails-table { width: 100%; border-collapse: collapse; margin-top: 16px; font-size: var(--fs-sm); }
.emails-table th { text-align: left; font-size: var(--fs-xs); text-transform: uppercase; color: var(--muted); padding: 6px 8px; border-bottom: 1px solid var(--border); }
.emails-table td { padding: 8px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.email-status { padding: 2px 8px; border-radius: 999px; font-size: var(--fs-xs); font-weight: 600; }
.email-status-sent { background: #ecfdf5; color: #065f46; }
.email-status-pending { background: #fff7ed; color: #9a3412; }
.email-status-failed { background: #fef2f2; color: #991b1b; }

/* ---------- pagine legali (B8) ---------- */

.legal-page { max-width: 680px; margin: 0 auto; padding: 24px 16px 60px; line-height: 1.6; }
.legal-page h1 { margin: 12px 0 4px; font-size: var(--fs-lg); }
.legal-page h2 { font-size: var(--fs-lg); margin: 28px 0 8px; }
.legal-page p { color: var(--text); }
.legal-page .lang-switch { margin-top: 32px; justify-content: flex-start; }

/* ---------- dashboard (punto 3) ---------- */
.dashboard-page { flex: 1; overflow-y: auto; padding: 16px 20px 60px; }
.dashboard-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; flex-wrap: wrap; }
.dashboard-header h1 { margin: 0; font-size: var(--fs-lg); }
.dashboard-info-wrap { position: relative; margin-left: auto; }
.dashboard-info-panel {
  position: absolute; top: calc(100% + 6px); right: 0; min-width: 210px;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); padding: 4px;
  display: none; /* nascosto di default — mostrato solo con .open via JS */
  flex-direction: column; z-index: 50;
}
.dashboard-info-panel.open { display: flex; }
/* Aspetto della voce: .menu-item (regola condivisa, sopra). .dashboard-info-item
   resta solo come selettore per il JS (querySelector della prima voce, frecce). */
.dashboard-filters { display: flex; gap: 10px; margin-bottom: 16px; flex-wrap: wrap; }
.dashboard-filters select {
  padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: #fff; font-size: var(--fs-sm);
}

/* Blocco 4 ("rifiniture di interfaccia e semplificazioni"): griglia di
   schede al posto delle fasce impilate a piena larghezza — adattiva,
   minimo 320px per scheda, 2-3 colonne secondo lo spazio. Su telefono
   torna a una colonna, sia per il media query esplicito sotto sia perché
   320px + margini è già quasi tutta la larghezza di uno schermo piccolo
   (il grid non avrebbe comunque spazio per una seconda colonna). */
.dashboard-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 14px; align-items: start;
}
/* Etichetta di sezione (RICHIEDE LA TUA AZIONE / IN ARRIVO / PROBLEMI),
   a piena larghezza sopra il proprio gruppo di schede. */
.dashboard-group-label {
  grid-column: 1 / -1;
  font-size: var(--fs-sm); font-weight: 700; text-transform: uppercase; letter-spacing: .02em;
  color: var(--muted); margin: 4px 0 -2px;
}
.dashboard-group-label.danger { color: var(--danger); }

/* Superficie bianca su tela grigia (var(--bg) sul body/.dashboard-page),
   coerente con .settings-section e le altre schede dell'app. Una scheda
   con molte righe (blocco 1, fascia "richiede la tua azione") può
   occupare due colonne — vedi dashboardCard({wide:true}) in app.js, la
   soglia "molte voci" è decisa lì. */
.dashboard-card {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 14px; display: flex; flex-direction: column; gap: 10px;
}
.dashboard-card-wide { grid-column: span 2; }
@media (max-width: 680px) { .dashboard-card-wide { grid-column: span 1; } }

.dashboard-card-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.dashboard-card-title { font-size: var(--fs-sm); font-weight: 700; color: var(--text); }
.dashboard-card-count {
  display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px;
  padding: 0 6px; border-radius: 999px; background: var(--bg); color: var(--muted);
  font-size: var(--fs-xs); font-weight: 700;
}

/* Scorre al proprio interno oltre una certa altezza — "Vedi tutti" (in
   app.js, mostrato solo se il contenuto è davvero più alto del riquadro)
   la espande rimuovendo il limite, mai un taglio a un numero fisso di
   righe: l'altezza di una riga varia da sezione a sezione. */
.dashboard-card-body { display: flex; flex-direction: column; max-height: 320px; overflow-y: auto; }
.dashboard-card-body.expanded { max-height: none; overflow-y: visible; }

/* Sessione "catena dei pallini rossi": la scheda "Richiede la tua azione"
   contiene sei gruppi nominati invece di essere una fra tante schede
   pari — ogni gruppo ha una propria intestazione (nome + pallino, stesso
   .dashboard-card-count riusato) subito sopra le sue righe, senza una
   cornice ciascuno (già dentro un'unica scheda bianca). */
.dashboard-action-card .dashboard-card-body { gap: 2px; }
.dashboard-action-group-header {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 10px 2px 4px; font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: .02em; color: var(--muted);
}
.dashboard-action-group-header:first-child { padding-top: 0; }
.dashboard-card-more {
  align-self: flex-start; border: none; background: none; color: var(--accent); font-size: var(--fs-xs);
  font-weight: 600; cursor: pointer; padding: 2px 0;
}
.dashboard-card-more:hover { text-decoration: underline; }

@media (max-width: 640px) {
  .dashboard-grid { grid-template-columns: 1fr; }
}

/* Righe: hairline fra loro invece di una cornice ciascuna — sono già
   dentro una scheda bianca (.dashboard-card), un'altra cornice ciascuna
   sarebbe una scatola dentro la scatola. */
.dashboard-row {
  display: flex; align-items: center; gap: 10px; padding: 8px 2px;
  border-bottom: 1px solid var(--border); transition: background var(--dur-fast) var(--ease-out);
}
.dashboard-card-body > .dashboard-row:last-child { border-bottom: none; }
.dashboard-row:hover { background: var(--bg); }
.dashboard-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
/* Blocco 3 (sessione "filtri, campi base..."): due righe invece di una
   sola — nome atleta + titolo insieme (vedi athleteLabel() in app.js)
   erano spesso più lunghi di quanto un'unica riga troncata potesse
   mostrare, soprattutto su telefono. -webkit-line-clamp:2 tronca coi
   puntini a fine SECONDA riga (supportato da ogni motore attuale,
   incluso Firefox da tempo, nonostante il prefisso -webkit-); il testo
   per intero resta comunque nel pannello di dettaglio al clic. */
.dashboard-row-title {
  font-size: var(--fs-sm); font-weight: 600;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.dashboard-row-meta { font-size: var(--fs-xs); color: var(--muted); }
.dashboard-row-when { font-size: var(--fs-xs); font-weight: 600; color: var(--muted); white-space: nowrap; flex-shrink: 0; }
.dashboard-row-when.urgent { color: var(--danger); }
.dashboard-row-actions { display: flex; gap: 6px; flex-shrink: 0; }
.dashboard-row-actions button {
  padding: 5px 10px; border-radius: var(--radius-sm); border: 1px solid var(--border); background: #fff;
  font-size: var(--fs-xs); font-weight: 600; cursor: pointer; transition: background var(--dur-fast) var(--ease-out);
}
.dashboard-row-actions button:hover { background: var(--bg); }
.dashboard-row-actions button.primary { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }
.dashboard-row-actions button.primary:hover { opacity: .92; }
.dashboard-row-actions button.danger { color: var(--danger); border-color: #fecaca; }

.dashboard-empty {
  padding: 40px 20px; text-align: center; color: var(--muted); font-size: var(--fs-md);
}

/* Blocco 4: link pubblico atleta — pagina server-rendered, zero JS,
   "solo navigazione fra mesi, nessuna interazione" (4c). */
.public-page { max-width: 640px; margin: 0 auto; padding: 24px 16px 60px; }
.public-header { display: flex; align-items: center; gap: 14px; margin-bottom: 20px; }
.public-logo { width: 48px; height: 48px; object-fit: contain; border-radius: var(--radius-sm); }
.public-header h1 { margin: 0; font-size: var(--fs-lg); }
.public-tenant { margin: 2px 0 0; color: var(--muted); font-size: var(--fs-sm); }
.public-month-nav {
  display: flex; align-items: center; justify-content: center; gap: 20px;
  padding: 10px 0; margin-bottom: 16px; border-bottom: 1px solid var(--border); font-size: var(--fs-md);
}
.public-month-nav a { color: var(--text); text-decoration: none; font-size: var(--fs-lg); padding: 0 8px; }
.public-month-nav a:hover { color: var(--accent); }
.public-empty { text-align: center; padding: 30px 0; }
.public-item-list { list-style: none; margin: 0; padding: 0; }
.public-item-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--border); flex-wrap: wrap;
}
.public-item-date { font-size: var(--fs-sm); color: var(--muted); flex-shrink: 0; }
.public-item-body { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.public-item-layer {
  font-size: var(--fs-xs); font-weight: 600; text-transform: uppercase; letter-spacing: .02em;
  color: var(--muted); background: var(--bg); padding: 2px 8px; border-radius: 999px;
}
.public-item-title { font-size: var(--fs-sm); }

/* Blocco 6c: barra di installazione PWA — discreta, in fondo allo
   schermo, mai un overlay che blocca il resto dell'interfaccia. */
.install-banner {
  position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 80;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--text); color: #fff; padding: 12px 16px; border-radius: var(--radius);
  box-shadow: var(--shadow-lg); font-size: var(--fs-sm);
}
.install-banner-text { flex: 1; min-width: 200px; display: inline-flex; align-items: center; gap: 4px; }
.install-share-icon { display: inline-flex; vertical-align: middle; flex-shrink: 0; }
.install-share-icon svg { display: block; flex-shrink: 0; }
.install-banner-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.install-banner-actions button.primary {
  background: var(--accent); color: var(--accent-contrast); border: none; border-radius: var(--radius-sm);
  padding: 7px 14px; font-size: var(--fs-sm); font-weight: 600; cursor: pointer;
}
.install-banner-close {
  background: none; border: none; color: #fff; opacity: .7; font-size: 18px; line-height: 1;
  cursor: pointer; padding: 4px;
}
.install-banner-close:hover { opacity: 1; }
@media (min-width: 640px) {
  .install-banner { left: auto; right: 20px; bottom: 20px; max-width: 420px; }
}

/* Blocco 6 ("rifiniture di interfaccia"): icona fissa d'installazione,
   discreta — "title" nativo del browser fa da suggerimento al passaggio
   del mouse, nessun tooltip scritto a mano.
   Blocco 5 (sessione "correzioni mobile..."): su iPhone l'icona c'era, era
   toccabile, ma non si vedeva. La causa reale: nessun bottone in questo
   file resetta -webkit-appearance, quindi Safari su iOS può mantenere il
   proprio aspetto nativo (sfondo/contorno di sistema) sopra un cerchio
   custom di soli 30px con dentro un tratto sottile da 18px — sul
   simulatore desktop (Chrome/Firefox) l'aspetto nativo non si impone allo
   stesso modo, il problema non si vedeva lì. appearance:none lo
   disattiva; il colore dell'icona è impostato ESPLICITAMENTE anche sullo
   svg stesso (non solo ereditato dal bottone) come seconda rete di
   sicurezza. Icona portata a 20px (minimo di specifica) e l'area di
   tocco del bottone a 44px (idem) — il cerchio resta invisibile a
   riposo (background:none), quindi ingrandirlo non aggiunge ingombro
   visivo, solo un bersaglio di tocco più comodo. */
.install-topbar-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin-left: 8px; border: none; border-radius: 50%;
  background: none; color: var(--muted); cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.install-topbar-btn:hover { background: var(--bg); color: var(--text); }
.install-topbar-btn svg { display: block; width: 20px; height: 20px; color: var(--muted); flex-shrink: 0; }
.install-topbar-btn:hover svg { color: var(--text); }

/* Sessione "correzione service worker...", blocco 1e: rete di sicurezza a
   tutto schermo — qui è l'UNICO contenuto visibile quando compare, quindi
   può essere un overlay pieno (a differenza della barra d'installazione,
   che convive col resto dell'interfaccia). */
/* BUG scoperto in produzione: "display: flex" qui sopra, applicata SEMPRE
   dal selettore di classe, ha specificità pari alla regola [hidden] {
   display: none } del foglio di stile del browser — e un foglio
   d'autore (questo) vince sempre a parità di specificità sul foglio
   nativo, quindi l'overlay restava visibile ANCHE con l'attributo hidden
   presente: compariva a ogni caricamento, sempre, indipendentemente da un
   errore vero. :not([hidden]) sotto restringe il layout flex al solo
   caso in cui l'attributo sia stato tolto da JS (showRecovery in
   index.php), lasciando che [hidden] faccia il suo lavoro normalmente. */
.app-recovery {
  position: fixed; inset: 0; z-index: 999; background: var(--bg); padding: 24px;
}
.app-recovery:not([hidden]) { display: flex; align-items: center; justify-content: center; }
.app-recovery-box {
  max-width: 360px; text-align: center; display: flex; flex-direction: column; gap: 16px;
}
.app-recovery-box p { color: var(--text); font-size: var(--fs-md); }
.app-recovery-box button {
  background: var(--accent); color: var(--accent-contrast); border: none; border-radius: var(--radius-sm);
  padding: 10px 20px; font-size: var(--fs-sm); font-weight: 600; cursor: pointer; align-self: center;
}

/* Blocco 1g: barra "nuova versione disponibile" — stessa posizione/stile
   della barra d'installazione, mai insieme (l'installazione non ha senso
   se l'app è già aperta e sta per ricaricarsi). */
/* Stesso bug (e stessa correzione) di .app-recovery qui sopra: "display"
   ristretto a :not([hidden]), altrimenti l'attributo hidden di partenza
   nell'HTML non ha alcun effetto contro una classe con pari specificità. */
.app-update-bar {
  position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 85;
  align-items: center; justify-content: space-between; gap: 12px;
  background: var(--text); color: #fff; padding: 12px 16px; border-radius: var(--radius);
  box-shadow: var(--shadow-lg); font-size: var(--fs-sm);
}
.app-update-bar:not([hidden]) { display: flex; }
.app-update-bar button {
  background: var(--accent); color: var(--accent-contrast); border: none; border-radius: var(--radius-sm);
  padding: 7px 14px; font-size: var(--fs-sm); font-weight: 600; cursor: pointer; flex-shrink: 0;
}
@media (min-width: 640px) {
  .app-update-bar { left: auto; right: 20px; bottom: 20px; max-width: 420px; }
}

/* Blocco 2: schema illustrato dei 3 passaggi d'installazione su iOS —
   impilato su telefono (dove si vede quasi sempre), affiancato su schermi
   larghi. */
.ios-steps { display: flex; flex-direction: column; gap: 16px; margin-top: 12px; }
.ios-step { display: flex; align-items: flex-start; gap: 12px; }
.ios-step-icon {
  position: relative; flex-shrink: 0; width: 36px; height: 36px; border-radius: 50%;
  background: var(--bg); color: var(--accent); display: flex; align-items: center; justify-content: center;
}
/* Blocco 1 (sessione "Brevo che non sincronizza..."): l'svg qui dentro
   (impostazioni.php, renderIosSteps) si affidava solo ai propri attributi
   HTML, senza display:block/flex-shrink:0 — stesso difetto strutturale
   ora coperto dalla regola in CLAUDE.md sez. 7. */
.ios-step-icon svg { display: block; flex-shrink: 0; }
.ios-step-num {
  position: absolute; top: -4px; right: -4px; width: 16px; height: 16px; border-radius: 50%;
  background: var(--accent); color: var(--accent-contrast); font-size: 10px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; line-height: 1;
}
.ios-step p { margin: 0; padding-top: 6px; font-size: var(--fs-sm); color: var(--text); }
@media (min-width: 640px) {
  .ios-steps { flex-direction: row; flex-wrap: wrap; }
  .ios-step { flex: 1 1 160px; flex-direction: column; align-items: center; text-align: center; }
  .ios-step p { padding-top: 0; }
}

/* ============================================================
   PAGINA DOCUMENTAZIONE (documentazione.php)
   ============================================================ */
.docs-page { background: var(--bg); min-height: 100dvh; }

.docs-topbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 12px;
  padding: 0 16px; height: 52px;
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.docs-back {
  display: flex; align-items: center; gap: 6px;
  color: var(--text); font-size: var(--fs-sm); font-weight: 600;
  text-decoration: none; flex-shrink: 0;
}
.docs-back:hover { color: var(--accent); }
.docs-back svg { display: block; flex-shrink: 0; }

.docs-search-wrap { flex: 1; position: relative; max-width: 360px; }
.docs-search {
  width: 100%; padding: 6px 12px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--bg);
  color: var(--text); font-size: var(--fs-sm); box-sizing: border-box;
}
.docs-search:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-alpha); }
.docs-search-results {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); z-index: 50; max-height: 380px; overflow-y: auto;
}
.docs-search-hit {
  display: flex; flex-direction: column; gap: 2px;
  padding: 10px 14px; text-decoration: none; color: var(--text);
  border-bottom: 1px solid var(--border-subtle);
}
.docs-search-hit:last-child { border-bottom: none; }
.docs-search-hit:hover { background: var(--bg); }
.docs-search-hit strong { font-size: var(--fs-sm); color: var(--accent); }
.docs-search-hit span { font-size: var(--fs-xs); color: var(--text-muted); line-height: 1.45; }
.docs-search-empty { padding: 14px; font-size: var(--fs-sm); color: var(--text-muted); text-align: center; }

.docs-layout { display: flex; min-height: calc(100dvh - 52px); }

/* Sidebar navigazione */
.docs-nav {
  width: 220px; flex-shrink: 0; padding: 20px 12px;
  border-right: 1px solid var(--border); position: sticky;
  top: 52px; height: calc(100dvh - 52px); overflow-y: auto;
}
.docs-chapter-select { display: none; }
.docs-chapter-list { list-style: none; margin: 0; padding: 0; }
.docs-chapter-list li { margin: 2px 0; }
.docs-chapter-link {
  display: block; padding: 6px 10px; border-radius: var(--radius-sm);
  font-size: var(--fs-sm); color: var(--text-muted); text-decoration: none;
  transition: background .12s, color .12s;
}
.docs-chapter-link:hover { background: var(--bg); color: var(--text); }
.docs-chapter-link.active { background: var(--accent-light); color: var(--accent); font-weight: 600; }

/* Area contenuto */
.docs-content {
  flex: 1; padding: 32px 24px; max-width: 780px;
  min-width: 0; /* prevent overflow */
}
.docs-chapter-header { margin-bottom: 24px; }
.docs-chapter-header h1 { font-size: var(--fs-xl); font-weight: 700; margin: 0 0 6px; color: var(--text); }
.docs-updated { font-size: var(--fs-xs); color: var(--text-muted); margin: 0; }

/* Indice paragrafi (TOC) */
.docs-toc {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 14px 18px; margin-bottom: 28px;
}
.docs-toc-label { font-size: var(--fs-xs); font-weight: 700; color: var(--text-muted); margin: 0 0 8px; text-transform: uppercase; letter-spacing: .04em; }
.docs-toc ol { margin: 0; padding: 0 0 0 18px; }
.docs-toc li { margin: 4px 0; }
.docs-toc a { font-size: var(--fs-sm); color: var(--text-muted); text-decoration: none; }
.docs-toc a:hover, .docs-toc a.active { color: var(--accent); }

/* Corpo del documento */
.docs-body { font-size: var(--fs-md); color: var(--text); line-height: 1.7; }
.docs-body h2 { font-size: var(--fs-lg); font-weight: 700; margin: 36px 0 12px; color: var(--text); border-bottom: 1px solid var(--border); padding-bottom: 6px; }
.docs-body h3 { font-size: var(--fs-md); font-weight: 700; margin: 24px 0 8px; color: var(--text); }
.docs-body h4 { font-size: var(--fs-sm); font-weight: 700; margin: 18px 0 6px; color: var(--text); }
.docs-body p { margin: 0 0 14px; }
.docs-body ul, .docs-body ol { margin: 0 0 14px 20px; padding: 0; }
.docs-body li { margin: 4px 0; }
.docs-body blockquote {
  border-left: 3px solid var(--accent); padding: 10px 16px; margin: 0 0 14px;
  background: var(--accent-light); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--text); font-style: italic;
}
.docs-body code {
  background: var(--bg); border: 1px solid var(--border); border-radius: 4px;
  padding: 1px 5px; font-size: .88em; font-family: monospace;
}
.docs-body a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.docs-body a:hover { text-decoration: none; }

/* Ancora per i titoli */
.doc-anchor {
  font-size: .75em; color: var(--text-muted); text-decoration: none;
  opacity: 0; margin-left: 6px; transition: opacity .15s;
}
h2:hover .doc-anchor, h3:hover .doc-anchor, h4:hover .doc-anchor { opacity: 1; }

/* Blocco "da verificare" */
.doc-verify {
  background: #fef3c7; border: 1px solid #f59e0b; border-radius: var(--radius-sm);
  padding: 10px 14px; margin-bottom: 14px; font-size: var(--fs-sm); color: #92400e;
}
[data-theme="dark"] .doc-verify { background: #451a03; border-color: #d97706; color: #fde68a; }

/* Segnaposto screenshot */
.doc-placeholder {
  background: var(--bg); border: 2px dashed var(--border); border-radius: var(--radius);
  padding: 24px; text-align: center; color: var(--text-muted); font-size: var(--fs-sm);
  margin: 0 0 14px;
}

/* Mobile: sidebar → select */
@media (max-width: 639px) {
  .docs-nav {
    width: 100%; position: static; height: auto; border-right: none;
    border-bottom: 1px solid var(--border); padding: 10px 14px;
  }
  .docs-chapter-select {
    display: block; width: 100%; padding: 7px 10px; border-radius: var(--radius-sm);
    border: 1px solid var(--border); background: var(--bg); color: var(--text);
    font-size: var(--fs-sm);
  }
  .docs-chapter-list { display: none; }
  .docs-layout { flex-direction: column; }
  .docs-content { padding: 20px 16px; }
  .docs-search-wrap { display: none; }
}

/* ============================================================
   TOUR ONBOARDING (driver.js override + checklist "Primi passi")
   ============================================================
   driver.js 1.3.1 porta il suo CSS (assets/vendor/driver.css) —
   qui si sovrascrivono solo i selettori che entrano nel tema
   AthlonFlow (colori, radius, ombre). Nessuna regola strutturale
   di driver è cambiata: si tocca solo l'estetica del popover. */

/* Popover driver.js */
.driver-popover {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  max-width: 340px;
}
.driver-popover-title {
  color: var(--text);
  font-weight: 700;
  font-size: var(--fs-md);
}
.driver-popover-description {
  color: var(--text);
  font-size: var(--fs-sm);
  line-height: 1.55;
}
.driver-popover-footer button {
  border-radius: var(--radius-sm);
  padding: 7px 14px;
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
}
.driver-popover-next-btn {
  background: var(--accent);
  color: var(--accent-contrast);
  border: none;
}
.driver-popover-next-btn:hover { background: var(--accent-hover); }
.driver-popover-prev-btn {
  background: transparent;
  color: var(--muted);
  border: none;
}
.driver-popover-close-btn { color: var(--muted); }
.driver-popover-progress-text {
  color: var(--muted);
  font-size: var(--fs-xs);
}
/* Frecce del popover (le 4 direzioni) — il colore del bordo lato "interno"
   della freccia va sincronizzato al colore del popover. */
.driver-popover-arrow-side-left .driver-popover-arrow { border-left-color: var(--bg); }
.driver-popover-arrow-side-right .driver-popover-arrow { border-right-color: var(--bg); }
.driver-popover-arrow-side-top .driver-popover-arrow { border-top-color: var(--bg); }
.driver-popover-arrow-side-bottom .driver-popover-arrow { border-bottom-color: var(--bg); }

/* Sezione "Perché?" espandibile nel popover (buildDesc in tour.js). */
.tour-why { margin-top: 10px; }
.tour-why > summary {
  font-size: var(--fs-xs);
  color: var(--accent);
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.tour-why > summary::-webkit-details-marker { display: none; }
.tour-why > summary::before { content: '?'; display: inline-block; margin-right: 4px; }
.tour-why-body {
  font-size: var(--fs-xs);
  color: var(--muted);
  margin-top: 6px;
  line-height: 1.5;
}

/* Barra fissa "Riprendi la guida" — showResumeReminder in tour.js. */
.tour-resume-bar {
  position: fixed;
  bottom: 12px;
  left: 12px;
  z-index: 9000;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: 10px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--fs-sm);
  color: var(--text);
}
.tour-resume-bar button {
  cursor: pointer;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  padding: 6px 12px;
}
#tour-resume-btn {
  background: var(--accent);
  color: var(--accent-contrast);
  border: none;
  font-weight: 600;
}
#tour-resume-btn:hover { background: var(--accent-hover); }
#tour-resume-dismiss {
  background: transparent;
  color: var(--muted);
  border: none;
  font-size: 18px;
  line-height: 1;
  padding: 4px 8px;
}

/* Checklist "Primi passi" nella dashboard. */
.onboarding-checklist {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 20px;
  transition: opacity .5s ease;
}
.onboarding-checklist.onboarding-fadeout { opacity: 0; }
.onboarding-checklist-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.onboarding-checklist-header h3 {
  font-size: var(--fs-md);
  font-weight: 700;
  margin: 0;
  color: var(--text);
}
.onboarding-checklist-close {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  padding: 4px 8px;
}

.onboarding-restart-note {
  font-size: var(--fs-sm);
  color: var(--muted);
  background: var(--surface);
  border-left: 3px solid var(--accent);
  padding: 6px 10px;
  margin: 0 0 12px;
  border-radius: 0 var(--radius) var(--radius) 0;
}
.onboarding-progress {
  height: 6px;
  background: var(--border);
  border-radius: 3px;
  margin-bottom: 14px;
  overflow: hidden;
}
.onboarding-progress-bar {
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
  transition: width .3s ease;
}
.onboarding-steps {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.onboarding-step {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--fs-sm);
  color: var(--text);
}
.onboarding-check {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 2px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  flex-shrink: 0;
  color: transparent;
}
.onboarding-step.done .onboarding-check {
  background: var(--accent);
  border-color: var(--accent);
  color: white;
}
.onboarding-step.todo .onboarding-label { color: var(--muted); }
.onboarding-action {
  margin-left: auto;
  font-size: var(--fs-xs);
  color: var(--accent);
  background: none;
  border: none;
  cursor: pointer;
  text-decoration: underline;
  font-weight: 600;
}
.onboarding-complete {
  text-align: center;
  color: var(--accent);
  font-weight: 600;
  margin-top: 12px;
  font-size: var(--fs-sm);
}

/* Riavvia il tour: pulsanti nella pagina profilo (Blocco H). */
.tour-restart-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 8px;
}
.tour-restart-btn { align-self: flex-start; }

/* Banner "Vuoi rifare il giro?" nella pagina documentazione. */
.docs-tour-banner {
  background: var(--accent-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
  font-size: var(--fs-sm);
  color: var(--text);
}
.docs-tour-banner button {
  background: var(--accent);
  color: var(--accent-contrast);
  border: none;
  border-radius: var(--radius-sm);
  padding: 6px 12px;
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
}
/* Avviso lingua di fallback — capitolo non disponibile nella lingua scelta. */
.docs-lang-notice {
  background: var(--warn-soft, #fefce8);
  border: 1px solid var(--warn-border, #fde68a);
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  font-size: var(--fs-sm);
  color: var(--text);
  margin-bottom: 16px;
}

