﻿/* ====================================================================== */
/* THEME TOKENS : "Carta e inchiostro" — warm paper, violet ink,          */
/* evidenziatore highlight. Light default + Lavagna-di-sera dark.         */
/* ====================================================================== */
/* ====================================================================== */
/* FONT IN CASA — Inter e Space Grotesk li serviamo noi, non Google.       */
/*                                                                        */
/* Prima di questo blocco OGNI pagina apriva una catena esterna in testa   */
/* al rendering: DNS + TLS verso fonts.googleapis.com → foglio CSS → DNS   */
/* + TLS verso fonts.gstatic.com → woff2. Due handshake su due host terzi  */
/* PRIMA che il primo carattere potesse essere disegnato, e il titolo      */
/* della home — che è l'elemento LCP, testo, non immagine — aspettava lì.  */
/*                                                                        */
/* I file sono ESATTAMENTE quelli che serviva Google (subset `latin` e     */
/* `latin-ext`, woff2 VARIABILI: un solo file copre 400/500/600/700, per   */
/* questo i pesi qui sono un intervallo e non quattro @font-face). Scarico */
/* una tantum, committati in assets/fonts/, licenza SIL OFL 1.1.          */
/*                                                                        */
/* `font-display: swap`: il testo si vede SUBITO col font di sistema e     */
/* viene ridisegnato appena il woff2 arriva. Mai testo invisibile, mai un  */
/* LCP che aspetta un font.                                               */
/*                                                                        */
/* Gli `unicode-range` sono quelli originali: `latin-ext` viene scaricato  */
/* SOLO se in pagina compare un carattere che sta in quell'intervallo      */
/* (nomi polacchi, turchi, cechi…), quindi su una pagina italiana costa    */
/* zero byte. L'italiano — accenti ed € compresi — sta tutto in `latin`.   */
/*                                                                        */
/* Conseguenza sulla CSP: fonts.googleapis.com e fonts.gstatic.com sono    */
/* USCITI da style-src e font-src, nei meta di ogni pagina e nel template  */
/* nginx. Un permesso in meno è un permesso in meno.                       */
/* ====================================================================== */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/fonts/inter-latin.woff2?v=3100e775") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/fonts/inter-latin-ext.woff2?v=34b9c504") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* SPACE GROTESK NON STA QUI — sta in `space-grotesk.css`, e lo caricano SOLO le dieci
   pagine che lo chiedevano anche prima a Google. Non è un capriccio: `style.css` lo
   leggono tutte e 62 le pagine, e diverse regole di questo stesso file dicono
   `font-family: "Space Grotesk", "Inter", …` (.hero__title, .section__header h2,
   .sk-welcome__title, .plan-card__name). Finché il font arrivava da un <link> per
   pagina, sulle altre 52 quel primo nome non risolveva e il titolo cadeva su Inter —
   che è come quelle pagine sono sempre state viste. Dichiarare qui il @font-face le
   avrebbe cambiate tutte di aspetto, e regalato a ciascuna 22 KB di font in più che
   prima non scaricava: una regressione travestita da ottimizzazione (misurata il
   2026-08-10: LCP di dashboard.html da 4,32 s a 4,72 s). */

:root {
  --bg0: #f7f6f2;
  --bg1: #ffffff;
  --bg2: #f3f1ec;
  /* Ink: warm violet-black instead of slate. */
  --text: #1d1a2b;
  /* --muted: WCAG 2.1 AA. #575468 on #ffffff ≈ 5.4:1, on #f7f6f2 ≈ 5.0:1,
     on #f3f1ec ≈ 4.8:1 (AA pass for normal text). */
  --muted: #575468;
  /* --dim: computed RGB ≈ #5f5c70 over the paper surfaces → ≥4.6:1 (AA). */
  --dim: rgba(29, 26, 43, 0.68);
  --border: #e6e3da;
  --accent-violet: #7857f0;
  --accent-blue: #4f5df0;
  /* Primary action ink-indigo: #5546d6 on #fff = 6.5:1 (AA normal text). */
  --accent: #5546d6;
  /* Text links on light surfaces: #4338ca on #fff = 7.9:1. */
  --accent-ink: #4338ca;
  --accent-soft: rgba(85, 70, 214, 0.10);
  /* Evidenziatore: marker-yellow swipe behind ink text (decorative bg only;
     ink #1d1a2b on top stays ≥ 12:1). */
  --hl: rgba(255, 216, 77, 0.5);
  --radius-card: 16px;
  --radius-control: 12px;
  --radius-pill: 999px;
  /* Violet-tinted soft elevation. */
  --shadow-s: 0 1px 2px rgba(45, 35, 90, 0.06), 0 2px 8px rgba(45, 35, 90, 0.06);
  --shadow-m: 0 2px 4px rgba(45, 35, 90, 0.06), 0 10px 24px rgba(45, 35, 90, 0.10);
  --shadow-l: 0 4px 8px rgba(45, 35, 90, 0.07), 0 18px 40px rgba(45, 35, 90, 0.14);
  /* Ex-neon glows, demoted to quiet selected-state emphasis. */
  --glow-s: 0 0 0 1px rgba(85, 70, 214, 0.22), 0 2px 10px rgba(85, 70, 214, 0.10);
  --glow-m: 0 0 0 1px rgba(85, 70, 214, 0.28), 0 4px 16px rgba(85, 70, 214, 0.16);
  --glow-l: 0 0 0 1px rgba(85, 70, 214, 0.32), 0 8px 26px rgba(85, 70, 214, 0.20);
  /* Crisp two-ring focus (visible on every surface, forced-colors friendly). */
  --focus-ring: 0 0 0 2px var(--bg1), 0 0 0 4px rgba(85, 70, 214, 0.9);
  --gradient-accent: linear-gradient(120deg, var(--accent-violet), var(--accent-blue));
  --bg: var(--bg0);
  --card: var(--bg1);
  --surface-1: var(--bg1);
  --surface-2: var(--bg2);
  --primary: var(--accent);
  --primary-soft: var(--accent-soft);
  --shadow: var(--shadow-s);
  --shadow-strong: var(--shadow-m);
  --glass: rgba(255, 255, 255, 0.78);
  --border-soft: var(--border);
  --border-strong: rgba(29, 26, 43, 0.14);
  /* Aliases consumed by legacy rules (were undefined → broken box-shadows). */
  --glow-primary: var(--glow-s);
  --glow-strong: var(--glow-m);
  --warning: var(--color-warning);
}

:root.dark {
  /* Lavagna di sera: violet-black, no neon. */
  --bg0: #0f0d16;
  --bg1: #15121f;
  --bg2: #1b1728;
  --text: rgba(244, 242, 250, 0.95);
  --muted: rgba(226, 222, 240, 0.72);
  /* --dim over dark surfaces ≥ 4.8:1 (AA). */
  --dim: rgba(244, 242, 250, 0.64);
  --border: rgba(255, 255, 255, 0.09);
  --border-soft: rgba(255, 255, 255, 0.09);
  --border-strong: rgba(255, 255, 255, 0.14);
  --accent-violet: #a78bfa;
  --accent-blue: #8b9dff;
  --accent: #8b9dff;
  /* Links on dark surfaces: light periwinkle ≈ 8:1 on #15121f. */
  --accent-ink: #b6a8ff;
  --accent-soft: rgba(139, 157, 255, 0.14);
  --hl: rgba(167, 139, 250, 0.28);
  --shadow-s: 0 2px 6px rgba(0, 0, 0, 0.35);
  --shadow-m: 0 6px 18px rgba(0, 0, 0, 0.45);
  --shadow-l: 0 14px 40px rgba(0, 0, 0, 0.55);
  --glow-s: 0 0 0 1px rgba(139, 157, 255, 0.28), 0 2px 10px rgba(139, 157, 255, 0.10);
  --glow-m: 0 0 0 1px rgba(139, 157, 255, 0.34), 0 4px 16px rgba(139, 157, 255, 0.14);
  --glow-l: 0 0 0 1px rgba(139, 157, 255, 0.40), 0 8px 26px rgba(139, 157, 255, 0.18);
  --focus-ring: 0 0 0 2px var(--bg1), 0 0 0 4px rgba(182, 168, 255, 0.9);
  --gradient-accent: linear-gradient(120deg, var(--accent-violet), var(--accent-blue));
  --bg: var(--bg0);
  --card: var(--bg1);
  --surface-1: var(--bg1);
  --surface-2: var(--bg2);
  --primary: var(--accent);
  --primary-soft: var(--accent-soft);
  --shadow: var(--shadow-s);
  --shadow-strong: var(--shadow-m);
  --glass: rgba(21, 18, 31, 0.82);
  --glow-primary: var(--glow-s);
  --glow-strong: var(--glow-m);
}

/* Guide (6/10/2026): i colori «carta» che le 600 guide usano con un ripiego chiaro scritto fisso
   (`var(--carta-2,#fbfaf5)`…). Col tema chiaro valgono come il ripiego; col scuro seguono la
   lavagna, invece di riquadri crema con testo chiaro. */
:root { --carta: #f4f1e9; --carta-2: #fbfaf5; --line: #ddd7c6; --line-2: #eae4d5; --ink: #1d1a2b; --ink-2: #403a56; --indaco: #5546d6; }
:root.dark { --carta: var(--bg2); --carta-2: var(--bg1); --line: rgba(255,255,255,.12); --line-2: rgba(255,255,255,.08); --ink: var(--text); --ink-2: rgba(244,242,250,.86); --indaco: #a78bfa; }
:root.dark .invito { background: var(--bg1); }
.guide .tl a.btn { display: block; width: fit-content; margin: 12px 0 4px; }
.guide .tl .invito__app { display: inline-block; margin-top: 6px; }

/* ====================================================================== */
/* ADDITIVE TOKENS (Slice 1) — spacing, type, semantic colors, z-index    */
/* All additive: do not rename or remove existing tokens.                 */
/* ====================================================================== */
:root {
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 64px;
  --text-xs: 12px; --text-sm: 14px; --text-base: 16px; --text-lg: 18px;
  --text-xl: 22px; --text-2xl: 28px; --text-3xl: 36px;
  --lh-tight: 1.2; --lh-base: 1.5; --lh-loose: 1.7;
  --color-success: #16a34a;
  --color-warning: #d97706;
  --color-danger: #dc2626;
  /* Varianti da TESTO (WCAG 1.4.3, 4,5:1): i token qui sopra sono sotto soglia su fondo
     chiaro — 3,30:1 il verde e 3,19:1 l'ambra. Restano giusti per bordi, sfondi e icone
     (1.4.11 chiede 3:1); dove colorano parole si usano questi: 5,02:1 su bianco entrambi. */
  --color-success-ink: #15803d;
  --color-warning-ink: #b45309;
  --color-info: var(--accent-blue);
  /* Identita' cromatica delle tre modalita' (Tutor / Orale / Esercizi). Le tinte delle pill
     non reggono il contrasto (#3b82f6 = 3,68:1 su bianco, #f59e0b = 2,15:1): questi sono i
     corrispettivi da bordo/icona, misurati su --bg0 e sul fondo tinto del pulsante —
     4,57:1 il piu' debole (l'ambra), contro il 3:1 che chiede la 1.4.11. Non portano MAI
     parole: l'etichetta resta --text (≥13,5:1 sul fondo tinto). */
  --mode-tutor: #1d4ed8;
  --mode-orale: #b45309;
  --mode-quiz: #6d28d9;
  --shadow-focus: var(--focus-ring);
  --z-nav: 40;
  --z-popover: 50;
  --z-modal: 60;
  --z-toast: 70;
  --ai-pill-bg: linear-gradient(120deg,
    color-mix(in srgb, var(--accent-violet) 18%, transparent),
    color-mix(in srgb, var(--accent-blue) 18%, transparent));
  --ai-pill-border: color-mix(in srgb, var(--accent-violet) 30%, transparent);
}
:root.dark {
  --color-success: #22c55e;
  --color-warning: #f59e0b;
  --color-danger: #ef4444;
  /* Su fondo scuro i token base sono gia' a 8,10:1 e 8,59:1: la variante da testo coincide. */
  --color-success-ink: #22c55e;
  --color-warning-ink: #f59e0b;
  /* Al buio le stesse tinte si invertono di chiarezza: bordo/icona ≥7,57:1 sul fondo tinto. */
  --mode-tutor: #93c5fd;
  --mode-orale: #fbbf24;
  --mode-quiz: #c4b5fd;
}

/* ====================================================================== */
/* UTILITY CLASSES (Slice 1) — token-based; replace inline styles         */
/* ====================================================================== */
.u-row { display: flex; gap: var(--space-3); align-items: center; }
.u-row--end { justify-content: flex-end; }
.u-stack-1 { display: flex; flex-direction: column; gap: var(--space-1); }
.u-stack-2 { display: flex; flex-direction: column; gap: var(--space-2); }
.u-stack-3 { display: flex; flex-direction: column; gap: var(--space-3); }
.u-flex-1 { flex: 1; }
.u-text-center { text-align: center; }
.u-mt-2 { margin-top: var(--space-2); }
.u-mt-3 { margin-top: var(--space-3); }
.u-my-2 { margin-top: var(--space-2); margin-bottom: var(--space-2); }
.u-mb-3 { margin-bottom: var(--space-3); }
.u-mb-4 { margin-bottom: var(--space-4); }
.u-mb-5 { margin-bottom: var(--space-5); }
.u-pad-card { padding: var(--space-5); }
.u-narrow { max-width: 800px; margin-inline: auto; }
.u-h2 { font-weight: 600; }
.u-empty-pad { padding: var(--space-5); text-align: center; }
.u-empty-pad--full { grid-column: 1 / -1; }
.u-empty-emoji { font-size: 48px; margin-bottom: var(--space-3); }
.u-skel-w-sm { width: 80px; }
.u-skel-w-md { width: 100px; }
.u-skel-w-lg { width: 150px; }
.u-skel-w-xl { width: 180px; }
.u-skel-w-2xl { width: 200px; }
.u-skel-mb { margin-bottom: var(--space-1); }
.u-alert-pad { padding: var(--space-4); }
.u-alert-pad--full { padding: var(--space-4); grid-column: 1 / -1; }

/* Consent checkbox group (register.html) */
.consent-checkboxes {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-4) 0;
}
.consent-label {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  font-size: var(--text-sm);
  cursor: pointer;
}
.consent-label input[type="checkbox"] { margin-top: 0.2rem; }

/* Accent left-border variant (e.g. dashboard "I miei progressi" card) */
.action-card--accent { border-left: 3px solid var(--accent-violet); }

/* ====================================================================== */
/* AI TRANSPARENCY PILL (EU AI Act Art. 50)                                */
/* Canonical class for AI-generated content disclosure.                   */
/* Existing inline AI pill markups continue to work; new code uses this.  */
/* ====================================================================== */
.ai-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  background: var(--ai-pill-bg);
  border: 1px solid var(--ai-pill-border);
  color: var(--text);
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: var(--lh-tight);
  position: relative;
  cursor: help;
}
.ai-pill::before {
  content: "✨";
  font-size: 12px;
  line-height: 1;
}
.ai-pill[data-tooltip]:hover::after,
.ai-pill[data-tooltip]:focus-visible::after {
  content: attr(data-tooltip);
  position: absolute;
  left: 0;
  top: calc(100% + 6px);
  z-index: var(--z-popover);
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-control);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-xs);
  font-weight: 500;
  white-space: normal;
  width: max-content;
  max-width: 260px;
  box-shadow: var(--shadow-m);
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .ai-pill { transition: none; }
}

* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
  /* Colonna a tutta altezza: il footer resta in fondo anche sulle pagine corte
     (prima restava a metà con una banda vuota sotto). */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
body > main,
body > .page { flex: 1 0 auto; }
body > .footer { margin-top: auto; }
/* I campi testo ereditano il font dell'app (le textarea cadevano sul monospace UA). */
textarea { font: inherit; }
a { color: inherit; text-decoration: none; }
/* I LINK DENTRO LE GUIDE SI DEVONO VEDERE (20/9/2026). La regola qui sopra va bene per l'app, dove
   ogni link è un bottone, una scheda o una voce di menu col suo stile. Nelle ~520 guide i link
   stanno DENTRO il testo («Argomenti collegati», «tutte le guide», «manda alla classe su
   WhatsApp») e uscivano identici al testo: stesso colore, nessuna sottolineatura — misurato in
   produzione, 11-18 link invisibili per pagina. Chi arriva da Google non vedeva dove andare, ed è
   anche WCAG 1.4.1 (un link non si distingue col solo contesto). `--accent-ink` è il gettone già
   pensato per il testo-link, chiaro e scuro. I bottoni (`.btn`) restano bottoni. */
.guide a:not(.btn) { color: var(--accent-ink); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.guide a:not(.btn):hover, .guide a:not(.btn):focus-visible { text-decoration-thickness: 2px; }

/* ====================================================================== */
/* THEME OVERRIDES (Skooly Neon Dark)                                      */
/* ====================================================================== */
:root {
  color-scheme: light;
}
:root.dark {
  color-scheme: dark;
}
*,:focus { outline-color: transparent; }
*:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Qui c'era il terzo fondo della barra, `--bg0`, in chiaro e in scuro. Quello
   scuro era il peggiore: `:root.dark .navbar` pesa (0,2,1) e batteva sia
   `.navbar` sia `.navbar.scrolled` del blocco NAVIGAZIONE 2026 — al buio la
   barra restava piena, con ombra e alone fissi, e lo stato «scrolled» non
   poteva cambiare niente. Il vetro c'era solo di giorno. */
.navbar__inner { gap: 12px; }
.navbar__logo img { filter: none; }
.navbar__links .navlink {
  color: var(--muted);
  border-radius: var(--radius-pill);
  padding: 8px 14px;
}
.navbar__links .navlink:hover,
.navbar__links .navlink.navlink--active {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 14%, var(--bg1));
  box-shadow: var(--glow-s);
}
.navbar__actions .btn { box-shadow: none; }

.card,
.panel,
.pricing-card,
.pricing-hero__glance,
.profile-panel,
.note-modal,
.history-card,
.subject-row,
.activity-item,
.materials-row,
.materials-head {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-s);
}
:root.dark .card,
:root.dark .panel,
:root.dark .pricing-card,
:root.dark .pricing-hero__glance,
:root.dark .profile-panel,
:root.dark .note-modal,
:root.dark .history-card,
:root.dark .subject-row,
:root.dark .activity-item,
:root.dark .materials-row,
:root.dark .materials-head {
  background: var(--surface-1);
  box-shadow: var(--shadow-m);
}
.card:hover { box-shadow: var(--shadow-m); border-color: var(--border-strong); }

.btn {
  border-radius: var(--radius-control);
  box-shadow: none;
}
.btn--primary {
  background: var(--gradient-accent);
  color: #fff;
  border: 1px solid transparent;
  box-shadow: var(--glow-m);
}
.btn--ghost {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  color: var(--text);
}
.btn--danger { background: #ef4444; color: #fff; }
/* Usata da contesto.js (CTA «Aggiungi materiale» su tutor/orale) e mai definita: il
   bottone usciva coi colori di default del browser — in tema scuro sembrava SPENTO
   (visita qualitativa 2026-08-09, S1). Stessi token del primario. */
.btn--accent {
  background: var(--gradient-accent);
  color: var(--on-accent, #fff);
  border: 1px solid transparent;
  box-shadow: var(--glow-m);
}
.btn:focus-visible { box-shadow: var(--focus-ring); }
/* Le tabelle larghe scorrono nel PROPRIO riquadro, mai la pagina intera (S2/S3). */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.input,
textarea,
select {
  border-radius: var(--radius-control);
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  color: var(--text);
  box-shadow: none;
}
.input:focus,
textarea:focus,
select:focus {
  box-shadow: var(--focus-ring);
  border-color: var(--accent);
}
::placeholder { color: var(--muted); }

.pill,
.chip,
.pref-item,
.tab-btn {
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-soft);
  background: var(--surface-1);
  color: var(--text);
  box-shadow: none;
}
.pill--accent,
.tab-btn.active {
  background: var(--gradient-accent);
  color: #fff;
  box-shadow: var(--glow-s);
  border-color: transparent;
}

.modal,
.note-modal,
.profile-panel {
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-l);
}
.note-modal-backdrop,
.profile-panel::backdrop {
  background: rgba(0,0,0,0.6);
  backdrop-filter: blur(6px);
}

.status-bar,
.alert,
.materials-head {
  background: color-mix(in srgb, var(--surface-1) 90%, var(--accent) 10%);
  border-color: var(--border-soft);
}

.transcript,
.option,
.materials-row:hover,
.history-card:hover,
.activity-item:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-m);
}

.navbar,
.btn,
.card,
.input,
textarea,
select,
.pill,
.chip,
.tab-btn { transition: all 0.18s ease; }

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

.container {
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 18px;
}

/* Posizione, fondo, bordo, ombra e vetro della barra stanno TUTTI nel blocco
   «NAVIGAZIONE 2026» in fondo al file (`.navbar` + `.navbar::before`). Qui
   resta il solo inchiostro: ridichiararli anche qui non era ridondanza
   innocua, era la falla. La cascata sovrascrive proprieta', non regole — e
   ogni proprieta' che il blocco nuovo non ripete (era il caso di
   `backdrop-filter`) sopravviveva qui, rifacendo di `.navbar` un containing
   block per i figli `position: fixed` e un backdrop root che lasciava lo
   pseudo-elemento senza niente da sfocare. Un fondo per la barra si dichiara
   in un posto solo. */
.navbar {
  color: var(--text);
}
.navbar__inner {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 10px 28px;
}
.navbar__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
.theme-toggle {
  display: none;
}
.navbar__logo img {
  /* logo.png/logo-scuro.png ritagliati sul contenuto (805x243, ~3.3:1):
     30px di altezza = wordmark leggibile ma discreto, non domina la navbar. */
  height: 30px;
  width: auto;
  display: block;
  object-fit: contain;
}
.navbar__links {
  display: flex;
  gap: 14px;
  align-items: center;
  flex: 1;
  justify-content: flex-start;
  margin-left: 12px;
}
.navbar__right {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-left: auto;
}
.navlink--active {
  color: var(--primary);
}
.navlink {
  padding: 6px 12px;
  border-radius: 10px;
  font-weight: 500;
  color: var(--text);
  position: relative;
  transition: color 0.18s ease;
}
.navlink:hover {
  color: var(--primary);
}
.navbar__actions { display: flex; gap: 10px; align-items: center; }
:root.dark .navlink { color: var(--muted); }
:root.dark .navlink--active { color: var(--accent-ink); }
:root.dark .navbar__actions .btn--ghost { border-color: var(--border-strong); color: var(--text); }
:root.dark .nav-toggle { box-shadow: var(--glow-primary); border-color: rgba(255,255,255,0.12); }

.nav-toggle {
  display: none;
  background: var(--card);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 10px;
  font-size: 18px;
  cursor: pointer;
  box-shadow: var(--shadow);
  /* Touch target: garantisce l'area d'impatto minima 44x44 su mobile. */
  min-width: 44px;
  min-height: 44px;
}
.nav-toggle span { display: inline-block; line-height: 1; }
:root.dark .nav-toggle { box-shadow: var(--glow-primary); border-color: rgba(255,255,255,0.12); color: #e0f2fe; background: color-mix(in srgb, var(--card) 85%, var(--primary) 15%); }

.theme-switch-wrap {
  display: inline-flex;
  align-items: center;
}
.theme-switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 82px;
  height: 38px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: linear-gradient(135deg, rgba(255,255,255,0.9), rgba(240,244,255,0.9));
  box-shadow: 0 6px 18px rgba(37,99,235,0.12);
  cursor: pointer;
  overflow: hidden;
  transition: all 0.2s ease;
}
.theme-switch:hover { box-shadow: 0 10px 26px rgba(37,99,235,0.16); transform: translateY(-1px); }
.theme-switch input { position: absolute; opacity: 0; pointer-events: none; }
:root.dark .theme-switch {
  background: linear-gradient(135deg, rgba(24,31,52,0.95), rgba(15,23,42,0.9));
  box-shadow: 0 10px 26px rgba(0,0,0,0.45);
}
.theme-switch__rail {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 100%;
  padding: 0 12px;
}
.theme-switch__icon {
  width: 14px;
  height: 14px;
  position: relative;
}
.theme-switch__sun {
  background: radial-gradient(circle at 50% 50%, #fbbf24 0%, #f59e0b 70%, transparent 80%);
  box-shadow:
    0 0 0 4px rgba(251,191,36,0.18),
    0 0 18px rgba(245,158,11,0.55);
  border-radius: 50%;
}
.theme-switch__moon {
  border-radius: 50%;
  background: radial-gradient(circle at 30% 30%, #cbd5e1 40%, transparent 45%), #0f172a;
  box-shadow: inset -4px -2px 8px rgba(255,255,255,0.15);
}
.theme-switch__thumb {
  position: absolute;
  left: 8px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: linear-gradient(145deg, #2563eb, #7c3aed);
  box-shadow:
    0 10px 25px rgba(37,99,235,0.35),
    inset 0 1px 2px rgba(255,255,255,0.45);
  transition: transform 0.28s ease, background 0.28s ease;
}
.theme-switch.is-dark .theme-switch__thumb {
  transform: translateX(38px);
  background: linear-gradient(145deg, #0f172a, #0b1021);
  box-shadow:
    0 12px 28px rgba(15,23,42,0.35),
    inset 0 1px 2px rgba(255,255,255,0.12);
}
.theme-switch::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 90% 50%, rgba(124,58,237,0.16), transparent 40%);
  opacity: 0.8;
  pointer-events: none;
  transition: opacity 0.25s ease;
}
.theme-switch.is-dark::after {
  opacity: 1;
  background: radial-gradient(circle at 10% 50%, rgba(16,185,129,0.18), transparent 40%);
}

@media (max-width: 900px) {
  .navbar__links { display: none; flex-direction: column; align-items: flex-start; gap: 10px; padding: 10px 0; }
  .navbar__links.mobile-open { display: flex; }
  .navbar__right.mobile-open { display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
  .navbar__actions { width: 100%; }
}

.btn {
  border: none;
  border-radius: 14px;
  padding: 10px 16px;
  font-weight: 700;
  cursor: pointer;
  transition: all 0.18s ease;
  /* Touch target minimo WCAG 2.5.5 (AAA) / 2.5.8 (AA): area d'impatto >= 44px
     senza toccare il padding visivo. inline-flex centra il testo nell'area. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 44px;
}
.btn--click { transition: transform 0.12s ease, box-shadow 0.18s ease; }
.btn--click:active { transform: scale(0.97); box-shadow: 0 10px 30px rgba(37,99,235,0.18); }
/* [hidden] deve vincere su qualunque `display:` dichiarato altrove. Senza questa riga ogni
   componente con display esplicito (.btn inline-flex, .upload-card grid, .ex-arena__grid,
   .profile-modal) resta VISIBILE quando il JS lo nasconde: il form "Crea una nuova classe"
   era permanentemente aperto proprio per questo. */
[hidden] { display: none !important; }
.btn:disabled,
.btn[aria-disabled="true"] { opacity: 0.6; cursor: not-allowed; transform: none; box-shadow: none; }
.btn:hover:not(:disabled):not([aria-disabled="true"]) { transform: translateY(-1px); box-shadow: var(--shadow); }
.btn--primary { background: var(--primary); color: #fff; }
.btn--ghost { background: var(--surface-1); color: var(--text); border: 1px solid var(--border-soft); }
.btn--ghost:hover { box-shadow: var(--shadow); }
.navbar__actions .btn {
  padding: 8px 18px;
  border-radius: 10px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  font-weight: 600;
}
.navbar__actions .btn.btn--ghost { border: 1px solid rgba(0,0,0,0.06); }
.btn--danger {
  background: #ef4444;
  color: #fff;
}
.btn--danger:hover {
  background: #dc2626;
  box-shadow: 0 8px 20px rgba(239, 68, 68, 0.3);
}
/* DARK-BTN: in dark il gradiente è periwinkle chiaro (#a78bfa→#8b9dff);
   testo inchiostro scuro = 6.6:1 / 7.2:1 sui due stop (WCAG AA). */
:root.dark .btn--primary { color: #171430; }
:root.dark .btn--primary:hover {
  box-shadow: var(--glow-m);
  transform: translateY(-1px);
}
:root.dark .btn--ghost:hover {
  background: color-mix(in srgb, var(--accent) 12%, var(--surface-1));
  border-color: var(--accent);
  box-shadow: var(--glow-s);
}
:root.dark .btn--danger:hover {
  background: #dc2626;
  box-shadow: 0 8px 24px rgba(239, 68, 68, 0.4);
}
.nav-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--gradient-accent);
  display: grid;
  place-items: center;
  color: #fff;
  font-weight: 800;
  text-transform: uppercase;
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}


/* (rimossa) `.navbar.scrolled` con bianco cablato: al buio avrebbe reso la barra bianca
   allo scroll. Restava innocua solo perche' una regola successiva la copriva per caso.
   Lo stato «scrolled» ora vive nel blocco NAVIGAZIONE 2026 in fondo al file, sui token. */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
}
.pill--ghost,
.pill--tutor,
.pill--orale,
.pill--quiz,
.pill--appunti,
.pill--pdf,
.pill--jpg {
  background: color-mix(in srgb, var(--surface-1) 85%, var(--accent) 15%);
  color: var(--text);
  border-color: var(--border-soft);
}

.hero {
  padding: 52px 0 32px;
}
.hero__title {
  margin: 10px 0;
  font-family: "Space Grotesk", "Inter", system-ui, sans-serif;
  font-size: clamp(34px, 4.4vw, 44px);
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.hero__subtitle { color: var(--muted); max-width: 640px; margin: 6px 0 16px; }
.hero__controls {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 520px;
}
.hero__controls--inline {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
}
/* C6 (retention): chip stat sull'hero — streak/XP/ripassi in faccia all'ingresso. */
.hero__stats { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 4px; }
.hero-stat {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; min-height: 32px;
  background: var(--surface-1); border: 1px solid var(--border);
  border-radius: 999px; font-weight: 700; font-size: 0.9rem; color: var(--text-1);
}
.hero-stat--streak { background: color-mix(in srgb, var(--accent-yellow, #ffd84d) 22%, var(--surface-1)); border-color: color-mix(in srgb, var(--accent-yellow, #ffd84d) 45%, var(--border)); }
.hero-stat--due { background: color-mix(in srgb, var(--accent-violet) 12%, var(--surface-1)); border-color: color-mix(in srgb, var(--accent-violet) 30%, var(--border)); color: var(--accent-ink); }

.eyebrow {
  display: inline-block;
  padding: 6px 12px;
  /* WCAG AA: violet on tinted bg needs ≥4.5:1. Use a darker violet (#5b21b6) on
     a lighter violet tint so contrast ratio is well above 4.5. */
  background: color-mix(in srgb, var(--accent-violet) 14%, var(--surface-1));
  color: var(--accent-ink);
  border-radius: 999px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: 12px;
}

.input-label {
  font-weight: 700;
  font-size: 13px;
  margin-bottom: 4px;
  display: inline-block;
}
.input {
  width: 100%;
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  padding: 12px 14px;
  font-size: 15px;
  background: var(--surface-1);
  color: var(--text);
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}
.input--lg { padding: 14px 16px; font-size: 16px; }
.input { box-sizing: border-box; }
/* MOBILE-TUTOR: la riga inline (hero__controls--inline) conteneva un .field che
   non poteva restringersi sotto il suo contenuto → ~42px di overflow orizzontale
   su telefono. flex-wrap + min-width:0 risolvono (fix flex standard). */
.hero__controls--inline { flex-wrap: wrap; }
/* Il campo riempie la riga su desktop (input ampio) e si restringe su mobile
   (flex-basis 100% + min-width:0) → niente overflow, larghezza generosa su desktop. */
.hero__controls--inline .field { flex: 1 1 100%; min-width: 0; max-width: 100%; }
.input--wide { min-width: 0; }

/* Locked Input State (topic lock from vision) */
.input.is-locked,
input.is-locked {
  background: color-mix(in srgb, var(--accent) 6%, var(--surface-1));
  border-color: var(--accent);
  cursor: not-allowed;
  position: relative;
}
.input.is-locked::placeholder {
  color: var(--accent);
}

/* ARGOMENTO + LINGUA sulla stessa riga — un solo posto dove guardare.
   Il campo dell'argomento si prende tutto lo spazio, la lingua sta stretta accanto: chi non la
   tocca legge «Italiano» e va avanti. Sotto i 520px va a capo e resta a piena larghezza, che
   su un telefono è più comodo di due controlli schiacciati. */
.campo-argomento {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.campo-argomento > .input:not(.input--lingua) { flex: 1 1 200px; min-width: 0; }
.input--lingua {
  flex: 0 0 auto;
  width: auto;
  padding-inline: 10px;
  font-size: 0.92rem;
  cursor: pointer;
}
@media (max-width: 520px) {
  .input--lingua { flex: 1 1 100%; width: 100%; }
}

/* Qui viveva `.ferma-skoo` (il pulsante «Fammi parlare» che pulsava mentre Skoo parlava). Il
   pulsante non c'è più: dal 2026-08-11 il barge-in del provider è acceso per tutti, quindi per
   riprendersi la parola si parla e basta. Regole tolte con lui, animazione compresa. */

/* Topic Lock Indicator */
.topic-lock-indicator {
  display: none;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  background: color-mix(in srgb, var(--accent) 12%, var(--bg));
  border-radius: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--accent);
  margin-left: 8px;
}
.topic-lock-indicator svg {
  width: 14px;
  height: 14px;
}
.topic-lock-indicator.is-visible {
  display: inline-flex;
}

/* ======== ELEGANT CUSTOM SELECT ======== */
.select,
select.select {
  width: 100%;
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  padding: 12px 40px 12px 14px;
  font-size: 15px;
  background: var(--surface-1);
  color: var(--text);
  cursor: pointer;
  transition: border-color 150ms ease, box-shadow 150ms ease, background 150ms ease;
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%236b7280' viewBox='0 0 16 16'%3E%3Cpath d='M4.646 5.646a.5.5 0 0 1 .708 0L8 8.293l2.646-2.647a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 16px;
}
.select:hover {
  border-color: var(--border-strong);
  background-color: var(--bg1);
}
.select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}
.select:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.select--lg {
  padding: 14px 44px 14px 16px;
  font-size: 16px;
}

/* Custom Select Wrapper (JS-enhanced) */
.sk-select {
  position: relative;
  width: 100%;
}
.sk-select__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  padding: 12px 14px;
  font-size: 15px;
  background: var(--surface-1);
  color: var(--text);
  cursor: pointer;
  transition: all 150ms ease;
}
.sk-select__trigger:hover {
  border-color: var(--border-strong);
  background: var(--bg1);
}
.sk-select.is-open .sk-select__trigger {
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.sk-select__value {
  flex: 1;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sk-select__value--placeholder {
  color: var(--muted);
}
.sk-select__arrow {
  width: 20px;
  height: 20px;
  color: var(--muted);
  transition: transform 200ms ease;
  flex-shrink: 0;
  margin-left: 8px;
}
.sk-select.is-open .sk-select__arrow {
  transform: rotate(180deg);
  color: var(--accent);
}
.sk-select__dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--surface-1);
  border: 1px solid var(--accent);
  border-top: none;
  border-radius: 0 0 14px 14px;
  max-height: 240px;
  overflow-y: auto;
  z-index: 100;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity 150ms ease, transform 150ms ease, visibility 0s 150ms;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.sk-select.is-open .sk-select__dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 150ms ease, transform 150ms ease, visibility 0s;
}
.sk-select__option {
  display: flex;
  align-items: center;
  padding: 12px 14px;
  cursor: pointer;
  transition: background 100ms ease;
  gap: 10px;
}
.sk-select__option:hover {
  background: color-mix(in srgb, var(--accent) 8%, var(--bg));
}
.sk-select__option.is-selected {
  background: color-mix(in srgb, var(--accent) 12%, var(--bg));
  color: var(--accent);
  font-weight: 600;
}
.sk-select__option:last-child {
  border-radius: 0 0 14px 14px;
}
.sk-select__option-icon {
  width: 20px;
  height: 20px;
  opacity: 0.7;
}
.sk-select__option-text {
  flex: 1;
}
.sk-select__option-desc {
  font-size: 12px;
  color: var(--muted);
  margin-top: 2px;
}
.sk-select__search {
  padding: 10px 14px;
  border-bottom: 1px solid var(--border-soft);
}
.sk-select__search input {
  width: 100%;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 8px 12px;
  font-size: 14px;
  background: var(--bg);
  color: var(--text);
}
.sk-select__search input:focus {
  outline: none;
  border-color: var(--accent);
}
.sk-select__empty {
  padding: 16px;
  text-align: center;
  color: var(--muted);
  font-size: 14px;
}

/* Multi-select variant styles */
.sk-select--open .sk-select__dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.sk-select__label {
  flex: 1;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sk-select__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  background: var(--accent);
  color: white;
  border-radius: 11px;
  font-size: 12px;
  font-weight: 600;
  margin-right: 4px;
}
.sk-select__options {
  max-height: 200px;
  overflow-y: auto;
  padding: 4px 0;
}
.sk-select__option--selected {
  background: color-mix(in srgb, var(--accent) 12%, var(--bg));
}
.sk-select__checkbox {
  width: 18px;
  height: 18px;
  border: 2px solid var(--border-strong);
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: all 100ms ease;
}
.sk-select__option input[type="checkbox"] {
  display: none;
}
.sk-select__option input[type="checkbox"]:checked + .sk-select__checkbox {
  background: var(--accent);
  border-color: var(--accent);
}
.sk-select__option input[type="checkbox"]:checked + .sk-select__checkbox::after {
  content: "";
  width: 10px;
  height: 10px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='white' viewBox='0 0 16 16'%3E%3Cpath d='M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z'/%3E%3C/svg%3E") center/contain no-repeat;
}
.sk-select__text {
  flex: 1;
  font-size: 14px;
}
.sk-select__mastery {
  font-size: 12px;
  color: var(--muted);
  padding: 2px 8px;
  background: color-mix(in srgb, var(--warning) 15%, var(--bg));
  border-radius: 10px;
}
.sk-select__actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  padding: 10px 14px;
  border-top: 1px solid var(--border-soft);
  background: var(--surface-1);
  border-radius: 0 0 14px 14px;
}

/* Dark mode adjustments */
:root.dark .sk-select__dropdown {
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}
:root.dark .select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%239ca3af' viewBox='0 0 16 16'%3E%3Cpath d='M4.646 5.646a.5.5 0 0 1 .708 0L8 8.293l2.646-2.647a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E");
}

.field { min-width: 200px; flex: 1; }

.section { padding: 18px 0 36px; }
.section__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.grid { display: grid; gap: 14px; }
/* `.grid` è anche la classe delle tabelle delle guide (`table.grid`). Senza questa riga la tabella
   diventa un contenitore a griglia: thead e tbody si impaginano ognuno per conto suo, e le
   intestazioni non stanno più sopra le loro colonne (21/9/2026, visto sulle tabelle di latino). */
table.grid { display: table; }
/* Tabelle delle guide a schede sul telefono (guide.js#tabelleASchede, 6/10/2026). */
@media (max-width:600px){div.grid-wrap--schede{overflow:visible;border:0}div.grid-wrap table.grid{min-width:0}div.grid-wrap--schede thead{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}div.grid-wrap--schede tr{display:block;border:1px solid var(--border);border-radius:12px;margin:0 0 10px;padding:4px 0}div.grid-wrap--schede td{display:block;border:0;padding:6px 14px}div.grid-wrap--schede td[data-etichetta]::before{content:attr(data-etichetta);display:block;font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin-bottom:2px}}
.grid--cards { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.grid--two { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

.card {
  background: var(--card);
  border-radius: 16px;
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  padding: 18px;
  position: relative;
}
.card h3 { margin: 6px 0; }
/* Sotto-sezione dentro una card (es. «4-bis» nell'informativa): stacca dal paragrafo
   precedente senza diventare un secondo titolo. */
.card h4 { margin: 18px 0 6px; font-size: 1.02rem; }
.card p { margin: 4px 0; color: var(--muted); }
/* "Il Twin ha notato…" — vignetta con mascotte parlante sulla dashboard (F1). */
.twin-insight-card { border-left: 3px solid var(--accent); background: var(--surface-1); }
.twin-vignette { display: flex; align-items: flex-start; gap: 14px; }
.twin-vignette__mascot {
  width: 76px; height: 76px; flex-shrink: 0;
  filter: drop-shadow(0 4px 10px rgba(29,26,43,.12));
  animation: twin-bob 3s ease-in-out infinite;
}
@keyframes twin-bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
@media (prefers-reduced-motion: reduce) { .twin-vignette__mascot { animation: none; } }
.twin-vignette__bubble {
  position: relative; flex: 1;
  background: var(--card); border: 1px solid var(--border); border-radius: 14px; padding: 12px 16px;
}
.twin-vignette__bubble::before {
  content: ""; position: absolute; left: -8px; top: 20px; width: 14px; height: 14px;
  background: var(--card); border-left: 1px solid var(--border); border-bottom: 1px solid var(--border);
  transform: rotate(45deg);
}
.twin-insight__stmt { color: var(--text) !important; font-size: 1.02rem; font-weight: 500; margin: 8px 0 12px; }
.twin-insight__grade { margin-top: 12px; }
/* "Parla con il tuo Twin" — note scritte dallo studente (F1.5). */
.twin-note-add { display: flex; gap: 8px; margin: 12px 0 8px; }
.twin-note-add .input { flex: 1; }
.twin-note-list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.twin-note-item { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 12px; background: var(--surface-1); border: 1px solid var(--border); border-radius: 10px; }
.twin-note-item__text { flex: 1; color: var(--text); }
@media (max-width: 560px) { .twin-note-add { flex-direction: column; } }
/* "Il tuo percorso di oggi" — stepper del percorso architettato dal Twin. */
.twin-plan { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.twin-plan__link {
  display: flex; align-items: center; gap: 14px; padding: 14px 16px;
  background: var(--card); border: 1px solid var(--border); border-radius: 14px;
  text-decoration: none; color: var(--text);
  transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}
.twin-plan__link:hover, .twin-plan__link:focus-visible { border-color: var(--accent); box-shadow: var(--shadow); transform: translateY(-1px); }
.twin-plan__num {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent); color: #fff; display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: .95rem;
}
.twin-plan__body { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.twin-plan__title { font-weight: 600; }
.twin-plan__go { flex-shrink: 0; color: var(--accent); font-weight: 600; font-size: .9rem; }
@media (max-width: 560px) { .twin-plan__go { display: none; } }
/* Il bottone «Inizia»: resta visibile anche da telefono (a differenza di __go, che era una
   freccia decorativa). È l'UNICO invito primario della sezione. */
.twin-plan__cta { flex-shrink: 0; white-space: nowrap; }
.twin-plan__step--fatto .twin-plan__link { opacity: .7; }
.twin-plan__step--fatto .twin-plan__num { background: var(--ok, var(--accent)); }
.twin-plan__azioni { display: flex; flex-wrap: wrap; gap: 6px; padding: 6px 0 0 44px; }

/* ── IL TWIN ORGANIZZATORE (piano di studio multi-giorno) ─────────────────── */
.piano-goal { margin: 0 0 12px; padding: 12px 14px; border: 1px solid var(--border); border-radius: 14px; background: var(--card); }
.piano-goal__line { margin: 0 0 4px; }
.piano-goal__narrativa { margin: 8px 0 2px; font-style: italic; }
.piano-goal__tutto { color: var(--accent); font-weight: 600; text-decoration: none; }
.piano-goal__tutto:hover, .piano-goal__tutto:focus-visible { text-decoration: underline; }
/* Monospazio: la barra è fatta di caratteri pieni/vuoti e senza passo fisso "balla". Il dato
   vero resta il testo accanto — WCAG: mai un'informazione affidata solo a un grafico. */
.piano-progress { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: -1px; color: var(--accent); }
.piano-cta { margin-top: 12px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* Il wizard resta, ma come SECONDA via: la prima è parlarne col Twin. */
.piano-cta__wizard { color: var(--muted); font-size: var(--text-sm); text-decoration: underline; }
.piano-wizard { display: flex; flex-direction: column; gap: 18px; }
.piano-wizard__step { border: 0; padding: 0; margin: 0; }
.piano-wizard__step legend { font-weight: 600; margin-bottom: 8px; }
.piano-wizard__radios { display: flex; flex-wrap: wrap; gap: 8px; }
.piano-wizard__campi { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 10px; }
.piano-wizard__campo { margin: 10px 0 0; flex: 1 1 200px; }
.piano-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 12px;
  border: 1px solid var(--border); border-radius: 999px; cursor: pointer; background: var(--card);
}
.piano-chip:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.piano-vista__azioni { display: flex; gap: 8px; flex-wrap: wrap; margin: 12px 0; }
.piano-giorni { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.piano-giorno { border-left: 3px solid var(--border); padding-left: 12px; }
.piano-giorno--oggi { border-left-color: var(--accent); }
.piano-giorno--prova { border-left-color: var(--accent); font-weight: 600; }
.piano-giorno__data { margin: 0 0 6px; font-weight: 600; }
.piano-giorno__items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.piano-item { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
.piano-item__testo { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.piano-item__sub { display: block; }
.piano-item__azioni { display: flex; flex-wrap: wrap; gap: 6px; }
.piano-item__stato { margin-left: 6px; }
@media (max-width: 560px) {
  .twin-vignette { flex-direction: column; align-items: center; text-align: center; }
  .twin-vignette__bubble::before {
    left: 50%; top: -8px; transform: translateX(-50%) rotate(45deg);
    border-left: none; border-bottom: none; border-top: 1px solid var(--border); border-right: 1px solid var(--border);
  }
}
.card--row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.card-list { display: flex; flex-direction: column; gap: 10px; }

.action-card {
  transition: transform 150ms ease, box-shadow 150ms ease, border-color 150ms ease;
  display: block;
  padding: 20px;
  will-change: transform;
}
.action-card:hover { transform: translateY(-3px); border-color: var(--primary); box-shadow: var(--shadow-strong); }
.action-card .cta { color: var(--primary); font-weight: 700; text-decoration: none; }
.action-card .cta:hover { text-decoration: underline; }
.is-disabled { opacity: 0.5; pointer-events: none; }
.card--tutor { background: #f9f5ff; }
.card--orale { background: #f1f5ff; }
.card--quiz { background: #f4fbf6; }
.card--appunti { background: #f4f9ff; }

.muted { color: var(--muted); font-size: 14px; }
.small { font-size: 13px; }
.strong { font-weight: 700; color: var(--text); }
.badge-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }

.panel {
  background: var(--card);
  border-radius: 16px;
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  padding: 18px;
  min-height: 220px;
}
.panel--center { display: grid; place-items: center; gap: 16px; text-align: center; }

.mic { display: grid; place-items: center; gap: 10px; padding: 14px; }
.mic__state { font-weight: 700; color: var(--muted); }

.transcript {
  border: 1px dashed var(--border);
  border-radius: 14px;
  padding: 12px;
  background: var(--surface-1);
  color: var(--text);
  min-height: 80px;
}
.transcript--answer {
  background: color-mix(in srgb, var(--surface-1) 92%, var(--accent) 8%);
}
:root.dark .transcript--answer {
  background: color-mix(in srgb, var(--surface-1) 88%, var(--accent) 12%);
  border-color: var(--border-soft);
}
.live-dot {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.live-dot::after, .live-dot::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #16a34a;
  animation: pulse 1.2s ease-in-out infinite;
}
.live-dot::before { animation-delay: 0.2s; }

.question {
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
}

.score {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  padding: 12px;
}
.score__value { font-size: 28px; font-weight: 800; color: var(--primary); }

.feedback {
  margin-top: 12px;
  padding: 12px;
  border-radius: 12px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  color: var(--muted);
}
.alert {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-control);
  margin-top: var(--space-3);
  font-weight: 600;
  border: 1px solid transparent;
  /* Gentle appear-in-place — the old slideInRight swept the alert across
     neighbouring controls (e.g. over the Google CTA on login). */
  animation: fadeInDown 0.25s ease;
}
.alert--error {
  background: #fef2f2;
  color: #b91c1c;
  border-color: #fecaca;
  border-left: 4px solid var(--color-danger);
}
:root.dark .alert--error {
  background: color-mix(in srgb, #b91c1c 15%, var(--surface-1));
  color: #fca5a5;
  border-color: rgba(239, 68, 68, 0.4);
}
.alert--success {
  background: #ecfdf3;
  color: #15803d;
  border-color: #bbf7d0;
  border-left: 4px solid var(--color-success);
}
/* `.alert--info` era usata (avviso beta su register.html) ma MAI definita: il riquadro
   esisteva trasparente, e in tema scuro l'avviso col codice di invito spariva del tutto. */
.alert--info {
  background: #eff6ff;
  color: #1d4ed8;
  border-color: #bfdbfe;
  border-left: 4px solid var(--color-info);
}
:root.dark .alert--info {
  background: color-mix(in srgb, #1d4ed8 18%, var(--surface-1));
  color: #93c5fd;
  border-color: rgba(96, 165, 250, 0.4);
}
.alert--warning {
  background: #fffbeb;
  color: #92400e;
  border-color: #fde68a;
  border-left: 4px solid var(--color-warning);
}
:root.dark .alert--warning {
  background: color-mix(in srgb, var(--color-warning) 15%, var(--surface-1));
  color: #fcd34d;
  border-color: rgba(245, 158, 11, 0.4);
}
:root.dark .alert--success {
  background: color-mix(in srgb, #15803d 15%, var(--surface-1));
  color: #86efac;
  border-color: rgba(34, 197, 94, 0.4);
}
.loading-inline {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--muted);
}
.spinner-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--primary);
  opacity: 0.7;
  animation: spinner-bounce 0.9s ease-in-out infinite;
}
.spinner-dot:nth-child(2) { animation-delay: 0.12s; }
.spinner-dot:nth-child(3) { animation-delay: 0.24s; }
@keyframes spinner-bounce {
  0%, 100% { transform: translateY(0); opacity: 0.7; }
  50% { transform: translateY(-4px); opacity: 1; }
}
.spinner {
  width: 14px;
  height: 14px;
  border: 2px solid rgba(0,0,0,0.1);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  display: inline-block;
  vertical-align: middle;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.quiz-card { display: grid; gap: 12px; }
.quiz-card {
  background: linear-gradient(135deg, #f8fbff, #ffffff);
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: var(--shadow-strong);
}
/* Quiz submissions results table (teacher) */
.quiz-results { margin-top: 12px; }
.quiz-results-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.quiz-results-table th,
.quiz-results-table td {
  text-align: left;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-soft);
}
.quiz-results-table th { color: var(--muted); font-weight: 600; }

.options { display: grid; gap: 8px; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
.option {
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid var(--border-soft);
  background: var(--surface-1);
  color: var(--text);
  cursor: pointer;
  font-weight: 600;
  transition: all 120ms ease;
}
.option:hover { border-color: var(--primary); color: var(--primary); }
.option.active { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }

.upload-card { display: grid; gap: 10px; justify-items: stretch; }
/* Il bottone in una griglia si stirava a tutta larghezza: un "Crea" largo 1100px. */
.upload-card > .btn { justify-self: start; }
/* Senza contenuto era un riquadro vuoto che sembrava un campo da compilare. */
.feedback:empty { display: none; }

.auth-card { max-width: 520px; margin: 0 auto; }
.auth-form { display: grid; gap: 10px; }

/* (Il vecchio `.auth-divider` non lo usava più nessuno: il separatore dei bottoni Google/Apple
   è `.oauth-oppure`, in assets/css/accesso.css.) */

/* Role Selector — auto-fit so 2 or 3 options both fill the row */
.role-selector {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
  margin: 8px 0 16px;
}
.role-option {
  cursor: pointer;
}
.role-option input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.role-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 16px 12px;
  background: var(--surface-1);
  border: 2px solid var(--border);
  border-radius: var(--radius-card);
  transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
}
.role-option input:checked + .role-card {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: var(--glow-s);
}
/* WCAG 2.4.7: the radio is visually hidden — surface its keyboard focus
   on the card, or tabbing through Studente/Genitore shows nothing. */
.role-option input:focus-visible + .role-card {
  box-shadow: var(--focus-ring);
  border-color: var(--accent);
}
.role-option:hover .role-card {
  border-color: var(--accent);
}
.role-icon {
  font-size: 28px;
  line-height: 1;
}
.role-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
}
@media (max-width: 480px) {
  .role-selector {
    grid-template-columns: 1fr;
  }
  .role-card {
    flex-direction: row;
    justify-content: flex-start;
    padding: 12px 16px;
  }
  .role-card--select { flex-direction: column; align-items: stretch; }
}

/* Feature List (Parent Dashboard) */
.feature-list {
  display: grid;
  gap: 16px;
}
.feature-item {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  padding: 16px;
  background: var(--surface-2);
  border-radius: var(--radius-card);
  border: 1px solid var(--border);
}
.feature-icon {
  font-size: 24px;
  line-height: 1;
  flex-shrink: 0;
}
.feature-item p {
  margin: 0;
}
.feature-item p.strong {
  font-weight: 600;
  margin-bottom: 4px;
}

.footer {
  border-top: 1px solid var(--border-soft);
  background: var(--surface-1);
  padding: 16px 0;
  margin-top: 24px;
}
.footer__inner { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.footer__links { display: flex; gap: 12px; color: var(--muted); font-size: 13px; }
.footer__inner span { color: var(--muted); font-size: 13px; }
/* Identificazione societaria obbligatoria (art. 2250 c.c.): sede, registro imprese, REA, P.IVA. */
.footer__legal {
  width: 100%;
  max-width: 1180px;
  margin: 10px auto 0;
  padding: 10px 18px 0;
  border-top: 1px solid var(--border-soft);
  color: var(--muted);
  font-size: 12px;
  line-height: 1.6;
}
.footer__legal a { color: inherit; text-decoration: underline; }

@media (max-width: 720px) {
  .navbar__links { display: none; }
  .hero { padding-top: 32px; }
  .hero__controls--inline { flex-direction: column; align-items: stretch; }
  .section__header { flex-direction: column; align-items: flex-start; }
  .navbar__actions { width: 100%; justify-content: flex-end; }
  .navbar__logo img { height: 26px; width: auto; }
  .card--row { flex-direction: column; align-items: flex-start; }
}

/* Quick actions + utility chips */
.quick-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 10px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: 14px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  color: var(--text);
  font-weight: 600;
  cursor: pointer;
  transition: all 0.18s ease;
  box-shadow: var(--shadow);
}
.chip:hover { transform: translateY(-1px); border-color: var(--primary); box-shadow: var(--shadow-strong); color: var(--primary); }
.chip svg { width: 16px; height: 16px; color: var(--primary); }

/* Class cards — discreet hover (no translate jumps) */
.class-card {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 16px;
  padding: 16px;
  box-shadow: var(--shadow);
  color: var(--text);
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: box-shadow 160ms ease, border-color 160ms ease;
}
.class-card:hover { border-color: var(--primary); box-shadow: var(--shadow-strong); }
.class-card:focus-within { border-color: var(--primary); box-shadow: var(--shadow-strong); }
.class-card__link { color: var(--text); text-decoration: none; font-weight: 600; }
.class-card__link:hover { color: var(--accent); text-decoration: underline; }
.class-card__link:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 4px; }
.class-card__header { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.class-card__actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.class-meta { display: flex; gap: 8px; align-items: center; color: var(--muted); font-size: 14px; }
.class-actions { display: flex; gap: 10px; flex-wrap: wrap; }

/* Skeleton loader for class list */
.skeleton-card {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 16px;
  padding: 16px;
  height: 120px;
  position: relative;
  overflow: hidden;
}
.skeleton-card::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, var(--text) 6%, transparent) 50%,
    transparent 100%);
  animation: skel-shimmer 1.2s linear infinite;
}
@keyframes skel-shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }

/* =====================================================================   CLASS DETAIL ECOSYSTEM — folders sidebar + materials grid
   ============================================================================ */
.cd-shell { display: grid; grid-template-columns: 260px 1fr; gap: 20px; align-items: start; }
@media (max-width: 768px) {
  .cd-shell { grid-template-columns: 1fr; }
  .cd-sidebar { position: fixed; left: 0; top: 0; bottom: 0; width: 280px; transform: translateX(-100%); z-index: 50; background: var(--surface-1); transition: transform 200ms ease; padding: 16px; overflow-y: auto; box-shadow: var(--shadow-strong); }
  .cd-sidebar.open { transform: translateX(0); }
  .cd-sidebar-toggle { display: inline-flex !important; }
}
.cd-sidebar {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  padding: 14px;
  display: flex; flex-direction: column; gap: 6px;
}
.cd-sidebar__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.cd-sidebar__title { font-weight: 600; font-size: 14px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; }
.cd-folder {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: 8px;
  cursor: pointer; color: var(--text); font-size: 14px;
  border: 1px solid transparent;
  transition: background-color 140ms ease, border-color 140ms ease;
}
.cd-folder:hover { background: var(--surface-2); }
.cd-folder.active { background: color-mix(in srgb, var(--primary) 12%, transparent); border-color: var(--primary); font-weight: 600; }
.cd-folder:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.cd-folder__icon { font-size: 16px; }
.cd-folder__count { margin-left: auto; font-size: 12px; color: var(--muted); }
.cd-folder.drop-target { background: color-mix(in srgb, var(--primary) 18%, transparent); border-color: var(--primary); }
.cd-sidebar-toggle { display: none; }

.cd-toolbar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-bottom: 14px; }
.cd-toolbar__title { font-weight: 700; font-size: 18px; margin: 0; flex: 1; }

.cd-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px; }
.cd-grid.dropzone { outline: 2px dashed transparent; border-radius: 12px; transition: outline-color 140ms ease, background-color 140ms ease; padding: 4px; }
.cd-grid.dropzone.over { outline-color: var(--primary); background: color-mix(in srgb, var(--primary) 6%, transparent); }
.cd-empty { grid-column: 1 / -1; padding: 40px 20px; text-align: center; color: var(--muted); border: 1px dashed var(--border-soft); border-radius: 12px; }

.cd-mat {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  padding: 14px;
  display: flex; flex-direction: column; gap: 8px;
  cursor: pointer;
  position: relative;
  transition: box-shadow 160ms ease, border-color 160ms ease;
}
.cd-mat:hover { box-shadow: var(--shadow-strong); border-color: var(--primary); }
.cd-mat:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.cd-mat__icon { font-size: 28px; }
.cd-mat__title { font-weight: 600; font-size: 14px; line-height: 1.3; word-break: break-word; color: var(--text); }
.cd-mat__sub { font-size: 12px; color: var(--muted); }
.cd-mat__kebab { position: absolute; top: 8px; right: 8px; background: transparent; border: none; cursor: pointer; padding: 4px 8px; border-radius: 6px; color: var(--muted); font-size: 18px; line-height: 1; }
.cd-mat__kebab:hover { background: var(--surface-2); color: var(--text); }
.cd-mat__menu { position: absolute; top: 36px; right: 8px; background: var(--surface-1); border: 1px solid var(--border-soft); border-radius: 8px; box-shadow: var(--shadow-strong); z-index: 5; min-width: 140px; display: none; }
.cd-mat__menu.open { display: block; }
.cd-mat__menu button { display: block; width: 100%; text-align: left; padding: 8px 12px; background: transparent; border: none; cursor: pointer; font-size: 13px; color: var(--text); }
.cd-mat__menu button:hover { background: var(--surface-2); }

.cd-modal {
  position: fixed; inset: 0; background: rgba(0,0,0,0.55);
  display: none; align-items: center; justify-content: center;
  z-index: 200; padding: 20px;
}
.cd-modal.open { display: flex; }
.cd-modal__inner {
  background: var(--surface-1); border-radius: 16px; padding: 24px;
  max-width: 480px; width: 100%; max-height: 90vh; overflow-y: auto;
  border: 1px solid var(--border-soft); box-shadow: var(--shadow-strong);
  position: relative;
}
.cd-modal__title { margin: 0 0 12px; font-size: 18px; font-weight: 700; }
.cd-modal__close { position: absolute; top: 16px; right: 16px; background: transparent; border: none; cursor: pointer; font-size: 20px; color: var(--muted); }

.cd-cta-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 16px; }
@media (max-width: 540px) { .cd-cta-row { grid-template-columns: 1fr; } }
.cd-cta {
  display: flex; flex-direction: column; gap: 6px;
  padding: 18px 14px; border-radius: 12px;
  border: 1px solid var(--border-soft);
  background: var(--surface-2);
  color: var(--text);
  font-weight: 600; font-size: 15px;
  cursor: pointer; text-align: center;
  transition: box-shadow 160ms ease, border-color 160ms ease, background-color 160ms ease;
}
.cd-cta:hover, .cd-cta:focus-visible { border-color: var(--primary); box-shadow: var(--shadow-strong); background: var(--surface-1); outline: none; }
.cd-cta__icon { font-size: 28px; }
.cd-cta__hint { font-size: 12px; color: var(--muted); font-weight: 400; }

.cd-upload-zone {
  border: 2px dashed var(--border-soft); border-radius: 12px;
  padding: 24px; text-align: center; color: var(--muted);
  cursor: pointer; transition: border-color 140ms ease, background-color 140ms ease;
}
.cd-upload-zone.over { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 8%, transparent); color: var(--text); }
.cd-upload-zone:hover { border-color: var(--primary); }

/* Status row / bars */
.status-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 12px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  color: var(--muted);
  font-weight: 600;
}
.progress {
  width: 100%;
  height: 8px;
  background: color-mix(in srgb, var(--text) 12%, var(--surface-1));
  border-radius: 999px;
  overflow: hidden;
}
.progress__bar {
  height: 100%;
  width: 40%;
  background: var(--gradient-accent);
  border-radius: 999px;
  transition: width 0.3s ease;
}

.pill--accent {
  background: color-mix(in srgb, var(--accent) 15%, var(--surface-1));
  color: var(--accent);
}
:root.dark .pill--accent {
  background: color-mix(in srgb, var(--accent) 20%, var(--surface-1));
  color: var(--accent);
}

/* Ultimo minuto della sessione vocale: Skoo lo dice a voce, la pillola lo accompagna. Colore
   d'attesa, non d'errore — la fine del tempo è normale, non un guasto.

   La pillola porta `pill--accent` dal markup e riceve `pill--ultimo` a −60 secondi. In tema
   chiaro basta l'ordine (stessa specificità, questa regola viene dopo); in tema SCURO no:
   `:root.dark .pill--accent` pesa 0-3-0 e vincerebbe su entrambe le proprietà, lasciando la
   pillola del preavviso identica a prima. Il segnale visivo dell'ultimo minuto sarebbe sparito
   per metà degli utenti — quindi la variante scura si dichiara con lo stesso peso. */
.pill--ultimo,
:root.dark .pill--ultimo {
  background: color-mix(in srgb, var(--warning) 18%, var(--surface-1));
  color: var(--warning);
}

/* Materials table */
.materials-table {
  display: grid;
  gap: 8px;
  max-height: 440px;
  overflow-y: auto;
  padding-right: 4px;
}
.materials-row {
  display: grid;
  grid-template-columns: minmax(220px, 1.8fr) minmax(140px, 1.05fr) minmax(90px, 0.6fr) minmax(320px, 1.8fr);
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--card);
}
.materials-head {
  font-weight: 700;
  color: var(--muted);
  border-style: dashed;
  position: sticky;
  top: 0;
  background: var(--card);
  z-index: 1;
}
.materials-title {
  max-width: 100%;
  display: inline-block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.materials-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
}
.materials-actions .btn--ghost {
  padding: 6px 8px;
  min-width: 0;
}
:root.dark .materials-row { background: color-mix(in srgb, var(--card) 90%, var(--bg) 10%); box-shadow: var(--glow-primary); }
:root.dark .materials-head { background: color-mix(in srgb, var(--card) 92%, var(--bg) 8%); }
:root.dark .materials-row { border-color: rgba(255,255,255,0.12); }

/* Landing Neo (one-screen hero) */
.landing-neo {
  position: relative;
  overflow: hidden;
  padding: 48px 0 28px;
  min-height: calc(100vh - 160px);
  display: flex;
  align-items: center;
}
.landing-neo__grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(320px, 1.05fr) minmax(320px, 0.95fr);
  gap: 32px;
  align-items: center;
}
@media (max-width: 960px) {
  .landing-neo { padding-top: 20px; min-height: unset; }
  .landing-neo__grid { grid-template-columns: 1fr; gap: 20px; }
}
.landing-aurora {
  position: absolute;
  width: 520px;
  height: 520px;
  top: -80px;
  left: -120px;
  background:
    radial-gradient(circle at 30% 40%, rgba(37,99,235,0.3), transparent 55%),
    radial-gradient(circle at 70% 60%, rgba(124,58,237,0.22), transparent 50%);
  filter: blur(42px);
  opacity: 0.75;
  animation: auroraShift 12s ease-in-out infinite;
}
.landing-aurora--right {
  left: auto;
  right: -140px;
  top: -60px;
  background:
    radial-gradient(circle at 40% 50%, rgba(109,220,255,0.28), transparent 60%),
    radial-gradient(circle at 70% 50%, rgba(37,99,235,0.3), transparent 55%);
  animation-delay: 3s;
}
:root.dark .landing-aurora,
:root.dark .landing-aurora--right {
  opacity: 0.9;
  filter: blur(38px) saturate(1.1);
}
.landing-copy {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.hero__title--neo {
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  font-size: clamp(28px, 3vw, 38px);
  letter-spacing: -0.02em;
  margin: 0;
  text-shadow: var(--glow-primary);
}
.hero__subtitle--wide {
  max-width: 680px;
  color: var(--muted);
  margin: 0;
}
.landing-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.landing-chips { display: flex; flex-wrap: wrap; gap: 10px; }
.chip--glow {
  background: linear-gradient(135deg, rgba(37,99,235,0.1), rgba(124,58,237,0.12));
  border-color: rgba(37,99,235,0.18);
  color: var(--text);
  box-shadow: var(--shadow), var(--glow-primary);
}
:root.dark .chip--glow {
  background: linear-gradient(135deg, rgba(109,220,255,0.22), rgba(124,58,237,0.16));
  border-color: rgba(255,255,255,0.14);
  color: var(--text);
}
.landing-steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px;
  margin-top: 6px;
}
.step-card {
  background: color-mix(in srgb, var(--card) 82%, var(--bg) 18%);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 12px;
  box-shadow: var(--shadow);
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}
:root.dark .step-card {
  background: linear-gradient(145deg, color-mix(in srgb, var(--card) 78%, #0b1021 22%), color-mix(in srgb, var(--card) 55%, var(--primary) 45%));
  border-color: rgba(255,255,255,0.08);
  box-shadow: var(--shadow-strong), var(--glow-primary);
}
.step-card:hover { transform: translateY(-3px); border-color: var(--primary); box-shadow: var(--shadow-strong); }
.step-card p { margin: 6px 0 0; color: var(--muted); font-size: 14px; }
.landing-visual { display: grid; gap: 12px; }
.orbital {
  position: relative;
  min-height: 420px;
  border-radius: 24px;
  padding: 28px;
  background: linear-gradient(145deg, color-mix(in srgb, var(--card) 70%, var(--primary) 30%), color-mix(in srgb, var(--card) 88%, var(--bg) 12%));
  border: 1px solid rgba(37,99,235,0.18);
  overflow: hidden;
  box-shadow: var(--shadow-strong), var(--glow-strong);
}
:root.dark .orbital {
  background:
    radial-gradient(circle at 50% 40%, rgba(109,220,255,0.16), transparent 50%),
    linear-gradient(155deg, #0b1021, #0f172a 38%, color-mix(in srgb, var(--primary) 38%, #0b1021 62%));
  border-color: rgba(255,255,255,0.08);
}
.orbital::after {
  content: "";
  position: absolute;
  inset: 18px;
  border-radius: 20px;
  background: radial-gradient(circle at 50% 50%, rgba(255,255,255,0.12), transparent 40%);
  filter: blur(18px);
  opacity: 0.7;
  pointer-events: none;
}
.orbital__core {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: linear-gradient(135deg, var(--primary), #7c3aed);
  color: #fff;
  padding: 16px 18px;
  border-radius: 18px;
  box-shadow: 0 18px 52px rgba(37,99,235,0.38), var(--glow-strong);
  text-align: center;
  min-width: 220px;
  animation: pulseCore 5.4s ease-in-out infinite;
}
:root.dark .orbital__core { color: #0b1021; }
.core-title { display: block; font-size: 18px; font-weight: 700; letter-spacing: -0.01em; }
.orbital__core small { display: block; margin-top: 4px; opacity: 0.9; font-weight: 600; }
.orbit {
  position: absolute;
  width: 46%;
  max-width: 260px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 12px 14px;
  box-shadow: var(--shadow);
  backdrop-filter: blur(6px);
  animation: floatOrbit 8s ease-in-out infinite;
}
:root.dark .orbit {
  background: color-mix(in srgb, var(--card) 80%, rgba(109,220,255,0.12) 20%);
  border-color: rgba(255,255,255,0.08);
  box-shadow: var(--shadow-strong);
}
.orbit__label { font-weight: 700; color: var(--primary); margin-bottom: 4px; }
.orbit p { margin: 0; color: var(--muted); font-size: 14px; }
.orbit--tutor { top: 14%; left: 6%; }
.orbit--orale { top: 8%; right: 4%; animation-delay: 0.6s; }
.orbit--vision { bottom: 16%; left: 10%; animation-delay: 1.2s; }
.orbit--quiz { bottom: 10%; right: 8%; animation-delay: 1.8s; }
@media (max-width: 960px) {
  .orbital { min-height: unset; padding: 18px; }
  .orbital__core,
  .orbit {
    position: static;
    width: 100%;
    max-width: none;
    animation: none;
    transform: none;
  }
  .orbital { display: grid; gap: 10px; }
}
.landing-stream { display: grid; gap: 10px; margin-top: 6px; }
.stream-card {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 12px;
  align-items: center;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 12px;
  box-shadow: var(--shadow);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
:root.dark .stream-card {
  background: color-mix(in srgb, var(--card) 76%, #0b1021 24%);
  border-color: rgba(255,255,255,0.08);
  box-shadow: var(--shadow-strong);
}
.stream-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-strong); }
.status-dot { width: 12px; height: 12px; border-radius: 50%; box-shadow: var(--glow-primary); }
.status-dot--live { background: linear-gradient(135deg, #22c55e, #0ea5e9); }
.status-dot--vision { background: linear-gradient(135deg, #f59e0b, #fb7185); }
.status-dot--twin { background: linear-gradient(135deg, #a855f7, #22d3ee); }
@keyframes auroraShift {
  0% { transform: translateY(0) scale(1); }
  50% { transform: translateY(18px) scale(1.05); }
  100% { transform: translateY(-6px) scale(1); }
}
@keyframes pulseCore {
  0% { transform: translate(-50%, -50%) scale(0.98); box-shadow: 0 18px 52px rgba(37,99,235,0.32), var(--glow-strong); }
  50% { transform: translate(-50%, -50%) scale(1.02); box-shadow: 0 24px 64px rgba(124,58,237,0.34), var(--glow-strong); }
  100% { transform: translate(-50%, -50%) scale(0.99); box-shadow: 0 18px 52px rgba(37,99,235,0.32), var(--glow-strong); }
}
@keyframes floatOrbit {
  0% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
  100% { transform: translateY(0); }
}

.tag-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }

/* Conversational avatars - preserved legacy selectors */
.mic__state {
  margin-top: 10px;
}

.drop-target {
  transition: box-shadow 0.18s ease, border-color 0.18s ease;
}
.drop-target.is-over {
  box-shadow: 0 0 0 3px rgba(37,99,235,0.18);
  border-color: var(--primary);
}

/* Tutor timeline, map, helpers */
.timeline,
.timeline__step,
.timeline__step--active,
.timeline__step--done {
  display: none !important;
}
.helpers { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.helper-btn--soft {
  background: var(--surface-2);
  border-color: color-mix(in srgb, var(--accent) 14%, transparent);
}
.helpers--wrap { justify-content: flex-start; }
.micro-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 10px;
}

.section--band {
  position: relative;
}
.section--band::before {
  content: "";
  position: absolute;
  inset: 12px 0;
  z-index: 0;
  background: linear-gradient(180deg, rgba(130,100,255,0.04), rgba(37,99,235,0.02));
  border-radius: 24px;
}
.section--band .container {
  position: relative;
  z-index: 1;
}

/* La card della CHIAMATA: unica superstite della colonna sinistra (founder, 22/8). Tiene
   anche il polso della sessione — pill Live, badge di stato, onda — che prima stava dentro
   la card della trascrizione. L'onda ha bisogno di una larghezza sua: dentro un grid
   `place-items: center` collasserebbe sul contenuto. */
.panel--tutor-left { gap: 14px; }
.panel--tutor-left .waveform { width: min(280px, 100%); }

/* ── LA PAGINA DAVANTI (RAG v2, §D3) ──────────────────────────────────────────
   La colonna che ha preso il posto delle card «La lezione» e «Riassunto»: dentro c'e' il
   foglio VERO del libro che Skoo sta spiegando, la sua strip di pagine e il numero — con
   scritto in che lingua e' (quello della carta o quello del PDF).
   Solo token: il tema scuro viene gratis, nessun colore nuovo. */
.pagina-viva {
  display: grid;
  gap: var(--space-3);
  align-content: start;
}
.pagina-viva__testa {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}
.pagina-viva__testa h3 { margin: 0; }
.pagina-viva__numero {
  margin: 0;
  font-weight: 700;
  font-size: var(--text-sm);
  color: var(--accent-ink);
}
/* Il foglio tiene le proporzioni di una pagina anche quando e' vuoto: senza, il pannello
   saltava di altezza a ogni giro di pagina e la lezione si muoveva sotto gli occhi. */
.pagina-viva__foglio {
  aspect-ratio: 1 / 1.414;
  max-height: min(70vh, 640px);
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
}
.pagina-viva__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
/* Senza pagina dentro, il riquadro si accorcia: la forma di un foglio ha senso attorno a un
   foglio, non attorno a una frase. */
.pagina-viva__foglio.is-vuoto { aspect-ratio: 1 / 0.6; }
.pagina-viva__dicitura {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
  text-align: center;
}
.pagina-viva__vuoto {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-sm);
}
/* MENTRE LA PAGINA E' IN VIAGGIO. Il render a 1600 px non e' istantaneo (134 ms su una scansione
   minimale, molto di piu' su una pagina di libro vera) e per tutti quei secondi qui restava
   l'invito «scegli un libro e avvia la lezione» — il contrario di quel che stava succedendo,
   mentre l'intestazione sopra diceva gia' «Pagina 141». Lo scheletro riempie il riquadro senza
   `is-vuoto`, cioe' tenendo la forma del foglio: quando l'immagine entra, l'altezza non salta. */
.pagina-viva__attesa {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  padding: var(--space-4);
}
.pagina-viva__scheletro {
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, var(--surface-2) 35%, var(--surface-1) 50%, var(--surface-2) 65%);
  background-size: 300% 100%;
  animation: pagina-viva-onda 1.6s linear infinite;
}
.pagina-viva__attesa-riga {
  position: relative;
  margin: 0;
  text-align: center;
}
@keyframes pagina-viva-onda {
  from { background-position: 150% 0; }
  to { background-position: -150% 0; }
}
/* Chi ha chiesto meno movimento tiene il riquadro fermo: resta la forma, resta la frase. */
@media (prefers-reduced-motion: reduce) {
  .pagina-viva__scheletro { animation: none; }
}
/* La strip: le pagine di QUESTA lezione, navigabili col dito. Nasce coi soli numeri e ogni
   bottone guadagna la sua miniatura quando quella pagina viene aperta davvero (vedi
   `pagina-viva.js`): un render gia' pagato, mai uno in piu'. */
.pagina-viva__strip {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  scrollbar-width: thin;
  padding-bottom: var(--space-1);
}
.pagina-viva__strip:empty { display: none; }
.pagina-viva__pagina {
  flex: 0 0 auto;
  width: 58px;
  display: grid;
  gap: var(--space-1);
  padding: var(--space-1);
  font: inherit;
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  cursor: pointer;
}
.pagina-viva__pagina:hover { border-color: var(--accent); color: var(--text); }
.pagina-viva__pagina:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.pagina-viva__pagina.is-attiva {
  border-color: var(--accent);
  color: var(--text);
  box-shadow: var(--glow-s);
}
.pagina-viva__mini {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1.414;
  object-fit: cover;
  border-radius: 6px;
  background: var(--surface-1);
}
.pagina-viva__nota { margin: 0; }

.card__header {
  display: flex;
  align-items: center;
  gap: 8px;
}
.card__header--inline {
  justify-content: space-between;
}

.state-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: 12px;
  font-weight: 700;
  background: var(--surface-2);
  color: var(--muted);
  border: 1px solid var(--border-soft);
}
.state-chip--live {
  background: color-mix(in srgb, #0ea5e9 12%, var(--surface-1));
  color: #0369a1;
  border-color: rgba(3,105,161,0.2);
}
.state-chip--thinking {
  background: color-mix(in srgb, #6366f1 12%, var(--surface-1));
  color: #4338ca;
  border-color: rgba(67,56,202,0.18);
}
.conversation-state { display: flex; gap: 10px; justify-content: center; align-items: center; }
.state-chip { border-radius: var(--radius-pill); }
:root.dark .state-chip--live,
:root.dark .state-chip--thinking {
  background: color-mix(in srgb, var(--accent) 18%, var(--surface-1));
  color: var(--text);
  border-color: var(--border-soft);
  box-shadow: var(--glow-s);
}
.mic__state {
  font-weight: 700;
  color: var(--muted);
}
.mic__state.is-live,
.mic__state.is-thinking {
  color: var(--text);
  text-shadow: var(--glow-s);
}

.live-badge {
  font-weight: 700;
  color: #0369a1;
}
:root.dark .live-badge {
  color: var(--accent);
}

.pill--success {
  background: color-mix(in srgb, #15803d 15%, var(--surface-1));
  color: #15803d;
}
:root.dark .pill--success {
  background: color-mix(in srgb, #15803d 20%, var(--surface-1));
  color: #86efac;
}
.pill--pulse { animation: pulse 1.8s ease-in-out infinite; }
.pill--source { border: 1px dashed rgba(37,99,235,0.26); }

.waveform {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
  height: 24px;
  margin-top: 8px;
}
.waveform span {
  display: block;
  width: 100%;
  background: linear-gradient(180deg, #60a5fa, #a855f7);
  border-radius: 10px;
  height: 10px;
  opacity: 0.4;
  animation: wave 1s ease-in-out infinite;
  animation-play-state: paused;
}
.waveform.is-live span { opacity: 0.9; animation-play-state: running; }
/* L'avviso «microfono spento» è una live region `role="status"` che resta SEMPRE nell'albero di
   accessibilità: una region che entra e esce dall'albero non produce un annuncio affidabile —
   per NVDA/JAWS/VoiceOver una region appena renderizzata è nuova, e ciò che vi compare dentro
   nello stesso istante non viene letto. Per questo NON si usa `display: none` (che rimuove il
   nodo dall'albero esattamente come `hidden`, cioè avrebbe la stessa patologia del male che
   voleva evitare): si toglie solo l'INGOMBRO, con la stessa tecnica di `.sr-only` — l'elemento
   resta renderizzato e nell'albero, ma non occupa spazio e non si vede. Vedi `aggiornaMic` in
   realtime.js. */
#mic-stato:empty {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
  background: none;
  box-shadow: none;
}
.waveform span:nth-child(2) { animation-delay: 0.1s; }
.waveform span:nth-child(3) { animation-delay: 0.2s; }
.waveform span:nth-child(4) { animation-delay: 0.3s; }
.waveform span:nth-child(5) { animation-delay: 0.4s; }

.badge-row--feedback { justify-content: flex-start; }

.topic-row { gap: 10px; flex-wrap: wrap; }
.btn-group { display: flex; gap: 8px; flex-wrap: wrap; }

/* ── Contesto unificato: «📎 Aggiungi materiale» ───────────────────────────
   Un bottone, uno sheet a tre sorgenti, UNA card con UNA sola ✕. Le miniature sono
   le stesse di prima (regole rinominate 1:1): quello che cambia è chi le possiede.
   Solo token: il tema scuro viene gratis, nessun hex nuovo. */
.ctx { display: grid; gap: var(--space-2); }
.ctx-entry { width: 100%; justify-content: center; }
@media (min-width: 641px) {
  .ctx-entry { width: auto; }
}

/* Sheet: bottom-sheet sul telefono, dialog centrato sopra i 640px. */
.ctx-sheet-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(6px);
}
.ctx-sheet-backdrop[hidden] { display: none; }
.ctx-sheet {
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
  padding-bottom: calc(var(--space-4) + env(safe-area-inset-bottom));
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-card) var(--radius-card) 0 0;
  box-shadow: var(--shadow-l);
  text-align: left;
  animation: ctxSlideUp 200ms ease;
}
@keyframes ctxSlideUp {
  from { transform: translateY(16px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
.ctx-sheet__title { margin: 0 0 var(--space-1); font-size: var(--text-lg); }
.ctx-sheet__row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: 52px;
  padding: var(--space-3);
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-control);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.ctx-sheet__row:hover { border-color: var(--accent); }
.ctx-sheet__row:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ctx-sheet__row strong { display: block; }
.ctx-sheet__row small { display: block; }
.ctx-sheet__icon { font-size: var(--text-xl); flex-shrink: 0; }
.ctx-sheet__cancel { width: 100%; min-height: 44px; margin-top: var(--space-1); }
@media (min-width: 641px) {
  .ctx-sheet-backdrop { align-items: center; }
  .ctx-sheet {
    max-width: 420px;
    border-radius: var(--radius-card);
    animation: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .ctx-sheet { animation: none; }
}

/* Card del materiale: evoluzione 1:1 della vecchia anteprima Vision. */
.ctx-card {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3);
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  align-items: flex-start;
  text-align: left;
}
/* Striscia miniature: fino a 3 + tessera «+N». Decorativa (aria-hidden): il conteggio è
   già scritto a parole in .ctx-card__name, che è ciò che uno screen reader annuncia. */
.ctx-card__thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  flex-shrink: 0;
  max-width: 128px;
}
.ctx-thumb {
  width: 56px;
  height: 56px;
  border-radius: 8px;
  object-fit: cover;
  border: 2px solid var(--border);
  background: var(--bg1);
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--muted);
}
.ctx-thumb--more { background: var(--surface-1); color: var(--text); }
@media (max-width: 480px) {
  .ctx-card__thumbs { max-width: 104px; }
  .ctx-thumb { width: 46px; height: 46px; }
}
.ctx-card__body { flex: 1; min-width: 0; }
.ctx-card__name {
  font-weight: 600;
  color: var(--text);
  font-size: var(--text-sm);
  margin-bottom: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ctx-card__status {
  font-size: var(--text-sm);
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 6px;
}
.ctx-card__status.is-loading { color: var(--accent); }
.ctx-card__status.is-loading::before {
  content: "";
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  flex-shrink: 0;
}
.ctx-card__status.is-success { color: var(--color-success-ink); }
.ctx-card__status.is-error { color: var(--color-danger); }
@media (prefers-reduced-motion: reduce) {
  .ctx-card__status.is-loading::before { animation: none; }
}
.ctx-card__action { margin-top: var(--space-2); }
/* WCAG 2.5.5: l'unica ✕ della pagina deve essere un bersaglio vero. */
.ctx-card__remove {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  color: var(--muted);
  cursor: pointer;
  border-radius: var(--radius-control);
  flex-shrink: 0;
}
.ctx-card__remove:hover { color: var(--color-danger); background: var(--surface-1); }
.ctx-card__remove:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ctx-card__remove svg { width: 20px; height: 20px; display: block; }
/* Con lo sheet aperto la pagina sotto non scorre. */
body.ctx-scroll-lock { overflow: hidden; }

/* La terza sorgente («Un tuo appunto») apre la lista degli appunti in una modal, montata da
   `notes.js#pickNote`. Le sue regole di LAYOUT vivevano in `appunti.css` — cioè nell'unico
   foglio che tutor/orale/esercizi NON caricano, e sono esattamente le tre pagine da cui quella
   lista si apre. Senza position/display/z-index il fondale finiva in coda al `<body>`: la lista
   sotto la piega, sotto il FAB, fuori dal flusso. Stanno qui, dove le legge ogni pagina
   (appunti.html compresa: carica anche style.css). Colori, ombra e animazione restano quelli
   già definiti sopra per `.note-modal`/`.note-modal-backdrop`: qui solo la geometria. */
.note-modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--space-3);
}
.note-modal-backdrop.is-open { display: flex; }
.note-modal {
  width: 100%;
  max-width: 480px;
  max-height: 80vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
}
.note-modal__header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.note-modal__list { display: flex; flex-direction: column; gap: var(--space-2); }
/* Stessa altezza delle righe dello sheet: si sceglie l'appunto col pollice, non col mouse. */
.note-modal__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 52px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-control);
}

/* Topic lock indicator styling */
.topic-lock-indicator {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: var(--accent);
  font-weight: 600;
  padding: 2px 8px;
  background: var(--accent-soft);
  border-radius: var(--radius-pill);
  margin-left: 8px;
}
.topic-lock-indicator svg {
  width: 12px;
  height: 12px;
}
.input.is-locked {
  background: var(--surface-2);
  border-color: var(--accent);
  box-shadow: var(--glow-s);
}
.btn--outline {
  background: var(--surface-1);
  color: var(--text);
  border: 1px solid color-mix(in srgb, var(--accent) 36%, transparent);
  box-shadow: var(--shadow);
}
.btn--outline:hover {
  border-color: var(--accent);
  box-shadow: var(--glow-s);
}
.btn--sm { padding: 6px 10px; border-radius: 10px; font-size: 13px; }
.btn--soft {
  background: color-mix(in srgb, var(--accent) 8%, var(--surface-1));
  color: var(--text);
  border: 1px solid color-mix(in srgb, var(--accent) 14%, transparent);
}
.btn--soft:hover {
  background: color-mix(in srgb, var(--accent) 14%, var(--surface-1));
  border-color: var(--accent);
}


.band-separator { height: 1px; background: var(--border); margin: 12px 0; }

.status-bar { background: #f8fafc; border: 1px solid var(--border); padding: 10px 12px; border-radius: 12px; font-weight: 700; color: var(--muted); }

/* Esercizi flow */
.mode-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}
.mode-card {
  border: 1px solid var(--border-soft);
  border-radius: 16px;
  padding: 14px;
  background: var(--surface-1);
  color: var(--text);
  box-shadow: var(--shadow);
  cursor: pointer;
  transition: all 0.18s ease;
}
.mode-card:hover { transform: translateY(-2px); border-color: var(--primary); box-shadow: var(--shadow-strong); }
.mode-card.active { border-color: var(--primary); box-shadow: var(--shadow-strong); }
.mode-card h4 { margin: 6px 0; }
.mode-meta { display: flex; gap: 6px; align-items: center; color: var(--muted); font-weight: 600; }

.question-meta { display: flex; justify-content: space-between; align-items: center; gap: 8px; color: var(--muted); font-weight: 600; }
.timer { font-weight: 700; color: var(--primary); }
.helpers { display: flex; gap: 8px; flex-wrap: wrap; }
.helper-btn {
  padding: 8px 10px;
  border: 1px solid var(--border-soft);
  background: var(--surface-1);
  color: var(--text);
  border-radius: 10px;
  font-weight: 700;
  cursor: pointer;
  transition: all 0.15s ease;
}
.helper-btn:hover {
  border-color: var(--primary);
  color: var(--primary);
  background: color-mix(in srgb, var(--accent) 8%, var(--surface-1));
}

.focus-banner {
  border: 1px solid #fecdd3;
  background: #fff1f2;
  color: #b91c1c;
  border-radius: 14px;
  padding: 12px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
}
:root.dark .focus-banner {
  background: color-mix(in srgb, #b91c1c 15%, var(--surface-1));
  border-color: rgba(239, 68, 68, 0.4);
  color: #fca5a5;
}

.results-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
}
.stat-card {
  padding: 14px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 14px;
  box-shadow: var(--shadow);
  color: var(--text);
}
.cta-row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; }

/* Profile mini panel */
.nav-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--gradient-accent);
  color: #fff;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
  transition: transform 0.15s ease;
}
.nav-avatar:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(37, 99, 235, 0.35);
}

/* Navbar logged-in actions */
.navbar__actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.navbar__actions .btn--sm {
  padding: 8px;
  min-width: 36px;
  min-height: 36px;
}

.navbar__actions .btn--sm svg {
  display: block;
}

.nav-logout {
  color: var(--muted);
}

.nav-logout:hover {
  color: var(--danger, #ef4444);
  background: rgba(239, 68, 68, 0.1);
}

/* ====================================================================== */
/* AUDIO-REACTIVE AVATAR SYSTEM                                            */
/* Uses CSS custom property --audio-level (0-1) set by JavaScript          */
/* ====================================================================== */
.avatars {
  display: flex;
  gap: 32px;
  align-items: center;
  justify-content: center;
}
.avatar-stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.avatar {
  /* Audio-reactive custom property (0-1), set by JS */
  --audio-level: 0;

  position: relative;
  width: 110px;
  height: 110px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
  color: #fff;
  font-weight: 700;
  letter-spacing: 0.3px;

  /* Gradient background */
  background:
    radial-gradient(circle at 30% 30%, rgba(255,255,255,0.32), transparent 55%),
    linear-gradient(145deg, rgba(59,130,246,0.45), rgba(124,58,237,0.35));
  border: 1px solid rgba(255,255,255,0.35);
  backdrop-filter: blur(10px);

  /* Audio-reactive transform and glow */
  transform: scale(calc(1 + var(--audio-level) * 0.12));
  box-shadow:
    0 0 calc(20px + var(--audio-level) * 40px) rgba(124,58,237, calc(0.2 + var(--audio-level) * 0.4)),
    0 12px 32px rgba(15,23,42,0.25),
    inset 0 1px 0 rgba(255,255,255,0.3);

  transition: background 0.2s ease;
  /* transform and box-shadow use will-change for smooth animation */
  will-change: transform, box-shadow;
}

/* Inner aura - audio reactive */
.avatar::before {
  content: "";
  position: absolute;
  inset: -14px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(124,58,237,0.38), transparent 60%);
  opacity: calc(0.4 + var(--audio-level) * 0.5);
  transform: scale(calc(1 + var(--audio-level) * 0.15));
  z-index: -1;
  pointer-events: none;
  will-change: opacity, transform;
}

/* Outer glow ring - audio reactive */
.avatar::after {
  content: "";
  position: absolute;
  inset: -24px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(59,130,246,0.25), transparent 55%);
  opacity: calc(0.15 + var(--audio-level) * 0.35);
  transform: scale(calc(0.95 + var(--audio-level) * 0.18));
  filter: blur(8px);
  z-index: -2;
  pointer-events: none;
  will-change: opacity, transform;
}

/* Avatar Inner Icon - Professional Look */
.avatar .avatar__icon {
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
}
.avatar .avatar__icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.15));
}
.avatar--student .avatar__icon {
  color: rgba(255, 255, 255, 0.95);
}
.avatar--ai .avatar__icon {
  color: rgba(255, 255, 255, 0.95);
}
/* Avatar Initial Letter */
.avatar .avatar__initial {
  font-size: 36px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.95);
  text-transform: uppercase;
  z-index: 2;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}

/* Center dot - fallback */
.avatar .avatar__dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 calc(10px + var(--audio-level) * 14px) rgba(255,255,255, calc(0.5 + var(--audio-level) * 0.4));
  position: relative;
  z-index: 1;
  will-change: box-shadow;
}

/* Label below avatar */
.avatar-label {
  font-size: 14px;
  font-weight: 800;
  color: var(--text);
  text-align: center;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

/* Student variant - green tint */
.avatar--student {
  background:
    radial-gradient(circle at 30% 30%, rgba(255,255,255,0.28), transparent 55%),
    linear-gradient(145deg, rgba(34,197,94,0.40), rgba(59,130,246,0.32));
}
.avatar--student::before {
  background: radial-gradient(circle, rgba(34,197,94,0.42), transparent 60%);
}
.avatar--student::after {
  background: radial-gradient(circle, rgba(34,197,94,0.28), transparent 55%);
}

/* AI variant - violet tint */
.avatar--ai {
  background:
    radial-gradient(circle at 30% 30%, rgba(255,255,255,0.32), transparent 55%),
    linear-gradient(145deg, rgba(124,58,237,0.45), rgba(99,102,241,0.35));
}
.avatar--ai::before {
  background: radial-gradient(circle, rgba(124,58,237,0.45), transparent 60%);
}
.avatar--ai::after {
  background: radial-gradient(circle, rgba(124,58,237,0.30), transparent 55%);
}

/* State classes - legacy support + enhancements */
.avatar.is-listening::after {
  opacity: calc(0.35 + var(--audio-level) * 0.4);
  transform: scale(calc(1.02 + var(--audio-level) * 0.12));
}
.avatar.is-thinking::before {
  animation: aura-think 1.4s ease-in-out infinite;
}
.avatar.is-speaking {
  --audio-level: 0.5; /* Fallback when JS not driving */
}
.avatar.is-speaking .avatar__dot {
  animation: talk 0.5s ease-in-out infinite;
}

/* Dark mode enhancements */
:root.dark .avatar {
  border-color: rgba(255,255,255,0.22);
  box-shadow:
    0 0 calc(24px + var(--audio-level) * 50px) rgba(34,211,238, calc(0.25 + var(--audio-level) * 0.45)),
    0 14px 38px rgba(0,0,0,0.35),
    inset 0 1px 0 rgba(255,255,255,0.18);
}
:root.dark .avatar::before {
  background: radial-gradient(circle, rgba(34,211,238,0.40), transparent 60%);
}
:root.dark .avatar::after {
  background: radial-gradient(circle, rgba(139,92,246,0.30), transparent 55%);
}
:root.dark .avatar--student::before {
  background: radial-gradient(circle, rgba(74,222,128,0.42), transparent 60%);
}
:root.dark .avatar--ai::before {
  background: radial-gradient(circle, rgba(139,92,246,0.45), transparent 60%);
}
:root.dark .avatar .avatar__dot {
  box-shadow: 0 0 calc(12px + var(--audio-level) * 18px) rgba(255,255,255, calc(0.6 + var(--audio-level) * 0.35));
}

/* Waveform animations */
.waveform.is-live span { animation: wave 0.9s ease-in-out infinite; }
.waveform.is-live span:nth-child(2) { animation-delay: 0.1s; }
.waveform.is-live span:nth-child(3) { animation-delay: 0.2s; }
.waveform.is-live span:nth-child(4) { animation-delay: 0.3s; }
.waveform.is-live span:nth-child(5) { animation-delay: 0.4s; }

/* Keyframe animations */
@keyframes aura-think {
  0% { transform: scale(0.92); opacity: 0.4; }
  50% { transform: scale(1.08); opacity: 0.7; }
  100% { transform: scale(0.92); opacity: 0.4; }
}
@keyframes talk {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.2); opacity: 0.75; }
}
@keyframes wave {
  0%, 100% { transform: scaleY(0.6); }
  50% { transform: scaleY(1.2); }
}

/* (Slice 1 dedup) Removed FINAL THEME OVERRIDES section duplicates:
   .navbar / :root.dark .navbar / .navlink (already defined L97-118)
   .card union (same rules already present L121-150)
   .btn / .input / .pill / .tab-btn / .note-modal-backdrop
   (already defined L150-220). Cascade order preserved. */

/* ====================================================================== */
/* CLEANUP WHITES / RESIDUALS (force tokens)                               */
/* ====================================================================== */
.page,
.section { background: var(--bg); }
.hero,
.pricing-hero,
.footer { background: var(--bg1); }

.btn--ghost,
.btn--open,
.btn--outline,
.btn--soft { background: var(--surface-1); border-color: var(--border-soft); color: var(--text); }

.chip,
.pref-item,
.file-drop,
.class-card,
.card,
.panel { background: var(--surface-1); color: var(--text); }
.option-btn { background: var(--surface-1); border: 1px solid var(--border-soft); color: var(--text); }
.option-btn:hover { background: color-mix(in srgb, var(--accent) 10%, var(--surface-1)); border-color: var(--accent); box-shadow: var(--shadow-m); }
.option-btn.selected { color: var(--text); border-color: var(--accent); box-shadow: var(--glow-s); }

.exercise-card.glass,
.generate-cta,
.card--hero-loading { background: var(--surface-1); border-color: var(--border-soft); box-shadow: var(--shadow-m); }

.answer-card,
.quiz-card,
.exercise-container,
.pricing-card,
.pricing-hero__glance { background: var(--surface-1); border-color: var(--border-soft); box-shadow: var(--shadow-m); color: var(--text); }

.card--tutor,
.card--orale,
.card--quiz,
.card--appunti,
.quiz-card,
.answer-card,
.transcript { background: var(--surface-1); }

.footer,
.navbar__actions .btn.btn--ghost { border-color: var(--border-soft); }

::selection { background: color-mix(in srgb, var(--accent) 24%, var(--bg)); color: var(--text); }

:root.dark .pricing-hero,
:root.dark .pricing-hero__glance,
:root.dark .pricing-card,
:root.dark .exercise-container,
:root.dark .exercise-card.glass,
:root.dark .generate-cta,
:root.dark .card--hero-loading,
:root.dark .quiz-card,
:root.dark .answer-card,
:root.dark .card--tutor,
:root.dark .card--orale,
:root.dark .card--quiz,
:root.dark .card--appunti,
:root.dark .transcript {
  background: var(--surface-1);
  border-color: var(--border-soft);
  box-shadow: var(--shadow-m);
}
:root.dark .status-bar,
:root.dark .alert,
:root.dark .materials-head { background: color-mix(in srgb, var(--surface-1) 90%, var(--accent) 10%); }

.question,
.plan-list li,
.avatar-label,
.plan-price__value { color: var(--text); }

/* Tutor hero: warm gradient */
.hero--tutor {
  background: radial-gradient(circle at 30% 30%, rgba(245,158,11,0.12), transparent 50%),
              radial-gradient(circle at 70% 60%, rgba(234,88,12,0.08), transparent 40%);
}
/* Orale hero: formal cool gradient */
.hero--orale {
  background: radial-gradient(circle at 30% 40%, rgba(99,102,241,0.12), transparent 50%),
              radial-gradient(circle at 70% 20%, rgba(124,58,237,0.08), transparent 40%);
}

/* Exercises premium */
.section--glow {
  background: radial-gradient(circle at 20% 20%, rgba(37,99,235,0.10), transparent 40%),
              radial-gradient(circle at 80% 10%, rgba(124,58,237,0.10), transparent 35%),
              radial-gradient(circle at 50% 80%, rgba(56,189,248,0.08), transparent 45%);
}
.card--stack { display: flex; flex-direction: column; gap: 10px; }
.pillrow { display: flex; flex-wrap: wrap; gap: 8px; }
.check-list { list-style: none; padding: 0; margin: 8px 0 0; display: grid; gap: 6px; }
.check-list li::before { content: "✓ "; color: var(--accent); font-weight: 700; }
.chip-list { display: flex; flex-wrap: wrap; gap: 8px; padding: 8px 0; }
.chip-list .pill { background: var(--surface-1); color: var(--text); border-color: var(--border-soft); }
.progress-group { display:flex; flex-direction:column; gap:4px; min-width:140px; }
.progress-bar { width:100%; height:6px; background:rgba(0,0,0,0.06); border-radius:999px; overflow:hidden; }
.progress-fill { height:100%; width:0%; background:var(--gradient-accent); transition:width .3s ease; }
.exercise-card.glass {
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--surface-1) 88%, var(--accent) 12%),
    color-mix(in srgb, var(--surface-1) 88%, var(--accent-violet) 12%)
  );
  border: 1px solid var(--border-soft);
  box-shadow: var(--shadow-m);
  border-radius: 18px;
  padding: 20px;
}
.question { font-size:18px; font-weight:600; margin-bottom:14px; }
.options { display:grid; gap:10px; }
.option-btn {
  width: 100%;
  padding: 13px 16px;
  border-radius: 14px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  color: var(--text);
  text-align: left;
  transition: all 0.18s ease;
  cursor: pointer;
}
.option-btn:hover {
  background: color-mix(in srgb, var(--accent) 10%, var(--surface-1));
  transform: translateY(-1px);
  box-shadow: var(--shadow-m);
}
.option-btn.selected {
  background: color-mix(in srgb, var(--accent) 18%, var(--surface-1));
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border-soft));
  box-shadow: var(--glow-s);
  color: var(--text);
}
.feedback-box { margin-top:12px; padding:12px; border-radius:14px; font-size:14px; }
.feedback-correct { background:rgba(76,217,100,0.15); border:1px solid rgba(76,217,100,0.45); color:#1f8a3d; }
.feedback-wrong { background:rgba(255,59,48,0.12); border:1px solid rgba(255,59,48,0.4); color:#b12a1f; }
:root.dark .feedback-correct {
  background: color-mix(in srgb, #22c55e 15%, var(--surface-1));
  border-color: rgba(34, 197, 94, 0.45);
  color: #86efac;
}
:root.dark .feedback-wrong {
  background: color-mix(in srgb, #ef4444 12%, var(--surface-1));
  border-color: rgba(239, 68, 68, 0.4);
  color: #fca5a5;
}

.exercise-actions { display:flex; gap:10px; flex-wrap:wrap; margin-top:14px; }

.class-list { display:grid; gap:12px; }
.code-box { margin-top:10px; padding:10px; border:1px dashed var(--border-soft); border-radius:var(--radius-control); background:var(--surface-1); color: var(--text); box-shadow: var(--shadow-s); }
.code-row { display:flex; gap:8px; align-items:center; justify-content:space-between; }

/* Pricing page */
.pricing-hero {
  position: relative;
  padding: 48px 0 24px;
  background: radial-gradient(circle at 85% 30%, rgba(124,58,237,0.18), transparent 40%),
              radial-gradient(circle at 95% 70%, rgba(37,99,235,0.12), transparent 30%);
  overflow: hidden;
}
.pricing-hero::after {
  content: "";
  position: absolute;
  width: 420px;
  height: 420px;
  border-radius: 50%;
  background: conic-gradient(from 120deg, rgba(124,58,237,0.18), rgba(37,99,235,0.16), rgba(16,185,129,0.12), rgba(124,58,237,0.18));
  right: -180px;
  top: -120px;
  filter: blur(12px);
  opacity: 0.8;
  animation: floatGlow 9s ease-in-out infinite alternate;
}
.pricing-hero__inner {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 20px;
  align-items: center;
  position: relative;
  z-index: 1;
}
.pricing-hero__glance {
  background: color-mix(in srgb, var(--card) 88%, var(--bg) 12%);
  border: 1px solid rgba(37,99,235,0.12);
  border-radius: 18px;
  padding: 16px;
  box-shadow: 0 16px 40px rgba(15,23,42,0.12);
}
.pricing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px;
}
/* Ancoraggio di valore sopra la griglia piani: contestualizza il prezzo vs le ripetizioni umane. */
.pricing-anchor {
  margin: 0 0 18px;
  padding: 12px 16px;
  border-left: 3px solid var(--accent);
  background: var(--surface-1);
  border-radius: 8px;
  color: var(--text);
  font-size: 0.98rem;
}
/* Sottotitolo "consigliato per…" sotto il nome del piano. */
.plan-forwho {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 0.85rem;
}
.pricing-card {
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 18px;
  /* Il colore pieno PRIMA del gradiente, e non è ridondanza: `color-mix()` non esiste su
     iOS Safari < 16.2 e su un browser che non lo capisce l'INTERA dichiarazione `background`
     viene scartata — la card resta senza fondo, cioè invisibile su pagina chiara. È la
     causa candidata di «i piani da telefono non si vedono» (founder, 2026-08-06). Con il
     colore pieno dichiarato prima, chi non capisce il gradiente vede comunque una card. */
  background-color: var(--card);
  background-image: linear-gradient(
    145deg,
    color-mix(in srgb, var(--card) 88%, var(--bg) 12%),
    color-mix(in srgb, var(--card) 76%, var(--primary) 24%)
  );
  box-shadow: 0 12px 32px rgba(15,23,42,0.12);
  position: relative;
  overflow: hidden;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.pricing-card:hover { transform: translateY(-4px); border-color: rgba(37,99,235,0.35); box-shadow: 0 20px 50px rgba(37,99,235,0.16); }
.pricing-card::after {
  content: "";
  position: absolute;
  inset: -20% -40%;
  background: radial-gradient(circle at 80% 10%, rgba(124,58,237,0.14), transparent 30%),
              radial-gradient(circle at 30% 90%, rgba(37,99,235,0.12), transparent 26%);
  z-index: 0;
}
.pricing-card > * { position: relative; z-index: 1; }
.pricing-card--featured {
  border-color: rgba(16,185,129,0.45);
  box-shadow: 0 24px 60px rgba(16,185,129,0.22);
}
.plan-head { display:flex; align-items:center; justify-content:space-between; gap:10px; }
.plan-price { display:flex; align-items:flex-end; gap:4px; margin:8px 0 6px; }
.plan-price__value { font-size: 30px; font-weight: 800; color: var(--primary); line-height: 1; }
.plan-price__note { color: var(--muted); font-weight: 700; }
.plan-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: var(--radius-control);
  background: color-mix(in srgb, #15803d 15%, var(--surface-1));
  color: #15803d;
  font-weight: 700;
}
:root.dark .plan-pill {
  background: color-mix(in srgb, #22c55e 18%, var(--surface-1));
  color: #86efac;
}
.pill-meta { display:inline-flex; align-items:center; gap:6px; padding:6px 10px; border-radius:var(--radius-control); background: color-mix(in srgb, var(--accent) 12%, var(--surface-1)); color: var(--text); font-weight:700; font-size:12px; }
.plan-meta { display:flex; flex-wrap:wrap; gap:8px; margin:10px 0; color: var(--muted); font-weight:700; font-size:13px; }
.plan-list { list-style:none; padding:0; margin:10px 0; display:grid; gap:6px; }
.plan-list li { display:flex; align-items:center; gap:8px; font-weight:600; color: var(--text); }
.plan-list li::before { content:'✓'; color: var(--accent); font-weight:800; }
.btn--wide { width: 100%; justify-content: center; display: inline-flex; }
.btn--glow { box-shadow: 0 12px 32px rgba(37,99,235,0.3); }
.topup-grid { display:flex; gap:10px; flex-wrap:wrap; }
.topup-card {
  border: 1px dashed color-mix(in srgb, var(--accent) 35%, transparent);
  padding: 12px 14px;
  border-radius: var(--radius-control);
  background: color-mix(in srgb, var(--accent) 4%, var(--surface-1));
  color: var(--text);
  font-weight: 700;
}
.b2b-card {
  border: 1px solid rgba(16, 185, 129, 0.28);
  background: linear-gradient(145deg, color-mix(in srgb, #10b981 8%, var(--surface-1)), color-mix(in srgb, var(--accent) 8%, var(--surface-1)));
  box-shadow: 0 14px 30px rgba(16, 185, 129, 0.18);
}

/* --- Gerarchia della vetrina prezzi ---------------------------------------------------
   Selettore privati/scuole, striscia della prova e cassetto dei piani secondari: la pagina
   mostrava tredici blocchi d'acquisto tutti allo stesso livello, qui si decide cosa si vede
   subito. Solo token, nessun colore a mano. */
.pricing-switch {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
}
.pricing-switch button {
  border: 0;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-weight: 600;
  padding: 10px 16px;
  min-height: 44px;              /* tap target WCAG 2.5.5 */
  border-radius: var(--radius-control);
  cursor: pointer;
}
.pricing-switch button[aria-pressed="true"] {
  color: var(--primary);
  background: var(--card);
  font-weight: 700;
}
/* La prova non si compra: è una striscia larga quanto la griglia, con l'unica azione vera
   (registrarsi). Sta dentro .pricing-card per restare coerente col tema chiaro/scuro. */
.pricing-card--trial {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.pricing-card--trial h3,
.pricing-card--trial p { margin: 0; }
#altri-piani {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px;
}
#altri-piani-toggle { grid-column: 1 / -1; justify-self: center; }
/* Selettore Mensile/Annuale (19/8, richiesta founder: «uno switch più figo, fluido, animato»).
   Stessa semantica di prima (due bottoni + aria-pressed), ma la selezione è un POLLICE che
   scivola sotto le etichette: il gruppo porta `data-periodo` e il ::before si sposta con una
   transition — niente JS di animazione, niente layout che salta. */
.pricing-switch--periodo {
  margin: 0 0 18px;
  position: relative;
  display: inline-grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  isolation: isolate;
}
.pricing-switch--periodo::before {
  content: "";
  position: absolute;
  inset: 4px calc(50% - 0px) 4px 4px;   /* metà sinistra, al netto del padding del gruppo */
  border-radius: var(--radius-control);
  background: var(--card);
  box-shadow: 0 1px 6px rgba(29, 26, 43, 0.12);
  transition: transform 260ms cubic-bezier(0.22, 1, 0.36, 1);
  z-index: -1;
}
.pricing-switch--periodo[data-periodo="year"]::before { transform: translateX(100%); }
.pricing-switch--periodo button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: color 200ms ease;
}
/* Il fondo del selezionato lo disegna il pollice: il bottone resta trasparente, o coprirebbe
   la scivolata con uno scatto. */
.pricing-switch--periodo button[aria-pressed="true"] { background: transparent; }
@media (prefers-reduced-motion: reduce) {
  .pricing-switch--periodo::before { transition: none; }
}
/* Il badge «2 mesi gratis» dentro il bottone non deve gridare più della parola che accompagna. */
.pricing-switch--periodo .pill { font-size: 12px; padding: 2px 8px; }
/* Al cambio di periodo il prezzo nuovo entra con un piccolo pop (classe ri-armata dal JS). */
.periodo-swap .plan-price__value {
  animation: prezzo-pop 340ms cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes prezzo-pop {
  0% { opacity: 0; transform: translateY(6px) scale(0.97); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .periodo-swap .plan-price__value { animation: none; }
}
/* Il badge «2 mesi gratis» dentro il bottone non deve gridare più della parola che accompagna. */
.pricing-switch--periodo .pill { font-size: 12px; padding: 2px 8px; }
/* La cifra davvero addebitata sull'annuale: piccola e muted, ma SEMPRE presente. Il numero
   grande è l'equivalente mensile — nessuno deve scoprire alla cassa che l'addebito è
   dodici volte quello che ha letto. */
.plan-price__fatturato { margin: -4px 0 6px; }
/* Le pill stanno in fila: su Bronze in modalità annuale ce ne sono due («Consigliato» e
   «2 mesi gratis») e senza contenitore andrebbero a capo storte. */
.plan-pills { display: flex; flex-wrap: wrap; gap: 6px; }
/* «2 mesi gratis» non è la stessa cosa di «Consigliato»: colore diverso (accento invece del
   verde della raccomandazione), così due pill affiancate restano due informazioni. */
.plan-pill--anno {
  background: color-mix(in srgb, var(--accent) 16%, var(--surface-1));
  color: var(--primary);
}
:root.dark .plan-pill--anno {
  background: color-mix(in srgb, var(--accent) 24%, var(--surface-1));
  color: var(--primary);
}
/* La promessa dei 14 giorni sta sotto il bottone che la mantiene, non in fondo alla pagina. */
.plan-trialnote { margin: 8px 0 0; text-align: center; }
/* La navbar è fissa: senza questo, «Vedi i piani» incolla il titolo sotto la barra. */
#piani { scroll-margin-top: 80px; }

@keyframes floatGlow {
  0% { transform: translateY(0) rotate(0deg); }
  100% { transform: translateY(18px) rotate(6deg); }
}

/* Dark theme fixes for pricing */
:root.dark .pricing-hero {
  background: radial-gradient(circle at 85% 30%, rgba(109,220,255,0.12), transparent 42%),
              radial-gradient(circle at 95% 70%, rgba(124,58,237,0.16), transparent 36%),
              linear-gradient(135deg, #0b1021 0%, #0f172a 40%, #0b1021 100%);
}
:root.dark .pricing-hero__glance {
  background: color-mix(in srgb, var(--card) 72%, var(--primary) 12%);
  border-color: rgba(255,255,255,0.08);
  box-shadow: var(--shadow-strong);
}
:root.dark .pricing-card {
  border-color: rgba(255,255,255,0.08);
  background: linear-gradient(
    145deg,
    color-mix(in srgb, var(--card) 86%, #0b1021 14%),
    color-mix(in srgb, var(--card) 70%, var(--primary) 30%)
  );
  box-shadow: var(--shadow-strong), var(--glow-primary);
}
:root.dark .pricing-card::after {
  opacity: 0.75;
}
:root.dark .plan-list li { color: var(--text); }
:root.dark .plan-list li::before { color: var(--primary); }
:root.dark .plan-price__value { color: var(--primary); }
:root.dark .plan-meta { color: var(--muted); }
:root.dark .topup-card {
  background: color-mix(in srgb, var(--primary) 12%, var(--card) 88%);
  border-color: rgba(109,220,255,0.35);
  color: var(--text);
}
:root.dark .b2b-card {
  background: linear-gradient(145deg, color-mix(in srgb, var(--card) 80%, #0b1021 20%), color-mix(in srgb, var(--card) 60%, var(--primary) 40%));
}

/* ====================================================================== */
/* SKELETON LOADER                                                         */
/* ====================================================================== */
.skeleton {
  background: linear-gradient(90deg, var(--surface-1) 25%, var(--surface-2) 50%, var(--surface-1) 75%);
  background-size: 200% 100%;
  animation: skeleton-pulse 1.5s ease-in-out infinite;
  border-radius: 4px;
}
@keyframes skeleton-pulse {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
.skeleton-text { height: 1em; margin-bottom: 0.5em; }
.skeleton-title { height: 1.5em; width: 60%; margin-bottom: 1em; }
.skeleton-card { height: 120px; }

/* (restyle dedup) The canonical toast system lives in the single block
   further down (border-left accent variant, matches ui.js markup). The
   duplicate colored-background system that lived here was removed — two
   definitions made light and dark themes render different components. */

/* ====================================================================== */
/* ENTERPRISE MOBILE RESPONSIVE - Touch-First Design                       */
/* ====================================================================== */

/* 1. Touch Targets - Minimum 44px for accessibility (WCAG 2.1 AAA) */
.btn,
.nav-avatar,
.chip,
.tab-btn,
.option-btn,
.helper-btn,
.nav-toggle,
.profile-panel__links a {
  min-height: 44px;
  min-width: 44px;
}

/* 2. Safe Area Support for iPhone notch/home indicator */
@supports (padding: env(safe-area-inset-bottom)) {
  .footer {
    padding-bottom: calc(16px + env(safe-area-inset-bottom));
  }
  .navbar {
    padding-top: env(safe-area-inset-top);
  }
  .toast-container {
    top: calc(20px + env(safe-area-inset-top));
    right: calc(20px + env(safe-area-inset-right));
  }
}

/* 3. Mobile Navigation Menu - Full Screen Overlay */
@media (max-width: 900px) {
  .navbar__inner {
    flex-wrap: wrap;
    padding: 10px 16px;
  }

  .navbar__links {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--bg);
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    padding: 80px 24px 24px;
    z-index: 998;
    gap: 8px;
    overflow-y: auto;
  }

  .navbar__links .navlink {
    padding: 14px 16px;
    font-size: 16px;
    border-radius: var(--radius-control);
    background: var(--surface-1);
    border: 1px solid var(--border-soft);
  }

  .navbar__right {
    order: 3;
    width: 100%;
    margin-top: 8px;
    justify-content: space-between;
  }

  .navbar__right.mobile-open {
    display: flex;
  }

  .theme-switch-wrap {
    order: -1;
  }
}

/* 4. Hero Section Mobile Optimization */
@media (max-width: 720px) {
  .hero {
    padding: 24px 0 32px;
    text-align: center;
  }

  .hero__title {
    font-size: clamp(24px, 7vw, 34px);
  }

  .hero__subtitle {
    font-size: 15px;
    margin: 8px auto 16px;
  }

  .hero__controls--inline {
    flex-direction: column;
    gap: 12px;
    align-items: stretch;
  }

  .btn-group {
    flex-direction: column;
    width: 100%;
  }

  .btn-group .btn {
    width: 100%;
  }

  .eyebrow {
    margin: 0 auto;
  }

  .landing-neo {
    padding: 20px 0;
    min-height: unset;
  }

  .landing-actions {
    flex-direction: column;
    gap: 12px;
  }

  .landing-actions .btn {
    width: 100%;
  }
}

/* 5. Cards Mobile Optimization */
@media (max-width: 480px) {
  .container {
    padding: 0 12px;
  }

  .card,
  .panel {
    padding: 16px;
  }

  .action-card {
    min-height: auto;
    padding: 16px;
  }

  .grid--cards {
    gap: 12px;
  }

  .auth-card {
    margin: 0 8px;
    padding: 20px 16px;
  }

  .class-card {
    padding: 14px;
  }

  .pricing-card {
    padding: 16px;
  }

  .exercise-card.glass {
    padding: 16px;
  }
}

/* 6. Form Elements Mobile - Prevent iOS Zoom (16px min font) */
@media (max-width: 720px) {
  .input,
  textarea,
  select,
  .option-btn {
    font-size: 16px;
  }

  .field {
    margin-bottom: 16px;
    min-width: 100%;
  }

  .auth-form {
    gap: 12px;
  }

  .role-selector {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .role-card {
    flex-direction: row;
    justify-content: flex-start;
    padding: 14px 16px;
    gap: 12px;
  }
  /* Le card GRANDI dell'onboarding restano una COLONNA (founder 19/8): la riga qui sopra
     è per il mini-selettore radio (icona+etichetta); su pill+titolo+lista+bottone
     schiacciava tutto in tre colonne illeggibili. Dopo, quindi vince. */
  .role-card--select { flex-direction: column; align-items: stretch; }
}

/* 7. Responsive Tables - Stack on Mobile */
@media (max-width: 720px) {
  .materials-table {
    max-height: none;
  }

  .materials-row {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 14px;
  }

  .materials-head {
    display: none;
  }

  .materials-row > * {
    width: 100%;
  }

  .materials-row::before {
    content: attr(data-label);
    font-weight: 700;
    color: var(--muted);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }

  .materials-actions {
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .materials-actions .btn {
    flex: 1;
    min-width: 100px;
  }
}

/* 8. Avatar & Realtime Mobile */
@media (max-width: 720px) {
  .avatars {
    flex-direction: column;
    gap: 24px;
  }

  .avatar {
    width: 90px;
    height: 90px;
  }

  .avatar::before {
    inset: -10px;
  }

  .avatar::after {
    inset: -18px;
  }

  .transcript {
    font-size: 14px;
    min-height: 100px;
    max-height: 180px;
    overflow-y: auto;
  }

  .waveform {
    height: 20px;
  }

  .question {
    font-size: 16px;
  }

  .score__value {
    font-size: 24px;
  }
}

/* 9. Pricing Grid Mobile
   La soglia è 720px, non 600: fra 600 e 719 la griglia teneva due colonne da ~280px, cioè
   due card di prezzi strizzate una accanto all'altra su un telefono in orizzontale o su un
   tablet piccolo. Sotto 720 il listino è una colonna sola. */
@media (max-width: 720px) {
  .pricing-grid {
    grid-template-columns: 1fr;
  }

  #altri-piani {
    grid-template-columns: 1fr;
  }

  .pricing-card--trial {
    flex-direction: column;
    align-items: flex-start;
  }

  .pricing-hero__inner {
    grid-template-columns: 1fr;
  }

  .plan-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }

  .plan-price__value {
    font-size: 26px;
  }

  .topup-grid {
    flex-direction: column;
  }

  .topup-card {
    width: 100%;
  }
}

/* 10. Footer Mobile */
@media (max-width: 600px) {
  .footer__inner {
    flex-direction: column;
    text-align: center;
    gap: 16px;
  }

  .footer__links {
    justify-content: center;
    flex-wrap: wrap;
  }
  /* Tap target più comodo per i link footer su mobile (erano ~20px). */
  .footer__links a { padding: 10px 8px; }
}

/* 11. Profile Panel Mobile */
@media (max-width: 480px) {
  .profile-panel {
    position: fixed;
    top: auto;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    border-radius: var(--radius-card) var(--radius-card) 0 0;
    max-height: 70vh;
    overflow-y: auto;
    transform: translateY(100%);
  }

  .profile-panel.is-open {
    transform: translateY(0);
  }
}

/* 12. Toast Mobile */
@media (max-width: 480px) {
  .toast-container {
    top: auto;
    bottom: 20px;
    right: 12px;
    left: 12px;
  }

  .toast {
    max-width: 100%;
  }
}

/* 13. Results & Stats Grid Mobile */
@media (max-width: 600px) {
  .results-grid,
  .mode-grid {
    grid-template-columns: 1fr;
  }

  .stat-card {
    padding: 12px;
  }

  .mode-card {
    padding: 12px;
  }
}

/* 14. Landing Visual Mobile */
@media (max-width: 720px) {
  .orbital {
    min-height: auto;
    padding: 16px;
  }

  .orbital__core {
    position: relative;
    transform: none;
    top: auto;
    left: auto;
    margin: 0 auto 16px;
    min-width: auto;
    width: 100%;
    max-width: 280px;
  }

  .orbit {
    position: relative;
    width: 100%;
    max-width: none;
    animation: none;
  }

  .landing-steps {
    grid-template-columns: 1fr;
  }

  .step-card {
    padding: 14px;
  }
}

/* 15. Quick Actions & Chips Mobile */
@media (max-width: 480px) {
  .quick-actions {
    flex-direction: column;
  }

  .quick-actions .chip {
    width: 100%;
    justify-content: center;
  }

  .landing-chips {
    flex-direction: column;
    width: 100%;
  }

  .landing-chips .chip {
    width: 100%;
    justify-content: center;
  }

  .helpers {
    flex-direction: column;
    width: 100%;
  }

  .helpers .helper-btn {
    width: 100%;
  }
}

/* 16. Class Cards Mobile */
@media (max-width: 480px) {
  .class-actions {
    flex-direction: column;
    width: 100%;
  }

  .class-actions .btn {
    width: 100%;
  }

  .code-row {
    flex-direction: column;
    gap: 10px;
  }
}

/* 17. Section Headers Mobile */
@media (max-width: 600px) {
  .section__header {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }

  .section__header .btn {
    width: 100%;
  }
}

/* 18. Feature List (Family Dashboard) Mobile */
@media (max-width: 480px) {
  .feature-item {
    flex-direction: column;
    text-align: center;
    gap: 12px;
  }

  .feature-icon {
    margin: 0 auto;
  }
}

/* 19. Print Styles */
@media print {
  .navbar,
  .nav-toggle,
  .theme-switch-wrap,
  .profile-panel,
  .toast-container,
  .btn,
  .helpers {
    display: none !important;
  }

  .card,
  .panel {
    break-inside: avoid;
    box-shadow: none;
    border: 1px solid #ddd;
  }

  body {
    background: #fff;
    color: #000;
  }
}

/* 20. High Contrast Mode Support */
@media (prefers-contrast: high) {
  :root {
    --border-soft: #000;
    --border-strong: #000;
  }

  .btn--primary {
    background: #000;
    color: #fff;
  }

  .btn--ghost {
    border-width: 2px;
  }
}

/* 21. Onboarding Specific Styles */
.onboarding-step {
  display: none;
  animation: fadeInStep 0.3s ease forwards;
}

.onboarding-step.active {
  display: block;
}

@keyframes fadeInStep {
  0% { opacity: 0; transform: translateY(10px); }
  100% { opacity: 1; transform: translateY(0); }
}

.tour-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  margin: 24px 0;
}

.tour-card {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  padding: 20px;
  text-align: center;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.tour-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-m);
}

.tour-icon {
  font-size: 36px;
  display: block;
  margin-bottom: 12px;
}

.tour-card h4 {
  margin: 0 0 8px;
  font-size: 16px;
  color: var(--text);
}

.tour-card p {
  margin: 0;
  font-size: 14px;
  color: var(--muted);
}

@media (max-width: 480px) {
  .tour-cards {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .tour-card {
    padding: 16px;
  }
}

/* 22. Analytics & Progress Styles (Teacher/Family) */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

.stats-grid .stat-card {
  text-align: center;
}

.stat-value {
  font-size: 32px;
  font-weight: 800;
  color: var(--accent);
  display: block;
  line-height: 1.2;
}

.stat-label {
  font-size: 13px;
  color: var(--muted);
  font-weight: 600;
  margin-top: 4px;
}

.student-list {
  display: grid;
  gap: 12px;
}

.student-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 16px;
  align-items: center;
  padding: 14px 16px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
}

@media (max-width: 600px) {
  .stats-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
  }

  .stat-value {
    font-size: 24px;
  }

  .student-row {
    grid-template-columns: 1fr;
    gap: 10px;
    text-align: center;
  }
}

/* 23. Quiz Generator Styles (Teacher) */
.quiz-generator {
  display: grid;
  gap: 20px;
}

.quiz-controls {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}

.quiz-preview {
  background: var(--surface-2);
  border: 1px dashed var(--border-soft);
  border-radius: var(--radius-card);
  padding: 20px;
  min-height: 200px;
}

.quiz-preview-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
  color: var(--muted);
  font-weight: 500;
}

/* 24. Family Profile Cards */
.profile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}

.profile-card {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  padding: 20px;
  text-align: center;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.profile-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-m);
}

.profile-card-avatar {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--gradient-accent);
  color: #fff;
  font-size: 24px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 12px;
}

.profile-card-name {
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 4px;
}

.profile-card-meta {
  font-size: 13px;
  color: var(--muted);
}

.profile-card-stats {
  display: flex;
  justify-content: center;
  gap: 20px;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--border-soft);
}

.profile-stat {
  text-align: center;
}

.profile-stat-value {
  font-size: 18px;
  font-weight: 800;
  color: var(--accent);
}

.profile-stat-label {
  font-size: 11px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.add-profile-card {
  border: 2px dashed var(--border-soft);
  background: transparent;
  cursor: pointer;
  min-height: 200px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--muted);
  transition: border-color 0.2s ease, color 0.2s ease;
}

.add-profile-card:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.add-profile-icon {
  font-size: 32px;
}

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

/* ====================================================================== */
/* ANIMATIONS & EFFECTS - Skooly Dynamic UI                               */
/* ====================================================================== */

/* Keyframe Animations */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes fadeInDown {
  from { opacity: 0; transform: translateY(-20px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes fadeInScale {
  from { opacity: 0; transform: scale(0.95); }
  to { opacity: 1; transform: scale(1); }
}

@keyframes slideInLeft {
  from { opacity: 0; transform: translateX(-30px); }
  to { opacity: 1; transform: translateX(0); }
}

@keyframes slideInRight {
  from { opacity: 0; transform: translateX(30px); }
  to { opacity: 1; transform: translateX(0); }
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

@keyframes bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

@keyframes shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

@keyframes glow-pulse {
  0%, 100% { box-shadow: var(--glow-s); }
  50% { box-shadow: var(--glow-l); }
}

@keyframes gradient-shift {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

@keyframes float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}

@keyframes wiggle {
  0%, 100% { transform: rotate(0deg); }
  25% { transform: rotate(-3deg); }
  75% { transform: rotate(3deg); }
}

/* Loading Spinner */
.spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

.spinner--sm {
  width: 20px;
  height: 20px;
  border-width: 2px;
}

.spinner--lg {
  width: 60px;
  height: 60px;
  border-width: 4px;
}

.spinner--accent {
  border-color: var(--accent-soft);
  border-top-color: var(--accent);
}

.spinner--white {
  border-color: rgba(255,255,255,0.3);
  border-top-color: #fff;
}

/* Loading Overlay */
.loading-overlay {
  position: fixed;
  inset: 0;
  background: var(--glass);
  backdrop-filter: blur(8px);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 16px;
  z-index: 9999;
  animation: fadeIn 0.2s ease;
}

.loading-overlay__text {
  color: var(--text);
  font-weight: 500;
}

/* Skeleton Loader */
.skeleton {
  background: linear-gradient(90deg, var(--surface-1) 25%, var(--surface-2) 50%, var(--surface-1) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
  border-radius: var(--radius-control);
}

.skeleton--text {
  height: 16px;
  width: 100%;
  margin-bottom: 8px;
}

.skeleton--title {
  height: 28px;
  width: 60%;
  margin-bottom: 12px;
}

.skeleton--avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
}

.skeleton--card {
  height: 120px;
  width: 100%;
}

.skeleton--pill {
  height: 24px;
  width: 50px;
  border-radius: var(--radius-pill);
}

.skeleton-card {
  opacity: 0.7;
}

/* Page Transitions */
.page {
  animation: fadeInUp 0.4s ease;
}

.page--fast {
  animation: fadeIn 0.2s ease;
}

/* Enhanced Navbar */
.navbar {
  animation: fadeInDown 0.3s ease;
}
/* `.navbar.navbar--scrolled` viveva qui con fondo e `backdrop-filter` propri.
   Lo stato «scrolled» ora alza bordo e ombra sui token (blocco NAVIGAZIONE
   2026) e non tocca piu' il fondo: le due dichiarazioni rimaste erano invisibili
   in diff e vive nel browser. Anche `transition: all` se n'e' andato — lo stesso
   file spiega, nel blocco del drawer, perche' interpolare tutto e' un rischio. */

.navbar__logo img {
  transition: transform 0.3s ease;
}

.navbar__logo:hover img {
  transform: scale(1.05);
}

.navlink {
  position: relative;
  transition: all 0.25s ease;
}

.navlink::before {
  content: '';
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 0;
  height: 2px;
  background: var(--gradient-accent);
  transition: width 200ms cubic-bezier(0.2, 0, 0, 1);
  transform: translateX(-50%);
  border-radius: 2px;
}

.navlink:hover::before,
.navlink.navlink--active::before {
  width: 60%;
}

/* Buttons — quiet, precise micro-interactions (no ripple, no infinite fx) */
.btn {
  position: relative;
  transition: transform 160ms cubic-bezier(0.2, 0, 0, 1),
              box-shadow 160ms cubic-bezier(0.2, 0, 0, 1),
              background-color 160ms ease,
              border-color 160ms ease,
              color 160ms ease;
}

.btn:hover {
  transform: translateY(-1px);
}

.btn:active {
  transform: translateY(0) scale(0.99);
  transition-duration: 60ms;
}

.btn--primary {
  background-image: var(--gradient-accent);
  box-shadow: var(--shadow-s), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

.btn--primary:hover {
  box-shadow: 0 4px 14px color-mix(in srgb, var(--accent) 35%, transparent),
              inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

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

/* Button with spinner */
.btn--loading {
  pointer-events: none;
  opacity: 0.8;
}

.btn--loading .btn__text {
  opacity: 0;
}

.btn--loading::after {
  content: '';
  position: absolute;
  width: 20px;
  height: 20px;
  border: 2px solid transparent;
  border-top-color: currentColor;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

/* Cards — static by default; lift is reserved for truly clickable cards
   (.action-card, .class-card, .cd-mat) which define their own hover. */
.card {
  transition: box-shadow 160ms ease, border-color 160ms ease;
}

.action-card {
  position: relative;
  overflow: hidden;
}

.action-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: var(--gradient-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s ease;
}

.action-card:hover::before {
  transform: scaleX(1);
}

.action-card .cta {
  transition: all 0.3s ease;
}

.action-card:hover .cta {
  transform: translateX(5px);
  color: var(--accent);
}

/* Colored Card Variants - colored shadow on hover only */
.card--appunti:hover { box-shadow: 0 10px 40px rgba(16, 185, 129, 0.15); }
.card--tutor:hover { box-shadow: 0 10px 40px rgba(59, 130, 246, 0.15); }
.card--orale:hover { box-shadow: 0 10px 40px rgba(245, 158, 11, 0.15); }
.card--quiz:hover { box-shadow: 0 10px 40px rgba(139, 92, 246, 0.15); }
.card--esercizi:hover { box-shadow: 0 10px 40px rgba(239, 68, 68, 0.15); }

/* Pills — no scale jump on hover */
.pill {
  transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease;
}

.pill--appunti {
  background: linear-gradient(135deg, rgba(16, 185, 129, 0.15), rgba(16, 185, 129, 0.05));
  color: #10b981;
  border-color: rgba(16, 185, 129, 0.3);
}

.pill--tutor {
  background: linear-gradient(135deg, rgba(59, 130, 246, 0.15), rgba(59, 130, 246, 0.05));
  color: #3b82f6;
  border-color: rgba(59, 130, 246, 0.3);
}

.pill--orale {
  background: linear-gradient(135deg, rgba(245, 158, 11, 0.15), rgba(245, 158, 11, 0.05));
  color: #f59e0b;
  border-color: rgba(245, 158, 11, 0.3);
}

.pill--quiz {
  background: linear-gradient(135deg, rgba(139, 92, 246, 0.15), rgba(139, 92, 246, 0.05));
  color: #8b5cf6;
  border-color: rgba(139, 92, 246, 0.3);
}

.pill--esercizi {
  background: linear-gradient(135deg, rgba(239, 68, 68, 0.15), rgba(239, 68, 68, 0.05));
  color: #ef4444;
  border-color: rgba(239, 68, 68, 0.3);
}

/* Hero Section Animations */
.hero {
  animation: fadeIn 0.5s ease;
}

.hero__title {
  animation: fadeInUp 0.6s ease 0.1s backwards;
}

.hero__subtitle {
  animation: fadeInUp 0.6s ease 0.2s backwards;
}

.hero__controls {
  animation: fadeInUp 0.6s ease 0.3s backwards;
}

/* Landing Page Effects */
.landing-neo {
  position: relative;
}

.landing-aurora {
  animation: float 6s ease-in-out infinite;
}

.landing-aurora--right {
  animation-delay: -3s;
}

.landing-copy {
  animation: slideInLeft 0.6s ease;
}

.landing-visual {
  animation: slideInRight 0.6s ease 0.2s backwards;
}

.orbital__core {
  animation: glow-pulse 3s ease infinite;
}

.orbit {
  animation: fadeInScale 0.4s ease backwards;
}

.orbit--tutor { animation-delay: 0.2s; }
.orbit--orale { animation-delay: 0.3s; }
.orbit--vision { animation-delay: 0.4s; }
.orbit--quiz { animation-delay: 0.5s; }

.orbit:hover {
  transform: scale(1.05);
  z-index: 10;
}

.stream-card {
  animation: slideInRight 0.4s ease backwards;
}

.stream-card:nth-child(1) { animation-delay: 0.3s; }
.stream-card:nth-child(2) { animation-delay: 0.4s; }
.stream-card:nth-child(3) { animation-delay: 0.5s; }

.stream-card:hover {
  transform: translateX(-5px);
  box-shadow: var(--shadow-m);
}

/* Step Cards Animation */
.step-card {
  animation: fadeInUp 0.5s ease backwards;
  transition: all 0.3s ease;
}

.step-card:nth-child(1) { animation-delay: 0.2s; }
.step-card:nth-child(2) { animation-delay: 0.3s; }
.step-card:nth-child(3) { animation-delay: 0.4s; }

.step-card:hover {
  transform: translateY(-5px);
}

/* Chip Glow Effect */
.chip--glow {
  animation: glow-pulse 2s ease infinite;
}

.chip--glow:nth-child(1) { animation-delay: 0s; }
.chip--glow:nth-child(2) { animation-delay: 0.3s; }
.chip--glow:nth-child(3) { animation-delay: 0.6s; }

/* Form Animations */
.field {
  animation: fadeInUp 0.4s ease backwards;
}

.field:nth-child(1) { animation-delay: 0.1s; }
.field:nth-child(2) { animation-delay: 0.15s; }
.field:nth-child(3) { animation-delay: 0.2s; }
.field:nth-child(4) { animation-delay: 0.25s; }

/* (restyle) removed glow-pulse animation on focus — the static focus ring
   in the canonical .input:focus rule is the whole treatment. */

/* Auth Card Animation */
.auth-card {
  animation: fadeInScale 0.4s ease;
}

/* Status Indicators */
.status-dot {
  animation: pulse 2s ease infinite;
}

.status-dot--live {
  background: #10b981;
  box-shadow: 0 0 10px rgba(16, 185, 129, 0.5);
}

.status-dot--vision {
  background: #3b82f6;
  box-shadow: 0 0 10px rgba(59, 130, 246, 0.5);
}

.status-dot--twin {
  background: #8b5cf6;
  box-shadow: 0 0 10px rgba(139, 92, 246, 0.5);
}

/* Avatar Animation */
.avatar {
  transition: all 0.3s ease;
}

.avatar:hover {
  transform: scale(1.05);
  box-shadow: var(--glow-m);
}

.avatar--speaking {
  animation: glow-pulse 1s ease infinite;
}

/* Transcript Animation */
.transcript {
  animation: fadeIn 0.3s ease;
}

.transcript p {
  animation: slideInLeft 0.3s ease;
}

/* Modal Animations */
.modal,
.note-modal,
.profile-panel {
  animation: fadeInScale 0.3s ease;
}

.modal-backdrop,
.note-modal-backdrop {
  animation: fadeIn 0.2s ease;
}

/* (Slice 1 dedup) Removed duplicate .alert / .alert--success/error/warning
   block — animation + border-left now consolidated in the canonical .alert
   definition above (~L1010). */

/* Pricing Card Hover — quiet lift, no perpetual glow on purchase UI */
.pricing-card {
  transition: transform 160ms cubic-bezier(0.2, 0, 0, 1), box-shadow 160ms ease, border-color 160ms ease;
}

.pricing-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-l);
}

.pricing-card--featured {
  box-shadow: var(--glow-m);
}

/* Footer Animation */
.footer {
  animation: fadeIn 0.5s ease 0.3s backwards;
}

/* Onboarding Animations */
.onboarding-step {
  animation: fadeInScale 0.5s ease;
}

.role-card {
  transition: transform 160ms cubic-bezier(0.2, 0, 0, 1), box-shadow 160ms ease, border-color 160ms ease, background-color 160ms ease;
}

.role-card:hover {
  transform: translateY(-2px);
}

.tour-card {
  animation: fadeInUp 0.4s ease backwards;
  transition: all 0.3s ease;
}

.tour-card:nth-child(1) { animation-delay: 0.1s; }
.tour-card:nth-child(2) { animation-delay: 0.2s; }
.tour-card:nth-child(3) { animation-delay: 0.3s; }
.tour-card:nth-child(4) { animation-delay: 0.4s; }

.tour-card:hover {
  transform: translateY(-5px);
  box-shadow: var(--shadow-m);
}


/* Progress Bar Animation */
.progress-bar {
  position: relative;
  height: 8px;
  background: var(--surface-2);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.progress-bar__fill {
  height: 100%;
  background: var(--gradient-accent);
  border-radius: var(--radius-pill);
  transition: width 0.5s ease;
  position: relative;
}

.progress-bar__fill::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
  animation: shimmer 2s infinite;
}

/* Welcome Animation */
.welcome-logo {
  animation: bounce 1s ease;
}

.welcome-title {
  animation: fadeInUp 0.6s ease 0.2s backwards;
}

.welcome-subtitle {
  animation: fadeInUp 0.6s ease 0.3s backwards;
}

/* Typing Indicator */
.typing-indicator {
  display: flex;
  gap: 4px;
  padding: 12px 16px;
  background: var(--surface-1);
  border-radius: var(--radius-card);
  width: fit-content;
}

.typing-indicator span {
  width: 8px;
  height: 8px;
  background: var(--muted);
  border-radius: 50%;
  animation: bounce 1.4s ease infinite;
}

.typing-indicator span:nth-child(1) { animation-delay: 0s; }
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }

/* Notification Badge */
.badge {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 18px;
  height: 18px;
  background: #ef4444;
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: bounce 0.5s ease;
}

.badge--accent {
  background: var(--gradient-accent);
}

/* Icon Animations */
.icon-spin {
  animation: spin 1s linear infinite;
}

.icon-pulse {
  animation: pulse 2s ease infinite;
}

.icon-bounce {
  animation: bounce 2s ease infinite;
}

/* Hover Lift Effect */
.hover-lift {
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.hover-lift:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-m);
}

/* Click Feedback */
.click-feedback {
  transition: transform 0.1s ease;
}

.click-feedback:active {
  transform: scale(0.97);
}

/* Ripple Effect Container */
.ripple {
  position: relative;
  overflow: hidden;
}

/* Empty State Animation */
.empty-state {
  animation: fadeIn 0.5s ease;
  text-align: center;
  padding: 48px 24px;
}

.empty-state__icon {
  font-size: 64px;
  animation: float 3s ease infinite;
  margin-bottom: 16px;
}

.empty-state__title {
  font-size: 20px;
  font-weight: 600;
  margin-bottom: 8px;
}

.empty-state__text {
  color: var(--muted);
  margin-bottom: 24px;
}

/* Success Checkmark Animation */
@keyframes checkmark {
  0% { stroke-dashoffset: 100; }
  100% { stroke-dashoffset: 0; }
}

.success-checkmark {
  width: 80px;
  height: 80px;
  animation: fadeInScale 0.4s ease;
}

.success-checkmark circle {
  fill: #10b981;
}

.success-checkmark path {
  stroke: #fff;
  stroke-width: 3;
  stroke-dasharray: 100;
  animation: checkmark 0.5s ease 0.2s forwards;
}

/* ====================================================================== */
/* TOAST NOTIFICATIONS                                                     */
/* ====================================================================== */

.toast-container {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 10000;
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 400px;
}

.toast {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-m);
  animation: slideInRight 0.3s ease, fadeIn 0.3s ease;
}

.toast--success {
  border-left: 4px solid #10b981;
  background: linear-gradient(90deg, rgba(16, 185, 129, 0.08), var(--surface-1));
}

.toast--error {
  border-left: 4px solid #ef4444;
  background: linear-gradient(90deg, rgba(239, 68, 68, 0.08), var(--surface-1));
}

.toast--warning {
  border-left: 4px solid #f59e0b;
  background: linear-gradient(90deg, rgba(245, 158, 11, 0.08), var(--surface-1));
}

.toast--info {
  border-left: 4px solid #3b82f6;
  background: linear-gradient(90deg, rgba(59, 130, 246, 0.08), var(--surface-1));
}

.toast__icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

.toast--success .toast__icon { color: #10b981; }
.toast--error .toast__icon { color: #ef4444; }
.toast--warning .toast__icon { color: #f59e0b; }
.toast--info .toast__icon { color: #3b82f6; }

.toast__message {
  flex: 1;
  font-size: 14px;
  color: var(--text);
}

.toast__close {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 20px;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  transition: color 0.2s ease;
}

.toast__close:hover {
  color: var(--text);
}

.toast-out {
  animation: slideOutRight 0.3s ease forwards;
}

@keyframes slideOutRight {
  to {
    opacity: 0;
    transform: translateX(100%);
  }
}

@media (max-width: 480px) {
  .toast-container {
    left: 12px;
    right: 12px;
    max-width: none;
  }
}

/* ====================================================================== */
/* ENHANCED COLOR ACCENTS                                                  */
/* ====================================================================== */

/* Gradient text effect */
.gradient-text {
  background: var(--gradient-accent);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

/* Glow effects for interactive elements */
.glow-hover:hover {
  box-shadow: var(--glow-m);
}

.glow-always {
  box-shadow: var(--glow-s);
}

/* Accent borders */
.accent-border {
  border-color: var(--accent);
}

.accent-border-gradient {
  border-image: var(--gradient-accent) 1;
}

/* Background accents */
.bg-accent-soft {
  background: var(--accent-soft);
}

.bg-gradient {
  background: var(--gradient-accent);
}

/* Vibrant status colors */
.text-success { color: #10b981; }
.text-error { color: #ef4444; }
.text-warning { color: #f59e0b; }
.text-info { color: #3b82f6; }
.text-accent { color: var(--accent); }

.bg-success { background: rgba(16, 185, 129, 0.15); }
.bg-error { background: rgba(239, 68, 68, 0.15); }
.bg-warning { background: rgba(245, 158, 11, 0.15); }
.bg-info { background: rgba(59, 130, 246, 0.15); }

/* ====================================================================== */
/* FEATURES SECTION (Phase 2)                                            */
/* ====================================================================== */
.section--features {
  padding: 80px 20px;
  background: var(--bg0);
}

/* Landing features keep the big centered header; everywhere else the
   canonical .section__header (defined near .section) stays left-aligned. */
.section--features .section__header {
  text-align: center;
  margin-bottom: 3rem;
  display: block;
}

.section--features .section__header h2 {
  font-size: 2.5rem;
  font-weight: 700;
  margin-bottom: 0.5rem;
}

/* App section titles: ink + short gradient stroke (the "journey path"). */
.section__header h2 {
  font-family: "Space Grotesk", "Inter", system-ui, sans-serif;
  font-size: var(--text-xl);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
  margin: 0 0 4px;
  position: relative;
  padding-bottom: 10px;
}
.section__header h2::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 36px;
  height: 3px;
  border-radius: 999px;
  background: var(--gradient-accent);
}

.features-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 2rem;
  margin-top: 2rem;
}

.feature-card {
  padding: 2rem;
  background: var(--card);
  border-radius: 16px;
  border: 1px solid var(--border);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.feature-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-strong);
}

.feature-icon {
  font-size: 3rem;
  margin-bottom: 1rem;
  display: block;
}

.feature-card h3 {
  font-size: 1.25rem;
  font-weight: 600;
  margin-bottom: 0.5rem;
  color: var(--text);
}

.feature-card p {
  color: var(--muted);
  line-height: 1.6;
}

/* Mobile responsive adjustments */
@media (max-width: 720px) {
  .section--features {
    padding: 60px 20px;
  }

  .section__header h2 {
    font-size: 2rem;
  }

  .features-grid {
    gap: 1.5rem;
    grid-template-columns: 1fr;
  }

  .feature-card {
    padding: 1.5rem;
  }

  .feature-icon {
    font-size: 2.5rem;
  }
}

/* ====================================================================== */
/* CHIP ANIMATIONS (Phase 2)                                             */
/* ====================================================================== */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.chip {
  animation: fadeInUp 0.5s ease forwards;
  opacity: 0;
}

.chip--fade-1 { animation-delay: 0s; }
.chip--fade-2 { animation-delay: 0.1s; }
.chip--fade-3 { animation-delay: 0.15s; }

/* Orbital hover effects */
.orbit {
  transition: transform 0.3s ease;
}

.orbit:hover {
  transform: scale(1.05);
}

/* Reduced Motion */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .chip {
    animation: none;
    opacity: 1;
  }

  .feature-card {
    transition: none;
  }

  .orbit {
    transition: none;
  }
}

/* ==================================================================   Family dashboard (dashboard-famiglia, progressi-famiglia, profili-famiglia)
   Migrated from inline <style> blocks. Uses existing design tokens.
   ========================================================================= */
.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
}
.kpi-card {
  padding: 18px;
  border-radius: var(--radius-card, 14px);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-s);
}
.kpi-card__label {
  color: var(--muted);
  font-size: 13px;
  margin: 0 0 6px;
}
.kpi-card__value {
  font-size: 28px;
  font-weight: 700;
  color: var(--text);
  margin: 0;
  line-height: 1.1;
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}
@media (min-width: 880px) {
  .grid-2 { grid-template-columns: 1fr 1fr; }
  .grid-2--ring { grid-template-columns: 220px 1fr; }
}

.chart-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-card, 14px);
  padding: 18px;
  box-shadow: var(--shadow-s);
}
.chart-card h3 {
  margin: 0 0 12px;
  font-size: 16px;
}
.chart-card svg {
  width: 100%;
  height: auto;
  display: block;
}
.chart-card--center {
  display: flex;
  align-items: center;
  justify-content: center;
}
/* progress ring keeps its compact intrinsic size (beats the generic .chart-card svg width:100%) */
.chart-card--center svg { width: 160px; height: 160px; max-width: 100%; }

.concept-row { padding: 8px 0; border-bottom: 1px dashed var(--border-soft, var(--border)); }
.concept-row:last-child { border-bottom: 0; }
.concept-row__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
  font-size: 14px;
}
.concept-row__name { color: var(--text); font-weight: 500; }
.concept-row__pct { color: var(--muted); font-variant-numeric: tabular-nums; }
.concept-row__bar {
  height: 6px;
  background: var(--bg2);
  border-radius: 999px;
  overflow: hidden;
}
.concept-row__bar > span {
  display: block;
  height: 100%;
  background: var(--gradient-accent, var(--accent));
  border-radius: inherit;
}

.table-clean {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.table-clean th,
.table-clean td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border-soft, var(--border));
}
.table-clean th {
  font-weight: 600;
  color: var(--muted);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.compliance-footer {
  font-size: 12px;
  color: var(--muted);
  padding: 16px;
  border-top: 1px solid var(--border);
  margin-top: 24px;
}

.child-select {
  padding: 8px 12px;
  border-radius: var(--radius-control, 12px);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--text);
  font: inherit;
}

.consent-list {
  list-style: none;
  padding: 0;
  margin: 8px 0 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.consent-list li {
  font-size: 14px;
  color: var(--text);
}

/* Layout helpers used across family/teacher dashboards.
   These replace small inline `style="..."` snippets. */
.row-between {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
}
.stack-sm { display: flex; flex-direction: column; gap: 8px; }
.stack-md { display: flex; flex-direction: column; gap: 16px; }
.text-center { text-align: center; }
.text-right { text-align: right; }
.mt-xs { margin-top: 4px; }
.mt-sm { margin-top: 8px; }
.mt-md { margin-top: 16px; }
.mt-lg { margin-top: 24px; }
.mt-xl { margin-top: 32px; }
.mb-sm { margin-bottom: 8px; }
.mb-md { margin-bottom: 16px; }
.mb-lg { margin-bottom: 24px; }
.is-hidden { display: none !important; }
.flex-row { display: flex; align-items: center; gap: 8px; }
.flex-row--gap-md { display: flex; align-items: center; gap: 12px; }
.flex-row--center { display: flex; align-items: center; justify-content: center; gap: 8px; }
.label-checkbox {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}
.btn-group--center { justify-content: center; }
.input--auto-width { width: auto; }
.skeleton-card--250 { height: 250px; }
.section--no-top { padding-top: 0; }
.progress-bar--200 { width: 200px; margin-top: 8px; }
.quick-actions--start { justify-content: flex-start; }

@media (prefers-reduced-motion: reduce) {
  .kpi-card,
  .chart-card,
  .concept-row__bar > span {
    transition: none !important;
    animation: none !important;
  }
}

/* ==============================================================   Esercizi M5 — Configurator + Loading + Arena (rebuilt)
   All tokens via :root vars. No hardcoded colors. WCAG 2.1 AA.
   ===================================================================== */

/* Skip link (a11y) */
.skip-link {
  position: absolute; left: -9999px; top: 8px;
  background: var(--surface-1); color: var(--text);
  padding: 8px 14px; border-radius: var(--radius-control);
  border: 1px solid var(--border-soft); font-weight: 600;
  z-index: var(--z-toast);
}
.skip-link:focus { left: 16px; box-shadow: var(--focus-ring); outline: none; }

/* ---- Configurator ---- */
.ex-config { display: flex; flex-direction: column; gap: var(--space-6); }
.ex-config__hero { text-align: left; max-width: 720px; }
.ex-config__title {
  margin: 6px 0 8px; font-size: var(--text-3xl); line-height: var(--lh-tight);
  background: var(--gradient-accent); -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.ex-config__lead { color: var(--muted); margin: 0 0 12px; max-width: 56ch; }
.ex-config__pills { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }

.ex-resume {
  display: grid; grid-template-columns: auto 1fr auto auto;
  align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: color-mix(in srgb, var(--accent) 6%, var(--surface-1));
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border-soft));
  border-radius: var(--radius-card);
  margin-top: var(--space-3);
}
.ex-resume__icon {
  width: 36px; height: 36px; display: grid; place-items: center;
  background: var(--gradient-accent); color: #fff; border-radius: 50%; font-weight: 700;
}
.ex-resume__body { display: flex; flex-direction: column; gap: 2px; }
.ex-resume__dismiss { padding: 4px 10px; font-size: var(--text-lg); line-height: 1; min-width: 44px; min-height: 44px; }

.ex-steps { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--space-5); counter-reset: step; }
.ex-step {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  padding: var(--space-5);
  box-shadow: var(--shadow-s);
}
.ex-step__head { display: flex; align-items: flex-start; gap: var(--space-3); margin-bottom: var(--space-4); }
.ex-step__num {
  width: 32px; height: 32px; display: grid; place-items: center;
  border-radius: 50%; background: var(--gradient-accent); color: #fff;
  font-weight: 700; flex-shrink: 0;
}
.ex-step__title { margin: 0; font-size: var(--text-xl); line-height: var(--lh-tight); }

/* Subjects */
.ex-subjects {
  display: grid; gap: var(--space-2);
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
.ex-subject {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  background: var(--surface-1); color: var(--text);
  border: 1px solid var(--border-soft); border-radius: var(--radius-control);
  cursor: pointer; transition: transform .12s ease, border-color .15s ease, box-shadow .18s ease, background .18s ease;
  font-weight: 500; font-size: var(--text-sm);
  min-height: 48px; text-align: left;
}
.ex-subject:hover { border-color: var(--accent); transform: translateY(-1px); box-shadow: var(--shadow-s); }
.ex-subject:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ex-subject.is-selected {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface-1));
  box-shadow: var(--glow-s);
}
.ex-subject__icon {
  width: 28px; height: 28px; display: grid; place-items: center;
  background: var(--surface-2); border-radius: 8px; font-size: 16px; flex-shrink: 0;
}
.ex-subject.is-selected .ex-subject__icon {
  background: var(--gradient-accent); color: #fff;
}

/* Topic */
.ex-topic { display: flex; flex-direction: column; gap: var(--space-2); }
.ex-topic__input { font-size: var(--text-base); padding: var(--space-3) var(--space-4); }
.ex-topic__hint { margin: 0; }
.ex-suggestions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.ex-chip {
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border-soft); border-radius: var(--radius-pill);
  padding: 6px 14px; font-size: var(--text-sm); cursor: pointer;
  transition: border-color .15s ease, background .15s ease, transform .12s ease;
}
.ex-chip:hover { border-color: var(--accent); transform: translateY(-1px); }
.ex-chip:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ex-chip--weak { border-color: color-mix(in srgb, var(--color-warning) 40%, var(--border-soft)); }
.ex-chip--weak.is-on {
  background: color-mix(in srgb, var(--accent) 18%, var(--surface-1));
  border-color: var(--accent); color: var(--text);
}
.ex-weak { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-3); }
.ex-weak__label { font-size: var(--text-xs); font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.ex-weak__chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* Modes */
.ex-modes {
  display: grid; gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.ex-mode {
  display: flex; flex-direction: column; gap: 6px; align-items: flex-start;
  padding: var(--space-4) var(--space-5);
  background: var(--surface-1); color: var(--text);
  border: 1px solid var(--border-soft); border-radius: var(--radius-card);
  cursor: pointer; transition: transform .12s ease, border-color .15s ease, box-shadow .18s ease;
  text-align: left; min-height: 130px;
}
.ex-mode:hover { transform: translateY(-2px); border-color: var(--accent); box-shadow: var(--shadow-m); }
.ex-mode:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ex-mode.is-selected {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, var(--surface-1));
  box-shadow: var(--glow-s);
}
.ex-diff-chip {
  padding: 6px 14px; border: 1px solid var(--border-soft); border-radius: var(--radius-pill);
  background: var(--surface-1); color: var(--text); font-size: 13px; font-weight: 500;
  cursor: pointer; transition: all 150ms ease;
}
.ex-diff-chip:hover { border-color: var(--accent); }
.ex-diff-chip[aria-checked="true"] { background: color-mix(in srgb, var(--accent) 12%, var(--surface-1)); border-color: var(--accent); color: var(--accent); }
.ex-diff-chip:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ex-mode__tag {
  font-size: var(--text-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  padding: 4px 10px; border-radius: var(--radius-pill);
  background: var(--gradient-accent); color: #fff;
}
.ex-mode__count { font-size: var(--text-xl); font-weight: 700; }
.ex-mode__desc { color: var(--muted); font-size: var(--text-sm); margin: 0; }
.ex-mode__meta { color: var(--muted); font-size: var(--text-xs); margin-top: auto; }

/* ── «DA DOVE STUDIAMO?» — le due strade della fonte ────────────────────────
   Founder, 2026-08-10: il libro «non segue lo schema visivo giusto e non viene
   considerato bene essendo alla fine e fatto così». Era una riga label+select
   appiccicata in fondo al passo della difficoltà. Il libro e il materiale al volo
   rispondono alla STESSA domanda — da dove prendo quello che ti chiedo — e adesso
   sono due riquadri affiancati con la stessa struttura: icona, titolo, una riga di
   spiegazione, il controllo. Stesso vocabolario delle chip materia e delle card
   modalità (superficie, bordo tenue, raggio dei controlli, accento sulla scelta
   attiva), così la fonte sembra progettata invece che aggiunta.

   Vive in tre posti con lo stesso vestito: dentro un passo numerato sul
   configuratore esercizi, e in versione compatta nell'hero di tutor e orale. */
.fonti { display: grid; gap: var(--space-3); }
.fonti__titolo {
  margin: 0;
  font-size: var(--text-sm); font-weight: 600;
  color: var(--muted);
}
/* `auto-fit` + `minmax`: due colonne dove c'è spazio, una sola sul telefono, senza
   un breakpoint da mantenere. `min(100%, …)` evita l'overflow a 320px. */
.fonti__griglia {
  display: grid; gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  align-items: start;
}
.fonte {
  display: flex; gap: var(--space-3);
  min-width: 0;
  padding: var(--space-4);
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-control);
  transition: border-color .15s ease, background .18s ease, transform .12s ease;
}
.fonte[hidden] { display: none; }
.fonte__icona { font-size: var(--text-xl); line-height: 1.15; flex-shrink: 0; }
.fonte__corpo { flex: 1; min-width: 0; display: grid; gap: var(--space-2); }
.fonte__titolo { margin: 0; font-size: var(--text-base); line-height: var(--lh-tight); }
.fonte__nota, .fonte__vuoto { margin: 0; }
/* La scelta ACCESA si vede: è la stessa lingua di `.ex-subject.is-selected`. */
.fonte.is-attiva {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, var(--surface-1));
}
/* IL RIQUADRO INTERO SI TOCCA (founder, 22/8: «non si clicca, non si apre nulla»).
   La mano e la pressione compaiono SOLO dove `libri.js` ha davvero installato un
   gesto (`.is-toccabile`): un riquadro che sembra premibile e non lo è è il difetto
   di partenza, non la sua cura. Il contenitore resta un div — il nome accessibile e
   il tab stop restano del controllo vero che ha dentro.

   E LA PRESSIONE NON È PIÙ `:active`. `:active` è del browser e non conosce le
   esclusioni della delega: si accendeva anche sulla card delle pagine dell'Art. 14,
   dove il tocco per scelta non fa niente. Il riquadro si schiacciava davvero, il
   bordo si accendeva, e al rilascio non succedeva nulla — cioè il difetto di partenza
   rifatto dentro la sua cura, e per giunta sotto questo commento. Adesso `is-premuto`
   la mette lo STESSO guardiano che decide se il tocco vale (`riquadroTocca` in
   libri.js): una regola sola, due letture. Alle zone inerti — marcate
   `data-riquadro-inerte` dal modulo, le stesse che la delega salta — resta il cursore
   del testo, perché lì si legge e si seleziona. */
.fonte.is-toccabile { cursor: pointer; }
.fonte.is-toccabile [data-riquadro-inerte] { cursor: auto; }
.fonte.is-premuto {
  /* La stessa lingua di `.btn--click:active`, tarata su una card invece che su un
     bottone: un riscontro che si vede anche col dito sopra al punto toccato. */
  transform: scale(0.98);
  border-color: var(--accent);
}
@media (prefers-reduced-motion: reduce) {
  .fonte { transition: none; }
  .fonte.is-premuto { transform: none; }
}
/* Dentro il riquadro i due controlli occupano la colonna: un select a 320px accanto
   a un bottone a tutta larghezza sarebbe di nuovo la riga scollegata di prima. E la
   via d'uscita del libro ha lo STESSO vestito del gemello «Aggiungi materiale»: era
   quell'asimmetria — un bottone di là, un link dentro una frase di qua — a far
   sembrare morto un riquadro che morto non doveva essere. */
.fonte .libro-scelta { margin-top: 0; }
.fonte .libro-scelta__select { width: 100%; max-width: 100%; min-height: 44px; }
.fonte .ctx-entry, .fonte .libro-entry { width: 100%; }
.fonte .libro-nota, .fonte .libro-carta { margin-top: 0; }
/* RIFINITURE VOCE (founder 19/8) — le card fonte non si restringono e non sforano.
   1. Su iOS un campo sotto i 16px fa ZOOMARE la pagina quando lo si tocca: al ritorno le
      card sembrano «rimpicciolite» e il contenuto sfora dai bordi. 16px minimi sul select
      e sui campi del materiale = niente autozoom, niente brutto effetto.
   2. Tutto cio' che vive dentro la card va a capo o si adatta, mai fuori dal bordo. */
.fonte .libro-scelta__select,
.ctx input, .ctx textarea, .ctx select { font-size: max(16px, 1rem); }
.fonte { overflow-wrap: anywhere; }
.fonte :where(img, canvas, svg) { max-width: 100%; height: auto; }
/* La CTA che parte e' ancorata: a tutta larghezza sotto le fonti, non un bottone sciolto
   a sinistra (founder: «Inizia interrogazione un po' fuori posto»). Vale per il gemello
   del tutor, cosi' le due pagine restano la stessa pagina. */
#start-orale, #start-tutor { width: 100%; margin-top: var(--space-2); }

/* CTA di chiusura del configuratore: statica. Da sticky copriva l'input
   dell'argomento (step 2) già alla prima apertura della pagina. */
.ex-config__cta {
  position: static;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  background: var(--surface-1);
  border: 1px solid var(--border-strong); border-radius: var(--radius-card);
  box-shadow: var(--shadow-l);
}
.ex-config__summary { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.btn--xl { padding: 14px 28px; font-size: var(--text-base); font-weight: 600; border-radius: var(--radius-control); }

@media (max-width: 640px) {
  .ex-config__cta { flex-direction: column; align-items: stretch; }
  .ex-config__cta .btn--xl { width: 100%; }
}

/* ---- Loading screen ---- */
.ex-loading { display: grid; place-items: center; min-height: 60vh; }
.ex-loading__card {
  max-width: 560px; width: 100%; text-align: center;
  background: var(--surface-1); border: 1px solid var(--border-soft);
  border-radius: var(--radius-card); padding: var(--space-7) var(--space-5);
  box-shadow: var(--shadow-m);
}
.ex-loading__spinner { display: inline-flex; gap: 6px; margin-bottom: var(--space-4); }
.ex-loading__dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--accent);
  animation: exDot 1.2s infinite ease-in-out;
}
.ex-loading__dot:nth-child(2) { animation-delay: .15s; background: var(--accent-violet); }
.ex-loading__dot:nth-child(3) { animation-delay: .3s; }
@keyframes exDot { 0%, 80%, 100% { transform: scale(.6); opacity: .5; } 40% { transform: scale(1); opacity: 1; } }
.ex-loading__title { margin: 0 0 6px; font-size: var(--text-2xl); }
.ex-loading__sub { margin: 0 0 var(--space-4); }
.ex-loading__progress {
  width: 100%; height: 6px; background: var(--surface-2);
  border-radius: var(--radius-pill); overflow: hidden; margin-bottom: var(--space-5);
}
.ex-loading__bar {
  height: 100%; width: 0%; background: var(--gradient-accent);
  transition: width .4s cubic-bezier(.22,.61,.36,1);
}
.ex-loading__tip {
  background: var(--surface-2); border: 1px solid var(--border-soft);
  border-radius: var(--radius-control); padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4); text-align: left;
}
.ex-loading__tip-label {
  font-size: var(--text-xs); font-weight: 700; color: var(--accent);
  text-transform: uppercase; letter-spacing: .05em;
}
.ex-loading__tip-text { margin: 4px 0 0; color: var(--text); transition: opacity .2s ease; }
.ex-loading__tip-text.is-fading { opacity: 0; }
.ex-loading__actions { display: flex; gap: var(--space-2); justify-content: center; flex-wrap: wrap; }

/* ---- Arena (play) ---- */
.ex-arena { display: flex; flex-direction: column; gap: var(--space-5); }
.ex-arena__top {
  display: grid; gap: var(--space-3) var(--space-4); align-items: center;
  grid-template-columns: 1fr 2fr auto;
  padding: var(--space-4) var(--space-5);
  background: var(--surface-1); border: 1px solid var(--border-soft);
  border-radius: var(--radius-card); box-shadow: var(--shadow-s);
}
.ex-arena__meta { min-width: 0; }
/* «Ne avevi chiesti 15, buoni ne sono venuti 3»: una riga sola, quieta, sotto l'argomento.
   Compare solo quando i due numeri differiscono, quindi non è rumore di ogni sessione. */
.ex-arena__monco { margin: var(--space-2) 0 0; max-width: 46ch; }
.ex-arena__monco[hidden] { display: none; }
.ex-arena__topic { margin: 2px 0 0; font-size: var(--text-lg); line-height: var(--lh-tight); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ex-arena__progress { display: flex; flex-direction: column; gap: 6px; min-width: 200px; }
.ex-arena__progress-row { display: flex; justify-content: space-between; align-items: center; }
.ex-arena__bar { width: 100%; height: 6px; background: var(--surface-2); border-radius: var(--radius-pill); overflow: hidden; }
.ex-arena__bar-fill { height: 100%; width: 0%; background: var(--gradient-accent); transition: width .35s cubic-bezier(.22,.61,.36,1); }
.ex-timer {
  font-variant-numeric: tabular-nums; font-weight: 600; font-size: var(--text-sm);
  padding: 2px 10px; border-radius: var(--radius-pill);
  background: var(--surface-2); border: 1px solid var(--border-soft);
}

@media (max-width: 720px) {
  .ex-arena__top { grid-template-columns: 1fr auto; }
  .ex-arena__progress { grid-column: 1 / -1; min-width: 0; }
}

.ex-arena__grid {
  display: grid; gap: var(--space-5);
  grid-template-columns: minmax(0, 1fr) 320px;
}
/* FIX: senza questo guard, `display:grid` vinceva sull'attributo [hidden] e lo skeleton di
   caricamento (#play-skeleton) restava visibile SOPRA la domanda già renderizzata. */

@media (max-width: 1024px) { .ex-arena__grid { grid-template-columns: 1fr; } }

/* Question card */
.ex-question-card {
  background: var(--surface-1); border: 1px solid var(--border-soft);
  border-radius: var(--radius-card); padding: var(--space-5) var(--space-6);
  box-shadow: var(--shadow-m); display: flex; flex-direction: column; gap: var(--space-4);
}
.ex-question-card__head { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; }
.ex-difficulty { background: color-mix(in srgb, var(--accent) 14%, var(--surface-1)); color: var(--text); border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border-soft)); }
.ex-concept { font-weight: 500; }
.ex-question-card__text {
  margin: 0; font-size: var(--text-2xl); line-height: 1.35; color: var(--text);
  font-weight: 600;
}

/* Options */
.ex-options { display: grid; gap: var(--space-2); }
.ex-option {
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  padding: var(--space-3) var(--space-4); min-height: 56px;
  background: var(--surface-1); color: var(--text);
  border: 1px solid var(--border-soft); border-radius: var(--radius-control);
  cursor: pointer; text-align: left; font-size: var(--text-base);
  transition: transform .12s ease, border-color .15s ease, box-shadow .18s ease, background .15s ease;
}
.ex-option:hover:not(:disabled) {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, var(--surface-1));
  transform: translateY(-1px);
}
.ex-option:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ex-option.is-selected {
  border-color: var(--accent); box-shadow: var(--glow-s);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface-1));
}
.ex-option.is-correct {
  border-color: var(--color-success);
  background: color-mix(in srgb, var(--color-success) 14%, var(--surface-1));
}
.ex-option.is-incorrect {
  border-color: var(--color-danger);
  background: color-mix(in srgb, var(--color-danger) 12%, var(--surface-1));
}
.ex-option:disabled { cursor: default; opacity: 1; }
.ex-option__key {
  width: 28px; height: 28px; display: grid; place-items: center;
  background: var(--surface-2); border: 1px solid var(--border-soft);
  border-radius: 8px; font-size: var(--text-xs); font-weight: 700; color: var(--muted);
  flex-shrink: 0;
}
.ex-option.is-selected .ex-option__key { background: var(--gradient-accent); color: #fff; border-color: transparent; }
.ex-option.is-correct .ex-option__key { background: var(--color-success); color: #fff; border-color: transparent; }
.ex-option.is-incorrect .ex-option__key { background: var(--color-danger); color: #fff; border-color: transparent; }
.ex-option__text { flex: 1; }
.ex-option--tf { justify-content: center; font-weight: 600; }

/* Open input */
.ex-open__input { width: 100%; resize: vertical; min-height: 96px; font-size: var(--text-base); }

/* Hint ladder */
.ex-hint {
  border: 1px dashed var(--border-soft); border-radius: var(--radius-control);
  padding: var(--space-2) var(--space-4); background: var(--surface-2);
}
.ex-hint__summary { cursor: pointer; font-weight: 600; color: var(--text); padding: 6px 0; list-style: none; }
.ex-hint__summary::-webkit-details-marker { display: none; }
.ex-hint__list { list-style: none; padding: 0; margin: var(--space-2) 0 0; display: flex; flex-direction: column; gap: var(--space-2); }
.ex-hint__step { display: flex; flex-direction: column; gap: 4px; }
.ex-hint__btn {
  display: flex; justify-content: space-between; align-items: center;
  background: var(--surface-1); border: 1px solid var(--border-soft); border-radius: var(--radius-control);
  padding: 8px 14px; cursor: pointer; font-size: var(--text-sm); color: var(--text);
}
.ex-hint__btn:hover { border-color: var(--accent); }
.ex-hint__btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ex-hint__btn.is-revealed { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--surface-1)); }
.ex-hint__lvl { font-weight: 600; }
.ex-hint__reveal { color: var(--accent); font-weight: 500; font-size: var(--text-xs); }
.ex-hint__btn.is-revealed .ex-hint__reveal { color: var(--muted); }
.ex-hint__text { margin: 0; padding: 8px 14px; color: var(--muted); font-size: var(--text-sm); }

/* Binario grammaticale (latino/greco): la griglia del paradigma + la tastiera greca.
   Fascicolo grammatica classica, 2026-08-18 — §7. Solo token, nessun colore hardcoded. */
.ex-griglia { margin: var(--space-2) 0; }
/* WCAG 1.4.10 Reflow: la TABELLA scorre nel suo riquadro, mai la pagina (stessa regola
   di .katex-display sopra — una tabella a 3 colonne su 360px altrimenti deborda). */
.ex-griglia__tabella {
  width: 100%; border-collapse: collapse; overflow-x: auto; display: block;
  font-size: var(--text-sm);
}
.ex-griglia__tabella caption {
  text-align: left; padding-bottom: var(--space-2); color: var(--muted); font-style: italic;
}
.ex-griglia__tabella th, .ex-griglia__tabella td {
  padding: 6px var(--space-3); border-bottom: 1px solid var(--border-soft); text-align: left;
  white-space: nowrap;
}
.ex-griglia__tabella th[scope="col"] { color: var(--muted); font-weight: 600; font-size: var(--text-xs); }
.ex-griglia__tabella th[scope="row"] { font-weight: 500; color: var(--text); }
.ex-griglia__cella--assente { color: var(--muted); }
/* La cella attiva: il colore non è mai l'unico canale (WCAG 1.4.1) — il "?" testuale e lo
   sr-only accanto restano anche senza percezione del colore. */
.ex-griglia__cella.is-attiva {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border-radius: 6px; font-weight: 700; color: var(--accent);
}

/* Tastiera greca: aiuto, non vincolo — collassabile per non mangiare metà viewport mobile. */
.ex-tastierina {
  border: 1px dashed var(--border-soft); border-radius: var(--radius-control);
  padding: var(--space-2) var(--space-4); background: var(--surface-2); margin-top: var(--space-2);
}
.ex-tastierina__summary { cursor: pointer; font-weight: 600; color: var(--text); padding: 6px 0; list-style: none; }
.ex-tastierina__summary::-webkit-details-marker { display: none; }
.ex-tastierina__body { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-2); }
.ex-tastierina__riga { display: flex; flex-wrap: wrap; gap: 6px; }
.ex-tastierina__tasto {
  min-width: 44px; min-height: 44px; display: grid; place-items: center;
  background: var(--surface-1); color: var(--text); border: 1px solid var(--border-soft);
  border-radius: 8px; font-size: var(--text-base); cursor: pointer;
}
.ex-tastierina__tasto:hover { border-color: var(--accent); }
.ex-tastierina__tasto:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ex-tastierina__riga--segni .ex-tastierina__tasto { font-size: var(--text-lg, var(--text-base)); color: var(--muted); }

/* Giochi interattivi (fascicolo giochi-matematica.md): retta/piano/ordina/bilancia. Un
   rivestimento sopra "gap"/"step" — quando c'è, sostituisce opzioni/textarea. Solo token,
   maniglie/bottoni ≥44×44 (WCAG 2.5.5), focus sempre visibile. */
.ex-game { margin: var(--space-2) 0 var(--space-3); }
.ex-game svg { width: 100%; height: auto; display: block; touch-action: none; }
.ex-game circle[role="slider"]:focus-visible,
.ex-game__ordina-btn:focus-visible,
.ex-game__bilancia-btn:focus-visible,
.ex-game__coord:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.ex-game__value {
  text-align: center; font-size: var(--text-lg, var(--text-base)); font-weight: 700;
  color: var(--accent); margin-top: var(--space-1, 4px);
}

/* G2 — piano: le due caselle x/y sono il canale-tastiera onesto (mai una "modalità
   speciale" da scoprire) e servono anche gli screen reader. */
.ex-game__coords { display: flex; gap: var(--space-3); justify-content: center; margin-top: var(--space-2); }
.ex-game__coord-label {
  display: flex; align-items: center; gap: 6px; font-size: var(--text-sm); color: var(--muted); font-weight: 600;
}
.ex-game__coord { width: 6.5em; }

/* G3 — ordina: card in lista, ▲/▼ SEMPRE presenti (il drag è un'aggiunta progressiva che
   questa v1 non implementa — i bottoni bastano da soli, mai l'unico modo diventa il drag). */
.ex-game__ordina { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.ex-game__ordina-card {
  display: flex; align-items: center; gap: var(--space-3);
  background: var(--surface-1); border: 1px solid var(--border-soft); border-radius: var(--radius-control);
  padding: var(--space-2) var(--space-3);
}
.ex-game__ordina-card.is-correct { border-color: var(--color-success); background: color-mix(in srgb, var(--color-success) 12%, var(--surface-1)); }
.ex-game__ordina-card.is-incorrect { border-color: var(--color-danger); background: color-mix(in srgb, var(--color-danger) 10%, var(--surface-1)); }
.ex-game__ordina-id {
  width: 28px; height: 28px; flex-shrink: 0; display: grid; place-items: center;
  background: var(--surface-2); border: 1px solid var(--border-soft); border-radius: 8px;
  font-weight: 700; font-size: var(--text-xs); color: var(--muted);
}
.ex-game__ordina-testo { flex: 1; min-width: 0; }
.ex-game__ordina-btn {
  min-width: 44px; min-height: 44px; display: grid; place-items: center;
  background: var(--surface-2); color: var(--text); border: 1px solid var(--border-soft);
  border-radius: 8px; font-size: var(--text-base); cursor: pointer; flex-shrink: 0;
}
.ex-game__ordina-btn:hover:not(:disabled) { border-color: var(--accent); }
.ex-game__ordina-btn:disabled { opacity: .45; cursor: default; }
.ex-game__ordina-soluzione { margin-top: var(--space-2); }

/* G4 — bilancia: l'equazione (KaTeX) è la verità, la bottoniera opera SEMPRE su entrambi i
   lati per costruzione — nessuna mossa "illegale" da impedire lato client. */
.ex-game__equazione { text-align: center; font-size: var(--text-lg, 1.15rem); margin: var(--space-2) 0; }
.ex-game__bilancia-ops { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: center; }
.ex-game__bilancia-btn {
  min-width: 44px; min-height: 44px; padding: 0 var(--space-3);
  background: var(--surface-1); color: var(--text); border: 1px solid var(--border-soft);
  border-radius: var(--radius-control); font-weight: 600; font-size: var(--text-base); cursor: pointer;
}
.ex-game__bilancia-btn:hover { border-color: var(--accent); }
.ex-game__bilancia-esito {
  text-align: center; font-weight: 600; color: var(--color-success); margin-top: var(--space-2);
}
.ex-game__bilancia-soluzione { margin-top: var(--space-2); }

@media (prefers-reduced-motion: reduce) {
  .ex-game *, .ex-game *::before, .ex-game *::after { transition: none !important; animation: none !important; }
}

/* Actions row */
.ex-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.kbd {
  display: inline-block; margin-left: 6px; padding: 1px 6px;
  font-family: ui-monospace, SFMono-Regular, monospace; font-size: 11px;
  background: rgba(255,255,255,.18); border: 1px solid rgba(255,255,255,.28);
  border-radius: 4px; color: inherit;
}
.btn--ghost .kbd { background: var(--surface-2); border-color: var(--border-soft); color: var(--muted); }

/* Result */
.ex-result {
  border-radius: var(--radius-control); padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-soft); background: var(--surface-2);
  display: flex; flex-direction: column; gap: var(--space-2);
  animation: exResultIn .25s cubic-bezier(.22,.61,.36,1);
}
@keyframes exResultIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.ex-result--ok {
  border-color: color-mix(in srgb, var(--color-success) 50%, var(--border-soft));
  background: color-mix(in srgb, var(--color-success) 10%, var(--surface-1));
}
.ex-result--ko {
  border-color: color-mix(in srgb, var(--color-danger) 50%, var(--border-soft));
  background: color-mix(in srgb, var(--color-danger) 8%, var(--surface-1));
}
/* F7-1 — il terzo stato: «Quasi!». Il giudice delle risposte aperte dice che il concetto c'e'
   a meta', e mezza risposta non e' ne' un verde ne' un rosso: dipingerla rossa e' l'ingiustizia
   che questo lavoro toglie, dipingerla verde e' regalare il voto. Stesse proporzioni di --ok e
   --ko, tinta d'ambra dai token. */
.ex-result--quasi {
  border-color: color-mix(in srgb, var(--color-warning) 50%, var(--border-soft));
  background: color-mix(in srgb, var(--color-warning) 10%, var(--surface-1));
}
.ex-result--neutral { background: var(--surface-2); }
.ex-result__head { display: flex; align-items: center; gap: var(--space-2); font-weight: 700; }
.ex-result__icon {
  width: 28px; height: 28px; display: grid; place-items: center;
  border-radius: 50%; color: #fff; font-weight: 700;
}
.ex-result--ok .ex-result__icon { background: var(--color-success); }
.ex-result--ko .ex-result__icon { background: var(--color-danger); }
/* Il glifo e' bianco (ereditato da .ex-result__icon): sul chiaro si usa la variante da testo
   dell'ambra (5,02:1), al buio la tinta e' gia' chiara e l'inchiostro si inverte sul fondo. */
.ex-result--quasi .ex-result__icon { background: var(--color-warning-ink); }
:root.dark .ex-result--quasi .ex-result__icon { color: var(--bg0); }
/* «Giusto, detto con parole tue!»: la riga che spiega perche' una risposta scritta a modo suo
   e' verde. Verde da TESTO (--color-success-ink, 5,02:1), non la tinta da bordo. */
.ex-result__parole-tue {
  margin: 0;
  color: var(--color-success-ink);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: var(--lh-base);
}
/* «Giusto! Occhio pero' alla grafia esatta: λύω» — la lezione che accompagna un verde pieno.
   Ambra da TESTO (--color-warning-ink), non la tinta da bordo: e' un'annotazione, non un
   verdetto, e sta dentro un riquadro gia' verde. */
.ex-result__forma {
  margin: 0;
  color: var(--color-warning-ink);
  font-size: var(--text-sm);
  line-height: var(--lh-base);
}
.ex-result__answer { margin: 0; }
/* La diagnosi dell'errore appena commesso: sta SOPRA la soluzione perche' e' il momento in cui
   si impara qualcosa (rapporto pedagogia 2026-08-09). Filetto a sinistra per distinguerla dalla
   soluzione senza gridare: il testo resta --text su --surface-1, contrasto gia' verificato. */
.ex-result__diagnosis {
  margin: 0;
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--color-danger);
  border-radius: var(--radius-control);
  background: var(--surface-1);
  color: var(--text);
  font-size: var(--text-sm);
  line-height: var(--lh-base);
}
/* Su un «Quasi!» il filetto della diagnosi non e' rosso: quello che manca non e' un errore. */
.ex-result__diagnosis--quasi { border-left-color: var(--color-warning); }
.ex-result__explain { display: flex; flex-direction: column; gap: var(--space-2); padding-top: var(--space-2); border-top: 1px dashed var(--border-soft); }
.ex-result__explain-text { margin: 0; color: var(--text); font-size: var(--text-sm); line-height: var(--lh-base); }

/* Side panel */
.ex-side__panel {
  background: var(--surface-1); border: 1px solid var(--border-soft);
  border-radius: var(--radius-card); padding: var(--space-4); box-shadow: var(--shadow-s);
  display: flex; flex-direction: column; gap: var(--space-3);
  position: sticky; top: 88px;
}
.ex-side__title { margin: 0; font-size: var(--text-base); }
.ex-side__row { display: flex; flex-direction: column; gap: var(--space-2); }
.ex-side__bar { width: 100%; height: 8px; background: var(--surface-2); border-radius: var(--radius-pill); overflow: hidden; }
.ex-side__bar-fill { height: 100%; background: var(--gradient-accent); transition: width .4s ease; width: 0%; }
.ex-side__bar-value { font-size: var(--text-sm); font-weight: 600; color: var(--text); align-self: flex-end; }
.ex-side__chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ex-related-chip { background: var(--surface-2); color: var(--text); border: 1px solid var(--border-soft); }
.ex-side__source { font-style: italic; }

/* Summary */
.ex-summary {
  background: var(--surface-1); border: 1px solid var(--border-soft);
  border-radius: var(--radius-card); padding: var(--space-6) var(--space-5);
  box-shadow: var(--shadow-m); display: flex; flex-direction: column; gap: var(--space-5);
}
.ex-summary__hero { text-align: center; }
.ex-summary__score {
  margin: 6px 0 4px; font-size: 64px; line-height: 1;
  background: var(--gradient-accent); -webkit-background-clip: text; background-clip: text; color: transparent;
  font-weight: 800;
}
.ex-summary__pct { margin: 0 0 var(--space-2); font-size: var(--text-lg); color: var(--text); }
.ex-summary__msg { margin: 0; max-width: 540px; margin-left: auto; margin-right: auto; }
.ex-summary__grid {
  display: grid; gap: var(--space-4);
  grid-template-columns: 1fr 1fr;
}
@media (max-width: 640px) { .ex-summary__grid { grid-template-columns: 1fr; } }
.ex-summary__col h3 { margin: 0 0 var(--space-2); font-size: var(--text-base); }
.ex-summary__list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.ex-summary__list li {
  padding: 8px 14px; background: var(--surface-2);
  border: 1px solid var(--border-soft); border-radius: var(--radius-pill);
  font-size: var(--text-sm);
}
.ex-summary__bars { display: flex; flex-direction: column; gap: var(--space-2); }
.ex-summary__bar-row { display: grid; grid-template-columns: 160px 1fr 50px; gap: var(--space-3); align-items: center; }
@media (max-width: 640px) { .ex-summary__bar-row { grid-template-columns: 1fr 1fr 50px; } }
.ex-summary__bar-label { font-size: var(--text-sm); color: var(--text); }
.ex-summary__bar { height: 8px; background: var(--surface-2); border-radius: var(--radius-pill); overflow: hidden; }
.ex-summary__bar-fill { height: 100%; background: var(--gradient-accent); transition: width .4s ease; }
.ex-summary__bar-value { font-size: var(--text-sm); font-weight: 600; text-align: right; }
.ex-summary__cta { display: flex; flex-wrap: wrap; gap: var(--space-3); justify-content: center; padding-top: var(--space-3); border-top: 1px dashed var(--border-soft); }

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  .ex-loading__dot,
  .ex-loading__bar,
  .ex-arena__bar-fill,
  .ex-side__bar-fill,
  .ex-summary__bar-fill,
  .ex-result,
  .ex-option,
  .ex-mode,
  .ex-subject {
    animation: none !important;
    transition: none !important;
  }
}


/* =====================================================   PROFILE REDESIGN (additive, scoped to .profile-redesign)
   Single-column, vertically scrollable, modern SaaS layout.
   ============================================================ */
.profile-redesign {
  background: var(--bg);
  min-height: 100vh;
  padding: clamp(24px, 4vw, 56px) 16px 80px;
}
.profile-redesign .profile-shell {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.profile-redesign .profile-card {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 16px;
  padding: clamp(20px, 3vw, 28px);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
html.dark .profile-redesign .profile-card {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}
.profile-redesign .profile-eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted, #64748b);
  margin: 0 0 6px;
}
.profile-redesign .profile-headline {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 6px;
  color: var(--text);
}
.profile-redesign .profile-helper {
  font-size: 13px;
  color: var(--muted, #64748b);
  margin: 0 0 16px;
  line-height: 1.5;
}
.profile-redesign .profile-section > .profile-helper:last-of-type { margin-bottom: 16px; }

/* Identity card */
.profile-redesign .profile-identity-card {
  padding: clamp(20px, 3vw, 28px);
}
.profile-redesign .profile-identity-row {
  display: flex;
  gap: 20px;
  align-items: center;
}
.profile-redesign .profile-avatar-wrap {
  position: relative;
  width: 96px;
  height: 96px;
  flex-shrink: 0;
  border-radius: 50%;
  overflow: hidden;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
}
.profile-redesign .profile-avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.profile-redesign .profile-avatar-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(15, 23, 42, 0.55);
  color: #fff;
  opacity: 0;
  cursor: pointer;
  transition: opacity 160ms ease;
}
.profile-redesign .profile-avatar-wrap:hover .profile-avatar-overlay,
.profile-redesign .profile-avatar-overlay:focus-within {
  opacity: 1;
}
.profile-redesign .profile-identity-text { min-width: 0; flex: 1; }
.profile-redesign .profile-identity-name {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.profile-redesign .profile-display-name {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--text);
  margin: 0;
  line-height: 1.2;
}
.profile-redesign .profile-display-email {
  margin: 4px 0 8px;
  color: var(--muted, #64748b);
  font-size: 14px;
  word-break: break-all;
}
.profile-redesign .profile-role-badge {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
}
.profile-redesign .profile-edit-name-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  padding: 6px 10px;
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease;
}
.profile-redesign .profile-edit-name-btn:hover {
  background: var(--surface-2);
  border-color: var(--border-strong);
}
.profile-redesign .profile-edit-name-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.profile-redesign .profile-status-line {
  margin-top: 12px;
  font-size: 13px;
  color: var(--muted, #64748b);
  min-height: 18px;
}
.profile-redesign .profile-status-line[data-kind="success"] { color: #16a34a; }
.profile-redesign .profile-status-line[data-kind="error"] { color: #dc2626; }
.profile-redesign .profile-status-line[data-kind="warn"] { color: #d97706; }

/* Field rows */
.profile-redesign .profile-field-row,
.profile-modal .profile-field-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}
.profile-redesign .profile-field-row--split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.profile-redesign .profile-field-label,
.profile-modal .profile-field-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: 0.01em;
}
.profile-redesign .profile-input,
.profile-redesign .profile-input--inline,
.profile-modal .profile-input {
  width: 100%;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid var(--border-soft);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.profile-redesign .profile-input:focus-visible,
.profile-redesign .profile-input--inline:focus-visible,
.profile-modal .profile-input:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* Le finestre del profilo (cambio email e password) stanno fuori da .profile-redesign: stessi campi,
   a 16 px perché sotto Safari su iPhone ingrandisce la pagina al tocco. Il codice: cifre grandi e larghe. */
.profile-modal .profile-input { font-size: 16px; }
.profile-modal #ce-codice { font-size: 24px; letter-spacing: 0.3em; text-align: center; font-variant-numeric: tabular-nums; padding: 12px; }
.profile-redesign .profile-input[readonly] {
  background: var(--bg);
  color: var(--muted, #64748b);
  cursor: default;
}
.profile-redesign .profile-input--inline {
  font-size: 22px;
  font-weight: 700;
  padding: 4px 8px;
}
.profile-redesign .profile-fieldset { border: 0; padding: 0; margin: 0 0 14px; }

/* Inline rows (CTA next to title) */
.profile-redesign .profile-inline-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-top: 1px solid var(--border-soft);
}
.profile-redesign .profile-inline-row:first-of-type { border-top: 0; padding-top: 0; }
.profile-redesign .profile-section .profile-inline-row:last-child { padding-bottom: 0; }
.profile-redesign .profile-inline-title {
  margin: 0 0 2px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}
.profile-redesign .profile-inline-row .profile-helper { margin: 0; }
.profile-redesign .profile-divider {
  height: 1px;
  background: var(--border-soft);
  margin: 14px 0;
}

/* Toggle (custom switch) */
.profile-redesign .profile-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-top: 1px solid var(--border-soft);
}
.profile-redesign .profile-toggle-row:first-of-type { border-top: 0; padding-top: 0; }
.profile-redesign .profile-switch {
  position: relative;
  width: 40px;
  height: 24px;
  flex-shrink: 0;
}
.profile-redesign .profile-switch input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
  margin: 0;
}
.profile-redesign .profile-switch-track {
  position: absolute;
  inset: 0;
  background: var(--border);
  border-radius: 999px;
  transition: background 160ms ease;
}
.profile-redesign .profile-switch-track::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 20px;
  height: 20px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(0,0,0,0.2);
  transition: transform 160ms ease;
}
.profile-redesign .profile-switch input:checked + .profile-switch-track {
  background: var(--accent);
}
.profile-redesign .profile-switch input:checked + .profile-switch-track::after {
  transform: translateX(16px);
}
.profile-redesign .profile-switch input:focus-visible + .profile-switch-track {
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* Interruttore non azionabile (es. consenso al dataset sotto i 14 anni): si vede che è
   bloccato senza affidarsi al solo colore — il perché è scritto nella nota accanto. */
.profile-redesign .profile-switch input:disabled { cursor: not-allowed; }
.profile-redesign .profile-switch input:disabled + .profile-switch-track {
  opacity: 0.45;
  background: var(--border);
}
.profile-redesign .profile-switch input:disabled + .profile-switch-track::after {
  box-shadow: none;
}

/* Chips (subjects) */
.profile-redesign .profile-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.profile-redesign .profile-chip {
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  color: var(--text);
  font-size: 13px;
  padding: 6px 12px;
  border-radius: 999px;
  cursor: pointer;
  transition: all 140ms ease;
}
.profile-redesign .profile-chip:hover { border-color: var(--border-strong); }
.profile-redesign .profile-chip.is-selected {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}
.profile-redesign .profile-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Radios */
.profile-redesign .profile-radio-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.profile-redesign .profile-radio {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  cursor: pointer;
  font-size: 13px;
  background: var(--surface-2);
  transition: all 140ms ease;
}
.profile-redesign .profile-radio:has(input:checked) {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}
.profile-redesign .profile-radio input { accent-color: var(--accent); }

/* Theme chips */
.profile-redesign .profile-theme-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.profile-redesign .profile-theme-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border-radius: 10px;
  border: 1px solid var(--border-soft);
  background: var(--surface-2);
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: all 140ms ease;
}
.profile-redesign .profile-theme-chip:hover { border-color: var(--border-strong); }
.profile-redesign .profile-theme-chip.is-active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}
.profile-redesign .profile-theme-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Actions row */
.profile-redesign .profile-actions-row {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 8px;
}

/* Danger zone */
.profile-redesign .profile-danger-zone {
  margin-top: 12px;
  padding: 14px;
  border: 1px solid color-mix(in srgb, #dc2626 24%, var(--border));
  border-radius: 12px;
  background: color-mix(in srgb, #dc2626 6%, transparent);
}
/* #b91c1c e non #dc2626: su #fdf2f2 il rosso chiaro faceva 4,4:1, un soffio SOTTO la
   soglia WCAG 4,5:1 (visita 2026-08-09 M2). Il tema scuro ha il suo override più giù. */
.profile-redesign .profile-danger-title { color: #b91c1c; }

/* Logout section */
.profile-redesign .profile-logout-section {
  margin-top: 8px;
  text-align: center;
  border: 1px dashed var(--border-soft);
  background: transparent;
}
.profile-redesign .profile-logout-title { font-size: 16px; }
.profile-redesign .profile-logout-btn {
  margin-top: 12px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: #dc2626;
  border-color: color-mix(in srgb, #dc2626 30%, var(--border));
}
.profile-redesign .profile-logout-btn:hover {
  background: color-mix(in srgb, #dc2626 8%, transparent);
  border-color: #dc2626;
}

/* Pills */
.profile-redesign .profile-pill {
  display: inline-flex;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}
.profile-redesign .profile-pill--ok {
  background: color-mix(in srgb, #16a34a 12%, transparent);
  color: #16a34a;
}

/* Modals */
.profile-redesign .profile-modal,
.profile-modal {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 16px;
}

.profile-modal-card {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 16px;
  padding: 24px;
  width: 100%;
  max-width: 420px;
  box-shadow: 0 20px 40px rgba(0,0,0,0.2);
}
.profile-modal-card h3 {
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 700;
}

/* Visually hidden */
.profile-redesign .visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* Mobile */
@media (max-width: 520px) {
  .profile-redesign .profile-identity-row {
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
  }
  .profile-redesign .profile-field-row--split { grid-template-columns: 1fr; }
  .profile-redesign .profile-inline-row,
  .profile-redesign .profile-toggle-row {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  .profile-redesign * { transition: none !important; }
}

/* =====================================================   NAV PROFILE LINK (replaces logout button + theme toggle)
   ============================================================ */
.nav-profile-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px 4px 4px;
  border-radius: 999px;
  border: 1px solid var(--border-soft);
  background: var(--surface-1);
  color: var(--text);
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  transition: background 140ms ease, border-color 140ms ease;
}
.nav-profile-link:hover {
  background: var(--surface-2);
  border-color: var(--border-strong);
}
.nav-profile-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.nav-avatar--auto {
  width: 28px; height: 28px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--accent);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  overflow: hidden;
  flex-shrink: 0;
}
.nav-avatar__img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.nav-profile-name { white-space: nowrap; }
@media (max-width: 520px) {
  .nav-profile-name { display: none; }
  .nav-profile-link { padding: 4px; }
}

/* ===================================================== * Esercizi · gamification + adaptive UI (2026-05-13)
 * ============================================================ */
.ex-arena__gamification {
  display: inline-flex; gap: 10px; align-items: center;
  margin-left: 12px;
}
.ex-gam-stat {
  display: inline-flex; gap: 6px; align-items: center;
  padding: 4px 10px; border-radius: 999px;
  background: var(--surface-2, var(--bg-2));
  border: 1px solid var(--border);
  font-size: var(--text-sm);
  color: var(--text);
}
.ex-gam-stat__label { color: var(--muted); font-weight: 500; }
.ex-gam-stat strong { font-variant-numeric: tabular-nums; }
.ex-gam-stat.is-pulse { animation: exGamPulse 600ms ease-out; }
@keyframes exGamPulse {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.08); background: var(--brand-50, var(--accent-bg, var(--surface-2))); }
  100% { transform: scale(1); }
}

.ex-xp-pop {
  position: fixed; top: 90px; right: 28px;
  padding: 8px 14px; border-radius: 999px;
  background: var(--brand, var(--accent, #4f46e5));
  color: #fff; font-weight: 700; font-size: var(--text-sm);
  pointer-events: none; opacity: 0;
  transition: transform 380ms cubic-bezier(.2,.7,.3,1), opacity 380ms ease;
  z-index: 50;
}
.ex-xp-pop.is-visible { opacity: 1; transform: translateY(-6px); }
@media (prefers-reduced-motion: reduce) {
  .ex-xp-pop, .ex-gam-stat.is-pulse { animation: none; transition: none; }
}

.ex-toast {
  position: fixed; bottom: 28px; left: 50%; transform: translateX(-50%);
  padding: 10px 18px; border-radius: 12px;
  background: var(--text); color: var(--bg);
  font-weight: 600; font-size: var(--text-sm);
  box-shadow: 0 8px 24px rgba(0,0,0,.18);
  z-index: 60; max-width: 90vw;
}

.ex-hint__counter { margin-left: auto; font-weight: 500; }
.ex-hint__summary { display: flex; align-items: center; gap: 8px; }

/* Recommendation cards (esercizi.html top) */
.ex-recs { margin: 0 0 24px; }
.ex-recs__title { margin: 0 0 4px; font-size: var(--text-lg); }
.ex-recs__grid {
  display: grid; gap: 12px; margin-top: 12px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.ex-rec-card {
  display: flex; flex-direction: column; gap: 6px;
  padding: 14px 16px; border-radius: 12px;
  background: var(--surface-2, var(--bg-2));
  border: 1px solid var(--border);
  cursor: pointer; text-align: left;
  transition: transform 160ms ease, border-color 160ms ease, box-shadow 160ms ease;
}
.ex-rec-card:hover, .ex-rec-card:focus-visible {
  transform: translateY(-2px);
  border-color: var(--brand, var(--accent));
  box-shadow: 0 6px 16px rgba(0,0,0,.06);
  outline: none;
}
.ex-rec-card__kind {
  display: inline-block; font-size: var(--text-xs);
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--brand, var(--accent)); font-weight: 700;
}
.ex-rec-card__topic { font-weight: 700; color: var(--text); }
.ex-rec-card__reason { color: var(--muted); font-size: var(--text-sm); }
.ex-rec-card__meta { color: var(--muted); font-size: var(--text-xs); margin-top: 4px; }

/* Weak-concept link inside result */
.ex-result__weak-link {
  margin-top: 8px; padding: 8px 12px; border-radius: 8px;
  background: var(--surface-2, var(--bg-2));
  font-size: var(--text-sm); color: var(--text);
  border-left: 3px solid var(--warning, #d97706);
}

/* ---- Graceful error modal (realtime + esercizi loading) ---- */
.sk-err-modal {
  position: fixed; inset: 0; z-index: var(--z-modal, 60);
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-4);
}
.sk-err-modal[hidden] { display: none !important; }
.sk-err-modal__backdrop {
  position: absolute; inset: 0;
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(6px);
}
.sk-err-modal__card {
  position: relative;
  max-width: 480px; width: 100%;
  background: var(--surface-1); color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-card);
  padding: var(--space-6) var(--space-5);
  box-shadow: var(--shadow-l);
  text-align: center;
  animation: skErrIn .25s cubic-bezier(.22,.61,.36,1);
}
@keyframes skErrIn {
  from { opacity: 0; transform: translateY(8px) scale(.98); }
  to   { opacity: 1; transform: translateY(0)   scale(1);   }
}
.sk-err-modal__icon {
  width: 48px; height: 48px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 22px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
  margin-bottom: var(--space-3);
}
.sk-err-modal[data-tone="warning"] .sk-err-modal__icon {
  background: color-mix(in srgb, var(--warning, #d97706) 18%, transparent);
  color: var(--warning, #d97706);
}
.sk-err-modal[data-tone="info"] .sk-err-modal__icon {
  background: color-mix(in srgb, var(--accent-violet, var(--accent)) 18%, transparent);
  color: var(--accent-violet, var(--accent));
}
.sk-err-modal__title { margin: 0 0 var(--space-2); font-size: var(--text-xl); line-height: var(--lh-tight); }
.sk-err-modal__body  { margin: 0 0 var(--space-4); color: var(--muted); }
.sk-err-modal__actions {
  display: flex; gap: var(--space-2); justify-content: center; flex-wrap: wrap;
}

/* ---- Loading steps (esercizi-loading) ---- */
.ex-loading__steps {
  display: flex; flex-direction: column; gap: 8px;
  margin: 0 0 var(--space-4); text-align: left;
}
.ex-loading__step {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 10px; border-radius: var(--radius-control);
  color: var(--muted); font-size: var(--text-sm);
  transition: color .25s ease, background .25s ease;
}
.ex-loading__step-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--surface-2); border: 1px solid var(--border-soft);
  flex: 0 0 auto;
}
.ex-loading__step.is-active {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.ex-loading__step.is-active .ex-loading__step-dot {
  background: var(--accent); border-color: var(--accent);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 22%, transparent);
}
.ex-loading__step.is-done { color: var(--text); }
.ex-loading__step.is-done .ex-loading__step-dot {
  background: var(--success, #16a34a); border-color: var(--success, #16a34a);
}
.ex-loading__percent {
  font-variant-numeric: tabular-nums; font-weight: 700;
  color: var(--accent); font-size: var(--text-sm);
  margin: 0 0 var(--space-2);
}

/* ── Cookie consent — compact, centered, theme-aware card (styling moved out of ui.js inline) ── */
.cookie-banner {
  position: fixed;
  left: 50%;
  bottom: clamp(0.75rem, 2vw, 1.25rem);
  transform: translateX(-50%);
  z-index: 9999;
  width: min(680px, calc(100% - 1.5rem));
  background: var(--surface-1, #fff);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-card, 14px);
  box-shadow: 0 10px 34px rgba(15, 23, 42, 0.18);
}
.cookie-banner__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 0.85rem 1.1rem;
}
.cookie-banner__text {
  flex: 1 1 260px;
  margin: 0;
  font-size: var(--text-sm, 14px);
  line-height: 1.45;
  color: var(--muted);
}
.cookie-banner__text .cta { color: var(--accent-ink); text-decoration: underline; }
.cookie-banner__actions {
  display: flex;
  gap: 0.5rem;
  flex-shrink: 0;
}
@media (max-width: 520px) {
  .cookie-banner { width: calc(100% - 1rem); bottom: 0.5rem; }
  .cookie-banner__inner { flex-direction: column; align-items: stretch; gap: 0.75rem; }
  /* In a column flexbox, flex-basis is the MAIN axis (height) — reset so the text hugs its content
     instead of reserving 260px of height (which left a big empty gap on phones). */
  .cookie-banner__text { flex: 0 0 auto; }
  .cookie-banner__actions { width: 100%; }
  .cookie-banner__actions .btn { flex: 1; }
}

/* ── Math visuals (esercizi: KaTeX formulas + SVG diagrams) ───────────────── */
.ex-visual { margin: 0 0 var(--space-4, 16px); display: flex; justify-content: center; }
.ex-visual:empty { display: none; margin: 0; }
.mathviz { margin: 0; max-width: 420px; width: 100%; background: var(--surface-1, #fff); border: 1px solid var(--border); border-radius: var(--radius-md, 12px); padding: 12px; }
.mathviz svg { display: block; width: 100%; height: auto; }
.mathviz__cap { text-align: center; font-size: .85rem; color: var(--muted); margin-top: 6px; }
#play-question .katex, .ex-option__text .katex, .ex-result__explain-text .katex, .ex-result__answer .katex { font-size: 1.05em; }
/* L'ESPONENTE NEGATIVO CHE SPARIVA (segnalato dal founder, 2026-08).
   In notazione scientifica "10^{-7}" il meno dell'esponente non si vedeva: la formula si
   leggeva "10 7". Il meno di KaTeX (U+2212 in KaTeX_Main) e' una barra orizzontale sottile,
   e alle dimensioni tight (KaTeX porta gli apici a .7em) la sua altezza scende sotto il
   pixel: l'hinting fa collassare i due bordi sulla stessa riga di pixel e non resta NIENTE
   da disegnare, nemmeno un antialias.
   Misurato a 1x contando i pixel scuri nel rettangolo del glifo, al variare della dimensione
   del testo contenitore da 12 a 30px: con font-size 1.05em spariva a 12/16/16.5/17px — e 16px
   e' esattamente la dimensione delle opzioni e della risposta. NON e' un errore di scala: ogni
   moltiplicatore ha una sua banda cieca (1.10em → 15-16px, 1.15em → 14.5-15.5px, 1.21em, cioe'
   il default di KaTeX → 14-14.5px). Il problema non e' quanto e' piccolo il testo, e' che una
   barra spessa mezzo pixel a volte non si arrotonda a niente.
   Un filo di contorno sulle sole parti tight garantisce l'inchiostro a ogni dimensione (nessuna
   banda cieca fra 12 e 30px) senza ingrassare visibilmente la formula. `currentColor`: eredita
   il colore del testo, quindi vale identico in tema chiaro e scuro. Dove -webkit-text-stroke
   non e' supportato si torna al comportamento di prima: nessuna regressione. */
.katex .mtight { -webkit-text-stroke: 0.02em currentColor; }
/* LA FORMULA SCORRE NEL SUO RIQUADRO, LA PAGINA NO (WCAG 1.4.10 Reflow).
   KaTeX dichiara `.katex-display > .katex { white-space: nowrap }`: una formula lunga —
   la risolutiva di secondo grado, una reazione con le frecce — su un telefono da 360px
   deborda, e senza un contenitore che scorra e' la PAGINA a scorrere di lato. Da li' in
   poi ogni riga di testo va inseguita orizzontalmente: il difetto peggiora tutto cio' che
   sta intorno, non solo la formula.
   `overflow-y: hidden` insieme a `overflow-x: auto` e' obbligatorio: con un solo asse
   `auto` il browser rende l'altro `auto` per specifica, e comparirebbe una barra
   verticale su ogni frazione (l'overflow verticale di KaTeX e' fisiologico).
   `padding-bottom` lascia respiro alla barra dove il sistema la disegna sopra il
   contenuto (Windows, Linux) invece di sovrapporla agli apici. */
.katex-display {
  overflow-x: auto;
  overflow-y: hidden;
  max-width: 100%;
  padding-bottom: 2px;
}


/* ====================================================================== */
/* RESTYLE 2026-07 — "Carta e inchiostro" component layer                 */
/* Signature highlight, first-run welcome checklist, onboarding styles    */
/* (migrated from onboarding.html inline <style>), AI-incident FAB.       */
/* ====================================================================== */

/* Evidenziatore: marker swipe behind key words. Ink text stays on top so
   contrast is unaffected (bg is a translucent yellow, ≥12:1 with --text). */
.hl {
  font-style: normal;
  background: linear-gradient(104deg, transparent 0.8%, var(--hl) 3%, var(--hl) 97%, transparent 99.5%);
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  padding: 0.04em 0.18em;
  border-radius: 0.25em;
}

/* ---- First-run welcome checklist (modules/tour.js) ------------------- */
.sk-welcome {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-4);
  align-items: start;
  padding: var(--space-5);
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 5%, var(--surface-1)), var(--surface-1) 60%);
  border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--border-soft));
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-s);
  margin-bottom: var(--space-5);
}
.sk-welcome__mascot {
  width: 64px;
  height: 64px;
  object-fit: contain;
}
.sk-welcome__body { min-width: 0; }
.sk-welcome__title {
  margin: 0 0 2px;
  font-family: "Space Grotesk", "Inter", system-ui, sans-serif;
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--text);
}
.sk-welcome__sub { margin: 0 0 var(--space-3); color: var(--muted); font-size: var(--text-sm); }
.sk-welcome__steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-2);
}
.sk-welcome__step { margin: 0; }
.sk-welcome__step a {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-control);
  background: var(--surface-1);
  color: var(--text);
  font-weight: 600;
  font-size: var(--text-sm);
  transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms cubic-bezier(0.2, 0, 0, 1);
}
.sk-welcome__step a:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-s);
  transform: translateY(-1px);
}
.sk-welcome__step a:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.sk-welcome__num {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-size: var(--text-xs);
  font-weight: 700;
}
.sk-welcome__step.is-done a { opacity: 0.72; }
.sk-welcome__step.is-done .sk-welcome__num {
  background: color-mix(in srgb, var(--color-success) 18%, var(--surface-1));
  color: var(--color-success-ink);
}
.sk-welcome__arrow { margin-left: auto; color: var(--muted); }
.sk-welcome__dismiss {
  margin-top: var(--space-3);
  background: none;
  border: none;
  /* 10px e non 4: a 390px il bersaglio era alto 24px (visita 2026-08-09, M8). */
  padding: 10px 0;
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.sk-welcome__dismiss:hover { color: var(--text); }
.sk-welcome__dismiss:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 4px; }
@media (max-width: 560px) {
  .sk-welcome { grid-template-columns: 1fr; }
  .sk-welcome__mascot { width: 48px; height: 48px; }
}

/* ---- Onboarding page (migrated from inline <style>) ------------------ */
.onboarding-progress {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin-top: 24px;
}
.progress-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--border);
  transition: background-color 0.3s ease, transform 0.3s ease;
}
.progress-dot.active {
  background: var(--gradient-accent);
  transform: scale(1.25);
}
.role-card--select { cursor: pointer; position: relative; overflow: hidden; }
.role-card--select::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--gradient-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s ease;
}
.role-card--select:hover::before { transform: scaleX(1); }
.role-card--select:hover { border-color: var(--accent); box-shadow: var(--shadow-m); }
.role-card--select.selected { border-color: var(--accent); box-shadow: var(--glow-m); }

.cog-q { border: none; padding: 0; margin: 0 0 28px; }
.cog-q__legend {
  font-size: 17px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 12px;
  padding: 0;
}
.cog-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}
.cog-opt {
  display: flex;
  align-items: center;
  gap: 12px;
  text-align: left;
  padding: 14px 16px;
  background: var(--surface-1);
  border: 2px solid var(--border);
  border-radius: var(--radius-card);
  color: var(--text);
  cursor: pointer;
  font: inherit;
  transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms cubic-bezier(0.2, 0, 0, 1);
}
.cog-opt:hover { border-color: var(--accent); transform: translateY(-1px); box-shadow: var(--shadow-s); }
.cog-opt:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.cog-opt.selected {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: var(--glow-s);
}
.cog-opt__emoji { font-size: 28px; flex-shrink: 0; }
.cog-opt__label { font-size: 14px; line-height: 1.4; }
/* Quiz v2: anno e materie sono chip compatte — flex-wrap, mai colonne strette su mobile.
   Stessi stati di .cog-opt (selected, focus ring): cambia solo la taglia. */
.cog-options--chips { display: flex; flex-wrap: wrap; gap: 8px; }
.cog-opt--chip { padding: 10px 14px; border-radius: var(--radius-pill); font-size: 14px; }
.cog-q__hint { font-weight: 400; font-size: 14px; color: var(--muted); }

/* ---- AI incident FAB (Art. 73) — token-based, theme-aware ------------ */
/* Ancorato all'area sicura: sull'iPhone il bordo inferiore è occupato dall'home indicator,
   e senza l'inset il bottone ci finiva sotto. */
.fab-ai {
  position: fixed;
  right: calc(16px + env(safe-area-inset-right, 0px));
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  z-index: var(--z-popover);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  min-height: 44px;
  background: var(--surface-1);
  color: var(--muted);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-m);
  font-size: var(--text-xs);
  font-weight: 600;
  cursor: pointer;
  transition: color 160ms ease, border-color 160ms ease, box-shadow 160ms ease, transform 160ms cubic-bezier(0.2, 0, 0, 1);
}
.fab-ai:hover { color: var(--text); border-color: var(--accent); transform: translateY(-1px); }
.fab-ai:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* Su schermo largo il simbolo non serve: la pastiglia porta la frase, come sempre. */
.fab-ai__icona { display: none; }
/* DA TELEFONO LA PASTIGLIA DIVENTA UN TONDO (18 agosto 2026).
   Reperto del founder, con schermata: su esercizi-play la pastiglia larga ~180px si posava
   sul campo risposta — quando la tastiera sale, il fisso resta incollato al bordo basso del
   viewport, cioè esattamente dove il browser porta il campo che ha il fuoco. Nascondere il
   canale Art. 73 non si può; ridurne l'impronta da 180x44 a 44x44 sì, ed è la stessa
   grammatica di ogni bolla d'aiuto. Il nome accessibile è sull'aria-label del bottone, non
   sul testo: qui sotto sparisce la parola, non la funzione. */
@media (max-width: 620px) {
  .fab-ai {
    width: 44px;
    padding: 0;
    justify-content: center;
    border-radius: 50%;
    font-size: var(--text-base);
  }
  .fab-ai__icona { display: block; }
  .fab-ai__testo { display: none; }
}
/* Il bottone non si può nascondere, allora è la PAGINA a fargli posto: in fondo copriva i
   link del footer, «Accessibilità» compreso. La classe la mette `ai-incident-report.js`,
   così il margine esiste solo dove il FAB esiste davvero. */
body.has-fab-ai { padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
/* `.ex-toast` (i badge di esercizi-play) e' fisso in basso come i toast comuni
   ma nasce fuori dalla libreria: se non lo si nomina qui accanto, resta indietro
   a ogni spostamento del fondo pagina. E' successo. */
body.has-fab-ai .toast-container,
body.has-fab-ai .ex-toast { bottom: calc(var(--space-5) + 56px + env(safe-area-inset-bottom, 0px)); }

.fab-ai-modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(15, 12, 26, 0.55);
  backdrop-filter: blur(4px);
}
.fab-ai-modal__card {
  background: var(--surface-1);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-l);
  padding: var(--space-5);
  max-width: 460px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
}
.fab-ai-modal__card h3 { margin: 0 0 6px; font-size: var(--text-lg); }
.fab-ai-modal__card label { display: block; font-weight: 600; font-size: var(--text-sm); margin: var(--space-3) 0 4px; }
.fab-ai-modal__card select,
.fab-ai-modal__card textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-control);
  background: var(--surface-1);
  color: var(--text);
  font: inherit;
}
.fab-ai-modal__actions { display: flex; gap: var(--space-2); justify-content: flex-end; margin-top: var(--space-4); }

/* Topic gate: dimmed-but-legible waiting state; enabled cards look normal
   (the old hardcoded 2px blue ring read as a stuck focus state). */
.action-card.is-gated {
  opacity: 0.6;
  /* NIENTE pointer-events:none: il gestore in topic-gate.js deve RICEVERE il tocco per
     bloccare la navigazione, spiegare («Scrivi prima un argomento») e rimandare il fuoco
     al campo. Con pointer-events:none toccare una card spenta non faceva nulla. */
  filter: saturate(0.55);
}

/* Pricing glance card: tighten default h4/p margins (inline resets removed). */
.pricing-hero__glance h4 { margin: 0 0 var(--space-2); }
.pricing-hero__glance p { margin: 0 0 var(--space-2); }

/* Onboarding compact hero (padding formerly set inline). */
.hero--compact { padding: 32px 0 16px; }

/* Barra quota famiglia: stati warn/danger via token (prima hex inline da JS). */
.progress-fill.is-warn { background: var(--color-warning); }
.progress-fill.is-danger { background: var(--color-danger); }

/* Pagella d'interrogazione (rubrica orale) — token only, WCAG AA. */
.rubric__head { display: flex; align-items: center; gap: 12px; margin-bottom: 4px; }
.rubric__title { margin: 0; font-size: 1.05rem; }
.rubric__voto {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; height: 44px; padding: 0 10px; border-radius: 12px;
  background: var(--accent-soft); color: var(--accent-ink);
  font-size: 1.25rem; font-weight: 800; border: 1px solid var(--border-soft);
}
:root.dark .rubric__voto { color: var(--text); }
.rubric__disclaimer { font-size: 0.8rem; color: var(--muted); margin: 0 0 10px; }
/* L'astensione del valutatore: prende il posto del badge, non lo imita. Neutra di proposito —
   non è un voto basso, è l'assenza di un voto (verdetto revisore 2026-08-09, difetto #2). */
.rubric__astensione {
  font-size: 0.92rem; color: var(--text); margin: 0 0 8px; padding: 10px 12px;
  border-radius: 12px; background: var(--surface-2);
  border: 1px solid var(--border-soft);
}
/* Dal 28/9 dice PERCHÉ il voto non c'è (titolo, frase del server) e porta a rifarla. */
.rubric__astensione-titolo { display: block; margin-bottom: 4px; }
.rubric__astensione-testo { margin: 0 0 8px; }
.rubric__criteria { margin: 0 0 10px; }
.rubric__criteria dt { font-weight: 700; margin-top: 8px; }
.rubric__criteria dd { margin: 2px 0 0; color: var(--muted); font-size: 0.92rem; }
.rubric__chips-row { margin: 8px 0; display: flex; flex-direction: column; gap: 6px; }
.rubric__chips { display: flex; flex-wrap: wrap; gap: 6px; }
.rubric__chips .chip { cursor: default; padding: 6px 10px; font-size: 0.85rem; }
.rubric__chips .chip:hover { transform: none; color: var(--text); border-color: var(--border-soft); box-shadow: var(--shadow); }
.chip--ok { border-left: 3px solid var(--color-success); }
.chip--warn { border-left: 3px solid var(--color-warning); }
.rubric__action { font-weight: 600; margin: 10px 0 0; }
/* L'azione in TESTA alla pagella (20/9/2026): è la riga che fa tornare domani, quindi sta
   sopra i criteri e si vede come un invito, non come una nota a piè di pagina. */
.rubric__action--testa {
  margin: 0 0 12px; padding: 12px 14px; border-radius: 12px;
  background: var(--accent-soft); color: var(--accent-ink);
  border: 1px solid var(--border-soft); font-size: 1rem;
}
:root.dark .rubric__action--testa { color: var(--text); }
/* La PRIMA interrogazione non porta un numero: questa etichetta prende il posto del badge e
   non lo imita — è un inizio, non una valutazione. */
.rubric__voto--partenza {
  min-width: 0; height: auto; padding: 8px 14px; font-size: 0.95rem; font-weight: 700;
  background: var(--surface-2); color: var(--text); letter-spacing: -0.01em;
}

/* Il momento-celebrazione della pagella (founder 19/8): la festa PRIMA dell'analisi.
   Un <dialog> nativo sopra orale.html — il Twin, il voto grande, le aree da rivedere e la
   porta del ripasso. Chiuso, si atterra sulla pagella completa (#orale-rubric). */
.pagella-festa {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  background: var(--surface-1);
  color: var(--text);
  padding: var(--space-6) var(--space-5) var(--space-5);
  width: min(92vw, 420px);
  text-align: center;
  box-shadow: var(--shadow-l);
}
.pagella-festa::backdrop { background: rgba(29, 26, 43, 0.55); }
.pagella-festa__twin {
  display: block;
  width: 96px;
  height: 96px;
  margin-inline: auto;
  animation: pagella-festa-pop 600ms cubic-bezier(0.22, 1, 0.36, 1);
}
.pagella-festa__titolo { margin: var(--space-3) 0 0; font-size: 1.3rem; }
.pagella-festa__voto {
  margin: var(--space-2) 0 0;
  font-size: 2.2rem;
  font-weight: 800;
  color: var(--accent-ink);
  font-variant-numeric: tabular-nums;
}
.pagella-festa__nota { margin: 2px 0 0; font-size: 0.8rem; color: var(--muted); }
.pagella-festa__label { margin: var(--space-4) 0 var(--space-1); font-weight: 700; font-size: 0.9rem; }
.pagella-festa__chips { justify-content: center; }
.pagella-festa__azione { margin: var(--space-3) 0 0; font-weight: 600; font-size: 0.92rem; }
.pagella-festa__azioni {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-5);
}
@keyframes pagella-festa-pop {
  from { transform: scale(0.6); opacity: 0; }
  60% { transform: scale(1.08); }
  to { transform: scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .pagella-festa__twin { animation: none; }
}

/* Toggle Colloquio di Maturità (orale.html) — token only. */
.maturita-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  margin: 8px 0; padding: 8px 12px; border-radius: 12px;
  border: 1px solid var(--border-soft); background: var(--surface-1);
  cursor: pointer; font-weight: 600; user-select: none;
}
.maturita-toggle input { accent-color: var(--accent); width: 18px; height: 18px; }
.maturita-toggle small { color: var(--muted); font-weight: 400; }
.maturita-toggle:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
/* Maturità 2026: col toggle attivo l'argomento non si sceglie più (le quattro discipline le
   assegna il Ministero all'indirizzo), quindi il campo si SPEGNE davvero — `disabled` lato DOM,
   qui solo il segnale visivo. Non si usa `.is-disabled`: quella classe azzera i pointer-events
   e porterebbe via il cursore "non-allowed", cioè la spiegazione visiva del perché. */
.input:disabled { opacity: 0.55; cursor: not-allowed; background: var(--surface-2); }
.field__hint { margin: 4px 0 0; font-size: 0.85rem; }
.maturita-note { margin: 0 0 8px; font-size: 0.85rem; max-width: 46ch; }
/* 25/9: ricerca sopra al selettore, discipline da dichiarare, «6 in condotta», fasi e griglia
   dell'Allegato A (montati da `lib/maturita-ui.js`) — token only. */
.maturita-cerca { margin: 0 0 6px; }
.maturita-dichiarate { display: grid; gap: 6px; margin: 8px 0 0; padding: 0; border: 0; min-width: 0; }
.maturita-dichiarate legend { padding: 0; margin: 0 0 4px; }
.maturita-condotta { display: grid; gap: 6px; margin: 8px 0 0; }
.maturita-condotta .maturita-toggle { font-weight: 500; }
.maturita-info { margin: 0 0 12px; padding: 10px 12px; border: 1px solid var(--border-soft); border-radius: 12px; background: var(--surface-1); font-size: 0.9rem; }
.maturita-info summary { cursor: pointer; font-weight: 600; }
.maturita-info ol, .maturita-livelli { margin: 6px 0 10px; padding-left: 1.25rem; }
.maturita-livelli li { margin: 2px 0; color: var(--muted); }
.maturita-indicatore p { margin: 8px 0 0; font-weight: 600; }

/* Certificato di trasparenza AI (dashboard dirigente) — stampabile. */
.transparency-report { margin-top: 12px; }
.transparency-report h4 { margin: 0 0 4px; }
.transparency-kpi { margin: 4px 0 0; font-size: 20px; font-weight: 700; }
.transparency-gov { margin: 12px 0 0; }
.transparency-gov dt { font-weight: 700; margin-top: 8px; }
.transparency-gov dd { margin: 2px 0 0; font-size: 0.92rem; }
@media print {
  /* In stampa resta solo il certificato: pagina pulita per DPO/collegio docenti. */
  body.printing-transparency .navbar, body.printing-transparency .hero,
  body.printing-transparency .section:not(:has(.transparency-report)) { display: none !important; }
  .transparency-report { display: block !important; }
}

/* ====================================================================== */
/* LAVORI DEL CORSO — riprogettazione 2026-07-26                          */
/*                                                                        */
/* Prima: righe identiche con striscia colorata a sinistra, tutte         */
/* intitolate "Compito", con il dato che conta (quante consegne) nel      */
/* carattere più piccolo. Qui la gerarchia segue la domanda di chi legge: */
/* il docente cerca "cosa devo fare adesso", lo studente "cosa devo       */
/* consegnare". Niente border-left decorativi: separazione con filetti e  */
/* spaziatura, urgenza con un fondo tenue.                                */
/* ====================================================================== */
/* La lista è già un flex con gap: i gruppi non aggiungono margini propri. */
.assignments-list { gap: 30px; }
.asg-gruppo { margin: 0; }
.asg-gruppo__testa {
  display: flex; align-items: baseline; gap: 10px;
  padding-bottom: 8px; border-bottom: 1px solid var(--border);
}
.asg-gruppo__titolo {
  margin: 0; font-size: 0.95rem; font-weight: 650; letter-spacing: 0.01em; color: var(--text);
}
.asg-gruppo__conteggio {
  font-variant-numeric: tabular-nums; font-size: 0.8rem; font-weight: 600;
  color: var(--muted); background: var(--surface-2);
  padding: 1px 8px; border-radius: var(--radius-pill);
}
.asg-gruppo__nota { margin: 6px 0 0; font-size: 0.82rem; color: var(--muted); }
.asg-gruppo__lista { display: flex; flex-direction: column; }

.asg-riga {
  display: grid; grid-template-columns: 28px 1fr auto; gap: 12px; align-items: start;
  padding: 14px 2px; border-bottom: 1px solid var(--border);
}
/* Quando non c'e' un'azione a destra la riga resta a due colonne. */
.asg-riga:not(:has(.asg-riga__azione)) { grid-template-columns: 28px 1fr; }
.asg-riga__azione { align-self: center; white-space: nowrap; }
.asg-riga__titolo--link { display: block; color: var(--text); text-decoration: none; }
.asg-riga__titolo--link:hover { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; }
.asg-riga__titolo--link:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 4px; }
.asg-riga:last-child { border-bottom: none; }
/* L'urgenza si legge come tinta di fondo, non come barra laterale. */
.asg-riga--urgente {
  background: color-mix(in srgb, var(--color-warning, #b45309) 7%, transparent);
  border-radius: var(--radius-control);
  padding-inline: 10px;
}
.asg-riga__tipo { font-size: 1.1rem; line-height: 1.4; opacity: 0.85; }
.asg-riga__titolo {
  margin: 0 0 3px; font-size: 1rem; font-weight: 600; line-height: 1.35; color: var(--text);
  text-wrap: balance;
}
/* Per il docente il titolo apre il resoconto: e' un <button>, quindi va ripulito dagli stili
   nativi e reso riconoscibile come comando senza aggiungere un pulsante in piu'. */
.asg-riga__titolo--azione {
  display: block; width: 100%; text-align: left;
  background: none; border: none; padding: 0; cursor: pointer; font-family: inherit;
}
.asg-riga__titolo--azione:hover { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; }
.asg-riga__titolo--azione:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 4px; }
.asg-riga__meta {
  margin: 0; display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline;
  font-size: 0.84rem; color: var(--muted);
}
.asg-riga__genere { font-weight: 600; color: var(--muted); }
.asg-riga__desc {
  margin: 6px 0 0; font-size: 0.88rem; color: var(--muted);
  max-width: 68ch; line-height: 1.5;
}
/* Lo stato è una parola prima che un colore: resta comprensibile senza percepirlo. */
.asg-stato { font-weight: 600; color: var(--muted); }
.asg-stato--attesa { color: var(--accent-ink); }
.asg-stato--ok { color: var(--color-success, #16a34a); }
.asg-stato--urgente { color: var(--color-warning, #b45309); }

/* Stato vuoto che insegna l'interfaccia invece di constatare il nulla. */
.asg-vuoto { padding: 28px 4px; max-width: 60ch; }
.asg-vuoto__titolo { margin: 0 0 6px; font-size: 1.02rem; font-weight: 650; color: var(--text); }
.asg-vuoto__testo { margin: 0; color: var(--muted); line-height: 1.55; }

@media (max-width: 560px) {
  .asg-riga { grid-template-columns: 22px 1fr; gap: 10px; }
  .asg-riga__titolo { font-size: 0.97rem; }
}

/* ====================================================================== */
/* SCHEDA CLASSE — riprogettazione 2026-07-26                             */
/*                                                                        */
/* Il nome della classe diventa l'elemento primario (prima era in uno     */
/* style inline dentro un link), la materia lo qualifica sopra, e il      */
/* codice d'ingresso — l'oggetto che il docente deve davvero consegnare   */
/* agli studenti — smette di essere un pallino grigio e diventa           */
/* monospaziato e leggibile a voce. "Elimina" scende sotto un filetto,    */
/* con peso tipografico minore: non deve stare accanto a "Apri classe".   */
/* ====================================================================== */
.class-list { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); align-items: start; }

.class-card__materia {
  order: -1; /* la materia precede il nome pur venendo dopo nel markup */
  margin: 0; font-size: 0.76rem; font-weight: 650;
  letter-spacing: 0.07em; text-transform: uppercase; color: var(--muted);
}
.class-card__nome {
  margin: 0; font-family: var(--font-display, inherit);
  font-size: 1.22rem; font-weight: 650; line-height: 1.25; color: var(--text);
  text-wrap: balance;
}
.class-card__link { display: block; }
.class-card__link:hover .class-card__nome { color: var(--accent-ink); }
.class-card__meta { margin: 0; font-size: 0.86rem; color: var(--muted); font-variant-numeric: tabular-nums; }

.class-card__codice {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 2px; padding: 10px 12px;
  background: var(--surface-2); border-radius: var(--radius-control);
}
.class-card__codice-et {
  flex-basis: 100%; font-size: 0.72rem; font-weight: 650;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted);
}
.class-card__codice-val {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  font-size: 1.05rem; font-weight: 600; letter-spacing: 0.14em; color: var(--text);
}
.class-card__codice .btn { margin-left: auto; }

/* L'azione irreversibile vive sotto un filetto, in peso minore: raggiungibile, non invitante. */
.class-card__pericolo {
  margin-top: 4px; padding-top: 10px; border-top: 1px solid var(--border-soft);
}
.class-card__delete {
  background: none; border: none; padding: 0; cursor: pointer;
  font: inherit; font-size: 0.82rem; color: var(--muted); text-decoration: underline;
  text-underline-offset: 3px;
}
.class-card__delete:hover { color: var(--color-danger, #b91c1c); }
.class-card__delete:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 3px; }

/* ====================================================================== */
/* === Mobile nav + form feedback redesign (2026-08-06) ===               */
/*                                                                        */
/* Quattro difetti riportati dal founder in test su telefono.             */
/*                                                                        */
/* 1) MENU MOBILE «buggato» — VOCE STORICA, il rimedio non esiste più.    */
/*    Il difetto era: .navbar dichiarava `backdrop-filter: blur(14px)`, e */
/*    un backdrop-filter crea un CONTAINING BLOCK per i discendenti       */
/*    position:fixed → il pannello "a tutto schermo" (.navbar__links,     */
/*    inset:0) veniva ritagliato dentro la barra (~60px) e le azioni      */
/*    Login/Registrati finivano DIETRO di esso, invisibili. Si rispose    */
/*    con un drawer laterale (scrim, X animata, focus trap, scroll-lock). */
/*    Dal 2026-08-09 il panino NON ESISTE PIÙ (direttiva founder): tutto  */
/*    quel blocco è stato rimosso e la navigazione mobile sta in vista,   */
/*    su due righe — vedi «STRISCIA COMPLETA + HEADER SENZA PANINO» in    */
/*    coda al file. Il blur, dal 2026-08-08, vive su .navbar::before.     */
/*                                                                        */
/* 2) TOAST/ALERT SOPRA I CAMPI. I toast erano ancorati in alto: con la   */
/*    tastiera aperta finivano proprio sopra il campo email. Ora sono     */
/*    ancorati in basso ovunque (safe-area inclusa) e non intercettano i  */
/*    tap (pointer-events sul solo toast). Gli errori di form restano in  */
/*    FLUSSO: .form-alert sopra il form, .form-error sotto il campo.      */
/*                                                                        */
/* 3) BOTTONI TROPPO GRANDI sotto i 600px: scala tipografica e padding    */
/*    ridotti, min-height 44px mantenuto (WCAG 2.5.5).                    */
/*                                                                        */
/* 4) LINK CONSENSO NON RICONOSCIBILI: `a { color: inherit;               */
/*    text-decoration: none }` è globale e .cta era ri-vestito solo       */
/*    dentro .action-card → i link "Privacy Policy"/"Termini" erano testo */
/*    normale. Qui la classe link canonica torna sottolineata e accent.   */
/*                                                                        */
/* Nota 2026-08-08: non più solo additivo — «NAVIGAZIONE 2026» (in coda)  */
/* ha RIMOSSO il blur da .navbar spostandolo sul ::before, di proposito.  */
/* ====================================================================== */

/* ---------------------------------------------------------------------- */
/* 2a. TOAST — ancorati in basso, mai sopra un campo                       */
/* ---------------------------------------------------------------------- */
.toast-container {
  top: auto;
  left: auto;
  right: calc(var(--space-5) + env(safe-area-inset-right, 0px));
  bottom: calc(var(--space-5) + env(safe-area-inset-bottom, 0px));
  /* column-reverse: il toast nuovo entra dal basso, i vecchi salgono. */
  flex-direction: column-reverse;
  align-items: flex-end;
  gap: var(--space-2);
  max-width: min(400px, calc(100vw - 2 * var(--space-5)));
  /* Il contenitore non deve rubare i tap alla pagina: solo i toast. */
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  animation: toastIn 260ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.toast-out { animation: toastOut 200ms ease forwards; }
.toast__close {
  flex: none;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
}
.toast__close:focus-visible { box-shadow: var(--focus-ring); outline: none; }

@keyframes toastIn {
  from { opacity: 0; transform: translateY(14px) scale(0.98); }
  to { opacity: 1; transform: none; }
}
@keyframes toastOut {
  to { opacity: 0; transform: translateY(10px) scale(0.98); }
}

@media (max-width: 720px) {
  .toast-container {
    left: calc(var(--space-3) + env(safe-area-inset-left, 0px));
    right: calc(var(--space-3) + env(safe-area-inset-right, 0px));
    bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
    max-width: none;
    align-items: stretch;
  }
  .toast { padding: var(--space-3) var(--space-4); border-radius: var(--radius-control); }
}

/* Col banner cookie in basso il toast sale sopra invece di sovrapporsi. */
body:has(.cookie-banner) .toast-container {
  bottom: calc(var(--space-5) + 92px + env(safe-area-inset-bottom, 0px));
}
@media (max-width: 520px) {
  body:has(.cookie-banner) .toast-container {
    bottom: calc(var(--space-3) + 168px + env(safe-area-inset-bottom, 0px));
  }
}

/* ---------------------------------------------------------------------- */
/* 2b. FEEDBACK DI FORM — in flusso, mai sovrapposto agli input            */
/* ---------------------------------------------------------------------- */
/* #auth-alert vive sopra il form: quando è vuoto non deve lasciare buchi, */
/* quando compare deve essere raggiungibile senza finire sotto la navbar.  */
/* 120 e non più 96 (2026-08-09): sul telefono l'header è ora di due righe */
/* dentro un vetro solo, 56 + 48 = 104px, e un alert portato in vista con  */
/* 96 finirebbe sotto la striscia. Sul desktop 120 > 64: innocuo.          */
#auth-alert:empty { display: none; }
#auth-alert.alert,
#auth-alert > .alert,
.form-alert {
  scroll-margin-top: 120px;
}
#auth-alert.alert,
#auth-alert > .alert {
  display: block;
  margin: 0 0 var(--space-4);
}

/* Blocco riusabile: errore/esito di un intero form, SOPRA il form. */
.form-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin: 0 0 var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-soft);
  border-left: 4px solid var(--muted);
  border-radius: var(--radius-control);
  background: var(--surface-2);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 500;
  line-height: var(--lh-base);
}
.form-alert--error {
  border-left-color: var(--color-danger);
  background: color-mix(in srgb, var(--color-danger) 8%, var(--surface-1));
}
.form-alert--success {
  border-left-color: var(--color-success);
  background: color-mix(in srgb, var(--color-success) 8%, var(--surface-1));
}
.form-alert--warning {
  border-left-color: var(--color-warning);
  background: color-mix(in srgb, var(--color-warning) 10%, var(--surface-1));
}

/* Errore del singolo campo: SEMPRE sotto l'input che lo ha generato. */
.form-field { display: grid; gap: 6px; }
.form-error {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: 2px 0 0;
  color: var(--color-danger);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: var(--lh-base);
}
.form-error::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  margin-top: 0.55em;
  border-radius: 50%;
  background: currentColor;
}
.form-error:empty { display: none; }
.form-hint {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: var(--lh-base);
}

.input.is-invalid,
.input[aria-invalid="true"],
textarea[aria-invalid="true"],
select[aria-invalid="true"] {
  border-color: var(--color-danger);
}
.input.is-invalid:focus,
.input[aria-invalid="true"]:focus,
textarea[aria-invalid="true"]:focus,
select[aria-invalid="true"]:focus {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 2px var(--bg1), 0 0 0 4px color-mix(in srgb, var(--color-danger) 70%, transparent);
}

/* ---------------------------------------------------------------------- */
/* 3. SCALA DEI BOTTONI SU MOBILE                                          */
/* ---------------------------------------------------------------------- */
/* Presenza solida ma proporzionata: l'area d'impatto resta 44px           */
/* (min-height), a calare sono corpo tipografico, peso e padding — così    */
/* il bottone smette di leggersi come un banner.                           */
@media (max-width: 600px) {
  .btn {
    font-family: inherit;
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0;
    line-height: 1.25;
    padding: 10px var(--space-4);
    border-radius: var(--radius-control);
    min-height: 44px;
  }
  .btn--sm {
    font-size: var(--text-xs);
    padding: 8px var(--space-3);
  }
  .btn--xl {
    font-size: var(--text-base);
    padding: 12px var(--space-5);
  }
  /* Le CTA impilate restano comode al pollice ma non diventano fasce. */
  .landing-actions,
  .hero__controls--inline {
    width: 100%;
    max-width: 26rem;
    margin-inline: auto;
  }
}

/* ---------------------------------------------------------------------- */
/* 4. LINK INLINE RICONOSCIBILI                                            */
/* ---------------------------------------------------------------------- */
/* `a { color: inherit; text-decoration: none }` è globale: senza questo   */
/* blocco i link dentro le label di consenso, negli alert e nei paragrafi  */
/* .muted sono indistinguibili dal testo (WCAG 1.4.1: il colore da solo    */
/* non basta → colore + sottolineatura).                                   */
a.cta,
a.link,
.consent-label a,
.muted a:not(.btn),
.field-note a:not(.btn) {
  color: var(--accent-ink);
  text-decoration: underline;
  text-decoration-thickness: max(1px, 0.055em);
  text-underline-offset: 0.18em;
  font-weight: 600;
  border-radius: 4px;
}
a.cta:hover,
a.link:hover,
.consent-label a:hover,
.muted a:not(.btn):hover,
.field-note a:not(.btn):hover {
  color: var(--accent);
  text-decoration-thickness: max(2px, 0.09em);
}
a.cta:focus-visible,
a.link:focus-visible,
.consent-label a:focus-visible,
.muted a:not(.btn):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
/* Dentro un alert il link resta del colore semantico dell'alert. */
.alert a,
.form-alert a {
  color: inherit;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

/* Checkbox di consenso: bersaglio più generoso e testo più arioso. */
.consent-label {
  gap: var(--space-3);
  align-items: flex-start;
  padding-block: 2px;
  line-height: var(--lh-loose);
}
.consent-label input[type="checkbox"] {
  flex: none;
  width: 22px;
  height: 22px;
  margin-top: 2px;
  accent-color: var(--accent);
  cursor: pointer;
}
.consent-label input[type="checkbox"]:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: 4px;
}

/* === Beta a numero chiuso: lista d'attesa in hero (2026-08-06) === */
.lp-hero__waitlist { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; max-width: 460px; margin: 0 auto; }
.lp-hero__waitlist .input { flex: 1 1 240px; min-height: 48px; }
.lp-hero__waitlist .btn { min-height: 48px; flex: 0 0 auto; }
.lp-hero__wl-msg { margin: 12px auto 0; font-size: 14px; min-height: 20px; max-width: 460px; }
/* Le due porte della hero (2026-08-08): chi ha il codice entra, chi non ce l'ha si mette in
   lista. Porta del codice evidenziata con l'accento — fondo PIENO dichiarato prima del
   color-mix, o su iOS < 16.2 la card resta trasparente (lezione .pricing-card). */
.lp-doors { display: grid; grid-template-columns: 1fr 1.15fr; gap: 12px; max-width: 680px; margin: 0 auto; text-align: left; }
.lp-door { border: 1px solid var(--border-soft); border-radius: var(--radius-card); background: var(--surface-1); padding: 16px 18px; display: flex; flex-direction: column; align-items: flex-start; }
.lp-door--invito { border-color: var(--accent); background: var(--surface-1); background: color-mix(in srgb, var(--accent) 6%, var(--surface-1)); border-color: var(--accent); }
.lp-door__title { margin: 0 0 6px; font-size: 17px; font-weight: 700; color: var(--text); }
.lp-door__text { margin: 0 0 12px; font-size: 14px; line-height: 1.5; color: var(--muted); }
.lp-door__cta { min-height: 48px; margin-top: auto; }
/* La porta del codice invito ha meno testo della gemella (che porta un modulo intero), e il
   `margin-top: auto` le lasciava 58px di buco fra il testo e il bottone contro i 12 dell'altra
   — un vuoto che si legge come «manca qualcosa». Qui il bottone segue il SUO testo; lo spazio
   che avanza va in fondo alla card, dove si legge come respiro. (Audit visivo 2026-08-09.) */
.lp-door--invito .lp-door__cta { margin-top: var(--space-2); }
.lp-door .lp-hero__waitlist { margin: auto 0 0; justify-content: flex-start; }
.lp-door .lp-hero__wl-msg { margin: 10px 0 0; max-width: none; }
@media (max-width: 640px) { .lp-doors { grid-template-columns: 1fr; } }
.lp-hero__wl-msg--ok { color: var(--success-ink, var(--accent-ink)); font-weight: 600; }
.lp-hero__wl-msg--errore { color: var(--danger-ink, #b3261e); }
.lp-hero__wl-msg--attesa { color: var(--muted); }
/* ====================================================================== */
/* === Profilo 2026 (2026-08-06) ===                                      */
/*                                                                        */
/* La pagina profilo diventa il posto in cui si CAPISCE in che piano si    */
/* sta. Tre pezzi nuovi, tutti scoped a .profile-redesign tranne il        */
/* banner, che vive sulla dashboard:                                      */
/*                                                                        */
/*  1. .plan-card — la sezione regina: nome del piano con badge di fascia, */
/*     prezzo, riga di stato ("si rinnova il…", "disdetto: attivo fino     */
/*     al…") e le quote come barre leggibili. Le barre sono                */
/*     role=progressbar con aria-valuenow e un aria-label parlante: il     */
/*     numero non vive solo nel colore (WCAG 1.4.1).                       */
/*  2. .usage-list / .consent-list — due liste, stessa grammatica.         */
/*  3. #plan-banner — l'avviso non invasivo in cima alla dashboard.        */
/*                                                                        */
/* I colori di fascia sono TOKEN nuovi (--plan-ink-*), non valori sparsi   */
/* nelle regole, e hanno una coppia chiaro/scuro.                          */
/*                                                                        */
/* WCAG 1.4.3 — MISURATI SULLA SUPERFICIE GIUSTA (fix review 2026-08-06).  */
/* L'unico posto in cui un --plan-ink è TESTO è .plan-badge, e lì il fondo */
/* NON è la carta: è color-mix(--plan-ink 10%, --surface-1), cioè un 10%   */
/* dell'inchiostro stesso. Annotare il rapporto su #ffffff misurava una    */
/* superficie che non esiste, e il gold ci passava sotto (4,31:1 reali su  */
/* testo 12px/700, che NON gode dell'esenzione large-text). I rapporti qui */
/* sotto sono calcolati sul fondo VERO del badge:                          */
/*   trial 6,31 · estate 4,82 · bronze 5,11 · silver 5,22 · gold 4,69      */
/*   · platinum 6,72 · family 4,64  — tutti ≥ 4,5:1.                       */
/* Blocco puramente additivo: nessuna regola precedente è stata toccata.   */
/* ====================================================================== */

:root {
  --plan-ink-trial: var(--muted);
  --plan-ink-estate: #a1541a;   /* 4,82:1 sul fondo del badge */
  --plan-ink-bronze: #8a5a2b;   /* 5,11:1 */
  --plan-ink-silver: #5c6470;   /* 5,22:1 */
  /* era #8a6d1f: 4,9:1 su carta bianca ma 4,31:1 sul fondo del badge, cioè
     sotto il minimo AA. Sceso di un gradino: 4,69:1 dove il testo sta davvero. */
  --plan-ink-gold: #836719;     /* 4,69:1 */
  --plan-ink-platinum: var(--accent-ink);
  --plan-ink-family: #1f7a4d;   /* 4,64:1 */
  --plan-ink: var(--accent-ink);
  /* Il VALORE della quota in ambra è testo 14px/700: --color-warning (#d97706)
     dà 3,19:1 su --surface-1, e il numero diventerebbe meno leggibile proprio
     oltre l'85% consumato, cioè quando conta di più. Questo è il tono per il
     testo (5,02:1); il riempimento della barra resta --color-warning, che è
     decorativo e non porta informazione da solo (1.4.1). */
  --quota-ink-low: #b45309;
}
:root.dark {
  --plan-ink-estate: #f0a868;
  --plan-ink-bronze: #d9a066;
  --plan-ink-silver: #c3cad6;
  --plan-ink-gold: #e2c66a;
  --plan-ink-family: #6ee7a8;
  /* Sulla lavagna l'ambra chiara sta a 8,59:1: nessun bisogno di scurirla. */
  --quota-ink-low: var(--color-warning);
}

/* ---------------------------------------------------------------------- */
/* 1. LA SEZIONE PIANO                                                     */
/* ---------------------------------------------------------------------- */
.profile-redesign .plan-card {
  position: relative;
  overflow: hidden;
  border-color: color-mix(in srgb, var(--plan-ink) 26%, var(--border-soft));
}
/* Filetto d'inchiostro della fascia: dice "sei qui" senza urlare. */
.profile-redesign .plan-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: var(--plan-ink);
}
.profile-redesign .plan-card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.profile-redesign .plan-card__title { min-width: 0; }
.profile-redesign .plan-card__name {
  font-family: "Space Grotesk", "Inter", system-ui, sans-serif;
  font-size: clamp(1.5rem, 5vw, 1.9rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: var(--lh-tight);
  color: var(--text);
  margin: 0;
}
.profile-redesign .plan-card__price {
  margin: var(--space-1) 0 0;
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--muted);
}
.profile-redesign .plan-card__renew {
  margin: var(--space-3) 0 0;
  font-size: var(--text-sm);
  line-height: var(--lh-base);
  color: var(--text);
}
.profile-redesign .plan-badge {
  flex: none;
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border-radius: var(--radius-pill);
  border: 1px solid color-mix(in srgb, var(--plan-ink) 34%, transparent);
  background: color-mix(in srgb, var(--plan-ink) 10%, var(--surface-1));
  color: var(--plan-ink);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
/* La fascia decide l'inchiostro una volta sola, sulla card intera. */
.profile-redesign .plan-card:has(.plan-badge[data-plan="trial"]) { --plan-ink: var(--plan-ink-trial); }
.profile-redesign .plan-card:has(.plan-badge[data-plan="estate"]) { --plan-ink: var(--plan-ink-estate); }
.profile-redesign .plan-card:has(.plan-badge[data-plan="bronze"]) { --plan-ink: var(--plan-ink-bronze); }
.profile-redesign .plan-card:has(.plan-badge[data-plan="silver"]) { --plan-ink: var(--plan-ink-silver); }
.profile-redesign .plan-card:has(.plan-badge[data-plan="gold"]) { --plan-ink: var(--plan-ink-gold); }
.profile-redesign .plan-card:has(.plan-badge[data-plan="platinum"]) { --plan-ink: var(--plan-ink-platinum); }
.profile-redesign .plan-card:has(.plan-badge[data-plan="family"]) { --plan-ink: var(--plan-ink-family); }

.profile-redesign .plan-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-soft);
}
.profile-redesign .plan-card__actions .btn { flex: 1 1 auto; justify-content: center; }
@media (min-width: 560px) {
  .profile-redesign .plan-card__actions .btn { flex: 0 0 auto; }
}

/* ---------------------------------------------------------------------- */
/* 2. QUOTE — la barra dice quanto resta, il piede dice di quanto          */
/* ---------------------------------------------------------------------- */
.profile-redesign .plan-quotas {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: var(--space-5);
}
.profile-redesign .quota { display: grid; gap: 6px; }
.profile-redesign .quota__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}
.profile-redesign .quota__label {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text);
}
.profile-redesign .quota__value {
  font-size: var(--text-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  text-align: right;
}
.profile-redesign .quota__bar {
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  overflow: hidden;
}
.profile-redesign .quota__fill {
  display: block;
  height: 100%;
  min-width: 2px;
  border-radius: inherit;
  background: var(--accent);
  transition: width 420ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* Barra = decorazione (colore pieno); valore = testo (tono che regge 1.4.3). */
.profile-redesign .quota.is-low .quota__fill { background: var(--color-warning); }
.profile-redesign .quota.is-low .quota__value { color: var(--quota-ink-low); }
.profile-redesign .quota.is-exhausted .quota__fill { background: var(--color-danger); }
/* --color-danger su --surface-1: 4,83:1 in chiaro, 4,90:1 in scuro — passa così com'è. */
.profile-redesign .quota.is-exhausted .quota__value { color: var(--color-danger); }
.profile-redesign .quota__foot {
  margin: 0;
  font-size: var(--text-xs);
  line-height: var(--lh-base);
  color: var(--muted);
}
.profile-redesign .quota__foot strong { color: var(--accent-ink); font-weight: 700; }
.profile-redesign .quota--nolimit .quota__value { color: var(--muted); font-weight: 600; }

/* ---------------------------------------------------------------------- */
/* 3. CONSUMI DEL PERIODO + CONSENSI — due liste, stessa grammatica        */
/* ---------------------------------------------------------------------- */
.profile-redesign .usage-list,
.profile-redesign .consent-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.profile-redesign .usage-item,
.profile-redesign .consent-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border-soft);
}
.profile-redesign .usage-item:last-child,
.profile-redesign .consent-item:last-child { border-bottom: 0; }
.profile-redesign .usage-item__label {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text);
}
.profile-redesign .usage-item__value {
  font-size: var(--text-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  text-align: right;
}
.profile-redesign .usage-item__of { color: var(--muted); font-weight: 500; }
.profile-redesign .consent-item .profile-inline-title { margin: 0; }
.profile-redesign .consent-item .profile-helper { margin: 2px 0 0; }
.profile-redesign #consent-list { margin-top: var(--space-2); }

/* ---------------------------------------------------------------------- */
/* 4. BANNER DEL PIANO IN DASHBOARD (modules/piano-banner.js)              */
/* ---------------------------------------------------------------------- */
/* Non è un popup e non copre niente: sta in flusso, sopra il contenuto,   */
/* e si può chiudere. Vive fuori da .profile-redesign per definizione.     */
#plan-banner {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  /* Stessa cassa del contenuto della dashboard (.container): il banner si allinea
     alle card sotto invece di galleggiare per conto suo. */
  max-width: 1180px;
  margin: var(--space-4) auto 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--border-soft));
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-control);
  background: color-mix(in srgb, var(--accent) 6%, var(--surface-1));
  color: var(--text);
  font-size: var(--text-sm);
  line-height: var(--lh-base);
}
#plan-banner.plan-banner--warning {
  border-color: color-mix(in srgb, var(--color-warning) 30%, var(--border-soft));
  border-left-color: var(--color-warning);
  background: color-mix(in srgb, var(--color-warning) 8%, var(--surface-1));
}
#plan-banner .plan-banner__text { flex: 1; margin: 0; min-width: 0; }
#plan-banner .plan-banner__cta {
  flex: none;
  color: var(--accent-ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 0.18em;
  white-space: nowrap;
}
#plan-banner .plan-banner__close {
  flex: none;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
}
#plan-banner .plan-banner__close:hover { background: var(--surface-2); color: var(--text); }
#plan-banner .plan-banner__close:focus-visible { outline: none; box-shadow: var(--focus-ring); }
@media (max-width: 600px) {
  #plan-banner { flex-wrap: wrap; margin-inline: var(--space-3); }
  #plan-banner .plan-banner__text { flex-basis: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .profile-redesign .quota__fill { transition: none; }
}

/* ====================================================================== */
/* === Toast v3 — pillola, non cartellone (2026-08-06) ===                */
/*                                                                        */
/* Il founder ha bocciato due volte i toast e aveva ragione: erano schede  */
/* larghe, chiare, con bordo colorato e sfumatura — cioè un ALERT travesti-*/
/* to da notifica, che pesa quanto il contenuto della pagina. Le app di    */
/* riferimento oggi (Linear, Vercel, iOS) fanno l'opposto: una pillola     */
/* piccola a superficie INVERTITA rispetto alla pagina, che si legge in un */
/* colpo d'occhio e sparisce. Lo stato non lo urla un bordo di 4px: lo dice*/
/* un punto colorato di 8.                                                 */
/*                                                                        */
/* Superficie invertita = scura sul tema chiaro, chiara-fredda sullo scuro:*/
/* è ciò che la fa leggere come «sistema che parla», non come un pezzo di  */
/* interfaccia rimasto acceso.                                            */
/* ====================================================================== */
:root {
  --toast-bg: rgba(24, 22, 37, 0.94);
  --toast-fg: #f5f4fb;
  --toast-fg-soft: rgba(245, 244, 251, 0.62);
}
:root.dark {
  --toast-bg: rgba(238, 238, 246, 0.95);
  --toast-fg: #17162a;
  --toast-fg-soft: rgba(23, 22, 42, 0.58);
}

.toast {
  gap: 10px;
  padding: 11px 14px;
  max-width: min(420px, calc(100vw - 32px));
  background: var(--toast-bg);
  background-image: none;      /* via la sfumatura colorata della v1 */
  border: none;
  border-left: none;           /* via la barra spessa: lo stato lo dice il punto */
  border-radius: 14px;
  color: var(--toast-fg);
  box-shadow: 0 8px 28px rgba(10, 8, 25, 0.28), 0 2px 6px rgba(10, 8, 25, 0.18);
  -webkit-backdrop-filter: saturate(1.4) blur(10px);
  backdrop-filter: saturate(1.4) blur(10px);
  font-size: 14px;
  line-height: 1.35;
}
.toast--success, .toast--error, .toast--warning, .toast--info {
  background: var(--toast-bg);
  background-image: none;
  border-left: none;
}

/* Il punto di stato: 8px, prima del testo. Sostituisce icona e bordo. */
.toast::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--toast-fg-soft);
}
.toast--success::before { background: #34d399; }
.toast--error::before   { background: #fb7185; }
.toast--warning::before { background: #fbbf24; }
.toast--info::before    { background: #60a5fa; }

/* L'icona della v1 resta nel markup di alcune pagine: qui non serve più. */
.toast .toast__icon { display: none; }

.toast__message { color: var(--toast-fg); font-size: 14px; }

/* La X non deve competere col messaggio: si accende al passaggio o col focus. */
.toast__close {
  width: 24px;
  height: 24px;
  color: var(--toast-fg-soft);
  opacity: 0.7;
  transition: opacity 140ms ease, color 140ms ease;
}
.toast__close:hover, .toast__close:focus-visible { opacity: 1; color: var(--toast-fg); }

/* Su telefono la pillola sta in BASSO AL CENTRO — dove arriva il pollice e dove
   nessun campo di form finisce coperto (era il difetto segnalato sul login). */
@media (max-width: 720px) {
  .toast-container {
    left: var(--space-4);
    right: var(--space-4);
    bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
    align-items: center;
    max-width: none;
  }
  .toast { width: 100%; max-width: 460px; }
}

/* ====================================================================== */
/* === La voce come conversazione: turni a bolle (2026-08-06) ===         */
/*                                                                        */
/* I sottotitoli dell'orale erano un blocco di testo unico in cui i delta  */
/* dello studente e quelli di Skoo si concatenavano: dopo due scambi non   */
/* si capiva più chi avesse detto cosa. Un'interrogazione è fatta di       */
/* TURNI, e questa è la forma che tutti sanno già leggere.                 */
/*                                                                        */
/* Chi parla sta a destra come in una chat (tu) e a sinistra (Skoo). Le    */
/* bolle non hanno la coda: a questa dimensione è rumore, e la direzione   */
/* la dicono già allineamento e colore.                                   */
/* ====================================================================== */
.vchat {
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* ALTEZZA FISSA, non `max-height`: con un tetto la card cresceva turno dopo turno fino al
     limite, e la pagina saltava sotto le dita mentre lo studente parlava. Ora il riquadro
     nasce della misura che avrà sempre e sono i messaggi a scorrere dentro (l'autoscroll in
     coda sta in voice-chat.js). */
  height: clamp(220px, 42vh, 420px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 4px 2px;
  scroll-behavior: smooth;
  text-align: left;
}
.vchat__turno { display: flex; flex-direction: column; gap: 3px; max-width: 84%; }
.vchat__turno--skoo { align-self: flex-start; align-items: flex-start; }
.vchat__turno--studente { align-self: flex-end; align-items: flex-end; }

.vchat__chi {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0 4px;
}

.vchat__bolla {
  margin: 0;
  padding: 9px 13px;
  border-radius: 16px;
  font-size: 15px;
  line-height: 1.45;
  white-space: pre-wrap;      /* il parlato ha le sue pause */
  overflow-wrap: anywhere;    /* una parola lunghissima non sfonda la bolla */
}
.vchat__turno--skoo .vchat__bolla {
  background: var(--surface-2, var(--surface-1));
  border: 1px solid var(--border-soft);
  border-bottom-left-radius: 6px;
  color: var(--text);
}
.vchat__turno--studente .vchat__bolla {
  background: color-mix(in srgb, var(--accent) 14%, var(--surface-1));
  background-color: var(--surface-1);   /* fallback: vedi .pricing-card, stesso motivo */
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border-soft));
  border-bottom-right-radius: 6px;
  color: var(--text);
}

/* Il turno ancora in corso respira: un filo di accento sul bordo. */
.vchat__bolla.is-live { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }

/* I tre puntini dell'attesa: Skoo che pensa, e (L3.2.1) noi che ascoltiamo lo studente
   nel secondo che passa fra la prima sillaba e la prima parola riconosciuta. Le regole sono
   volutamente indipendenti dal ruolo: la bolla eredita gia' il lato e il colore da
   `--skoo` / `--studente`. */
.vchat__pensa .vchat__bolla { display: inline-flex; gap: 4px; align-items: center; padding: 12px 14px; }
.vchat__pensa i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--muted);
  animation: vchatPuntini 1.15s ease-in-out infinite;
}
.vchat__pensa i:nth-child(2) { animation-delay: 0.16s; }
.vchat__pensa i:nth-child(3) { animation-delay: 0.32s; }
@keyframes vchatPuntini {
  0%, 60%, 100% { opacity: 0.32; transform: translateY(0); }
  30%           { opacity: 1;    transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) {
  .vchat { scroll-behavior: auto; }
  .vchat__pensa i { animation: none; opacity: 0.6; }
}
@media (max-width: 600px) {
  .vchat { max-height: 46vh; }
  .vchat__turno { max-width: 92%; }
  .vchat__bolla { font-size: 15px; }
}

/* «Studia subito» — le tre azioni primarie dentro la hero della dashboard studente.
   Il gesto piu' frequente del prodotto (scrivi l'argomento → parti) costava quattro
   sezioni di scroll su telefono. La fila sta sotto al campo e larga quanto il campo:
   l'allineamento dice «questi pulsanti sono di quel campo».
   Tre colonne UGUALI a ogni larghezza — sono pari fra loro, e una pila verticale li
   farebbe leggere come una sequenza da percorrere invece che come una scelta.
   Icona sopra ed etichetta sotto perche' a 360px la riga icona+testo non ci sta:
   (360 − 36 di container − 16 di gap) / 3 = 102px per pulsante, e «Esercizi» da solo
   ne chiede ~63. Impilando, la larghezza smette di essere il vincolo.
   Colori: solo i token --mode-*, e mai sotto le parole. */
.hero__start {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
  margin-top: var(--space-1);
}
.start-btn {
  --mode: var(--accent);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: 64px; /* pollice comodo: ben oltre i 44px minimi */
  padding: var(--space-2) var(--space-1);
  border: 1px solid var(--mode);
  border-radius: var(--radius-control);
  background: color-mix(in srgb, var(--mode) 7%, var(--surface-1));
  color: var(--text);
  font-weight: 700;
  font-size: var(--text-sm);
  line-height: var(--lh-tight);
  text-align: center;
  text-decoration: none;
  transition: background-color 160ms ease, box-shadow 160ms ease, transform 160ms ease;
}
.start-btn--tutor { --mode: var(--mode-tutor); }
.start-btn--orale { --mode: var(--mode-orale); }
.start-btn--quiz  { --mode: var(--mode-quiz); }
.start-btn__icon { flex: none; width: 22px; height: 22px; color: var(--mode); }
.start-btn:hover {
  background: color-mix(in srgb, var(--mode) 14%, var(--surface-1));
  box-shadow: var(--shadow-s);
  transform: translateY(-1px);
}
.start-btn:active { transform: translateY(0); }

/* In attesa dell'argomento. Due scelte deliberate, entrambe contro l'ovvio:
   1) NIENTE pointer-events:none — il tocco deve arrivare a topic-gate.js, che riporta il
      fuoco sul campo. Spegnere il puntatore trasformerebbe il tocco in un nulla di fatto,
      che e' il modo piu' rapido per far credere allo studente che l'app sia rotta.
   2) NIENTE opacity — abbassa anche il contrasto del testo. Qui l'etichetta passa a
      --muted su --surface-2, che misura 6,47:1 al chiaro e 7,38:1 al buio: leggibile
      pur essendo palesemente spenta. Il tratteggio fa il resto del lavoro semantico. */
.start-btn.is-gated {
  background: var(--surface-2);
  border-style: dashed;
  border-color: var(--muted);
  color: var(--muted);
  box-shadow: none;
  transform: none;
}
.start-btn.is-gated .start-btn__icon { color: var(--muted); }

/* L'anello di fuoco va DOPO .is-gated, e con la stessa specificita': .start-btn.is-gated
   azzera la box-shadow (serve a spegnere l'ombra di hover) e a parita' di peso vince la
   regola che viene dopo — messo prima, il fuoco spariva proprio sui pulsanti bloccati.
   E bloccati lo sono per meta': restano tabbabili e attivabili, e attivandoli portano il
   fuoco sul campo. Un comando raggiungibile da tastiera senza anello e' 2.4.7 violata,
   e axe non se ne accorge perche' non valuta gli stili di fuoco. */
.start-btn:focus-visible,
.start-btn.is-gated:focus-visible {
  box-shadow: var(--focus-ring);
}

@media (prefers-reduced-motion: reduce) {
  .start-btn { transition: none; }
  .start-btn:hover, .start-btn:active { transform: none; }
}
/* fine «Studia subito» */

/* ====================================================================== */
/* NAVIGAZIONE 2026 — una lingua sola, due barre                          */
/* ---------------------------------------------------------------------- */
/* In alto, ovunque e per tutti i ruoli: vetro. In basso, solo sul         */
/* telefono e solo per lo studente: la barra a portata di pollice, col     */
/* Tutor AI rialzato al centro. Stesse icone, stesso accento, stessa idea  */
/* di dove sta il prodotto: chi passa dal telefono al portatile deve       */
/* riconoscere il posto, non reimparare la mappa.                          */
/*                                                                        */
/* Il vetro sta su un ::before e NON su .navbar. Motivo tutt'altro che     */
/* estetico: `backdrop-filter` crea un containing block, e il pannello del */
/* drawer (position:fixed, figlio di .navbar) ci resterebbe prigioniero —  */
/* e' il bug che questo file ha gia' pagato una volta. Uno pseudo-elemento */
/* senza figli filtra lo sfondo senza intrappolare nessuno.                */
/* ====================================================================== */
:root {
  --nav-h: 64px;
  /* Vetro delle barre. 0,90 e non il --glass a 0,78: sotto quella soglia il
     testo --muted su contenuto scuro che scorre sotto scendeva a 4,33:1.
     A 0,90 misura 5,84:1 al chiaro e 6,27:1 al buio, nel caso peggiore. */
  --nav-glass: rgba(255, 255, 255, 0.9);
  --nav-line: rgba(29, 26, 43, 0.10);
  /* Inchiostro sopra l'accento pieno: bianco al chiaro (4,77:1 sul violetto
     piu' chiaro del gradiente), inchiostro scuro al buio (6,51:1) — al buio
     l'accento e' una tinta CHIARA e il bianco sopra sarebbe illeggibile.
     Stesso valore gia' usato da `:root.dark .btn--primary`. */
  --on-accent: #ffffff;
  --tabbar-h: 62px;
  --tabbar-orlo: 10px;
}
:root.dark {
  --nav-glass: rgba(21, 18, 31, 0.9);
  --nav-line: rgba(255, 255, 255, 0.10);
  --on-accent: #171430;
}

/* ---------------------------------------------------------------------- */
/* 1. BARRA IN ALTO — vetro, su tutte le pagine e tutti i ruoli            */
/* ---------------------------------------------------------------------- */
.navbar {
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
  background: transparent;
  border-bottom: 1px solid var(--nav-line);
  box-shadow: none;
  isolation: isolate;
  transition: border-color 200ms ease, box-shadow 200ms ease;
}
.navbar::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Fallback: dove il vetro non esiste (o e' spento dalle preferenze di
     sistema) la barra e' piena. Mai testo su un fondo indefinito. */
  background: var(--bg1);
  transition: background-color 200ms ease;
}
@supports ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .navbar::before {
    background: var(--nav-glass);
    -webkit-backdrop-filter: saturate(160%) blur(18px);
    backdrop-filter: saturate(160%) blur(18px);
  }
}
.navbar.scrolled,
.navbar.navbar--scrolled {
  border-bottom-color: var(--border-strong);
  box-shadow: var(--shadow-s);
}
/* Nessuna contro-regola per il drawer: il fondo pieno che il blocco del drawer
   metteva su `.navbar` e' stato tolto alla fonte, non coperto qui. Due regole
   che si annullano a vicenda sono un debito, non una difesa. */

.navbar__inner {
  min-height: var(--nav-h);
  gap: var(--space-4);
}
.navbar__logo img { transition: opacity 180ms ease; }
.navbar__logo:hover img { transform: none; opacity: 0.82; }

/* --- Voci: icona + etichetta, pillola all'attivo, puntino sotto -------- */
.navbar__links .navlink {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 9px 14px;
  border-radius: var(--radius-pill);
  color: var(--muted);
  font-weight: 600;
  font-size: var(--text-sm);
  white-space: nowrap;
  background: transparent;
  box-shadow: none;
  transition: color 180ms cubic-bezier(0.2, 0, 0, 1),
              background-color 180ms cubic-bezier(0.2, 0, 0, 1);
}
.navlink__ico {
  width: 18px;
  height: 18px;
  flex: none;
  opacity: 0.9;
}
.navbar__links .navlink:hover {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 9%, transparent);
  box-shadow: none;
}
.navbar__links .navlink.navlink--active,
.navbar__links .navlink[aria-current] {
  color: var(--accent-ink);
  background: var(--accent-soft);
  box-shadow: none;
}
.navbar__links .navlink[aria-current] .navlink__ico { opacity: 1; stroke-width: 2.2; }
/* Il puntino sotto la pillola: e' la firma che le due barre hanno in comune.
   Sostituisce il filetto di .navlink::before (stessa pseudo, piu' specifica). */
.navbar__links .navlink::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -7px;
  width: 4px;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  transform: translateX(-50%) scale(0);
  transition: transform 200ms cubic-bezier(0.2, 0, 0, 1);
}
.navbar__links .navlink.navlink--active::before,
.navbar__links .navlink[aria-current]::before { transform: translateX(-50%) scale(1); }

/* --- «Tutor AI»: il prodotto, non una voce di menu --------------------- */
.navbar__links .navlink--cta,
.navbar__links .navlink--cta:hover,
.navbar__links .navlink--cta[aria-current] {
  color: var(--on-accent);
  background: var(--gradient-accent);
  padding-inline: var(--space-4);
  box-shadow: 0 1px 2px rgba(45, 35, 90, 0.12),
              0 6px 18px color-mix(in srgb, var(--accent) 26%, transparent);
}
.navbar__links .navlink--cta .navlink__ico { opacity: 1; }
.navbar__links .navlink--cta::before { content: none; }
.navbar__links .navlink--cta:hover { transform: translateY(-1px); }
/* Sei gia' sul Tutor: l'anello lo dice senza spegnere il pulsante. */
.navbar__links .navlink--cta[aria-current] {
  box-shadow: 0 0 0 2px var(--bg1), 0 0 0 4px color-mix(in srgb, var(--accent) 55%, transparent);
}

/* --- 901–1120px: la riga si stringe, le icone si tolgono di mezzo ------ */
/* Con 5 voci + CTA + azioni, le icone facevano traboccare la barra prima  */
/* dei 1120px. Sparisce la decorazione, non l'informazione.                */
@media (min-width: 901px) and (max-width: 1120px) {
  .navbar__links { gap: 0; }
  .navbar__links .navlink { padding-inline: 10px; }
  .navbar__links .navlink > .navlink__ico { display: none; }
  .navbar__links .navlink--cta > .navlink__ico { display: block; }
  /* A 901px la riga sta in piedi con un nome corto. Con «Alessandro» no: il nome
     si accorcia con l'ellissi invece di spingere fuori la barra — e resta un nome,
     non un avatar anonimo. */
  .navbar__right .nav-profile-name {
    display: inline-block;
    max-width: 9ch;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: bottom;
  }
}
@media (min-width: 901px) {
  .navbar__links {
    justify-content: center;
    gap: var(--space-1);
    margin-left: var(--space-4);
    min-width: 0;
  }
}

/* ---------------------------------------------------------------------- */
/* 2. BARRA IN BASSO — solo telefono, solo studente                        */
/* ---------------------------------------------------------------------- */
.tabbar {
  position: fixed;
  z-index: var(--z-nav);
  left: max(var(--tabbar-orlo), env(safe-area-inset-left, 0px));
  right: max(var(--tabbar-orlo), env(safe-area-inset-right, 0px));
  bottom: calc(var(--tabbar-orlo) + env(safe-area-inset-bottom, 0px));
  /* Sul telefono occupa la larghezza piena; sui 700-760px (tablet in verticale)
     si ferma e resta centrata — cinque voci larghe 150px l'una non sono una barra,
     sono una fila di cartelli. Left+right+max-width+margin auto: il box e'
     sovravincolato e i margini automatici assorbono il resto, cioe' centrano. */
  max-width: 460px;
  margin-inline: auto;
  display: grid;
  /* Colonne quante sono le celle: 5 (studente/docente/genitore/sloggato) o 3
     (dirigente). `grid-auto-flow: column` + `grid-auto-columns: 1fr` si adatta
     al numero di voci senza colonne vuote — NON hardcodare repeat(5,1fr). */
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  align-items: end;
  height: var(--tabbar-h);
  padding: 5px 4px;
  border: 1px solid var(--nav-line);
  border-radius: 22px;
  background: var(--bg1);
  box-shadow: var(--shadow-l);
}
@supports ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .tabbar {
    background: var(--nav-glass);
    -webkit-backdrop-filter: saturate(160%) blur(20px);
    backdrop-filter: saturate(160%) blur(20px);
  }
}
.tabbar__voce {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-height: 48px;
  padding: 3px 2px;
  border-radius: 16px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.15;
  text-align: center;
  text-decoration: none;
  transition: color 160ms cubic-bezier(0.2, 0, 0, 1);
}
.tabbar__cerchio {
  display: grid;
  place-items: center;
  width: 38px;
  height: 26px;
  border-radius: var(--radius-pill);
  background: transparent;
  transition: background-color 180ms cubic-bezier(0.2, 0, 0, 1), transform 180ms cubic-bezier(0.2, 0, 0, 1);
}
.tabbar__ico { width: 22px; height: 22px; }
/* Attivo = tre segnali, non solo il colore (WCAG 1.4.1): pillola dietro
   l'icona, tratto piu' spesso, etichetta piu' pesante. */
.tabbar__voce.is-attiva { color: var(--accent-ink); font-weight: 700; }
.tabbar__voce.is-attiva .tabbar__cerchio { background: var(--accent-soft); }
.tabbar__voce.is-attiva .tabbar__ico { stroke-width: 2.4; }
.tabbar__voce:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.tabbar__voce:active .tabbar__cerchio { transform: scale(0.94); }

/* --- La voce centrale: la «S» del marchio, rialzata, che apre l'hub ----- */
/* È un <button> (apre un pannello, non naviga): si azzerano gli stili UA. */
.tabbar__voce--centro {
  justify-content: flex-end;
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
  position: relative;
}
/* La freccina sopra la S — «c'è dell'altro qui dentro», detto senza una parola.
   Il tondo non naviga: apre un pannello che sale dal basso, ma da fermo sembra un
   pulsante come gli altri e nessuno pensa a toccarlo (richiesta founder 2026-08-11).
   Sta attaccata al TONDO e non al bottone, perché il tondo sporge di 26px sopra la
   barra: ancorarla al bottone la stamperebbe addosso alla S. Piccola, nel colore
   dell'accento e appena velata: si nota se la cerchi, non ruba la scena al marchio.
   Ad hub aperto ruota e punta in giù, com'è giusto che faccia. */
.tabbar__voce--centro .tabbar__cerchio { position: relative; }
.tabbar__voce--centro .tabbar__cerchio::before {
  content: "";
  position: absolute;
  left: 50%;
  /* +8px: l'anello di vetro attorno al tondo è 5px, la freccia gli resta sopra. */
  bottom: calc(100% + 8px);
  width: 8px;
  height: 8px;
  margin-left: -4px;
  border-top: 2px solid var(--accent);
  border-left: 2px solid var(--accent);
  border-radius: 1px;
  transform: rotate(45deg);
  opacity: .8;
  pointer-events: none;
  transition: transform .22s ease, opacity .22s ease;
}
.tabbar__voce--centro[aria-expanded="true"] .tabbar__cerchio::before {
  transform: rotate(225deg);
  opacity: .55;
}
@media (prefers-reduced-motion: reduce) {
  .tabbar__voce--centro .tabbar__cerchio::before { transition: none; }
}
.tabbar__voce--centro .tabbar__cerchio {
  width: 54px;
  height: 54px;
  margin-top: -26px;
  border-radius: 50%;
  color: var(--on-accent);
  background: var(--gradient-accent);
  /* L'anello e' lo stesso vetro della barra: il pulsante la buca invece di
     sembrarci appoggiato sopra. */
  box-shadow: 0 0 0 5px var(--nav-glass),
              0 8px 22px color-mix(in srgb, var(--accent) 40%, transparent);
}
.tabbar__voce--centro .tabbar__ico { width: 26px; height: 26px; }
/* Il fuoco segue la forma: sul tondo rialzato l'anello sta sul tondo, non sulla
   cella rettangolare che il pulsante deborda. */
.tabbar__voce--centro:focus-visible { box-shadow: none; }
.tabbar__voce--centro:focus-visible .tabbar__cerchio {
  box-shadow: 0 0 0 4px var(--bg1), 0 0 0 7px var(--accent);
}
/* La «S» resta NEUTRA: un hub è un lancio, non una destinazione — niente stato
   «sei qui» sul centro, nemmeno quando la pagina corrente è un'azione dell'hub. */
.tabbar__esse { width: 26px; height: 26px; }

/* --- Convivenza: il fondo pagina, il FAB dell'Art. 73, i toast, i cookie */
body.has-tabbar {
  padding-bottom: calc(var(--tabbar-h) + 22px + env(safe-area-inset-bottom, 0px));
}
body.has-tabbar.has-fab-ai {
  /* 104px, non 78: il FAB sta a tabbar+20 ed è alto 44 → occupa fino a tabbar+64;
     con 78 il link «Accessibilità» del footer restava COPERTO di 26px a fondo pagina
     (misurato a 390×844 su 8 pagine, visita 2026-08-09 M4). 64 + 40 di respiro. */
  padding-bottom: calc(var(--tabbar-h) + 104px + env(safe-area-inset-bottom, 0px));
}
body.has-tabbar .fab-ai {
  bottom: calc(var(--tabbar-h) + 20px + env(safe-area-inset-bottom, 0px));
}
/* `.ex-toast` sta in questo elenco e non altrove: e' l'unico fisso in basso che
   non esce dalla libreria dei toast, e senza queste due righe si posava sulla
   barra (28→68px dal fondo contro i 10→72px della barra) coprendo il tondo del
   Tutor AI — proprio su esercizi-play, dove i badge arrivano piu' spesso. */
body.has-tabbar .toast-container,
body.has-tabbar .ex-toast {
  bottom: calc(var(--tabbar-h) + 22px + env(safe-area-inset-bottom, 0px));
}
body.has-tabbar.has-fab-ai .toast-container,
body.has-tabbar.has-fab-ai .ex-toast {
  bottom: calc(var(--tabbar-h) + 78px + env(safe-area-inset-bottom, 0px));
}
body.has-tabbar .cookie-banner {
  bottom: calc(var(--tabbar-h) + 22px + env(safe-area-inset-bottom, 0px));
}

@media print { .tabbar, .hub, .hub__velo { display: none !important; } }

/* Dashboard studente: le card che ripetono la fila «Studia subito» non arrivano sul
   telefono (motivazione estesa nel commento in dashboard.html). Sopra i 900px — dove la
   barra in basso non c'è — il pannello completo resta intatto (segue la barra: 760→900). */
@media (max-width: 900px) {
  .action-card--doppione { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .navbar::before,
  .navbar__links .navlink,
  .navbar__links .navlink::before,
  .tabbar__voce,
  .tabbar__cerchio { transition: none; }
  .navbar__links .navlink--cta:hover,
  .tabbar__voce:active .tabbar__cerchio { transform: none; }
  .hub, .hub__velo { transition: none; animation: none; }
}

/* ---------------------------------------------------------------------- */
/* 3. L'HUB — bottom sheet modale aperto dalla «S» del centro              */
/* ---------------------------------------------------------------------- */
/* Le azioni ad alto impatto del ruolo. Velo + foglio ancorato in basso,   */
/* chiusura per ✕/velo/Esc (la maniglia è decorativa, mai il solo swipe).  */
/* Tutto a token, tema-aware; z-modal (60) > barra (z-nav 40) così copre   */
/* la tab bar. La maschera scura è l'alfa del velo di .fab-ai-modal.        */
.hub__velo {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  background: rgba(15, 12, 26, 0.55);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  animation: hub-velo-in 200ms ease;
}
.hub {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: var(--z-modal);
  max-width: 560px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4)
           max(var(--space-4), env(safe-area-inset-bottom, 0px));
  background: var(--bg1);
  border: 1px solid var(--nav-line);
  border-bottom: 0;
  border-radius: 24px 24px 0 0;
  box-shadow: var(--shadow-l);
  animation: hub-in 240ms cubic-bezier(0.2, 0, 0, 1);
}
.hub__maniglia {
  width: 40px;
  height: 4px;
  margin: 2px auto var(--space-1);
  border-radius: var(--radius-pill);
  background: var(--nav-line);
}
.hub__testata {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.hub__titolo { margin: 0; font-size: var(--text-base); font-weight: 700; color: var(--text); }
.hub__chiudi {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  flex: none;
  border: 0;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--muted);
  cursor: pointer;
}
.hub__chiudi svg { width: 22px; height: 22px; }
.hub__chiudi:hover { background: color-mix(in srgb, var(--accent) 9%, transparent); color: var(--text); }
.hub__chiudi:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.hub__lista { display: flex; flex-direction: column; gap: var(--space-2); }
.hub__azione {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 56px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--nav-line);
  border-radius: var(--radius-card);
  background: var(--surface-1);
  color: var(--text);
  text-decoration: none;
}
.hub__azione:hover { background: color-mix(in srgb, var(--accent) 7%, var(--surface-1)); }
.hub__azione:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* Riga di SERVIZIO (feedback): stessa forma delle azioni ma voce più quieta — è un
   <button> e non un lancio di prodotto, quindi non compete con l'eroe. Larghezza piena
   e testo a sinistra perché il default dei bottoni li centrerebbe. */
.hub__azione--servizio {
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
  background: transparent;
  border-style: dashed;
}
.hub__azione--servizio .hub__nome { font-weight: 600; color: var(--muted); }
.hub__azione--servizio:hover { background: var(--surface-2); }
.hub__ico {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  flex: none;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent-ink);
}
.hub__svg { width: 22px; height: 22px; }
.hub__testo { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.hub__nome { font-weight: 700; font-size: var(--text-sm); color: inherit; }
.hub__sub { font-size: var(--text-xs); color: var(--muted); }
/* L'EROE: card grande, gradiente accent, la prima azione a portata di pollice. */
.hub__eroe {
  min-height: 64px;
  border: 0;
  background: var(--gradient-accent);
  color: var(--on-accent);
}
.hub__eroe:hover { background: var(--gradient-accent); }
.hub__eroe .hub__ico {
  background: color-mix(in srgb, var(--on-accent) 22%, transparent);
  color: var(--on-accent);
}
.hub__eroe .hub__nome { font-size: var(--text-base); }
.hub__eroe .hub__sub { color: var(--on-accent); opacity: 0.9; }
@keyframes hub-in { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes hub-velo-in { from { opacity: 0; } to { opacity: 1; } }
/* fine NAVIGAZIONE 2026 */

/* ====================================================================== */
/* COLLAUDO INTEGRITÀ UI — 2026-08-08 (in coda per regola d'onda: si       */
/* aggiunge, non si riscrivono sezioni altrui; vince per cascata)          */
/* ====================================================================== */

/* 1. SPINNER DEL CTA CENTRATO. `.btn--loading::after` è absolute senza
   offset: resta alla POSIZIONE STATICA — dopo il testo reso trasparente —
   e appare spostato a destra del centro (riprodotto a 360px su login:
   è il «dimensionamento del CTA» segnalato dal founder sull'errore di
   accesso). Coordinate del centro + margine di mezzo spinner (20px). */
.btn--loading::after {
  top: 50%;
  left: 50%;
  margin: -10px 0 0 -10px;
}

/* 2. PILL DELLE MODALITÀ: la legge dei token (vedi commento sui --mode-*)
   dice che l'etichetta non porta MAI la tinta di marca — #f59e0b su bianco
   fa 2,15:1. La correzione esisteva (blocco a ~705) ma il blocco storico a
   ~4232 la ripristinava a valle con gli hex, vincendo in cascata. Qui, in
   coda, l'etichetta torna --text (≥12:1 sui fondi tenui, misurato) e la
   tinta d'identità resta su bordo e sfondo (1.4.11 chiede solo 3:1). */
.pill--tutor,
.pill--orale,
.pill--quiz,
.pill--appunti,
.pill--esercizi {
  color: var(--text);
}
.pill--tutor   { border-color: color-mix(in srgb, var(--mode-tutor) 45%, transparent); }
.pill--orale   { border-color: color-mix(in srgb, var(--mode-orale) 45%, transparent); }
.pill--quiz    { border-color: color-mix(in srgb, var(--mode-quiz) 45%, transparent); }
.pill--appunti { border-color: color-mix(in srgb, var(--color-success-ink) 45%, transparent); }
.pill--esercizi { border-color: color-mix(in srgb, var(--color-danger) 45%, transparent); }

/* 3. BOTTONE DISTRUTTIVO: #ef4444 sotto testo bianco fa 3,76:1 (bocciato:
   «Elimina» sul profilo è testo 12px). Il letto che regge il bianco è
   #dc2626 (4,83:1) — lo stesso valore di --color-danger chiaro — promosso
   a token perché vale IN ENTRAMBI i temi (il bianco poggia sul rosso, non
   sul fondo pagina). L'hover conserva lo scurirsi di prima. */
:root { --color-danger-strong: #dc2626; }
.btn--danger { background: var(--color-danger-strong); }
.btn--danger:hover { background: color-mix(in srgb, var(--color-danger-strong) 85%, black); }

/* 4. ZONA PERICOLO DEL PROFILO IN SCURO: titolo e «Esci» erano #dc2626
   cablato anche al buio (3,82:1 su --surface-1). Col token la tinta segue
   il tema: #dc2626 in chiaro (identico a prima), #ef4444 in scuro (4,9:1
   misurato su #15121f). */
.profile-redesign .profile-danger-title,
.profile-redesign .profile-logout-btn { color: var(--color-danger); }
.profile-redesign .profile-logout-btn {
  border-color: color-mix(in srgb, var(--color-danger) 30%, var(--border));
}

/* 5. PRICING, fila «cosa è incluso» (.plan-meta): tre voci in grassetto
   separate solo da 8px si leggevano come un'unica frase sgrammaticata
   («Esercizi che si correggono Appunti in ripasso»). Un punto mediano
   tipografico tra le voci, senza toccare il markup. */
.plan-meta span + span::before {
  content: "· ";
  color: var(--muted);
  font-weight: 400;
}

/* 6. BERSAGLI DA DITO (WCAG 2.5.8). Le caselle nude del browser sono 13px:
   dentro le impostazioni del profilo e i toggle famiglia si mancavano col
   pollice (misurato 13×13 a 360px). 18px + accent-color, come già fa
   .maturita-toggle. E il «nascondi questa guida» era alto 22px: il minimo
   è 24 — padding, non font. */
.profile-redesign input[type="checkbox"],
.label-checkbox input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--accent);
  flex: none;
}
.sk-welcome__dismiss {
  min-height: 24px;
  padding-block: 4px;
}

/* 7. ANELLO DI FUOCO MANCANTE (WCAG 2.4.7, misurato con Tab reale):
   a) i .navlink della barra non avevano NESSUN indicatore di focus
      (box-shadow:none, outline:none) — invisibili da tastiera;
   b) sui CTA della barra (Login/Registrati) l'ombra di riposo di
      `.navbar__actions .btn` (riga ~646) batte `.btn:focus-visible`
      (riga ~350) a parità di specificità per ordine di cascata.
   Qui, in coda, l'anello vince di nuovo. */
.navlink:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-pill);
}
.navbar__actions .btn:focus-visible {
  box-shadow: var(--focus-ring);
}


/* ============================================================
 * POST-COLLAUDO INTEGRITÀ (2026-08-08) — i tre rilievi del revisore che il
 * catalogo aveva mancato, tutti di cascata in tema scuro.
 * ============================================================ */
/* 1. Il CTA «Tutor AI» al buio: `:root.dark .navlink` (0,3,0) batteva
   `.navbar__links .navlink--cta` (0,2,0) e l'inchiostro --on-accent promesso dal
   commento non si applicava MAI — testo --muted sul gradiente accent = 1,61:1
   misurato. Stessa specificità, in coda: ora vince questa. */
:root.dark .navbar__links .navlink--cta,
:root.dark .navbar__links .navlink--cta .navlink__testo { color: var(--on-accent); }
/* 2. L'iniziale dell'avatar al buio: bianco su --accent scuro = 2,51:1. */
:root.dark .nav-avatar--auto { color: var(--on-accent); }
/* 3. Il fix dei bersagli colpiva anche gli input NASCOSTI degli interruttori del
   profilo (inset:0 → 18px): innocuo per l'utente ma fuori bersaglio. Ripristino. */
.profile-redesign .profile-switch input[type="checkbox"] { position: absolute; inset: 0; opacity: 0; width: auto; height: auto; }
/* 4. Caselle di consenso: il minimo 2.5.8 è 24px — si ALZA a 24, non si scende
   a 18 come proponeva il fix deferito (bocciato dal revisore). */
.consent-label input[type="checkbox"],
.label-checkbox input[type="checkbox"] { width: 24px; height: 24px; }

/* ============================================================================
   PARLA CON IL TUO TWIN (2026-08-09) — la card in Studia e il pannello chat.
   Solo token: nessun colore scritto a mano, quindi il tema scuro arriva gratis.

   Sta QUI e non in fondo al file di proposito: `tests/unit/header-mobile.test.js`
   prende «il blocco header» come la fetta che va dal marcatore della sezione
   successiva fino a FINE FILE, e su quella fetta pretende zero colori cablati e
   nessuna @media verso il desktop. Un blocco nuovo accodato in coda finirebbe
   dentro quella fetta e farebbe fallire un collaudo che parla d'altro. (Per la
   stessa ragione il titolo di quella sezione non si cita qui alla lettera: il
   test la cerca con un indexOf, e la prima occorrenza vince.)
   ============================================================================ */
/* --- La card d'ingresso, in Studia ----------------------------------------
   Vive dentro la hero (ultimo blocco): vedi il commento in dashboard.html per il
   perché. Qui serve solo staccarla dal campo argomento e disfare l'allineamento
   al centro che la hero impone sotto i 720px (la @media di «Hero Section Mobile
   Optimization», più su in questo file) — un teaser di tre righe centrato si
   legge male, e questa card è testo prima che bottone. */
.hero__twin { margin-top: var(--space-5); }
.twin-talk {
  display: flex; align-items: center;
  gap: var(--space-4); flex-wrap: wrap;
  text-align: left;
}
.twin-talk__corpo { flex: 1 1 240px; min-width: 0; }
.twin-talk__titolo { margin: 0 0 4px; }
.twin-talk__teaser { margin: 0; max-width: 62ch; }
/* La seconda porta: un LINK, non un secondo bottone. La gerarchia della hero regge un solo
   bersaglio pieno (vedi il commento su `btn--soft` in dashboard.html); questa è la strada
   lunga — la chat intera — e si prende quando si sa già di volerla. */
.twin-talk__intera {
  display: inline-flex; align-items: center; min-height: 44px;
  margin-top: 2px;
  color: var(--accent-ink); font-size: 0.9rem; font-weight: 600;
}
.twin-talk__cta { min-height: 44px; }

/* --- L'AVATAR DEL TWIN ----------------------------------------------------
   Il fallback non è un ramo di codice: è lo STATO DI PARTENZA. Il cerchio è un
   gradiente di token e l'iniziale la scrive il CSS da `data-fallback`, quindi
   l'avatar esiste anche senza JavaScript e anche senza il file PNG (che oggi
   non c'è). L'immagine, quando c'è, si limita a coprirlo; se il caricamento
   fallisce, twin-chat.js la toglie e sotto ricompare il cerchio. Non si vede
   mai un rettangolo rotto, né un buco. */
.twin-avatar {
  position: relative; flex-shrink: 0;
  width: 34px; height: 34px; border-radius: 50%;
  overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--gradient-accent);
  box-shadow: inset 0 0 0 1px var(--border-strong);
}
.twin-avatar::after {
  content: attr(data-fallback);
  color: var(--on-accent);
  font-size: 0.94rem; font-weight: 700; line-height: 1;
}
.twin-avatar__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.twin-avatar--grande { width: 46px; height: 46px; }
.twin-avatar--grande::after { font-size: 1.2rem; }

/* --- LA GUARDIA D'USCITA --------------------------------------------------
   Il pop-up che chiede se restare quando una lezione, un'interrogazione o una
   sessione di esercizi è ancora aperta. Il markup lo costruisce
   `assets/js/modules/lib/guardia-uscita.js` (una sola implementazione per tutte
   e tre le superfici); qui c'è solo il vestito, e solo con token.

   È un `<dialog>` nativo aperto con `showModal()`: backdrop, inerzia della
   pagina dietro, trappola del focus ed Esc li dà il browser.

   I `max-*` NON sono ridondanti — stessa storia di `.twin-chat`: il foglio di
   stile della UA impone a `dialog:modal` un `max-width: calc(100% - 6px - 2em)`
   che un `width` nostro non batte. Finché ce ne dichiariamo uno, la larghezza
   promessa è quella mantenuta. */
.sk-guardia {
  width: min(460px, calc(100vw - 2rem));
  max-width: min(460px, calc(100vw - 2rem));
  padding: var(--space-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--card);
  color: var(--text);
  /* Il dialogo eredita dal punto in cui è scritto (il `<body>`), e diverse pagine
     centrano il testo nella sezione che lo ospita: qui si allinea a sinistra, che
     è come si legge un fumetto. */
  text-align: left;
  box-shadow: var(--shadow-l);
  z-index: var(--z-modal);
}
.sk-guardia[open] { display: block; }
/* Lo scrim è l'unico colore scritto a mano del blocco, e per forza: `::backdrop`
   eredita le custom property dall'elemento d'origine solo dai browser del 2023 in
   poi — un `var(--token)` qui diventerebbe trasparente sul parco più vecchio. */
.sk-guardia::backdrop { background: rgba(29, 26, 43, 0.45); }
:root.dark .sk-guardia::backdrop { background: rgba(0, 0, 0, 0.6); }

.sk-guardia__riga { display: flex; align-items: flex-start; gap: var(--space-3); }
.sk-guardia__faccia { margin-top: 2px; }
/* Il fumetto: carta più chiara, inchiostro violetto sul filo a sinistra — che è
   anche la punta che indica il Twin senza bisogno di uno pseudo-elemento in più. */
.sk-guardia__fumetto {
  flex: 1; min-width: 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent-violet);
  border-radius: var(--radius-card);
  background: var(--surface-2);
}
/* L'evidenziatore dietro il titolo: decorativo, l'inchiostro sopra resta pieno. */
.sk-guardia__titolo {
  margin: 0 0 var(--space-1);
  font-size: var(--text-lg); line-height: var(--lh-tight);
  background-image: linear-gradient(var(--hl), var(--hl));
  background-repeat: no-repeat;
  background-size: 100% 0.5em;
  background-position: 0 88%;
}
.sk-guardia__testo { margin: 0; color: var(--muted); line-height: var(--lh-base); }

.sk-guardia__azioni {
  display: flex; gap: var(--space-2); justify-content: flex-end; flex-wrap: wrap;
  margin-top: var(--space-4);
}

@keyframes skGuardiaIn {
  from { opacity: 0; transform: translateY(8px) scale(.98); }
  to   { opacity: 1; transform: translateY(0)   scale(1);   }
}
/* L'animazione è un di più: chi ha chiesto meno movimento vede il pop-up e basta. */
@media (prefers-reduced-motion: no-preference) {
  .sk-guardia[open] { animation: skGuardiaIn .18s cubic-bezier(.22,.61,.36,1); }
}

/* --- Il pannello ----------------------------------------------------------
   `<dialog>` nativo: backdrop, Esc e focus trap li dà il browser.

   DIMENSIONI DICHIARATE DUE VOLTE, e non è una svista: `width` E `max-width`,
   `height` E `max-height`. Il 9 agosto 2026 il founder ha detto che il pannello
   era un francobollo; misurando a 390x844 veniva fuori 352px di larghezza dove il
   CSS ne prometteva 374 (`calc(100vw - 16px)`), centrato con 19px di margine per
   parte che nessuno aveva scritto. Il colpevole è il foglio di stile del BROWSER:
   Chromium applica ai dialoghi modali
       dialog:modal { max-width: calc(100% - 6px - 2em); max-height: idem; }
   — quei 6px+2em sono lo spazio che la UA riserva al bordo e al `padding: 1em`
   suoi, che noi azzeriamo: con root a 16px diventano 38px sottratti a viewport
   PIENO, cioè 390-38 = 352. Un `width` non batte un `max-width`, e in DevTools la
   regola si vede solo aprendo gli stili della UA: perciò la promessa «foglio a
   tutta larghezza» è rimasta scritta e mai mantenuta, in silenzio. Finché ci
   dichiariamo un `max-*` nostro, la UA non ha più voce in capitolo — su qualunque
   viewport e a qualunque dimensione del font di sistema. NON TOGLIERE i `max-*`
   credendoli ridondanti: sono l'unica riga che tiene. */
.twin-chat {
  /* Una superficie di conversazione, non un avviso: su desktop ~860px di larghezza
     e ~720px di altezza PIENA (non «al massimo»), così il log ha spazio vero e il
     pannello non cambia forma a ogni messaggio che arriva. */
  width: min(860px, 90vw);
  max-width: min(860px, 90vw);
  height: min(80vh, 720px);
  max-height: min(80vh, 720px);
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--card);
  color: var(--text);
  /* Il dialogo sta nel top layer ma EREDITA dal punto in cui è scritto nel documento,
     e lì è la hero — che sotto i 720px allinea tutto al centro (`@media (max-width:
     720px) { .hero { text-align: center } }`, sezione «Hero Section Mobile
     Optimization»). Senza questa riga la chat si apriva col titolo, la disclosure e
     ogni bolla incolonnati al centro: da telefono sembrava una schermata di
     benvenuto, non una conversazione. */
  text-align: left;
  box-shadow: var(--shadow-l);
  z-index: var(--z-modal);
}
.twin-chat[open] { display: flex; flex-direction: column; }
/* Lo scrim è l'UNICO colore scritto a mano del blocco, e per forza: `::backdrop`
   eredita le custom property dall'elemento d'origine solo dai browser del 2023 in
   poi — un `var(--token)` qui diventa trasparente sul parco installato più vecchio,
   cioè niente scrim e un dialogo che galleggia sul nulla. */
.twin-chat::backdrop { background: rgba(29, 26, 43, 0.45); }
:root.dark .twin-chat::backdrop { background: rgba(0, 0, 0, 0.6); }
/* Lo stesso scrim per il foglio dei piani all'avvio (paywall-avvio.js, revisione 24/9): con
   `var(--text)` era un velo quasi BIANCO al buio, e nessuno scrim sul parco più vecchio. Sta QUI,
   prima dei libri, perché da «I MIEI LIBRI» in giù il file non ha colori scritti a mano. */
.paywall-avvio::backdrop { background: rgba(29, 26, 43, 0.45); }
:root.dark .paywall-avvio::backdrop { background: rgba(0, 0, 0, 0.6); }

.twin-chat__testa {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.twin-chat__chi { flex: 1; min-width: 0; }
.twin-chat__titolo { margin: 0; font-size: 1.02rem; }
/* Art. 50: sempre visibile, e non affidata al solo colore — c'è il glifo e la parola «AI». */
.twin-chat__ai {
  margin: 2px 0 0;
  font-size: 0.78rem; color: var(--muted);
  display: flex; align-items: center; gap: 5px;
}
.twin-chat__chiudi {
  flex-shrink: 0;
  min-width: 44px; min-height: 44px;
  border: 1px solid var(--border); border-radius: var(--radius-control);
  background: var(--surface-1); color: var(--text); cursor: pointer; font-size: 1rem;
}
.twin-chat__chiudi:hover { background: var(--primary-soft); }
.twin-chat__chiudi:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.twin-chat__memoria { margin: 10px 14px 0; }

/* --- Il log ---------------------------------------------------------------- */
.twin-chat__log {
  flex: 1; overflow-y: auto; overscroll-behavior: contain;
  padding: var(--space-4);
  display: flex; flex-direction: column; gap: var(--space-3);
  scroll-behavior: smooth;
}
/* La conversazione POGGIA sul campo di scrittura e cresce verso l'alto, come in ogni
   app di messaggi. Con un pannello alto sul serio le prime due bolle, ancorate in cima,
   lasciavano mezzo schermo di vuoto fra sé e l'input: spazio guadagnato e subito
   sprecato. Si fa con un margine automatico sul primo figlio e NON con
   `justify-content: flex-end`, che quando il log deborda rende irraggiungibile ciò che
   sta in cima; un margine `auto` in troppo poco spazio vale semplicemente zero. */
.twin-chat__log > :first-child { margin-top: auto; }
/* Due limiti insieme, e servono entrambi: la percentuale tiene la bolla staccata dal
   bordo opposto (si vede che è di qualcuno), i `ch` tengono la RIGA leggibile — in un
   pannello da 860px una bolla al 90% farebbe righe da 90 caratteri, che si perdono. */
.twin-riga { display: flex; align-items: flex-end; gap: 8px; max-width: min(90%, 54ch); }
.twin-riga--twin { align-self: flex-start; }
.twin-riga--tu { align-self: flex-end; flex-direction: row-reverse; }

.twin-bolla {
  min-width: 0;
  padding: 12px 16px;
  border: 1px solid var(--border); border-radius: 16px;
  animation: twin-bolla-entra 200ms ease both;
}
@keyframes twin-bolla-entra { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
/* 16px pieni e interlinea 1.55: è il corpo del testo che uno studente legge davvero,
   non una didascalia. Ereditava e basta, e bastava un `.small` di passaggio sopra per
   rimpicciolirlo senza che nessuno se ne accorgesse. */
.twin-bolla__testo {
  margin: 0; white-space: pre-wrap; overflow-wrap: anywhere;
  font-size: 1rem; line-height: 1.55;
}

/* ── IL MARKDOWN RESO (`lib/md-lite.js`) ───────────────────────────────────────
   Il Twin è un modello e scrive markdown anche quando nessuno glielo chiede. Il
   renderer lo legge e ne fa nodi; qui si vestono, e si vestono con i token — mai
   una tinta a mano, mai un pixel dove può stare un `em`, così le distanze fra i
   paragrafi crescono insieme al corpo del testo di chi lo ha alzato da sistema.
   Il corpo del Twin è un `<div>`, non un `<p>`: `pre-wrap` qui non serve più (gli
   a capo sono già diventati blocchi) e lascerebbe righe vuote fantasma. */
.twin-bolla__testo--md { white-space: normal; }
.md__p { margin: 0; overflow-wrap: anywhere; }
.md__p + .md__p,
.md__p + .md__titolo,
.md__p + .md__elenco,
.md__elenco + .md__p,
.md__titolo + .md__elenco { margin-top: 0.6em; }
/* Un titoletto è un `<p>` in grassetto e non un heading: dentro un log di
   conversazione un `<h4>` entrerebbe nella struttura del documento — e nella
   lista dei titoli di uno screen reader — come se fosse una sezione di pagina. */
.md__titolo { font-weight: 600; }
.md__elenco { margin: 0.4em 0 0; padding-left: 1.3em; }
.md__voce { margin: 0.22em 0; overflow-wrap: anywhere; }
.md__voce::marker { color: var(--muted); }
.md__forte { font-weight: 600; }
.md__enfasi { font-style: italic; }
/* Il codice in riga: fondo chiaro sul fondo scuro della bolla del Twin, così una
   formula o un comando si staccano invece di sciogliersi nel paragrafo. */
.md__code {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.92em;
  padding: 0.08em 0.34em;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface-1);
  overflow-wrap: anywhere;
}
/* La coda: l'angolo dal lato di chi parla si stringe. È l'unico segnale di forma
   che distingue le due voci oltre alla posizione e al fondo — e regge anche a
   contrasto ridotto, dove le due tinte si somigliano. */
.twin-bolla--tu {
  align-self: flex-end;
  background: var(--primary-soft); border-color: transparent;
  border-bottom-right-radius: 5px;
}
.twin-bolla--twin { background: var(--surface-2); border-bottom-left-radius: 5px; }

/* «Sta scrivendo»: tre puntini che respirano. */
.twin-punti { display: inline-flex; align-items: center; gap: 5px; padding: 3px 0; }
.twin-punti__p {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--muted);
  animation: twin-punto 1.2s ease-in-out infinite;
}
.twin-punti__p:nth-child(2) { animation-delay: 0.16s; }
.twin-punti__p:nth-child(3) { animation-delay: 0.32s; }
@keyframes twin-punto {
  0%, 60%, 100% { opacity: 0.32; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}

/* Chi ha chiesto meno movimento non lo riceve: i puntini restano, fermi e leggibili,
   la bolla non entra scivolando e il log non insegue lo scroll con l'animazione. */
@media (prefers-reduced-motion: reduce) {
  .twin-punti__p { animation: none; opacity: 0.6; }
  .twin-bolla { animation: none; }
  .twin-chat__log { scroll-behavior: auto; }
}

/* Le tre domande d'apertura: un trampolino, non un menu. Rientrate come le bolle
   del Twin, perché è il Twin che le sta offrendo. */
.twin-chat__spunti { display: flex; flex-wrap: wrap; gap: 8px; padding-left: 42px; }
.twin-chip {
  /* IMBOTTITURA VERTICALE, non solo `min-height`. Con `padding: 0 14px` un suggerimento di
     una riga stava bene — ci pensava il min-height a centrarlo — ma uno che VA A CAPO
     («Ho la verifica di fisica giovedi': preparami un piano») incollava le due righe al
     bordo alto e a quello basso della pastiglia. E' il difetto che il founder ha visto a
     occhio il 24/8: «occhio all'interlinea tra le carte e le parole». Dieci pixel sopra e
     sotto: a una riga la pastiglia resta di 44 px (10+20+10 = 40 < 44, vince il minimo),
     a due righe cresce e respira. */
  min-height: 44px; padding: 10px 14px;
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--surface-1); color: var(--accent-ink);
  font: inherit; font-size: 0.88rem; font-weight: 500;
  text-align: left; cursor: pointer;
  transition: background-color .16s ease, border-color .16s ease;
}
.twin-chip:hover { background: var(--primary-soft); border-color: var(--accent); }
.twin-chip:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* SPENTE quando l'invio è chiuso — Twin che sta rispondendo, quota finita per oggi.
   `twin-chat.js` le disabilita insieme al campo: un bersaglio che il codice rifiuta deve
   LEGGERSI rifiutato, altrimenti resta invitante e tradisce chi lo tocca. Il `:hover` va
   annullato a mano: in CSS si applica anche ai bottoni disabilitati. */
.twin-chip:disabled { opacity: 0.45; cursor: not-allowed; }
.twin-chip:disabled:hover { background: var(--surface-1); border-color: var(--border); }

/* Righe di servizio: guasti e limiti, in italiano e con la via d'uscita accanto. */
.twin-chat__servizio { margin: 2px 0 2px 42px; font-size: 0.9rem; color: var(--muted); }
.twin-chat__servizio--stop { color: var(--text); font-weight: 500; }
.twin-chat__riprova {
  border: none; background: none; padding: 0; cursor: pointer;
  font: inherit; font-weight: 600; color: var(--accent-ink); text-decoration: underline;
}
.twin-chat__riprova:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-control); }
.twin-chat__riprova:disabled { opacity: 0.45; cursor: not-allowed; text-decoration: none; }

.twin-diario {
  border: 1px dashed var(--border); border-radius: var(--radius-control);
  padding: 12px 14px; background: var(--surface-2);
}
.twin-diario__titolo { margin: 0 0 6px; font-size: 0.95rem; }
/* Il diario lo scrive il job notturno IN MARKDOWN, e dal 22 agosto 2026 passa dal
   renderer come le bolle: niente più `pre-wrap` (gli a capo sono già blocchi) e
   niente più cancelletti a schermo. */
.twin-diario__testo { font-size: 0.94rem; color: var(--text); }

/* --- Cose che tengo a mente -----------------------------------------------
   L'altra metà della memoria del Twin: il diario lo scrive lui di notte, queste
   gliele detta lo studente parlando («segnati che giovedì ho storia»). Stessa
   cornice tratteggiata del diario, di proposito: sono la stessa cosa vista da
   due lati, e due scatole diverse le farebbero sembrare due funzioni.

   La data è EVIDENZIATA, e non con il solo colore: sta su una riga sua, sopra
   il testo, in grassetto e con la tinta d'accento. Chi non distingue le tinte
   legge comunque «giovedì 13 agosto · fra 3 giorni», che è l'informazione. */
.twin-note {
  border: 1px dashed var(--border); border-radius: var(--radius-control);
  padding: 12px 14px; background: var(--surface-2);
}
.twin-note__titolo { margin: 0 0 8px; font-size: 0.95rem; }
.twin-note__vuoto { margin: 0; font-size: 0.94rem; color: var(--muted); }
.twin-note__elenco { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.twin-note__riga { display: flex; align-items: center; gap: 8px; }
.twin-note__corpo { flex: 1; min-width: 0; }
.twin-note__data {
  display: block;
  font-size: 0.78rem; font-weight: 700; color: var(--accent-ink);
  text-transform: capitalize;
}
.twin-note__testo { display: block; font-size: 0.94rem; color: var(--text); overflow-wrap: anywhere; }
/* Da dito come tutti gli altri bersagli del pannello: eliminare una nota è un
   gesto piccolo, ma è comunque distruttivo — un bersaglio stretto lo si sbaglia. */
.twin-note__elimina {
  flex-shrink: 0;
  min-width: 44px; min-height: 44px;
  border: 1px solid var(--border); border-radius: var(--radius-control);
  background: var(--surface-1); color: var(--text);
  font: inherit; font-size: 1rem; line-height: 1; cursor: pointer;
}
.twin-note__elimina:hover { background: var(--primary-soft); }
.twin-note__elimina:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.twin-note__elimina:disabled { opacity: 0.45; cursor: not-allowed; }

/* --- La riga di scrittura -------------------------------------------------- */
.twin-chat__form {
  display: flex; gap: 8px; align-items: center;
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--border);
  background: var(--surface-1);
}
/* 16px NON è una scelta estetica: `.input` sta a 15px, e Safari su iPhone ingrandisce
   la pagina da solo quando un campo a fuoco ha meno di 16px — la chat si apriva zoomata
   e storta. Sedici è la soglia, e qui si scrive esplicita perché non dipenda da `.input`. */
.twin-chat__input { flex: 1; min-width: 0; min-height: 44px; font-size: 1rem; border-radius: var(--radius-pill); }
.twin-chat__invia {
  flex-shrink: 0;
  width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: 50%;
  background: var(--gradient-accent); color: var(--on-accent);
  cursor: pointer;
}
.twin-chat__invia svg { width: 20px; height: 20px; }
.twin-chat__invia:disabled { opacity: 0.45; cursor: not-allowed; }
.twin-chat__invia:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* La via di fuga: sempre visibile, sempre cliccabile (niente gate dell'argomento). */
.twin-chat__vie { display: flex; flex-wrap: wrap; gap: 8px; padding: 12px 14px 14px; border-top: 1px solid var(--border); }
.twin-chat__via {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 14px;
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--surface-1); color: var(--accent-ink);
  font-size: 0.9rem; font-weight: 500; text-decoration: none; cursor: pointer;
}
.twin-chat__via:hover { background: var(--primary-soft); }
.twin-chat__via:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* L'entrata dalla vignetta «Il Twin ha notato…»: è lì che nasce la domanda «perché?». */
.twin-vignette__parla {
  display: inline-block; margin-top: 10px; padding: 8px 0;
  border: none; background: none; cursor: pointer;
  color: var(--accent-ink); font: inherit; font-weight: 600; text-decoration: underline;
}
.twin-vignette__parla:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-control); }

/* --- Il consiglio del Twin: tipo, perché, azione ---------------------------
   Il pulsante portava la FRASE del server come titolo — ottanta caratteri dentro una capsula,
   tre righe centrate — e la durata (`micro.minutes`) sul web non si vedeva affatto. Il disegno
   approvato dal founder il 22/8 separa i tre lavori: la targhetta dice il TIPO, la frase dice
   il PERCHÉ, il bottone dice COSA FAI e si porta la durata come medaglietta.
   Le regole stanno qui in fondo di proposito: devono vincere sul `.btn` di base, che nel foglio
   è dichiarato più volte e più in alto. */
.twin-consiglio { margin: 12px 0 10px; }
.twin-consiglio__tipo { margin-bottom: 6px; }
.twin-consiglio__frase { color: var(--muted); margin: 0; }
.twin-cta {
  display: flex; width: 100%; min-height: 48px;
  align-items: center; justify-content: space-between;
  /* `wrap` + `min-height` (non `height`): ai corpi di testo grandi la medaglietta va a capo e il
     bottone cresce. L'alternativa sarebbe tagliare il testo, che WCAG 1.4.4 non ammette. */
  flex-wrap: wrap; gap: 8px 12px; text-align: left;
}
.twin-cta__azione { white-space: normal; }
/* Capsula OUTLINE: `currentColor` non introduce un colore nuovo, quindi il testo resta esattamente
   quello che il bottone ha già provato contro il proprio fondo. Un riempimento sotto l'etichetta
   ne abbasserebbe il contrasto proprio dove nessuno tornerebbe a misurarlo. */
.twin-cta__durata {
  display: inline-block; padding: 2px 10px; border: 1px solid currentColor;
  border-radius: var(--radius-pill); font-size: 0.85rem; font-weight: 600; white-space: nowrap;
}

/* --- La card del piano, dentro la conversazione ----------------------------
   Il piano nasce parlando (founder, 18 agosto 2026): la proposta compare in coda al log,
   e da lì si conferma con un tocco. Il bordo TRATTEGGIATO della proposta è lo stesso del
   diario e delle note — «questa è roba del Twin, non una schermata dell'app» — e diventa
   pieno quando il piano è attivo, cioè quando esiste davvero nel database.
   Lo stato non è mai affidato al solo bordo: la pastiglia lo dice a parole (WCAG 1.4.1). */
.twin-piano {
  border: 1px solid var(--border); border-radius: var(--radius-control);
  padding: 12px 14px; background: var(--surface-2);
  display: flex; flex-direction: column; gap: 8px;
}
.twin-piano--proposta { border-style: dashed; }
.twin-piano--chiuso { opacity: 0.85; }
.twin-piano__stato {
  align-self: flex-start; margin: 0; padding: 2px 10px;
  border-radius: var(--radius-pill); background: var(--primary-soft);
  color: var(--accent-ink); font-size: 0.78rem; font-weight: 700;
}
.twin-piano__obiettivo { margin: 0; font-size: 0.98rem; color: var(--text); }
.twin-piano__label { font-weight: 700; }
.twin-piano__quando { color: var(--muted); font-weight: 500; }
.twin-piano__dose,
.twin-piano__avanzamento,
.twin-piano__sub { margin: 0; font-size: 0.9rem; color: var(--muted); }
.twin-piano__sub { font-weight: 600; color: var(--text); }
.twin-piano__barra { font-family: var(--font-mono, monospace); letter-spacing: -1px; color: var(--accent); }
.twin-piano__blocchi { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.twin-piano__blocco { display: flex; align-items: center; gap: 8px; }
.twin-piano__blocco-testo { flex: 1; min-width: 0; font-size: 0.92rem; color: var(--text); overflow-wrap: anywhere; }
.twin-piano__fila { flex-shrink: 0; font-size: 0.82rem; color: var(--muted); }
.twin-piano__inizia { flex-shrink: 0; text-decoration: none; }
.twin-piano__voto { margin: 0; font-size: 0.9rem; color: var(--text); }
.twin-piano__nota,
.twin-piano__legge { color: var(--muted); font-size: 0.85rem; font-weight: 400; }
.twin-piano__legge { margin: 0; }
.twin-piano__azioni { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.twin-piano__conferma { min-height: 44px; }
/* «Cambia qualcosa» non è un secondo bottone primario: è l'invito a continuare a parlare,
   e come i «Riprova» delle righe di servizio ha la forma di un link. */
.twin-piano__cambia {
  min-height: 44px; padding: 0 10px;
  border: none; background: none; cursor: pointer;
  font: inherit; font-weight: 600; color: var(--accent-ink); text-decoration: underline;
}
.twin-piano__cambia:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-control); }
.twin-piano__conferma:disabled { opacity: 0.45; cursor: not-allowed; }
.twin-piano__tutto {
  display: inline-flex; align-items: center; min-height: 44px;
  color: var(--accent-ink); font-size: 0.9rem; font-weight: 600;
}

/* --- Telefono (misurato a 390px) ------------------------------------------
   Il pannello è un FOGLIO: tutta la larghezza, incollato al bordo basso, alto
   88svh, angoli arrotondati solo in cima. Il pollice arriva prima al campo che
   al titolo, e il gesto è quello che ogni app di messaggi ha insegnato.

   È stato un rettangolo galleggiante fino al 9 agosto 2026 (352x608 misurati,
   65% del viewport, 19px di aria per parte): due cause sovrapposte, entrambe
   invisibili nel sorgente. La prima è il `max-width` della UA — spiegato sopra,
   sulla regola base. La seconda è questa: il foglio si fermava SOPRA la tab bar
   (`margin-bottom: var(--tabbar-h) + …`) per lasciarla in vista. Ma la barra
   sotto un dialogo modale è già morta — il ::backdrop di showModal() prende
   tutti i tocchi, e il commento di allora lo ammetteva — quindi la si mostrava
   accesa e non funzionante, pagandola con 82px di foglio in meno. Ora il foglio
   la copre: è un modale, si dichiara tale, e chi vuole cambiare sezione lo
   chiude prima. Il posto della safe area non si perde, si sposta DENTRO l'ultima
   riga (vedi `.twin-chat__vie`), dove serve davvero.

   `svh` e non `vh`: su iPhone `100vh` è l'altezza col browser a barre nascoste,
   cioè più del visibile — il foglio finirebbe sotto la barra degli indirizzi
   proprio dove sta il campo di scrittura. Il `vh` resta come ripiego per i
   browser che `svh` non lo conoscono. */
@media (max-width: 620px) {
  /* Due righe, non quattro: avatar e titolo accanto (è la faccia di chi parla, non
     un'illustrazione da mettere in cornice sopra), teaser sotto, bottone a tutta
     larghezza in fondo. Misurato a 390x844: impilando tutto la card finiva a 263px
     e il bottone «Parla con il tuo Twin» cadeva dietro la barra in basso — un
     ingresso senza porta finché non scorri. Così sta in 201px e si vede intero.

     Era `flex-direction: column`, e in colonna `flex: 1 1 240px` sul corpo smetteva
     di essere una larghezza minima e diventava un blocco ALTO 240px, cioè un buco
     fra titolo e bottone: la griglia toglie di mezzo la trappola invece di
     rattopparla, perché `flex-basis` in un grid item non ha alcun effetto.
     Il `minmax(0, …)` è ciò che permette al teaser di andare a capo invece di
     allargare la colonna: senza, la traccia `1fr` non scende sotto il contenuto. */
  .twin-talk {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    /* `start` e non `center`: centrato, l'avatar scivolava accanto al teaser e il
       titolo restava scoperto: una faccia che guarda il testo sbagliato. */
    align-items: start;
    gap: var(--space-3) var(--space-4);
  }
  .twin-talk__cta { grid-column: 1 / -1; width: 100%; justify-content: center; }

  .twin-chat {
    width: 100%;
    max-width: 100%;
    height: 88vh;
    max-height: 88vh;
    height: 88svh;
    max-height: 88svh;
    /* `auto` in cima spinge il foglio in fondo; zero sui tre lati che toccano il
       bordo. Senza gli zeri resterebbe il `margin: auto` della UA, che lo
       ricentrerebbe — ed era l'altra metà dei 19px di aria. */
    margin: auto 0 0;
    border-width: 1px 0 0;
    border-radius: var(--radius-card) var(--radius-card) 0 0;
  }
  /* Respiro da telefono: il testo del Twin sale a 17px, il log ha più aria e le
     tre domande diventano righe intere da toccare col pollice. */
  .twin-chat__log { padding: var(--space-4) var(--space-4) var(--space-3); gap: var(--space-4); }
  .twin-bolla__testo { font-size: 1.0625rem; }
  .twin-riga { max-width: 100%; }
  .twin-chat__spunti, .twin-chat__servizio { padding-left: 0; margin-left: 0; }
  .twin-chip { width: 100%; font-size: 0.95rem; }
  /* Il piano si conferma col pollice: il bottone prende la riga, «Cambia qualcosa» la sua. */
  .twin-piano__azioni { flex-direction: column; align-items: stretch; }
  .twin-piano__conferma { width: 100%; justify-content: center; }
  .twin-piano__blocco { flex-wrap: wrap; }
  /* L'ultima riga del foglio poggia sul bordo dello schermo: la tacca in basso
     dell'iPhone si scavalca qui, non lasciando un vuoto sotto tutto il pannello. */
  .twin-chat__vie { padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px)); }
}

/* ==========================================================================
   `twin.html` — LA CHAT INTERA COL TWIN (onda 7, 2026-08-23)
   --------------------------------------------------------------------------
   Il pannello della dashboard è un dialogo che si apre SOPRA la pagina; questa
   è la pagina. Tre scelte, e sono tutte e tre risposte a un difetto visto:

   1. LA COLONNA DELLE CONVERSAZIONI ESISTE SOLO DA 1024px. Sotto quella soglia
      una colonna fissa mangerebbe metà della riga di testo — e la riga di testo
      è il prodotto. Da lì in giù diventa un pannello che si apre dal bottone
      «Le tue chat» e si richiude con Esc, col ✕ o aprendo una conversazione.
   2. IL LOG SCORRE, LA PAGINA NO. La conversazione ha un'altezza dichiarata e
      lo scorrimento sta DENTRO di lei: se scorresse la pagina, il campo di
      scrittura se ne andrebbe fuori schermo proprio mentre ci si scrive.
   3. SOLO TOKEN, come tutto il resto del file: la pagina eredita chiaro e scuro
      senza una riga di JavaScript.

   Le bolle, i chip e le righe di servizio sono le STESSE della dashboard
   (`.twin-riga`, `.twin-bolla`, `.twin-chip`, `.twin-chat__servizio`): qui si
   vestono solo le parti che quella chat non ha — la colonna, il composer con la
   foto, la barra sotto la risposta, la carta del supporto.
   ========================================================================== */

.page--twinpage { padding-block: var(--space-4) var(--space-6); }

.twinpage {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  align-items: stretch;
}

/* --- La colonna delle conversazioni ---------------------------------------- */
.twinpage__lato {
  display: flex; flex-direction: column; gap: var(--space-3);
  min-width: 0;
  padding: var(--space-4);
  border: 1px solid var(--border); border-radius: var(--radius-card);
  background: var(--card); color: var(--text);
}
/* `display: flex` batte il `display: none` che il browser dà a `[hidden]`: senza questa
   riga la colonna resterebbe a schermo anche per chi non ha nessuna cronologia da vedere
   (minori sotto i 14: la chat è effimera, e prometterne una sarebbe una bugia). */
.twinpage__lato[hidden] { display: none; }
.twinpage__lato-testa { display: flex; align-items: center; gap: var(--space-2); }
.twinpage__lato-titolo { margin: 0; flex: 1; font-size: 1rem; }
.twinpage__chiudi-lato {
  flex-shrink: 0; min-width: 44px; min-height: 44px;
  border: 1px solid var(--border); border-radius: var(--radius-control);
  background: var(--surface-1); color: var(--text); font-size: 1rem; cursor: pointer;
}
.twinpage__chiudi-lato:hover { background: var(--primary-soft); }
.twinpage__chiudi-lato:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.twinpage__nuova { width: 100%; justify-content: center; }
.twinpage__elenco {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 4px;
  overflow-y: auto; min-height: 0;
}
.twinpage__voce { display: flex; align-items: center; gap: 4px; }
/* Il titolo della conversazione lo scrive il server dalla prima domanda: può essere lungo
   quanto vuole e deve stare in UNA riga, altrimenti la colonna si allarga a fisarmonica
   ogni volta che si apre una chat nuova. */
.twinpage__voce-apri {
  flex: 1; min-width: 0;
  min-height: 44px; padding: 0 10px;
  border: 1px solid transparent; border-radius: var(--radius-control);
  background: none; color: var(--text);
  font: inherit; font-size: 0.92rem; text-align: left; cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.twinpage__voce-apri:hover { background: var(--surface-2); }
.twinpage__voce-apri:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* La conversazione aperta si riconosce da DUE segnali, non dal solo colore: lo sfondo e il
   grassetto. Chi non distingue le tinte legge comunque quale sta guardando. */
.twinpage__voce--attiva .twinpage__voce-apri {
  background: var(--primary-soft); border-color: var(--accent);
  font-weight: 600; color: var(--accent-ink);
}
.twinpage__voce-via {
  flex-shrink: 0; min-width: 44px; min-height: 44px;
  border: 1px solid transparent; border-radius: var(--radius-control);
  background: none; color: var(--muted);
  font: inherit; font-size: 1rem; line-height: 1; cursor: pointer;
}
.twinpage__voce-via:hover { background: var(--surface-2); color: var(--text); }
.twinpage__voce-via:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.twinpage__lato-nota { margin: 0; }
.twinpage__lato-nota:empty { display: none; }
.twinpage__svuota {
  margin-top: auto;
  border: none; background: none; padding: 8px 0;
  font: inherit; font-size: 0.85rem; font-weight: 600;
  color: var(--muted); text-decoration: underline; text-align: left; cursor: pointer;
}
.twinpage__svuota:hover { color: var(--text); }
.twinpage__svuota:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-control); }

/* --- La conversazione ------------------------------------------------------ */
.twinpage__chat {
  display: flex; flex-direction: column; min-width: 0;
  /* Un'altezza DICHIARATA, non «quanto viene»: è ciò che tiene il campo di scrittura
     sempre a schermo e lo scorrimento dentro il log. `svh` è l'altezza col browser a
     barre VISIBILI (su iPhone `vh` è di più del visibile, e il campo finirebbe sotto la
     barra degli indirizzi); `vh` resta come ripiego dove `svh` non si conosce. */
  height: 74vh;
  height: 74svh;
  min-height: 460px;
  border: 1px solid var(--border); border-radius: var(--radius-card);
  background: var(--card); color: var(--text);
  overflow: hidden;
}
.twinpage__testa {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.twinpage__apri-lato {
  flex-shrink: 0;
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--surface-1); color: var(--accent-ink);
  font: inherit; font-size: 0.88rem; font-weight: 500; cursor: pointer;
}
.twinpage__apri-lato:hover { background: var(--primary-soft); }
.twinpage__apri-lato:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.twinpage__chi { flex: 1; min-width: 0; }
.twinpage__titolo { margin: 0; font-size: 1.02rem; }
/* Art. 50, in testa al thread: sempre visibile, mai affidata al solo colore — c'è il glifo
   e c'è la parola «AI». Chi riapre una conversazione di due mesi fa la rilegge subito. */
.twinpage__ai {
  margin: 2px 0 0;
  font-size: 0.78rem; color: var(--muted);
  display: flex; align-items: center; gap: 5px;
}
.twinpage__testa-azioni { flex-shrink: 0; }
.twinpage__testa-tasto {
  min-height: 44px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--surface-1); color: var(--text);
  font: inherit; font-size: 0.85rem; cursor: pointer;
}
.twinpage__testa-tasto:hover { background: var(--primary-soft); }
.twinpage__testa-tasto:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* La chat effimera lo dice, con la frase del server e non con una nostra. */
.twinpage__effimera {
  margin: 0; padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  font-size: 0.85rem; color: var(--muted);
}
.twinpage__effimera[hidden] { display: none; }

.twinpage__log { flex: 1; min-height: 0; }

/* --- L'allegato: l'anteprima sta SOPRA il campo, dove si scrive ------------- */
.twinpage__allegato {
  display: flex; align-items: center; gap: var(--space-3);
  margin: 0 14px; padding: 10px;
  border: 1px dashed var(--border); border-radius: var(--radius-control);
  background: var(--surface-2);
}
.twinpage__allegato[hidden] { display: none; }
.twinpage__allegato-img {
  flex-shrink: 0;
  width: 56px; height: 56px; object-fit: cover;
  border-radius: var(--radius-control); background: var(--surface-1);
}
.twinpage__allegato-corpo { flex: 1; min-width: 0; }
.twinpage__allegato-stato { margin: 0; font-size: 0.88rem; color: var(--text); overflow-wrap: anywhere; }
.twinpage__allegato-via {
  flex-shrink: 0; min-width: 44px; min-height: 44px;
  border: 1px solid var(--border); border-radius: var(--radius-control);
  background: var(--surface-1); color: var(--text); font-size: 1rem; cursor: pointer;
}
.twinpage__allegato-via:hover { background: var(--primary-soft); }
.twinpage__allegato-via:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* La foto mandata resta DENTRO la bolla: è parte della domanda, non un allegato a parte. */
.twinpage__miniatura {
  display: block; width: 100%; max-width: 220px;
  margin: 0 0 8px; border-radius: 12px;
  border: 1px solid var(--border);
}

/* --- Il composer ----------------------------------------------------------- */
.twinpage__composer {
  display: flex; gap: 8px; align-items: flex-end;
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--border);
  background: var(--surface-1);
}
/* Un solo bottone, due modi: sul telefono il sistema propone la fotocamera, sul portatile
   il file. Un `<label>` e non un bottone, perché è l'input file a fare il lavoro. */
.twinpage__foto {
  flex-shrink: 0;
  width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 50%;
  background: var(--surface-2); color: var(--accent-ink); cursor: pointer;
}
.twinpage__foto:hover { background: var(--primary-soft); border-color: var(--accent); }
.twinpage__foto svg { width: 20px; height: 20px; }
/* Il fuoco vive sull'input (che è `sr-only`), quindi il segno di fuoco va disegnato
   sull'etichetta: senza, chi naviga da tastiera non vede mai dove si trova. */
.twinpage__foto:has(:focus-visible), [data-twin-foto]:focus-visible + .twinpage__foto {
  outline: none; box-shadow: var(--focus-ring);
}
/* Il campo cresce con quello che ci si scrive (`twin-threads.js` misura l'altezza) e oltre
   il tetto scorre: `resize: none` perché la maniglia di ridimensionamento su un composer è
   un comando che non fa quello che sembra. */
.twinpage__input {
  resize: none; max-height: 168px;
  padding-top: 10px; padding-bottom: 10px;
  line-height: 1.45;
}
/* `.twin-chat__invia` è `display: inline-flex`, che batte il `display: none` che il browser
   dà a `[hidden]`: senza questa riga «Invia» e «Stop» sarebbero a schermo tutti e due. */
.twin-chat__invia[hidden] { display: none; }
/* «Stop» non è «Invia» dipinto d'altro colore: è un comando di segno OPPOSTO, e si legge —
   sulla pagina del Twin come nel pannello del lettore, che monta lo stesso motore. */
.twin-chat__stop {
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border);
}
.twin-chat__stop:hover { background: var(--primary-soft); }

.twinpage__vie { margin-top: 0; }

/* --- Sotto una risposta: i chip delle azioni, copia, rigenera --------------- */
/* Il chip di un'AZIONE non è uno spunto: apre una superficie che costa (una sessione vocale
   si paga al minuto, una generazione di esercizi è una chiamata). Si distingue, così il dito
   sa cosa sta per far partire — e parte sempre e solo dal dito. */
.twin-chip--azione { border-color: var(--accent); color: var(--accent-ink); font-weight: 600; }
.twin-chip--azione:hover { background: var(--primary-soft); }

.twinpage__barra { display: flex; flex-wrap: wrap; gap: var(--space-2); padding-left: 42px; }
.twinpage__barra-tasto {
  min-height: 36px; padding: 0 8px;
  border: none; background: none;
  font: inherit; font-size: 0.82rem; font-weight: 600;
  color: var(--muted); text-decoration: underline; cursor: pointer;
}
.twinpage__barra-tasto:hover { color: var(--text); }
.twinpage__barra-tasto:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-control); }
.twinpage__barra-tasto:disabled { opacity: 0.45; cursor: not-allowed; text-decoration: none; }

/* Una riga di servizio che invita ad aspettare non deve gridare come un guasto. */
.twin-chat__servizio--attesa { color: var(--muted); }

/* --- La carta del supporto: il 200 che NON è una risposta del Twin ---------- */
/* Su un segnale di autolesionismo il server instrada, non fa rispondere il Twin. Quindi qui
   NON c'è un avatar e NON c'è una bolla: è una scheda, e si vede che è un'altra cosa. */
.twinpage__supporto {
  align-self: stretch;
  padding: 14px 16px;
  border: 1px solid var(--accent); border-radius: var(--radius-card);
  background: var(--primary-soft); color: var(--text);
}
.twinpage__supporto-testo { margin: 0 0 10px; font-size: 1rem; line-height: 1.55; }
.twinpage__supporto-via {
  display: inline-flex; align-items: center; min-height: 44px;
  font-weight: 600; color: var(--accent-ink);
}

/* --- Da 1024px: la colonna esiste, e resta ---------------------------------- */
@media (min-width: 1024px) {
  /* FLEX E NON `grid-template-columns: 264px minmax(0,1fr)`, e non è una preferenza di stile:
     è un difetto misurato (collaudo avversariale del 24/8/2026, a 1280 px sulla pagina vera).
     `[hidden]` toglie la colonna dai grid item, e l'auto-placement metteva la CONVERSAZIONE
     nella prima traccia: `chat.width = 264px` con mille pixel di pagina vuoti a destra. Non
     era un caso di bordo — capitava SEMPRE al primo paint (la colonna nasce `hidden` e compare
     solo dopo `GET /threads`), PER SEMPRE al minore di 14 anni (chat effimera, colonna mai
     accesa) e PER SEMPRE se quella chiamata falliva. In flex una colonna che non c'è non
     lascia il proprio posto vuoto e non ruba quello dell'altra: la conversazione prende
     l'intera riga da sola, senza che nessuno debba dirglielo. */
  .twinpage { display: flex; align-items: stretch; }
  .twinpage__lato { flex: 0 0 264px; max-height: 74svh; }
  .twinpage__chat { flex: 1 1 auto; }
  /* Il pannello è una colonna permanente: aprirlo e chiuderlo non ha più senso. */
  .twinpage__apri-lato, .twinpage__chiudi-lato { display: none; }
}

/* --- Sotto 1024px: la colonna diventa un pannello che entra da sinistra ------ */
@media (max-width: 1023px) {
  .twinpage__lato {
    position: fixed; inset: 0 auto 0 0; z-index: var(--z-modal);
    width: min(320px, 86vw);
    border-radius: 0 var(--radius-card) var(--radius-card) 0;
    box-shadow: var(--shadow-l);
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform .18s ease, visibility .18s;
  }
  .twinpage__lato--aperto { transform: none; visibility: visible; }
  .twinpage__chat { height: 78svh; }
}

@media (max-width: 620px) {
  .twinpage__chat { border-radius: var(--radius-control); }
  .twinpage__testa { padding: 10px 12px; gap: var(--space-2); }
  /* SUL TELEFONO RESTA LA SOLA ICONA, MA IL NOME NO — quello resta per chi non la vede.
     Con `display: none` su questa parola il bottone perdeva il proprio nome accessibile:
     dentro c'era solo il glifo, che è `aria-hidden`, e axe lo segnalava come violazione
     CRITICA (WCAG 4.1.2, «button-name») — un comando senza nome per uno screen reader.
     Si nasconde alla vista con la tecnica di `.sr-only`, così il nome continua a nascere
     dal testo visibile su desktop e non da un `aria-label` duplicato che può divergere. */
  .twinpage__apri-lato span:last-child {
    position: absolute;
    width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
  }
  .twinpage__barra, .twinpage__azioni { padding-left: 0; }
  .twinpage__composer { padding: var(--space-3); }
  /* L'ultima riga poggia sul bordo: la tacca in basso dell'iPhone si scavalca qui. */
  .twinpage__vie { padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px)); }
}

/* LA BARRA IN BASSO OCCUPA SPAZIO VERO, e va tolto all'altezza della conversazione: senza,
   il campo di scrittura finisce SOTTO la barra — cioè il comando più usato della pagina
   coperto da una decorazione. Si lega alla barra vera e al suo scheletro di primo paint,
   che è la stessa coppia di condizioni della pillola del lettore. */
@media (max-width: 900px) {
  body.has-tabbar .twinpage__chat,
  :root.pre-tabbar body:not(.has-tabbar) .twinpage__chat {
    height: calc(78svh - var(--tabbar-h));
  }
}

@media (prefers-reduced-motion: reduce) {
  .twinpage__lato { transition: none; }
}

/* ====================================================================== */
/* I MIEI LIBRI — la sezione in Appunti, il selettore sulle tre superfici  */
/* e la card che dichiara le pagine usate (Art. 14 AI Act).                */
/*                                                                        */
/* Solo token: niente colore cablato. La card deve essere DISCRETA — è     */
/* un'informazione di servizio, non un annuncio: se gridasse, dopo tre     */
/* lezioni nessuno la leggerebbe più, e il giorno in cui il retrieval      */
/* sbaglia è esattamente la riga che va letta.                             */
/* ====================================================================== */

.libri { margin-bottom: 24px; }
.libri-testa {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.libri-testa__titolo { font-size: 1.1rem; margin: 0 0 2px; }
.libri-testa p { margin: 0; }
.libri-esito { margin: 0 0 10px; }
.libri-esito:empty { display: none; }
.libri-lista {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
  gap: 12px;
}
.libri-vuoto { margin: 0; }

.libri-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px;
  /* Stessa lingua delle card del drive (appunti.css `.card-tile`): due dialetti nella stessa
     pagina non sono «alla Classroom». Solo token, nessun colore cablato (§2.4). */
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  background: var(--surface-1);
  box-shadow: var(--shadow-s);
  transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
}
.libri-card:hover {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border-soft));
}
.libri-card__testa { display: flex; align-items: flex-start; gap: 10px; }
.libri-card__icona { font-size: 1.4rem; line-height: 1.2; }
.libri-card__titoli { flex: 1 1 auto; min-width: 0; }
/* Un titolo lungo NON deve spingere la card fuori dalla griglia sul telefono. */
.libri-card__titolo { margin: 0; font-size: 1rem; overflow-wrap: anywhere; }
.libri-card__materia { margin: 2px 0 0; }
/* Il menu ⋯ (Rinomina / Elimina): stesso bottone del drive, qui inline nella testa della card
   invece che assoluto sopra l'icona — la card libro non ha un riquadro icona a parte. */
.libri-card__menu {
  flex: 0 0 auto;
  width: 28px; height: 28px;
  border: 0; border-radius: var(--radius-control);
  background: none;
  color: var(--muted);
  font-size: 1rem;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background 120ms ease, color 120ms ease;
}
.libri-card__menu:hover { background: var(--surface-2); color: var(--text); }
.libri-card__menu:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.libri-card__stato { margin: 0; font-size: 0.88rem; color: var(--muted); }
.libri-card__stato.is-pronto { color: var(--color-success-ink); }
.libri-card__stato.is-parziale { color: var(--color-warning-ink); }
.libri-card__stato.is-errore { color: var(--color-danger); }

.libri-card__barra {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  overflow: hidden;
}
.libri-card__barra-riempimento {
  height: 100%;
  background: var(--gradient-accent);
  transition: width 0.4s ease;
}
@media (prefers-reduced-motion: reduce) {
  .libri-card__barra-riempimento { transition: none; }
}

.libri-card__progresso {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}
.libri-card__progresso-label { font-size: 0.85rem; color: var(--muted); }
.libri-card__progresso-input { width: 5.5rem; padding: 6px 8px; }

/* ── Il selettore: una riga, e solo se c'è almeno un libro ─────────────── */
.libro-scelta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}
.libro-scelta__label { font-size: 0.9rem; color: var(--muted); }
/* Bersaglio d'impatto >= 44px (WCAG 2.5.5 AAA / 2.5.8 AA): con `padding: 8px` il
   campo si fermava a 37, ed era l'unica cosa premibile di tutto il riquadro. */
.libro-scelta__select { max-width: min(100%, 320px); padding: 8px 10px; min-height: 44px; }

/* ── Il disclaimer del Twin: cosa diventa «argomento» con un libro scelto ──
   Compare SOLO a libro scelto, quindi non è rumore per chi non usa i libri: è la
   riga che spiega perché la stessa casella, da quel momento, fa un altro mestiere.
   Discreta come la card delle pagine — la faccia di Skoo basta a farla notare. */
.libro-nota {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-top: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  background: var(--surface-2);
}
.libro-nota[hidden] { display: none; }
.libro-nota__avatar { width: 30px; height: 30px; }
.libro-nota__testo { margin: 0; font-size: var(--text-sm); line-height: var(--lh-base); color: var(--muted); }

/* ── La card delle pagine dichiarate ──────────────────────────────────── */
.libro-carta {
  margin-top: 8px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-control);
  background: var(--surface-2);
}
.libro-carta[hidden] { display: none; }
/* «Non ho trovato» non è un errore rosso: è una risposta onesta, e si vede che è diversa. */
.libro-carta.is-miss { border-left-color: var(--color-warning); }
/* Una nota di servizio («il libro che avevi scelto adesso non c'è»): più quieta di un miss. */
.libro-carta.is-nota { border-left-color: var(--border); }
.libro-carta__testo { margin: 0 0 6px; font-size: 0.9rem; overflow-wrap: anywhere; }
.libro-carta__nota { margin: 0; }
/* Le azioni della card (§P4/§P5): «Non sono queste?» sul hit, le tre uscite sul miss. */
.libro-carta__azioni { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.libro-carta__azioni:empty { display: none; }
.libro-carta__cerca { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.libro-carta__cerca-input { flex: 1 1 180px; padding: 8px 10px; }
.libro-carta__esiti:empty { display: none; }
.libro-carta__lista { list-style: none; margin: 8px 0 0; padding: 0; }
.libro-carta__esito {
  padding: 6px 0;
  border-top: 1px solid var(--border);
  font-size: 0.85rem;
  overflow-wrap: anywhere;
}

/* I blocchi del 24/9 stanno QUI, prima del lettore e dell'header compatto: quei due devono
   restare in coda al file (lettore-ui.test.js legge l'ultimo prefers-reduced-motion,
   header-mobile.test.js conta le regole fuori dalle @media dopo il blocco dell'header). */
/* ======================================================================
   IL FOGLIO DEI PIANI ALL'AVVIO (dashboard studente, paywall-avvio.js — 24/9/2026).
   Facoltativo e chiudibile in quattro modi (X, «Continua gratis», Esc, clic fuori): su telefono
   sale dal basso come un foglio, da computer è una scheda al centro. Solo token, chiaro e scuro.
   ====================================================================== */
.paywall-avvio {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  background: var(--surface-1);
  color: var(--text);
  padding: 0;
  width: min(92vw, 460px);
  max-height: min(90dvh, 820px);
  overflow-y: auto;
  box-shadow: var(--shadow-l);
}
/* Il colore dello scrim sta accanto a quello del Twin (qui solo la sfocatura): vedi lì perché è scritto a mano. */
.paywall-avvio::backdrop { backdrop-filter: blur(3px); }
.paywall-avvio[open] { animation: paywall-avvio-entra 280ms cubic-bezier(0.22, 1, 0.36, 1); }
.paywall-avvio__foglio {
  position: relative;
  padding: var(--space-5) var(--space-5) var(--space-4);
  text-align: center;
  background:
    radial-gradient(120% 60% at 50% 0%, var(--accent-soft), transparent 70%),
    var(--surface-1);
}
.paywall-avvio__chiudi {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: 44px;
  height: 44px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--text);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
}
.paywall-avvio__chiudi:hover { background: var(--surface-1); }
.paywall-avvio__chiudi:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.paywall-avvio__skoo {
  display: block;
  width: 144px;
  height: 144px;
  margin: 0 auto var(--space-2);
}
.paywall-avvio__titolo { margin: 0; font-size: 1.35rem; line-height: 1.25; }
.paywall-avvio__sotto { margin: var(--space-2) auto 0; max-width: 36ch; color: var(--muted); font-size: 0.95rem; }
.paywall-avvio__inclusi {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
  display: grid;
  gap: var(--space-1);
  text-align: left;
  font-size: 0.9rem;
}
.paywall-avvio__inclusi li { position: relative; padding-left: 1.5em; }
.paywall-avvio__inclusi li::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--accent-ink);
  font-weight: 800;
}
.paywall-avvio__piani {
  border: 0;
  margin: var(--space-4) 0 0;
  padding: 0;
  display: grid;
  gap: var(--space-2);
  text-align: left;
}
.paywall-avvio__piano {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--space-3);
  align-items: start;
  padding: var(--space-3);
  border: 1.5px solid var(--border-soft);
  border-radius: var(--radius-control);
  background: var(--surface-1);
  cursor: pointer;
  transition: border-color 150ms ease, background-color 150ms ease;
}
.paywall-avvio__piano:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.paywall-avvio__piano:has(input:focus-visible) { box-shadow: var(--focus-ring); }
.paywall-avvio__radio { grid-row: span 2; margin-top: 3px; width: 18px; height: 18px; accent-color: var(--accent); }
.paywall-avvio__piano-testa { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.paywall-avvio__nome { font-weight: 700; }
.paywall-avvio__piano-testa .plan-pill { padding: 2px 8px; font-size: 0.75rem; }
.paywall-avvio__prezzo { margin-left: auto; font-weight: 800; font-variant-numeric: tabular-nums; }
.paywall-avvio__piano-corpo { display: grid; gap: 2px; font-size: 0.85rem; color: var(--muted); }
.paywall-avvio__azioni {
  position: sticky;
  bottom: 0;
  margin: var(--space-4) calc(-1 * var(--space-5)) calc(-1 * var(--space-4));
  padding: var(--space-3) var(--space-5) var(--space-4);
  background: var(--surface-1);
  border-top: 1px solid var(--border-soft);
}
.paywall-avvio__nota { margin: var(--space-2) 0 0; }
.paywall-avvio__errore { margin: var(--space-2) 0 0; color: var(--color-danger); }
.paywall-avvio__gratis { margin-top: var(--space-2); }
.paywall-avvio__tutti { display: inline-block; margin-top: var(--space-3); color: var(--accent-ink); }
@media (max-width: 600px) {
  .paywall-avvio {
    width: 100%;
    max-width: 100%;
    margin: auto 0 0;
    border-radius: var(--radius-card) var(--radius-card) 0 0;
    max-height: 92dvh;
  }
  .paywall-avvio[open] { animation-name: paywall-avvio-sale; }
  .paywall-avvio__foglio { padding: var(--space-4) var(--space-4) 0; }
  .paywall-avvio__azioni {
    margin: var(--space-4) calc(-1 * var(--space-4)) 0;
    padding: var(--space-3) var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom));
  }
  .paywall-avvio__skoo { width: 112px; height: 112px; }
}
@keyframes paywall-avvio-entra {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to { opacity: 1; transform: none; }
}
@keyframes paywall-avvio-sale {
  from { transform: translateY(100%); }
  to { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .paywall-avvio[open] { animation: none; }
  .paywall-avvio__piano { transition: none; }
}
/* Dall'app il foglio non nasce nemmeno (il modulo esce alla prima riga): questa è la cintura. */
.dal-app .paywall-avvio { display: none !important; }

/* La pagella in arrivo (orale.html, 24/9): dopo «Termina» il pannello dice che la sta scrivendo,
   invece di restare vuoto; se tarda, dice dove la troverà (realtime.js#inviaFineSessione). */
.rubric__attesa {
  margin: 0;
  color: var(--muted);
  font-weight: 600;
  animation: rubric-attesa-respiro 1.6s ease-in-out infinite;
}
.rubric__attesa--ritardo { animation: none; font-weight: 400; }
.rubric__attesa a { color: var(--accent-ink); font-weight: 600; }
@keyframes rubric-attesa-respiro {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.7; }
}
@media (prefers-reduced-motion: reduce) {
  .rubric__attesa { animation: none; }
}

/* «Ti è stata utile questa pagella?» (founder, 27/9): in riga sotto la pagella appena arrivata,
   sobria — due bottoni di pari peso da 44px, poi «Grazie.» e il campo facoltativo
   (lib/pagella-utile.js). Nessun dialogo, nessun colore d'allarme. */
.pagella-utile {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-soft);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.pagella-utile__domanda { margin: 0; font-weight: 600; color: var(--text); }
.pagella-utile__scelte { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.pagella-utile__scelta { flex: 1 1 120px; min-height: 44px; }
.pagella-utile__seguito { display: flex; flex-direction: column; gap: var(--space-2); }
.pagella-utile__seguito:empty { display: none; }
.pagella-utile__grazie { margin: 0; font-weight: 600; color: var(--text); }
.pagella-utile__grazie:focus { outline: none; }
.pagella-utile__commento { display: flex; flex-direction: column; gap: var(--space-2); }
.pagella-utile__etichetta { font-weight: 600; color: var(--text); }
.pagella-utile__campo { width: 100%; min-height: 88px; padding: var(--space-2) var(--space-3); resize: vertical; }
.pagella-utile__aiuto { margin: 0; font-size: 0.85rem; color: var(--muted); }
.pagella-utile__invia { align-self: flex-start; min-height: 44px; }
.pagella-utile__avviso { margin: 0; font-size: 0.92rem; color: var(--text); }
.pagella-utile__avviso:empty { display: none; }

/* IL MESSAGGIO DI SOSTEGNO (revisione di sicurezza, 27/9): in cima alla sezione della sessione di
   orale.html e tutor.html, quando `session/end` porta un segnale di disagio (lib/sostegno-voce.js).
   La regione (`role="alert"`) esiste vuota dalla nascita della pagina e NON si nasconde — una
   regione viva spenta e riaccesa non sempre si annuncia —: vuota non ha regole, quindi non occupa
   spazio. Col messaggio ha l'aspetto della card dell'app (support-card.tsx): fondo tinto d'avviso,
   bordo, cuore. Nessun bottone: non si chiude. */
.sostegno-voce--attivo {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  padding: var(--space-4);
  border-radius: var(--radius-card);
  border: 1px solid color-mix(in srgb, var(--color-warning) 45%, transparent);
  background: color-mix(in srgb, var(--color-warning) 10%, var(--surface-1));
  color: var(--text);
}
.sostegno-voce__icona { flex: none; font-size: 1.5rem; line-height: 1.2; color: var(--color-warning-ink); }
.sostegno-voce__testo { margin: 0; font-size: 1.05rem; line-height: 1.55; font-weight: 500; color: var(--text); }

/* «Lascia una recensione» nel profilo dello studente (24/9): due link discreti agli store.
   Dall'app (`?app=1`) mai: stessa cintura della navigazione del sito. */
.profile-recensione-link { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; white-space: nowrap; }
.profile-recensione-link a { color: var(--accent-ink); font-weight: 600; }
.dal-app #recensione-row {
  display: none !important;
}

/* Le regole delle pagine d'accesso stanno in assets/css/accesso.css (caricato solo da login,
 registrazione, password dimenticata e nuova password). */


/* ═══════════════════════════════════════════════════════════════════════════
   IL LETTORE — il libro aperto, e il Twin accanto (RAG v2 §D6)
   ═══════════════════════════════════════════════════════════════════════════
   Tre vincoli di UX che qui sono regole di CSS, non intenzioni:

   · NIENTE SALTI. Il foglio ha un'altezza sua dal primo paint, e l'immagine ci
     sta dentro con `object-fit: contain`. Lo scheletro e la pagina vera
     occupano lo stesso spazio: quando il JPEG arriva non si muove una riga. Un
     lettore che sobbalza a ogni pagina girata è illeggibile.
   · LA CHAT NON COPRE MAI LA PAGINA SU DESKTOP. Da 1024px in su il corpo è una
     griglia a due colonne e il pannello è la seconda: si affianca, non si
     sovrappone. Sotto, dove una colonna non ci sta, diventa un foglio che sale
     dal basso — con la maniglia per rimandarlo giù.
   · BERSAGLI DA 44px E FUOCO VISIBILE ovunque, comandi e strip compresi: si usa
     col pollice su un telefono e con il Tab su una tastiera.
   Solo token: nessun colore scritto a mano. */
.page--lettore { padding-block: var(--space-4) var(--space-7); }

.lettore { max-width: 1400px; margin-inline: auto; padding-inline: var(--space-4); }
.lettore-vuoto { padding: var(--space-6) 0; }

.lettore__testa {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  padding-bottom: var(--space-3);
}
.lettore__chi { flex: 1; min-width: 180px; }
.lettore__titolo { margin: 0; font-size: 1.15rem; line-height: 1.3; }
.lettore__materia { margin: 2px 0 0; }
.lettore__azioni { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.lettore__segnalibro { margin: 0 0 var(--space-3); }

.lettore__corpo { display: grid; gap: var(--space-4); align-items: start; }

/* --- Il foglio ----------------------------------------------------------- */
.lettore__pagina { min-width: 0; }
.lettore-foglio {
  --lettore-zoom: 1;
  --lettore-h: min(70vh, 760px);
  position: relative;
  height: var(--lettore-h);
  display: flex; align-items: center; justify-content: center;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface-2);
  box-shadow: var(--shadow-s);
}
.lettore-foglio.is-zoom { justify-content: flex-start; align-items: flex-start; }
.lettore-foglio__img {
  display: block;
  max-width: 100%; max-height: 100%;
  width: auto; height: auto;
  object-fit: contain;
  transition: height 140ms ease;
}
/* LO ZOOM CRESCE LA SCATOLA, non la disegna più grande. Un `transform: scale()` non entra nel
   layout: l'immagine sarebbe ingrandita e il contenitore non avrebbe nulla da scorrere, cioè si
   vedrebbe solo il centro della pagina e il resto sarebbe irraggiungibile. Con l'altezza vera
   l'`overflow: auto` qui sopra fa il suo mestiere e la pagina si esplora davvero. */
.lettore-foglio.is-zoom .lettore-foglio__img {
  max-width: none; max-height: none;
  width: auto; height: calc(var(--lettore-h) * var(--lettore-zoom));
}
.lettore-foglio.is-vuoto { flex-direction: column; gap: var(--space-3); padding: var(--space-5); text-align: center; }
.lettore-foglio__riga { margin: 0; max-width: 46ch; }
/* Lo scheletro tiene la FORMA di un foglio, non un rettangolo qualunque: chi
   guarda capisce che sta arrivando una pagina, non un errore. */
.lettore-foglio__scheletro {
  width: min(100%, 54vh);
  height: 100%;
  border-radius: var(--radius-control);
  background: linear-gradient(100deg, var(--surface-1) 30%, var(--primary-soft) 50%, var(--surface-1) 70%);
  background-size: 300% 100%;
  animation: lettore-attesa 1.4s ease-in-out infinite;
}
@keyframes lettore-attesa { from { background-position: 100% 0; } to { background-position: 0 0; } }

/* --- I comandi ----------------------------------------------------------- */
.lettore__comandi {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
  gap: var(--space-2);
  padding: var(--space-3) 0 var(--space-1);
}
.lettore__tasto {
  min-width: 44px; min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: var(--radius-control);
  background: var(--surface-1); color: var(--text);
  font-size: 1.05rem; cursor: pointer;
}
.lettore__tasto:hover:not(:disabled) { background: var(--primary-soft); border-color: var(--accent); }
.lettore__tasto:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.lettore__tasto:disabled { opacity: 0.4; cursor: not-allowed; }
.lettore__salto { display: flex; align-items: center; gap: var(--space-2); }
.lettore__numero { width: 5.5rem; min-height: 44px; text-align: center; border-radius: var(--radius-control); }
.lettore__dove { white-space: nowrap; }
.lettore__zoom { display: inline-flex; gap: var(--space-2); }
.lettore__onesta { margin: 0 0 var(--space-3); text-align: center; }

/* --- La strip ------------------------------------------------------------ */
.lettore-strip {
  display: flex; gap: var(--space-2);
  overflow-x: auto; overscroll-behavior-x: contain;
  padding: var(--space-2) 0 var(--space-3);
  scrollbar-width: thin;
}
.lettore-strip__voce {
  position: relative; flex: 0 0 auto;
  width: 52px; min-height: 72px;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding: 0 0 2px;
  overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--radius-control);
  background: var(--surface-2); color: var(--muted);
  font-size: 0.78rem; cursor: pointer;
}
.lettore-strip__voce:hover { border-color: var(--accent); }
.lettore-strip__voce:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.lettore-strip__voce.is-attiva { border-color: var(--accent); color: var(--text); font-weight: 600; }
.lettore-strip__mini { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.85; }
.lettore-strip__num {
  position: relative;
  padding: 1px 6px; border-radius: var(--radius-pill);
  background: var(--surface-1);
}

/* --- Il Twin ------------------------------------------------------------- */
/* Il bottone flottante: sta sopra il pollice, non sopra la pagina. */
.lettore-twin__apri {
  position: fixed; right: var(--space-4);
  bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
  z-index: var(--z-popover);
  display: inline-flex; align-items: center; gap: var(--space-2);
  min-height: 48px; padding: 6px 16px 6px 6px;
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--card); color: var(--text);
  box-shadow: var(--shadow-l); cursor: pointer;
}
.lettore-twin__apri:hover { background: var(--primary-soft); }
.lettore-twin__apri:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.lettore-twin__apri-testo { font-weight: 600; font-size: 0.95rem; }
/* A PANNELLO APERTO LA PILLOLA NON ESISTE — a ogni larghezza, e questa riga è stata a lungo
   solo dentro la finestra del telefono. Su desktop il pannello è la seconda colonna in
   `position: sticky` (che crea un contesto di impilamento a z=0) mentre la pillola è
   `z-index: var(--z-popover)`: dipingeva SOPRA il pannello, e precisamente sugli ultimi ~40px,
   cioè sulla riga del campo e sul tondo «invia». La chat che copre il proprio comando di invio
   è la stessa promessa rotta di «la chat non copre mai la pagina», in miniatura. Chiudere si
   chiude col ✕, con Esc e — sul telefono — con la strisciata. */
body.ha-twin-aperto .lettore-twin__apri { display: none; }
/* SOPRA LA BARRA, ma solo dove la barra c'è davvero. `var(--tabbar-h, 0px)` non cadeva MAI sul
   suo fallback — `--tabbar-h: 62px` è definita su `:root`, non su `body.has-tabbar` — quindi
   la pillola galleggiava 78px sopra il bordo anche dove barra non ce n'è (desktop stretto).
   Il rialzo si lega alla barra vera e al suo scheletro di primo paint: nessuna delle due
   esiste sopra i 900px, ed è esattamente la finestra di questa regola. */
@media (max-width: 900px) {
  body.has-tabbar .lettore-twin__apri,
  :root.pre-tabbar body:not(.has-tabbar) .lettore-twin__apri {
    bottom: calc(var(--space-4) + var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
  }
}

.lettore-twin {
  display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: var(--radius-card);
  background: var(--card); color: var(--text);
  overflow: hidden;
}
.lettore-twin[hidden] { display: none; }
.lettore-twin__maniglia { display: none; }
.lettore-twin .twin-chat__log { min-height: 220px; }
.lettore-twin__orale { display: flex; flex-direction: column; gap: 6px; padding: 0 14px 10px; }
.lettore-twin__orale-label { font-size: 0.85rem; color: var(--muted); }
.lettore-twin__orale-riga { display: flex; gap: var(--space-2); }

/* Da 1024px il pannello è una COLONNA accanto al foglio: la pagina resta intera.
   `:has()` non è una comodità — è ciò che permette alla colonna di NON esistere
   quando il Twin è chiuso, senza una classe da tenere in sincrono in due file.
   Dove `:has()` non c'è, il pannello resta sotto al foglio: si legge lo stesso. */
@media (min-width: 1024px) {
  .lettore__corpo:has(.lettore-twin:not([hidden])) { grid-template-columns: minmax(0, 1fr) 380px; }
  .lettore-twin { position: sticky; top: var(--space-4); max-height: calc(100vh - var(--space-7)); }
  .lettore-twin__apri { bottom: var(--space-5); }
}

/* Sotto i 1024px il pannello sale dal basso e si ritrae con una strisciata. */
@media (max-width: 1023px) {
  .lettore-twin {
    position: fixed; inset: auto 0 0 0; z-index: var(--z-modal);
    max-height: 82vh;
    border-radius: var(--radius-card) var(--radius-card) 0 0;
    box-shadow: var(--shadow-l);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    animation: lettore-sale 200ms ease both;
  }
  /* LA MANIGLIA È UN BERSAGLIO, non una decorazione. La barretta che si vede resta alta 4px —
     è un segno, non un comando — ma la fascia che accetta il pollice è alta 44px come ogni
     altro comando di questa pagina. Prima il gesto di chiusura era agganciato ESATTAMENTE a
     quei 4 pixel: dichiarato nel report e, sul telefono, irraggiungibile. La strisciata ora
     prende anche l'intestazione del foglio (lettore.js), che è il posto dove la mano va da
     sola; `touch-action: none` perché su questa fascia il dito trascina il foglio, non scorre
     la pagina sotto. */
  .lettore-twin__maniglia {
    display: block; flex: 0 0 auto;
    min-height: 44px; margin: 0;
    touch-action: none; cursor: grab;
  }
  .lettore-twin__maniglia::before {
    content: ""; display: block;
    width: 44px; height: 4px; margin: 20px auto 0;
    border-radius: var(--radius-pill); background: var(--border);
  }
  /* Stessa fascia, stesso gesto: l'intestazione è la presa naturale del foglio. */
  .lettore-twin .twin-chat__testa { touch-action: none; cursor: grab; }
  .lettore-twin .twin-chat__testa button { cursor: pointer; touch-action: manipulation; }
  .lettore-twin .twin-chat__log { min-height: 180px; }
}
@keyframes lettore-sale { from { transform: translateY(16px); opacity: 0; } to { transform: none; opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .lettore-foglio__scheletro { animation: none; }
  .lettore-foglio__img { transition: none; }
  .lettore-twin { animation: none; }
}

/* ============================================================================
   `/prova` — LA LANDING DELLA CAMPAGNA (onda 6, 2026-08-23)
   ----------------------------------------------------------------------------
   Una colonna sola, larga quanto un pollice, senza niente che si muova. Le tre
   scelte che valgono più di tutte le altre messe insieme:

   1. NIENTE ANIMAZIONI. Chi arriva qui ha visto otto secondi di video e ha già
      il pollice sullo schermo: ogni transizione è tempo tolto alla lettura, e
      ogni elemento che entra «con grazia» è un layout che salta (CLS) mentre
      qualcuno sta per toccare la CTA. Il collaudo misura CLS ≤ 0,1: qui non si
      anima nulla, ed è per quello che ci sta.
   2. LA CTA È SEMPRE LA STESSA, e sempre larga quanto lo schermo. Tre occasioni
      di toccarla, una sola azione possibile.
   3. SOLO TOKEN. Nessun colore scritto a mano: la landing eredita chiaro e
      scuro dal resto del sito senza una riga di JS.
   ========================================================================= */
body.prova {
  background: var(--bg0);
  color: var(--text);
}
.prova-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 20px;
  max-width: 560px;
  margin: 0 auto;
}
.prova-top__accedi {
  color: var(--accent-ink);
  font-weight: 600;
  text-decoration: none;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.prova main {
  max-width: 560px;
  margin: 0 auto;
  padding: 0 20px 40px;
}
.prova-hero { padding: 8px 0 28px; }
.prova-hero__occhiello {
  color: var(--muted);
  font-weight: 600;
  margin: 0 0 6px;
}
.prova-hero__titolo {
  font-size: clamp(30px, 9vw, 44px);
  line-height: 1.1;
  margin: 0 0 12px;
}
.prova-hero__sub {
  font-size: 17px;
  line-height: 1.5;
  margin: 0 0 20px;
}
.prova-hero__patto { margin: 10px 0 0; color: var(--muted); }
.prova-hero__nota { margin: 4px 0 0; color: var(--dim); font-size: 14px; }
/* La CTA: piena, alta, toccabile. 52px è la misura comoda per un pollice, non
   il minimo accessibile — il minimo (44px) qui sarebbe un risparmio miserabile. */
.prova-cta {
  display: block;
  width: 100%;
  min-height: 52px;
  line-height: 52px;
  padding: 0 20px;
  text-align: center;
  font-size: 17px;
  font-weight: 700;
  border-radius: var(--radius-pill);
}
.prova-sezione, .prova-prezzo, .prova-demo, .prova-chiusura {
  padding: 26px 0;
  border-top: 1px solid var(--border);
}
.prova-sezione h2, .prova-prezzo h2, .prova-demo h2 {
  font-size: clamp(22px, 6vw, 28px);
  line-height: 1.2;
  margin: 0 0 12px;
}
.prova-sezione p, .prova-prezzo p { margin: 0 0 12px; line-height: 1.5; }
.prova-lista, .prova-passi { margin: 0; padding-left: 22px; line-height: 1.6; }
.prova-lista { list-style: none; padding-left: 0; }
.prova-lista li { padding: 8px 0; border-bottom: 1px solid var(--border); }
.prova-lista li:last-child { border-bottom: 0; }
.prova-prezzo h2 { font-size: clamp(26px, 7.5vw, 34px); }
.prova-secondario { color: var(--accent-ink); }
.prova-faq { margin: 0; }
.prova-faq dt { font-weight: 700; margin-top: 14px; }
.prova-faq dd { margin: 4px 0 0; color: var(--muted); line-height: 1.5; }
.prova-voce { margin: 0 0 16px; padding: 0 0 0 14px; border-left: 3px solid var(--primary-soft); }
.prova-voce p { margin: 0 0 4px; }
.prova-voce cite { color: var(--muted); font-size: 14px; font-style: normal; }
/* Lo spazio del video è RISERVATO dal contenitore, non conquistato dal video quando
   arriva: il giorno in cui la registrazione esisterà, comparirà dentro una scatola
   che ha già la sua altezza. Un video che si «apre» spinge in giù la CTA proprio
   mentre qualcuno la sta toccando. */
.prova-demo [data-prova-video] {
  aspect-ratio: 9 / 16;
  max-height: 62vh;
  margin: 0 auto;
  background: var(--bg2);
  border-radius: var(--radius-card);
  overflow: hidden;
}
.prova-demo video { width: 100%; height: 100%; object-fit: cover; display: block; }
.prova-piccolo { color: var(--muted); font-size: 14px; margin: 10px 0 0; }
.prova-chiusura { border-top: 1px solid var(--border); }
.prova-footer {
  max-width: 560px;
  margin: 0 auto;
  padding: 24px 20px 40px;
  text-align: center;
}
.prova-footer a { color: var(--muted); }

/* ============================================================================
   REGISTRAZIONE IN DUE PASSI + «SU COSA TI INTERROGO?» (onda 6, 2026-08-23)

   Tre pezzi, tutti sobri di proposito: sono superfici di decisione, non di
   racconto. Nessun colore cablato — solo i token di `:root`, così il tema
   scuro arriva gratis e il contrasto resta quello già verificato AA.
   ========================================================================= */

/* Il conta-passi: dice DOVE si è, e la via di ritorno sta sulla stessa riga. */
.passo__conta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin: 0 0 4px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.passo__indietro {
  background: none;
  border: 0;
  padding: 4px 0;
  color: var(--accent-ink, var(--accent));
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
}
.passo__indietro:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 6px; }

/* (L'indicatore a barra `.forza` è stato sostituito il 25/9/2026 dalla lista viva delle regole,
   `.regole`, in assets/css/accesso.css.) */
/* Il codice promo: in fondo, chiuso, e che non sembri un campo obbligatorio. */
.codice { margin: 8px 0; }
.codice > summary {
  cursor: pointer;
  padding: 10px 0;
  /* Nell'accento del marchio e non in `--muted`: e' un COMANDO, non una nota a pie' di
     pagina. Richiesta founder («la voce hai un codice, in blu, che si apre»), e la ragione
     e' che chi cerca quel campo lo cerca a colpo d'occhio: grigio su bianco non si trova.
     Token e non colore scritto a mano, cosi' regge anche il tema scuro senza una
     seconda regola. (E l'esadecimale NON si scrive nemmeno qui: `lettore-ui.test.js`
     scandisce il testo grezzo di questo blocco, commenti compresi, e fa bene — un
     colore documentato e' un colore che prima o poi qualcuno incolla.) */
  color: var(--accent);
  font-size: 14px;
  font-weight: 600;
}
.codice > summary:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 8px; }
.codice[open] > summary { color: var(--text); }

/* «Su cosa ti interrogo?»: una domanda sola, e tre modi per rispondere. */
.primo__card { display: grid; gap: 12px; max-width: 560px; margin: 0 auto; }
.primo__titolo { margin: 0; font-size: clamp(24px, 5vw, 32px); line-height: 1.15; }
.primo__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.primo__chip {
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  border-radius: var(--radius-pill);
  padding: 10px 16px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  /* 44px di bersaglio anche dove il testo è corto: è un controllo da pollice. */
  min-height: 44px;
}
.primo__chip[aria-pressed="true"] {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-ink, var(--accent));
}
.primo__chip:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.primo__card .input[aria-invalid="true"] { border-color: var(--color-danger); }

/* IL MODULO DI SUPPORTO (`support.html`) — il campo esca per i robot, e l'esito del l'invio. */
.esca { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
#supporto-esito[data-tono="ok"] { color: var(--color-success); }
#supporto-esito[data-tono="ko"] { color: var(--color-danger); }

/* ============================================================================
   HEADER COMPATTO ≤900px + UNA BARRA SOLA IN BASSO (founder, 2026-08-09, v3).
   La striscia in alto (riga 2) è MORTA: duplicava la tab bar. Sotto i 900px
   l'header è UNA riga sola — logo + identità (chip avatar per i loggati,
   Login+Registrati per lo sloggato) — e TUTTA la navigazione vive nella barra
   in basso (§ NAVIGAZIONE 2026, punto 2), per ogni ruolo e per lo sloggato, con
   l'hub «S» al centro. Niente panino, niente striscia, niente pannello: la
   navigazione è sempre in vista e a portata di pollice.

   Lo `scroll-margin-top` degli alert di form resta a 120px in loco (~7148): un
   header a una riga è più basso, ma il valore già copre il caso peggiore.

   DESKTOP ≥901px: non sfiorato. Tutto sta dentro @media (max-width: …).
   ============================================================================ */

@media (max-width: 900px) {
  /* 0. IL PANINO NON ESISTE. initNavbar rimuove il nodo dal DOM; questa regola
     evita anche il lampo pre-idratazione del bottone nell'HTML statico. */
  .nav-toggle { display: none; }

  /* 1. HEADER A UNA RIGA — 56px: bersaglio 44 + 6px sopra e sotto. Vale su OGNI
     pagina ≤900px (non più solo dove c'era la striscia). */
  .navbar .navbar__inner {
    flex-wrap: nowrap;
    min-height: 0;
    gap: var(--space-3);
    padding: 6px var(--space-4);
  }
  .navbar .navbar__brand { margin-right: auto; min-width: 0; flex-shrink: 1; }
  .navbar .navbar__brand .navbar__logo img {
    max-width: 34vw;
    object-fit: contain;
    object-position: left center;
  }

  /* Le azioni stanno in riga 1 su OGNI pagina, con e senza striscia: neutralizza
     il legacy «a tutta riga sotto la barra» (~482 e ~3172), nato quando le voci
     andavano a capo. */
  .navbar .navbar__right {
    display: inline-flex;
    order: 0;
    align-items: center;
    justify-content: flex-end;
    width: auto;
    gap: var(--space-2);
    margin: 0 0 0 auto;
    flex-shrink: 0;
  }
  .navbar .navbar__inner .navbar__actions { width: auto; }

  /* Chip avatar: cerchio da 36px dentro un bersaglio da dito ≥44px (WCAG 2.5.5).
     Il minimo 44 del blocco touch-target (~3086) sta sul LINK, non sul cerchio. */
  .navbar .navbar__inner .nav-profile-link { min-height: 44px; gap: var(--space-2); }
  .navbar .navbar__inner .nav-avatar--auto {
    width: 36px;
    height: 36px;
    min-width: 36px;
    min-height: 36px;
    font-size: var(--text-sm);
  }

  /* Bottoni da sloggato: stretti di padding, MAI di altezza (i 44px restano). */
  .navbar .navbar__inner .navbar__actions .btn {
    padding: 8px 12px;
    font-size: var(--text-sm);
  }

  /* Il pill «Feedback» del desktop non sta in riga 1: la voce vive nel Profilo. */
  .navbar #sk-fb-navlink { display: none; }
}

/* 3. Sotto i 520px il nome accanto all'avatar è già nascosto (~6110): il chip
   diventa un tondo, e il tondo vuole essere quadrato e centrato. */
@media (max-width: 520px) {
  .navbar .navbar__inner .nav-profile-link {
    padding: 4px;
    min-width: 44px;
    justify-content: center;
  }
}

/* 4. Sotto i 360px logo + Login + Registrati: si stringe il contorno (wordmark
   più corto, padding più sottile), mai il bersaglio da dito. */
@media (max-width: 360px) {
  .navbar .navbar__inner .navbar__actions .btn { padding: 8px 10px; }
  .navbar .navbar__brand .navbar__logo img { max-width: 26vw; }
}

/* ============================================================================
   ANTI-FLASH DI SESSIONE (founder, 2026-08-09 01:20). Tra una pagina e l'altra
   la navbar statica mostrava «Login/Registrati» per un attimo anche ai loggati,
   finché renderNavAuth non costruiva il chip. nav-state.js (render-blocking nel
   <head>) marca :root.is-authed PRIMA del primo paint: i bottoni pubblici non
   si vedono mai; il chip arriva con l'idratazione sullo stesso posto.
   ============================================================================ */
:root.is-authed .navbar__actions > a.btn[href="/login.html"],
:root.is-authed .navbar__actions > a.btn[href="/register.html"] { display: none; }

/* ============================================================================
   LA BARRA C'È GIÀ AL PRIMO FOTOGRAMMA (founder, 2026-08-09: «la navbar non deve
   apparire dopo il refresh ma esserci sempre»). La barra vera la costruisce
   tabbar.js, quindi per un istante non c'era e il fondo pagina saltava di ~72px.
   nav-state.js — render-blocking nel <head> — marca :root.pre-tabbar prima del
   primo paint: qui si riserva lo spazio e si disegna uno SCHELETRO identico per
   forma, posizione e vetro. Quando tabbar.js monta quella vera (body.has-tabbar)
   lo scheletro si spegne nello stesso fotogramma: nessun salto, nessun lampo.
   ============================================================================ */
@media (max-width: 900px) {
  /* Lo spazio in fondo è riservato SUBITO, non a idratazione avvenuta. */
  :root.pre-tabbar body { padding-bottom: calc(var(--tabbar-h) + 22px + env(safe-area-inset-bottom, 0px)); }

  :root.pre-tabbar body:not(.has-tabbar)::after {
    content: "";
    position: fixed;
    z-index: var(--z-nav);
    left: max(var(--tabbar-orlo), env(safe-area-inset-left, 0px));
    right: max(var(--tabbar-orlo), env(safe-area-inset-right, 0px));
    bottom: calc(var(--tabbar-orlo) + env(safe-area-inset-bottom, 0px));
    max-width: 460px;
    margin-inline: auto;
    height: var(--tabbar-h);
    border: 1px solid var(--nav-line);
    border-radius: 22px;
    background: var(--bg1);
    box-shadow: var(--shadow-l);
    pointer-events: none; /* è un disegno, non un controllo: non intercetta i tocchi */
  }
  @supports ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
    :root.pre-tabbar body:not(.has-tabbar)::after {
      background: var(--nav-glass);
      -webkit-backdrop-filter: saturate(160%) blur(20px);
      backdrop-filter: saturate(160%) blur(20px);
    }
  }
}

/* Pagine legali aperte DALL'APP (`?app=1`) — App Store 3.1.1.
   Da Termini e Privacy, che l'app apre accanto al prezzo per obbligo 3.1.2, non si deve poter
   raggiungere il checkout web: si toglie la navigazione del sito e resta il testo legale.
   `!important` è deliberato: queste regole devono vincere su qualunque stile che navbar e
   tabbar si applicano da sole dopo essere state costruite. */
.dal-app .navbar,
.dal-app .tabbar,
.dal-app .footer__links {
  display: none !important;
}

/* Il link a "pagina prezzi" dentro il corpo di terms.html (§4) — la via che le tre regole
   sopra non coprivano (review avversariale, 1/9): non è navigazione, è prosa, quindi
   `display:none` da solo avrebbe spezzato la frase. Stessa tecnica delle regole sopra —
   pura CSS, nessun JS, nessuna finestra di cache fredda — ma con DUE varianti del testo
   invece di una: quella collegata (default, per il sito) e quella in prosa (default nascosta
   con l'attributo `hidden`, per l'app). La classe `.dal-app` è già su <html> PRIMA che il
   parser arrivi a leggere questo paragrafo (nav-state.js, sincrono, capo del <head>): il
   motore CSS applica la regola giusta al primo render, senza che l'una compaia mai insieme
   all'altra. */
.dal-app .link-prezzi-web {
  display: none !important;
}
.dal-app .link-prezzi-app {
  display: inline !important;
}
