:root {
  /* Palette allineata a Volleyball_AI_app/wwwroot/css/palette.css */
  --navy: #052767;
  --navy-hover: #0a2d7a;
  --navy-mid: #243761;
  --navy-dark: #121d35;
  --blue: #3b82f6;
  --blue-hover: #2563eb;
  --blue-light: #7baaf7;
  --orange: #e8720c;
  --orange-hover: #b85a09;
  --grey-50: #f5f7fc;
  --grey-200: #e3e6ec;
  --grey-600: #5b6472;
  --text: #1a1f2b;
  --radius: 12px;
  --max-width: 1140px;
}

/* Toglie il rettangolo blu che Safari/Chrome mobile disegnano brevemente su qualunque elemento
   "tappabile" (bottoni, ma anche i <g> SVG con un click handler come le frecce di direzione o le
   traiettorie) — un evidenziatore di sistema pensato per link/bottoni nativi, non per grafici
   interattivi con già un proprio stato hover/attivo via CSS. Va su "*" (non solo html/body)
   perché il supporto a questa proprietà, storicamente non standard, non la eredita in modo
   affidabile sugli elementi discendenti in tutti i browser. */
* { -webkit-tap-highlight-color: transparent; }

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
  color: var(--text);
  background: #fff;
  line-height: 1.55;
}

img { max-width: 100%; display: block; }

a { color: inherit; }

.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 24px;
}

/* Header */
header {
  background: #fff;
  color: var(--text);
  border-bottom: 1px solid var(--grey-200);
  box-shadow: 0 1px 3px rgba(5, 39, 103, 0.06);
  position: sticky;
  top: 0;
  z-index: 50;
}

header.header-reveal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  transform: translateY(-100%);
  opacity: 0;
  transition: transform 0.35s ease, opacity 0.35s ease;
}

header.header-reveal.is-visible {
  transform: translateY(0);
  opacity: 1;
}

/* Toggle da JS (mvRevealBtn in js/main.js, sezione "Rimozione dei tempi morti" da telefono):
   nasconde la toolbar anche se .is-visible è presente (scroll oltre l'hero) — stessa specificità
   di quella regola, ma dichiarata dopo, quindi vince quando entrambe le classi sono presenti. */
header.header-reveal.header-force-hidden {
  transform: translateY(-100%);
  opacity: 0;
}

/* Indicatore verticale dei container della pagina principale (solo da PC, vedi index.html): un
   cerchio numerato per ogni ".screen-section", impilati uno sopra l'altro, centrati verticalmente
   nello schermo e uniti da una linea (::before, dietro ai cerchi). Nascosto da telefono nel
   blocco @media più sotto, e da JS (classe is-hidden) mentre si è ancora sulla hero, che non ha
   un cerchio proprio (vedi commento su updatePageDots in js/main.js). z-index sotto l'header (50),
   che comunque non lo sovrappone mai (l'header sta in alto, i cerchi restano centrati a sinistra). */
.page-dots {
  position: fixed;
  left: 28px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  opacity: 1;
  transition: opacity 0.35s ease;
}

.page-dots.is-hidden {
  opacity: 0;
  pointer-events: none;
}

/* Linea che unisce i cerchi: NON deve attraversarli, solo i tratti liberi tra un cerchio e il
   successivo. Un singolo elemento (::before, alto quanto tutta la colonna) con un
   repeating-linear-gradient invece di un colore pieno: ogni periodo di 44px (30px di diametro
   cerchio + 14px di gap, gli stessi valori di .page-dot/gap qui sopra) è trasparente per i primi
   30px (dove cade un cerchio) e colorato per i restanti 14px (il vuoto fino al cerchio dopo) — dato
   che il primo cerchio parte esattamente da top:0 (nessun padding sopra, solo gap tra i figli),
   il pattern si allinea da solo ad ogni cerchio senza bisogno di calcolarne la posizione via JS. */
.page-dots::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  transform: translateX(-50%);
  background: repeating-linear-gradient(
    to bottom,
    transparent 0px,
    transparent 30px,
    rgba(5, 39, 103, 0.25) 30px,
    rgba(5, 39, 103, 0.25) 44px
  );
}

.page-dot {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 2px solid var(--navy);
  background: rgba(255, 255, 255, 0.85);
  color: var(--navy);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  opacity: 0.25;
  transition: opacity 0.25s ease, transform 0.25s ease, background 0.25s ease, color 0.25s ease;
}

.page-dot:hover {
  opacity: 1;
}

/* I due cerchi adiacenti a quello selezionato — vedi updatePageDots in js/main.js. */
.page-dot.is-near {
  opacity: 0.5;
}

.page-dot.is-active {
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
  opacity: 0.75;
  transform: scale(1.15);
}

.navbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 24px;
  max-width: var(--max-width);
  margin: 0 auto;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  font-size: 1.2rem;
  text-decoration: none;
  color: var(--navy);
}

.brand-logo {
  height: 44px;
  width: auto;
  display: block;
}

nav.nav-links {
  display: flex;
  align-items: center;
  gap: 28px;
}

nav.nav-links a {
  text-decoration: none;
  color: var(--grey-600);
  font-weight: 500;
  font-size: 0.95rem;
  transition: color 0.15s;
}

nav.nav-links a:hover,
nav.nav-links a.active {
  color: var(--navy);
}

nav.nav-links a.btn-primary,
nav.nav-links a.btn-primary:hover {
  color: #fff;
}

.btn {
  display: inline-block;
  padding: 11px 22px;
  border-radius: 8px;
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  text-align: center;
  border: none;
  cursor: pointer;
  transition: transform 0.15s, box-shadow 0.15s, background 0.15s;
}

.btn-primary {
  background: var(--blue);
  color: #fff;
  box-shadow: 0 4px 14px rgba(59, 130, 246, 0.35);
}

.btn-primary:hover {
  background: var(--blue-hover);
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(59, 130, 246, 0.45);
}

.btn-ghost {
  background: transparent;
  color: var(--navy);
  border: 1px solid var(--grey-200);
}

.btn-ghost:hover {
  background: var(--grey-50);
}

.menu-toggle {
  display: none;
  background: none;
  border: none;
  color: var(--navy);
  font-size: 1.6rem;
  cursor: pointer;
}

/* Hero (condivisa anche da tutorial.html: foto + overlay scuro) */
.hero {
  color: #fff;
  padding: 0;
}

.hero-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center 30%;
}

.hero-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(11, 30, 61, 0.88) 0%, rgba(11, 30, 61, 0.78) 45%, rgba(11, 30, 61, 0.95) 100%);
}

/* Pagina download.html: unico uso reale di .hero/.hero-bg/.hero-overlay sopra (era rimasto solo
   nel CSS, non referenziato da nessun HTML). position:relative + overflow:hidden sulla section
   fanno da ancora per .hero-bg (position:absolute, sotto) e ne tagliano i bordi. */
.download-hero {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1 1 auto;
  min-height: 0;
  text-align: center;
  padding: 24px;
}

/* La sezione occupa lo spazio restante sotto l'header dentro il flex-column impostato su
   body.download-page (vedi sotto): niente più min-height:100vh qui, altrimenti la somma con
   l'altezza dell'header supererebbe lo schermo e comparirebbe una barra di scorrimento verticale. */
body.download-page {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

body.download-page header {
  flex-shrink: 0;
}

.download-hero-content {
  position: relative;
  z-index: 1;
  max-width: 560px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.download-hero-content .logo-circle {
  width: 116px;
  height: 116px;
  border-radius: 50%;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 12px;
}

.download-hero-content .brand-logo {
  height: 64px;
  margin-bottom: 0;
}

.download-hero-content h1 {
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  margin: 0;
}

.download-hero-content p {
  color: #d7deed;
  margin: 0 0 18px;
}

.download-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
}

/* display:flex qui (invece di ereditare l'inline-block di .btn) centra il testo anche in verticale:
   .download-actions non fissa align-items, quindi di default (stretch) i due pulsanti vengono
   allungati alla stessa altezza (quello "Mac" è più alto per via della riga "Prossimamente" sotto)
   e senza questo il testo di un pulsante più basso in origine (quello Windows) resterebbe
   ancorato in alto invece che centrato nell'altezza allungata. */
.download-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 220px;
  padding: 15px 28px;
  font-size: 1.05rem;
}

/* Pulsante "Mac" bianco pieno (invece del contorno trasparente di base di .btn-ghost, pensato per
   uno sfondo bianco e comunque poco leggibile su quello scuro dell'hero) per farlo risaltare sulla
   foto di sfondo — resta comunque semi-trasparente/spento grazie a .is-disabled qui sotto, che è
   quello che lo segnala come "non ancora disponibile". */
.download-hero .btn-ghost {
  background: #fff;
  color: var(--navy);
  border-color: transparent;
}

/* Mac non ancora distribuito (vedi documentation/sviluppi-futuri.md nel repo dell'app): pulsante
   presente ma non cliccabile, per non promettere un download che non esiste ancora — niente
   href, solo lo stesso aspetto di .btn-ghost con opacità ridotta e cursore "not-allowed". */
.download-btn.is-disabled {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

.download-btn.is-disabled small {
  display: block;
  font-weight: 400;
  font-size: 0.75rem;
  margin-top: 2px;
}

/* Hero della home: niente foto, sfondo bianco, testo scuro, a tutta altezza. position:relative
   serve da ancora per .hero-scroll-hint (position:absolute, sotto) — messo qui sulla <section>
   stessa, non su .hero-media, perché resta l'unico antenato con un box vero a ogni breakpoint
   (.hero-media/.hero-content sotto i 720px diventano display:contents per la griglia mobile). */
/* Titolo e testo sopra la foto: il velo dell'hero della home è più leggero di quello di
   download.html (si vede la palestra, non un velo nero), quindi la leggibilità sui punti chiari
   dell'immagine è affidata a questa ombra morbida. */
.hero.hero-home h1,
.hero.hero-home p.lead {
  text-shadow: 0 2px 14px rgba(5, 20, 45, 0.55);
}

/* Foto di sfondo dell'hero della home (images/stock/sfondo_no_name.jpg, 1536x1024 — stessa
   inquadratura della precedente "schiaccaita 3.jpg" ma senza il watermark, e con lo stesso
   rapporto 3:2, quindi tutte le percentuali qui sotto restano valide) e velo scuro
   sopra di lei. È un <img> e non un "background" della section per poterla ancorare a un suo
   punto preciso:
   - da PC il punto al 43,75% dell'altezza (il pixel 350 sugli 800 della vecchia foto) resta a metà altezza
     dello schermo, mentre in orizzontale la foto è semplicemente centrata;
   - da telefono (vedi il blocco @media in fondo) è il giocatore che schiaccia a stare al centro
     dello schermo: il suo centro sta al 35,86% della larghezza e al 43,75% dell'altezza (erano
     430px e 350px sulla vecchia foto da 1199x800).
   In entrambi i casi il meccanismo è lo stesso: il punto di riferimento sullo schermo è
   top/left 50%, e la translate in percentuale risale della stessa frazione DELL'IMMAGINE (le
   percentuali di translate si calcolano sull'elemento stesso), quindi è esattamente quel punto a
   cadere al centro, a qualsiasi dimensione e senza JS. Una background-position in percentuale non
   potrebbe: allinea il punto X dell'immagine al punto X del contenitore, non al 50%.
   --hero-photo-w riproduce "cover" con i soli valori noti in CSS. Con il punto d'aggancio non
   centrato non basta più la maggiore tra 100vw e il rapporto della foto: perché nessun bordo
   resti scoperto serve che la porzione più corta rispetto al punto d'aggancio copra comunque
   mezzo schermo, cioè larghezza >= 100vw / (2 x frazione più piccola) e altezza >= 100dvh /
   (2 x frazione più piccola) — da cui 172dvh (verticale, 0,4375) e, da telefono, 140vw
   (orizzontale, 0,3586). */
.hero-bg-home,
.hero-chart-layer,
.hero-veil-home {
  position: absolute;
  z-index: 0;
}

.hero-bg-home,
.hero-chart-layer {
  left: 50%;
  top: 50%;
  width: var(--hero-photo-w);
  max-width: none; /* annulla "img { max-width: 100% }" globale */
  height: auto;
  transform: translate(-50%, -43.75%);
}

/* NB: .hero-player-cutout (il ritaglio del giocatore, vedi index.html) non ha regole proprie —
   prende tutto da .hero-bg-home qui sopra, z-index: 0 compreso. Sta sopra sfondo, velo e grafico
   solo perche' il suo <img> viene DOPO di loro nel markup: fra elementi posizionati con lo stesso
   z-index decide la posizione nel DOM. Funziona, ma basta riordinare due tag nell'hero per
   capovolgerlo. Per renderlo esplicito servirebbe un livello fra le decorazioni e il contenuto,
   che oggi non c'e': sfondo/velo/grafico stanno a 0 e testi/.hero-eff-card a 1, quindi andrebbe
   rinumerata tutta la scala (decorazioni 0, ritaglio 1, contenuto 2) verificando a schermo che
   nulla nell'hero resti indietro. Finche' non si fa, l'ordine del markup e' vincolante. */

.hero-veil-home {
  inset: 0;
  background: linear-gradient(180deg, rgba(11, 30, 61, 0.66) 0%, rgba(11, 30, 61, 0.51) 45%, rgba(11, 30, 61, 0.51) 66.67%, rgba(11, 30, 61, 0.97) 100%);
  /* fermo a 0,51 fino ai due terzi, poi sempre più scuro fino al bordo inferiore */
}

/* Foto e velo sono posizionati, quindi verrebbero disegnati sopra il contenuto della griglia (che
   non lo è): testi e pulsanti tornano davanti con un z-index proprio. */
.hero.hero-home h1,
.hero.hero-home p.lead,
.hero-home .hero-actions,
.hero-home .hero-scroll-hint {
  position: relative;
  z-index: 1;
}

/* Hero della home. Lo sfondo vero sono .hero-bg-home/.hero-veil-home qui sopra (foto + velo):
   qui resta solo un colore di riempimento sotto di loro. */
.hero.hero-home {
  position: relative;
  color: #fff;
  background: #0b1e3d;
  /* Da PC la stessa griglia a spazi elastici già usata da telefono (vedi il blocco
     @media max-width:600px in fondo, che la ridefinisce con due righe in più per l'invito a
     scorrere): 3 elementi (titolo, testo, pulsanti) e gli spazi fra loro, tutti uguali (1fr)
     tranne titolo→testo, volutamente più stretto (0.5fr) perché sono due parti dello stesso
     blocco. Lo spazio in cima non è più elastico: è quello che allinea il titolo alla mano del
     giocatore (vedi --hero-title-top). Essendo tutti in "fr", crescono e si stringono insieme
     all'altezza della finestra invece di restare fissi in px. */
  --hero-text-left: 53%;
  /* Larghezza a cui viene resa la foto di sfondo: è il "cover" scritto a mano (vedi .hero-bg-home
     più sotto), e serve anche qui perché da lei dipende la scala dell'immagine, quindi la
     posizione a schermo di un suo pixel. */
  --hero-photo-w: max(100vw, 172dvh);
  /* Distanza dal bordo superiore a cui cade il pixel 189 della foto, cioè la mano del giocatore:
     il pixel 350 sta per costruzione a metà altezza (50dvh) e 189 gli sta 161 pixel sopra, che
     sulla foto resa valgono 161/1199 = 13,428% della sua larghezza. Ci si allinea la CIMA del
     titolo (vedi le righe della griglia qui sotto). */
  --hero-title-top: calc(50dvh - 0.13428 * var(--hero-photo-w));
  /* la foto (.hero-bg-home) sborda apposta oltre i bordi della section per poter restare ancorata
     al suo pixel 350: senza questo ritaglio si vedrebbe sopra le sezioni successive. */
  overflow: hidden;
  display: grid;
  /* Prima riga: lo spazio che porta il titolo esattamente all'altezza della mano del giocatore
     (max(0px, ...) per le finestre molto larghe e basse, dove quel punto cadrebbe sopra il bordo
     e la riga risulterebbe negativa). Da lì in giù gli spazi elastici: titolo→testo stretto
     (0.5fr), testo→pulsanti e pulsanti→bordo inferiore pieni (1fr) e uguali tra loro.
     Non c'è più una riga per la scritta "Spike Net": il marchio sta ora solo nella barra bianca
     del menu, visibile fin da subito anche in home (vedi index.html). */
  grid-template-rows:
    max(0px, var(--hero-title-top))
    auto 0.5fr auto 1fr auto 1fr;
  row-gap: 0;
  padding: 0 24px;
  text-align: center;
  height: 100vh;
  height: 100dvh; /* segue l'altezza reale dello schermo anche su mobile */
}

/* .hero-media/.hero-content perdono la propria box (stesso trucco di .split-text-col altrove):
   titolo, testo e pulsanti — annidati dentro di loro nell'HTML — diventano così item diretti
   della griglia qui sopra, insieme a .hero-logo che è già loro fratello. Di conseguenza il
   padding/max-width che .hero-content forniva si sposta sulla section (sopra), e lo sfondo
   bianco che .hero-media portava non serve più (ora c'è la foto sulla section). */
.hero-home .hero-media,
.hero-home .hero-content {
  display: contents;
}

.hero.hero-home h1 { grid-row: 2; }
.hero.hero-home p.lead { grid-row: 4; }
.hero-home .hero-actions { grid-row: 6; }

/* I margini verticali fissi di titolo e testo si sommerebbero agli spazi elastici della griglia,
   rendendoli diversi tra loro: la distanza la decide solo la griglia.
   A sinistra invece il margine è voluto: nella foto di sfondo lo schiacciatore in sospensione
   occupa all'incirca dal 22% al 50% della larghezza dell'immagine, quindi titolo e testo partono
   appena oltre (--hero-text-left) e sono allineati a sinistra, per non finirgli sopra. È una
   percentuale, non un valore in px, perché la foto è in "cover": su uno schermo più largo il
   giocatore si allarga insieme al testo e il rapporto resta lo stesso. Scritta "Spike Net" e
   pulsanti restano invece centrati rispetto alla pagina. */
.hero.hero-home h1,
.hero.hero-home p.lead {
  margin: 0 0 0 var(--hero-text-left);
  text-align: left;
}

/* "Vedi come funziona" + frecce animate verso l'alto — terzo figlio di .hero-actions (invece del
   link omonimo, nascosto da telefono sotto i 600px, vedi @media più sotto), quindi di default
   nascosto qui (su desktop resta solo il pulsante). L'impilamento sotto il pulsante (con lo
   stesso gap:16px già usato tra i due pulsanti in origine, non un valore scelto a parte) è opera
   di .hero-actions, che sotto i 600px passa a flex-direction:column apposta — vedi quel commento
   per il perché non basta il flex-wrap di base. È un <a href="#stats"> (stesso target/gestore di
   click del pulsante omonimo, vedi index.html): serve quindi resettare lo stile blu/sottolineato
   di default del link e riabilitare pointer-events (a differenza di prima, quando era un div
   puramente decorativo) — non interferisce con lo swipe globale gestito in js/main.js perché un
   tap senza spostamento verticale significativo genera comunque un evento "click" (intercettato
   qui) invece che uno swipe (che richiede >40px di movimento, vedi touchend in js/main.js). */
.hero-lead-br {
  display: none;
}

.hero-scroll-hint {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: #fff;
  text-decoration: none;
  cursor: pointer;
}

/* stesso font di "Scarica per Windows" (.hero-home .hero-actions .btn, più sotto): font-family
   invariato (eredita da body in entrambi i casi, nessuna dichiarazione propria), stessi
   font-weight/font-size. */
.hero-scroll-text {
  font-size: 1.15rem;
  font-weight: 600;
  white-space: nowrap;
}

.hero-scroll-arrows {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.hero-scroll-arrow {
  width: 22px;
  height: 11px;
  color: #fff;
  animation: hero-scroll-bounce 1.6s ease-in-out infinite;
}

/* le due frecce sono impilate una sull'altra (margin-top negativo) e sfalsate nel tempo
   (animation-delay) così l'occhio percepisce un movimento continuo verso il basso (le frecce
   puntano in giù, verso il contenuto/la schermata successiva — non due frecce che rimbalzano in
   modo identico e sincronizzato) */
.hero-scroll-arrow-2 {
  margin-top: -4px;
  animation-delay: 0.3s;
}

@keyframes hero-scroll-bounce {
  0%, 100% { opacity: 0.25; transform: translateY(-5px); }
  50% { opacity: 1; transform: translateY(3px); }
}

/* Invito a scorrere, uno per ogni schermata da telefono (non solo nell'hero, che ha già il
   proprio ".hero-scroll-hint" sopra) TRANNE l'ultima ("Pronto a provarlo sulla tua squadra?":
   nessun elemento .section-scroll-hint nel suo HTML, quindi niente da nascondere lì) — un
   pulsante per ogni .screen-section invece di un singolo elemento fisso in fondo allo schermo:
   così scorre naturalmente insieme al resto del contenuto della sua sezione invece di restare
   ancorato allo schermo mentre la pagina scorre sotto di lui. position:absolute (non fixed) è
   proprio la chiave di questo: ancorato alla sua <section> (position:relative, vedi .screen-section
   sopra), non alla viewport — dato che ogni sezione occupa esattamente uno schermo (design
   dell'intero scroll-a-container), il risultato visivo a riposo è lo stesso identico posto in
   basso, ma stavolta segue il container invece di restare fisso. Stesse frecce/animazione
   (".hero-scroll-arrows"/".hero-scroll-arrow", riusate via HTML invece di duplicare qui lo
   stile). Nascosto su desktop (di base) — vedi @media max-width:600px più sotto per display/
   posizionamento, qui solo il reset a "niente sfondo/bordo" comune a entrambi i casi (un
   <button>, non un <a> come nell'hero: non porta a un id preciso ma sempre "una schermata
   avanti", gestito in js/main.js). I ":has()" sotto coprono gli stati "a schermo intero" della
   STESSA sezione (box "Prova" aperto, tabella di "Rimozione dei tempi morti" visibile), dove
   comparirebbe sopra contenuto che non c'entra. */
.section-scroll-hint {
  display: none;
  background: none;
  border: none;
  padding: 8px;
  margin: 0;
  cursor: pointer;
}

@media (max-width: 600px) and (orientation: portrait) {
  .section-scroll-hint {
    display: block;
    position: absolute;
    left: 50%;
    bottom: 10px;
    transform: translateX(-50%);
    z-index: 5;
  }
  .screen-section:has(.split.mtry-open) .section-scroll-hint,
  .screen-section:has(.mv-container.mv-table-visible) .section-scroll-hint {
    display: none;
  }
}

/* Comparsa in ingresso dell'hero: ogni elemento entra in sequenza dalla propria direzione
   (scritta "Spike Net" dall'alto, titolo da sinistra, testo da destra, infine pulsanti+invito a
   scorrere dal basso), 0.5s ciascuna con uno sfalsamento di 0.15s tra un gruppo e il successivo
   così l'ordine si vede chiaramente invece di comparire tutti insieme. A differenza delle altre
   comparse in scroll del sito (".reveal-split", tutte sotto i 600px): qui NON è dentro un
   @media, quindi vale anche da desktop/tablet — unica eccezione richiesta al resto (mobile-only)
   di questo blocco di modifiche. ".hero-scroll-hint" resta comunque invisibile da desktop
   (display:none altrove in questo file): l'animazione le si applica comunque, semplicemente non
   si vede mai finché l'elemento stesso non torna visibile sotto i 600px. Stesso meccanismo JS di
   ".reveal-split" (setRevealVisible in js/main.js, esteso anche a ".hero-reveal") — nome diverso
   da ".reveal-split" apposta per non ereditare lo stile desktop di quella classe (pensato per il
   pattern split-media/split-text-col, che l'hero non usa). */
.hero-reveal .hero-logo {
  opacity: 0;
  transform: translateY(-50px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.hero-reveal h1 {
  opacity: 0;
  transform: translateX(-50px);
  transition: opacity 0.5s ease, transform 0.5s ease;
  transition-delay: 0.15s;
}
.hero-reveal p.lead {
  opacity: 0;
  transform: translateX(50px);
  transition: opacity 0.5s ease, transform 0.5s ease;
  transition-delay: 0.3s;
}
.hero-reveal .hero-actions,
.hero-reveal .hero-scroll-hint {
  opacity: 0;
  transform: translateY(50px);
  transition: opacity 0.5s ease, transform 0.5s ease;
  transition-delay: 0.45s;
}
.hero-reveal.is-visible .hero-logo,
.hero-reveal.is-visible h1,
.hero-reveal.is-visible p.lead,
.hero-reveal.is-visible .hero-actions,
.hero-reveal.is-visible .hero-scroll-hint {
  opacity: 1;
  transform: translate(0, 0);
}

.hero.hero-home h1 {
  color: #fff;
  font-size: clamp(1.6rem, 3.2vw, 2.4rem);
}

.hero.hero-home p.lead {
  color: rgba(255, 255, 255, 0.88);
  font-size: 1.7rem;
}

/* Affiancati e della stessa larghezza, allineati a sinistra sotto il testo (stesso
   --hero-text-left di titolo e paragrafo, vedi sopra). Due colonne "1fr" in un contenitore largo
   quanto il suo contenuto: sotto un vincolo di max-content le colonne in fr si equivalgono e
   prendono tutte la larghezza del pulsante più largo ("Vedi come funziona"), quindi i due
   pulsanti restano uguali senza fissare una larghezza in px. */
.hero-home .hero-actions {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  width: max-content;
  margin-left: var(--hero-text-left);
  gap: 16px;
}

.hero-home .hero-actions .btn {
  padding: 16px 32px;
  font-size: 1.15rem;
}

/* Stesso trattamento del .btn-ghost dentro .cta-band (sfondo scuro): quello di default ha testo
   navy e bordo grigio chiaro, illeggibile sopra la foto. */
.hero-home .hero-actions .btn-ghost {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.45);
}
.hero-home .hero-actions .btn-ghost:hover {
  background: rgba(255, 255, 255, 0.12);
}

.hero-logo {
  flex: none;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 64px 24px 36px;
  /* trasparenti (erano #fff): lo sfondo ora è la foto sulla section, vedi .hero.hero-home sopra */
  background: transparent;
}

.hero-media {
  position: relative;
  overflow: hidden;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  background: transparent;
}

.hero-content {
  position: relative;
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 80px 24px 90px;
  text-align: center;
}

.hero-logo img {
  height: 72px;
  width: auto;
  /* il logo ha parti navy (testa e gamba) che sullo sfondo scuro dell'hero sparirebbero: un alone
     chiaro attorno alla sagoma le stacca dalla foto senza aggiungere il cerchio bianco usato
     invece nell'hero di download.html (.logo-circle). */
  filter: drop-shadow(0 0 10px rgba(255, 255, 255, 0.55));
}

.hero-logo span {
  font-weight: 800;
  font-size: clamp(1.8rem, 3.4vw, 2.8rem);
  color: #fff;
}

.eyebrow {
  display: inline-block;
  background: rgba(59, 130, 246, 0.15);
  color: var(--blue-light);
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 20px;
}

.hero h1 {
  font-size: clamp(2rem, 4.5vw, 3.2rem);
  margin: 0 0 18px;
  font-weight: 800;
  letter-spacing: -0.01em;
}

.hero p.lead {
  font-size: 1.15rem;
  color: #d7dcea;
  max-width: 640px;
  margin: 0 auto 34px;
}

.hero-actions {
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
}

/* Sections */
section {
  padding: 80px 0;
}

section.alt {
  background: var(--grey-50);
}

/* Media split */
.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
  align-items: center;
}

.split.reverse .split-media { order: 2; }
.split.reverse .split-text { order: 1; }

/* comparsa in scroll: il video entra da sinistra, il testo da destra (con un piccolo ritardo dopo il video) */
.reveal-split {
  align-items: start;
  grid-template-columns: 2fr 1fr;
  column-gap: 32px;
  max-width: 900px;
  margin-left: auto;
  margin-right: auto;
}

/* niente padding superiore, così il margine dalla sezione precedente resta uguale a quello sotto l'hero */
section.stats-alt {
  padding-top: 0;
}

/* più spazio tra la tabella (con le card di distribuzione/direzioni sovrapposte, che sporgono
   oltre il suo bordo) e il testo a fianco, rispetto al gap standard di .reveal-split */
section.stats-alt .reveal-split {
  column-gap: 64px;
}

.reveal-split .split-text-col {
  text-align: left;
}

.reveal-split .split-media,
.reveal-split .split-text-col {
  opacity: 0;
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.reveal-split .split-media {
  transform: translateX(-60px);
}

.reveal-split .split-text-col {
  transform: translateX(60px);
  transition-delay: 0.25s;
}

.reveal-split.is-visible .split-media,
.reveal-split.is-visible .split-text-col {
  opacity: 1;
  transform: translateX(0);
}

/* variante speculare: immagine a destra (2/3), testo a sinistra (1/3) — stessa comparsa, direzioni invertite */
.reveal-split.reveal-reverse {
  grid-template-columns: 1fr 2fr;
}

.reveal-split.reveal-reverse .split-media {
  transform: translateX(60px);
}

.reveal-split.reveal-reverse .split-text-col {
  transform: translateX(-60px);
}

.reveal-split.reveal-reverse.is-visible .split-media,
.reveal-split.reveal-reverse.is-visible .split-text-col {
  transform: translateX(0);
}

.reveal-split .reveal-title {
  font-size: clamp(1.5rem, 2.8vw, 2rem);
  margin: 0 0 16px;
  font-weight: 800;
  color: var(--blue);
}

/* Pagina organizzata a "container" a schermo intero: il primo (hero) è alto quanto lo schermo, tutti i
   successivi sono alti quanto lo schermo meno la barra del menu (--header-h, calcolata in js/main.js).
   Lo snap da un container all'altro è gestito interamente in JS (non da scroll-snap CSS: andrebbe in
   conflitto con l'animazione, "cortocircuitandola" e rendendola istantanea invece che graduale). */
.screen-section {
  position: relative; /* ancora per .section-scroll-hint (position:absolute), vedi più sotto */
  height: calc(100vh - var(--header-h, 76px));
  height: calc(100dvh - var(--header-h, 76px));
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0;
}

/* testo dei paragrafi "Analisi dettagliata azioni" e "Statistiche di squadra", ingranditi
   rispetto al corpo standard e allineati alla stessa dimensione tra loro */
.lead-text {
  font-size: 1.3rem;
  line-height: 1.6;
}

@media (prefers-reduced-motion: reduce) {
  .reveal-split .split-media,
  .reveal-split .split-text-col,
  .reveal-split .reveal-title,
  .reveal-split .split-text,
  .mstb-overlay-card,
  .mv-container .mv-head,
  .mv-container .mv-head h2,
  .mv-container .mv-head-mobile-text,
  .mv-container .mv-preview-video,
  .mv-container .mv-sidebar,
  .hero-reveal .hero-logo,
  .hero-reveal h1,
  .hero-reveal p.lead,
  .hero-reveal .hero-actions,
  .hero-reveal .hero-scroll-hint,
  .tutorial-hero-reveal .tutorial-intro-text,
  .tutorial-hero-reveal .tintro-card,
  .step-text,
  .step-video {
    transition: none;
    transform: none;
    opacity: 1;
  }
  .hero-scroll-arrow {
    animation: none;
    transform: none;
    opacity: 1;
  }
}

/* riquadro della tabella: stessa dimensione/rapporto del riquadro del video (620:492), tabella
   allineata in alto e "in fondo" (z-index sotto le card di distribuzione/direzioni attacco, che
   le si sovrappongono — vedi .mstb-overlay più sotto) */
.stats-table-media {
  aspect-ratio: 620 / 492;
  position: relative;
}

.stats-table-media .mstb-wrap {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  position: relative;
  z-index: 1;
}

/* Solo contenitore di scroll (orizzontale se .mstb-table supera i 460px di min-width, verticale
   se il contenuto eccede l'altezza di .stats-table-media): niente più bordo/raggio qui sopra —
   .mstb-wrap ha height:100% del riquadro (vedi .stats-table-media .mstb-wrap sopra), quasi sempre
   più alto della tabella vera e propria (che si allinea in cima, justify-content:flex-start),
   quindi un bordo su di lui includerebbe anche lo spazio vuoto sotto la tabella invece di seguirne
   il contorno reale — vedi il bordo su .mstb-table stesso, sotto. */
.mstb-wrap {
  overflow-x: auto;
  overflow-y: auto;
}

/* Card "Distribuzione attacchi" e "Direzioni attacco" — stessa grafica dei grafici campo dello
   Studio Partita dell'app (StudioViewer: ChartCard/DistributionCourt), con dati di esempio.
   Sovrapposte alla parte bassa della tabella per dare profondità al riquadro. */
.mstb-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.mstb-overlay-card {
  position: absolute;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 16px 32px rgba(11, 30, 61, 0.2);
  opacity: 0;
  transition: opacity 0.6s ease, transform 0.6s ease;
  transition-delay: 0.55s;
}

.mstb-overlay-label {
  font-size: 0.6rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: rgba(0, 0, 0, 0.45);
}

.mstb-overlay-sublabel {
  font-size: 0.56rem;
  font-weight: 600;
  color: rgba(0, 0, 0, 0.3);
  margin-top: -2px;
}

.mstb-dist-svg,
.mstb-court-svg {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 6px;
}

.mstb-overlay-dist {
  right: -5%;
  bottom: -8%;
  width: 42%;
  transform: translateY(18px) rotate(6deg) scale(0.92);
}

.mstb-overlay-court {
  left: -3%;
  bottom: -10%;
  width: 30%;
  z-index: 3;
  transition-delay: 0.7s;
  transform: translateY(18px) rotate(-5deg) scale(0.92);
}

.reveal-split.is-visible .mstb-overlay-card {
  opacity: 1;
}

.reveal-split.is-visible .mstb-overlay-dist {
  transform: translateY(0) rotate(6deg) scale(1);
}

.reveal-split.is-visible .mstb-overlay-court {
  transform: translateY(0) rotate(-5deg) scale(1);
}

.mstb-table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  min-width: 460px;
  font-size: 0.72rem;
  background: #fff;
}

/* Contorno solo sulla tabella di "Statistiche di squadra" (non su .mstb-wrap, che la contiene ma
   è spesso più alto di lei — vedi il commento lì sopra), non su .mstb-table in generale: la
   "Battuta opposto"/"Dati schiacciata" riusano .mstb-table per la stessa grafica ma non devono
   ereditare questo contorno (la prima ha già lo sfondo proprio di .mstb-overlay-stats attorno,
   che l'angolo arrotondato+overflow:hidden qui sotto lascerebbe intravedere nei 4 angoli della
   tabella; la seconda ha già il proprio contorno-card, un secondo contorno sarebbe ridondante) —
   selettore scoped su .stats-table-media, l'unico contenitore di questa tabella specifica. Un
   bordo vero (più marcato delle righe interne, che vanno da rgba(0,0,0,0.05) a 0.12 — vedi sotto —
   così la tabella risulta chiaramente delimitata) al posto della sottile ombra "0 1px 5px" di una
   versione precedente, che sfumando ai lati leggeva soprattutto come una linea ombreggiata sotto
   il riquadro, non come un contorno. "outline", non "border": con border-collapse:collapse (sopra)
   il bordo esterno della tabella entra nello stesso algoritmo di conflitto usato per decidere
   quale bordo "vince" a ogni intersezione tra celle, e il risultato — almeno nei browser testati —
   è che il colore dichiarato viene ignorato (il contorno appare bianco/invisibile). outline non fa
   parte di quel modello: si disegna sopra al contenuto, fuori dal flusso del box, quindi rispetta
   sempre il colore impostato — con outline-offset negativo per farlo combaciare con il bordo della
   tabella invece che sporgere oltre. overflow:hidden necessario perché il raggio non lasci
   scoperti gli angoli quadrati degli sfondi delle celle di intestazione (.mstb-th-group/
   .mstb-th-sub, sfondo #f0f4ff) che altrimenti sporgerebbero oltre l'angolo arrotondato. */
.stats-table-media .mstb-table {
  border-radius: var(--radius);
  outline: 1.5px solid rgba(11, 30, 61, 0.4);
  outline-offset: -1.5px;
  overflow: hidden;
}

.mstb-col-role { width: 40px; }
.mstb-col-stat { width: 42px; }

.mstb-th-group {
  background: #f0f4ff;
  color: rgba(0, 0, 0, 0.45);
  font-size: 0.6rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.35rem 0.3rem;
  text-align: center;
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

.mstb-th-sub {
  background: #f0f4ff;
  color: rgba(0, 0, 0, 0.4);
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.35rem 0.3rem;
  text-align: center;
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

.mstb-td-player {
  font-weight: 600;
  color: #1a1a2e;
  padding: 0.4rem 0.5rem;
  border-top: 1px solid rgba(0, 0, 0, 0.05);
}

.mstb-td-role {
  text-align: center;
  color: rgba(0, 0, 0, 0.5);
  font-size: 0.7rem;
}

.mstb-td {
  padding: 0.4rem 0.3rem;
  text-align: center;
  border-top: 1px solid rgba(0, 0, 0, 0.05);
  color: #1a1a2e;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.mstb-eff { font-weight: 700; }

.mstb-total-row { border-top: 1.5px solid rgba(0, 0, 0, 0.12); }

.mstb-total-label {
  font-weight: 700;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: rgba(0, 0, 0, 0.45);
  text-align: center;
}

.mstb-total-cell { font-weight: 700; background: rgba(59, 130, 246, 0.03); }

/* linea verticale marcata tra i blocchi Ruolo / Battuta / Ricezione / Attacco, come nell'app */
.mstb-vsep { border-left: 1px solid rgba(0, 0, 0, 0.1) !important; }

/* Classe messa/tolta da updateStatsTableFit in js/main.js: da telefono, quando nemmeno le 8
   colonne rimaste (il gruppo Ricezione è già nascosto nel blocco @media in fondo) stanno nello
   schermo e .mstb-wrap comincia a scorrere in orizzontale, sparisce anche "Tot" della Battuta —
   il totale è l'unico ricavabile dal resto della riga, Err e Pts no. Come per Ricezione va
   nascosto anche il <col> e non solo le celle: con table-layout:fixed lo spazio della colonna
   resterebbe altrimenti riservato. Il colspan del gruppo "Battuta" (3 -> 2) lo aggiorna il JS,
   perché non è esprimibile in CSS. La linea verticale prima di Battuta stava sulla cella "Tot":
   passa alla cella che diventa la prima del gruppo. */
.mstb-table.mstb-no-serve-tot colgroup col:nth-child(2),
.mstb-table.mstb-no-serve-tot thead tr:nth-child(2) th:nth-child(2),
.mstb-table.mstb-no-serve-tot tbody tr > :nth-child(2) {
  display: none;
}

.mstb-table.mstb-no-serve-tot thead tr:nth-child(2) th:nth-child(3),
.mstb-table.mstb-no-serve-tot tbody tr > :nth-child(3) {
  border-left: 1px solid rgba(0, 0, 0, 0.1) !important;
}

/* Sezione "Visualizza velocemente ogni azione": video con la card statistiche del giocatore
   sovrapposta, stessa logica delle card di Statistiche di squadra ma con un'unica card centrata
   in basso e celle cliccabili che spostano il video sull'azione corrispondente (vedi js/main.js). */
.opposto-video-media {
  position: relative;
}

/* il video sorgente è 1280x720: ritaglia 1/6 a sinistra e 1/6 a destra (rimane la fascia centrale
   4/6), mostrando nel player solo quella. Il wrapper ha l'aspect-ratio della fascia ritagliata
   (32:27) e il video, allargato al 150% e centrato, viene tagliato dall'overflow:hidden. */
.opposto-video-crop {
  position: relative;
  overflow: hidden;
  aspect-ratio: 32 / 27;
  border-radius: var(--radius);
  box-shadow: none;
}

/* selettore più specifico di ".split-media video" (che altrimenti, a parità di specificità e
   dichiarato dopo nel foglio di stile, vincerebbe sovrascrivendo max-width/height/ritaglio) */
.opposto-video-media .opposto-video-crop video {
  position: absolute;
  top: 0;
  left: 50%;
  width: 150%;
  max-width: none;
  height: 100%;
  transform: translateX(-50%);
  border-radius: 0;
  box-shadow: none;
}

/* Sezione "Ogni attacco, con la sua traiettoria": il video sorgente è 1920x1080. La finestra di
   ritaglio è un rettangolo centrato orizzontalmente sul bounding box delle traiettorie, dimensioni
   854.545x721.023px (rapporto 32:27, il riquadro resta identico agli altri box della pagina) —
   zoom del 10% rispetto alla versione precedente (940x793.125px) ottenuto rimpicciolendo il
   ritaglio mantenendo fisso il bordo inferiore (y=943 nel campo originale): il bordo superiore si
   sposta quindi più in basso (da y=149.875 a y=221.977), avvicinando le traiettorie al bordo
   superiore del player. Il video viene ingrandito uniformemente (224.681% = 1920/854.545 in
   larghezza, 149.788% = 1080/721.023 in altezza — stesso fattore, nessuna deformazione) e
   spostato di cropX/originalW e cropY/originalH (in % della SUA dimensione resa, coerente con
   transform:translate) così quell'area risulta allineata in alto a sinistra nel riquadro;
   l'eccedenza viene tagliata dall'overflow. */
.attacchi-video-media {
  position: relative;
}

.attacchi-video-crop {
  position: relative;
  overflow: hidden;
  aspect-ratio: 32 / 27;
  border-radius: var(--radius);
  box-shadow: 0 20px 45px rgba(11, 30, 61, 0.18);
}

.attacchi-video-media .attacchi-video-crop video {
  position: absolute;
  top: 0;
  left: 0;
  width: 224.681%;
  max-width: none;
  height: 149.788%;
  /* scale(1.02) aggiuntivo: senza, il bordo vero del video sorgente può cadere esattamente sul
     confine del ritaglio — un filo di sotto-pixel dove compositing/decodifica GPU e overflow:hidden
     non si allineano perfettamente lascia intravedere quel bordo (bande nere/bianche di 1px,
     sfarfallanti da un frame all'altro). Zoomando dell'ulteriore 2% attorno al centro (transform-
     origin di default) si guadagna ~1% di margine per lato, che assorbe l'errore di arrotondamento
     senza spostare percettibilmente l'inquadratura (il translate successivo resta lo stesso: è
     calcolato sul riquadro di layout, non sulla dimensione già scalata). */
  transform: translate(-19.882%, -20.553%) scale(1.02);
  border-radius: 0;
  box-shadow: none;
}

/* Traiettorie della palla (alzata prima della schiacciata) sovrapposte al video: il viewBox
   (0 0 854.545 721.023) coincide esattamente con la finestra ritagliata sopra, quindi le coordinate dei
   dati (già ricalcolate con lo stesso offset in js/main.js) si allineano senza altri calcoli. */
.attacchi-traj-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.traj-group {
  cursor: pointer;
}

.traj-hit {
  fill: none;
  stroke: transparent;
  stroke-width: 26;
  pointer-events: stroke;
}

.traj-line {
  fill: none;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.352;
  filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.55));
  pointer-events: none;
  transition: opacity 0.15s ease, stroke-width 0.15s ease;
}

/* "corrente" = il frame in riproduzione ora sta dentro la finestra di questa traiettoria
   (calcolato in js/main.js, stesso criterio di MontageBallOverlay/ball-trajectory.js dell'app):
   piena opacità e tratto più marcato, come al passaggio del mouse. */
.traj-group.is-current .traj-line,
.traj-group:hover .traj-line {
  opacity: 1;
}

.traj-group.is-current .traj-line,
.traj-group:hover .traj-line {
  stroke-width: 5;
}

/* Pallina animata che segue la posizione esatta nel frame corrente lungo la traiettoria attiva
   (interpolata tra i due punti più vicini) — stesso concetto della scia gialla di
   ball-trajectory.js, qui un singolo punto con alone luminoso invece della scia sfumata. */
.traj-ball {
  pointer-events: none;
  fill: rgba(255, 220, 0, 0.95);
  stroke: rgba(120, 80, 0, 0.6);
  stroke-width: 1;
  filter: drop-shadow(0 0 4px rgba(255, 200, 0, 0.85));
  opacity: 0;
  transition: opacity 0.1s ease;
}

.traj-ball.is-visible {
  opacity: 1;
}

/* Scia di puntini che sfumano dietro la pallina animata (posizioni recenti, non solo quella
   attuale) — stesso concetto della "scia gialla" di ball-trajectory.js nell'app, qui come pool
   di cerchi creati una volta in js/main.js e riposizionati/scoloriti a ogni frame. */
.traj-trail-dot {
  pointer-events: none;
  fill: rgba(255, 220, 0, 0.9);
}

/* Card "Altezza / Velocità" dell'attacco corrente, sovrapposta a cavallo del bordo SUPERIORE del
   player (stessa idea della legenda sotto, ma speculare: top:0 + translateY(-50%) mette il centro
   della card sul bordo superiore, metà dentro e metà fuori dal video). Stesso sfondo di
   .attacchi-traj-legend, per coerenza tra le due card sovrapposte allo stesso video. */
.attacchi-stats-overlay {
  position: absolute;
  left: 50%;
  top: 0;
  z-index: 2;
  transform: translate(-50%, -50%);
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 10px 20px rgba(11, 30, 61, 0.18);
  padding: 2px;
}

/* .attacchi-stats-table ha già .mstb-table per la stessa grafica delle altre tabelle del sito
   (Statistiche di squadra/Battuta opposto): qui sovrascriviamo solo larghezza (min-width/
   width:100% pensati per tabelle a più colonne, non per questo riquadro a 2 celle), sfondo
   (uguale al box che la contiene, così si fondono) e bordi delle celle (tolti: il contorno della
   card è già sufficiente in un riquadro così piccolo). Selettore con tag (table.attacchi-stats-
   table) per battere .mstb-table a parità di specificità, indipendentemente dall'ordine nel
   foglio di stile. */
table.attacchi-stats-table {
  width: auto;
  min-width: 280px;
  background: #fff;
}

table.attacchi-stats-table .mstb-td {
  border: none;
  font-size: 0.85rem;
  padding: 0.45rem 1.1rem;
}

/* linea grigia a metà del box, tra la cella "Altezza" e quella "Velocità" */
table.attacchi-stats-table .mstb-td + .mstb-td {
  border-left: 2px solid var(--grey-200);
}

/* riga "Dati schiacciata": stessa tipografia di .mstb-total-label (etichetta di riepilogo delle
   altre tabelle), su un'unica cella a tutta larghezza sopra le due celle valore, separata da essa
   con la stessa linea grigia del divisorio Altezza/Velocità */
.attacchi-stats-title {
  text-align: center;
  font-weight: 700;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: rgba(0, 0, 0, 0.45);
  padding: 0.35rem 0.5rem 0.15rem;
  border-bottom: 1px solid var(--grey-200);
}

/* Legenda: spiega il significato dei colori delle traiettorie (stessa convenzione di "Direzioni
   attacco" in Statistiche di squadra), in una card sovrapposta al bordo inferiore del player —
   stesso stile di .mstb-overlay-card, centrata orizzontalmente e a cavallo del bordo (bottom:0 +
   translateY(50%) mette il CENTRO della card sul bordo, quindi metà dentro e metà fuori dal
   video). Larghezza "auto": senza una width esplicita, un elemento position:absolute si
   restringe al contenuto, quindi nessuno spazio vuoto ai lati del testo. Va sul contenitore
   esterno (.attacchi-video-media, non .attacchi-video-crop) perché quest'ultimo ha
   overflow:hidden per il ritaglio del video e taglierebbe la metà "fuori" della card. */
.attacchi-traj-legend {
  position: absolute;
  left: 50%;
  bottom: 0;
  z-index: 2;
  transform: translate(-50%, 50%);
  display: flex;
  flex-wrap: nowrap;
  gap: 6px 14px;
  padding: 7px 14px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 10px 20px rgba(11, 30, 61, 0.18);
  white-space: nowrap;
}

.attacchi-traj-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.78rem;
  color: rgba(0, 0, 0, 0.55);
}

.attacchi-traj-legend-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
}

.attacchi-traj-legend-dot-outline {
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.3);
}

/* bottom:0 + translate(-50%, 50%) mette il CENTRO della card esattamente sul bordo inferiore del
   video, quindi sempre metà dentro/metà fuori qualunque sia l'altezza della card (stessa tecnica
   di .attacchi-traj-legend sopra) — a differenza del vecchio bottom:-10%, una percentuale scelta
   a occhio che non garantiva un vero 50/50. Nessuna width qui (implicitamente "auto"): con "left"
   impostato ma non "right", un elemento position:absolute si restringe al contenuto
   (shrink-to-fit) — la card è quindi sempre larga esattamente quanto le serve alla tabella sotto
   (che a sua volta si dimensiona sul proprio contenuto, vedi .mstb-table-compact), invece di
   avere una percentuale fissa scelta a occhio; max-width resta come tetto di sicurezza. */
.mstb-overlay-stats {
  left: 50%;
  bottom: 0;
  max-width: 300px;
  background: #fff;
  box-shadow: none;
  transform: translate(-50%, calc(50% + 18px)) scale(0.92);
  pointer-events: auto;
}

.reveal-split.is-visible .mstb-overlay-stats {
  transform: translate(-50%, 50%) scale(1);
}

/* "Battuta opposto, #8" centrato sulla larghezza della card (.mstb-overlay-card è un flex column,
   quindi lo span si stira già a piena larghezza: basta text-align) — stessa tecnica già usata da
   .ricezioni-overlay-court .mstb-overlay-label. */
.mstb-overlay-stats .mstb-overlay-label {
  text-align: center;
}

/* stessa grafica di .mstb-table ma senza il min-width pensato per la tabella a 13 colonne: qui
   bastano 4 colonne, dimensionate ciascuna sul proprio contenuto (table-layout:auto, invece di
   "fixed" a colonne uguali) così "In gioco" — l'unica intestazione su due parole — non va mai a
   capo (white-space:nowrap sotto, in più come garanzia) senza dover allargare anche le altre tre
   colonne (Tot/Ace/Err, una sola parola) più del necessario: la tabella nel complesso risulta
   più stretta di quando tutte e quattro le colonne erano forzate alla stessa larghezza. */
.mstb-table-compact {
  min-width: 0;
  table-layout: auto;
}

.mstb-table-compact .mstb-th-sub,
.mstb-table-compact .mstb-td {
  padding-left: 0.55rem;
  padding-right: 0.55rem;
  white-space: nowrap;
  border: 1px solid rgba(0, 0, 0, 0.12);
}

.mstb-stat-btn {
  cursor: pointer;
  font-weight: 700;
  color: var(--blue);
  transition: background 0.15s ease, color 0.15s ease;
}

.mstb-stat-btn:hover {
  background: rgba(59, 130, 246, 0.1);
}

.mstb-stat-btn:active {
  background: rgba(59, 130, 246, 0.22);
}

/* resta evidenziata l'ultima statistica premuta (di default "Tot", impostata già in HTML) */
.mstb-stat-btn.is-active {
  background: rgba(59, 130, 246, 0.18);
  box-shadow: inset 0 0 0 1.5px var(--blue);
}

/* Sezione "Tracciamento accurato di ogni giocatore": video con il grafico "Direzioni ricezione"
   sovrapposto (vedi index.html per i dettagli sui meccanismi, presi da TabMontageGrafici.razor).
   Il video sorgente è 1280x720: ritaglia 1/9 a sinistra e 2/9 a destra (rimane la fascia centrale
   6/9 = 2/3, stessa frazione di .opposto-video-crop — infatti l'aspect-ratio risultante è lo
   stesso 32:27, quindi il riquadro ha le stesse dimensioni degli altri box della pagina). */
.ricezioni-video-media {
  position: relative;
}

.ricezioni-video-crop {
  position: relative;
  overflow: hidden;
  aspect-ratio: 32 / 27;
  border-radius: var(--radius);
  box-shadow: 0 20px 45px rgba(11, 30, 61, 0.18);
}

.ricezioni-video-media .ricezioni-video-crop video {
  position: absolute;
  top: 0;
  left: 0;
  width: 150%;
  max-width: none;
  height: 100%;
  transform: translateX(-11.111%);
  border-radius: 0;
  box-shadow: none;
}

/* Grafico "Direzioni ricezione", a cavallo del bordo inferiore del video, centrato in
   orizzontale — stessa tecnica di .mstb-overlay-stats/.spike-speed-bar (bottom:0 + translate
   (-50%, 50%) mette il CENTRO del box esattamente sul bordo, sempre metà dentro/metà fuori
   qualunque sia l'altezza del box). Width scelta a mano (nessuna indicazione di frazione precisa
   per questo box, a differenza di ".spike-speed-bar"): abbastanza larga da stare comoda la
   colonna titolo+legenda accanto al mezzo campo, con un max-width perché su schermi larghi non
   diventi eccessiva (entrambe leggermente ridotte rispetto alla versione precedente, 78%/420px,
   per un riquadro un po' più compatto). Titolo+legenda a sinistra, campo a destra:
   .ricezioni-overlay-court (di base un flex column, ereditato da .mstb-overlay-card) diventa qui
   una riga; .ricezioni-court-info raggruppa titolo e legenda impilati verticalmente nella colonna
   di sinistra. padding-top/bottom ridotti rispetto agli 8px (tutti i lati) di .mstb-overlay-card:
   meno margine sopra/sotto il contenuto, lasciando invariato quello laterale.
   Qui sotto (padding-top/bottom 2.5px, dimezzati rispetto ai 5px della versione precedente, e
   width/max-width ridotte a 58%/300px invece di 72%/380px) è la versione "schermo largo": sotto
   gli 860px in verticale si torna ai valori precedenti (vedi il blocco @media più sotto), quindi
   questa riduzione vale solo su tablet/desktop, non su telefono. Il solo padding non bastava a
   far vedere una vera differenza di dimensione (2.5px in meno per lato sono impercettibili): a
   ridurre davvero l'altezza del riquadro è soprattutto la larghezza, perché l'SVG (in riga,
   accanto alla colonna testo) prende la propria altezza dall'aspect-ratio della propria
   larghezza resa — restringendo la riga si restringe (e quindi si abbassa) anche il campo. */
.ricezioni-overlay-court {
  left: 50%;
  bottom: 0;
  width: 58%;
  max-width: 300px;
  padding-top: 2.5px;
  padding-bottom: 2.5px;
  transform: translate(-50%, calc(50% + 18px)) scale(0.92);
  pointer-events: auto;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
}

.reveal-split.is-visible .ricezioni-overlay-court {
  transform: translate(-50%, 50%) scale(1);
}

.ricezioni-court-info {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
  min-width: 0;
}
.ricezioni-overlay-court .ricezioni-court-svg {
  flex: 1;
  width: auto;
  min-width: 0;
}

/* Ulteriore 5% di riduzione del campo, solo "schermo largo": si somma al 10% già ottenuto
   allargando il viewBox in index.html (universale, a ogni risoluzione — vedi il commento lì).
   Qui invece serve una regola CSS in più (non solo viewBox) perché possa essere annullata sotto
   gli 860px in verticale (il blocco @media più sotto la azzera con transform:none) — il viewBox
   è un attributo SVG, non è possibile condizionarlo via media query. transform non tocca lo
   spazio occupato in layout (a differenza di un cambio di width/height), quindi il riquadro
   attorno resta della stessa dimensione: il campo appare solo un po' più piccolo al suo interno,
   con più margine vuoto tutt'attorno. */
.ricezioni-court-svg {
  transform: scale(0.95);
}

/* campo azzurrino (invece dello sfondo bianco di .mstb-overlay-card, ereditato quando il
   rettangolo era fill:none) */
.ricezioni-court-svg .court-rect {
  fill: rgba(230, 240, 255, 0.7);
}

.ricezioni-court-svg .court-arrow-group {
  cursor: pointer;
}

/* Hitbox più ampia delle frecce: ".court-arrow-hit" in index.html è una seconda <line>, stesse
   coordinate di ".court-arrow-line" ma trasparente e molto più spessa (1.1 unità contro 0.285),
   quindi invisibile ma "cliccabile" per un raggio più largo attorno alla linea visibile — il
   clic (delegato sul <g>, vedi js/main.js) arriva comunque al gruppo qualunque discendente venga
   colpito. pointer-events:stroke forza l'hit-test sul tracciato dello stroke indipendentemente
   dal fatto che sia dipinto (di norma un colore "transparent" potrebbe non contare come
   "painted" per il default pointer-events:visiblePainted). */
.ricezioni-court-svg .court-arrow-hit {
  pointer-events: stroke;
}

/* frecce disegnate il 50% più spesse rispetto al default SVG (stroke-width inline 0.19 →
   0.285); le punte (poligoni) sono scalate della stessa proporzione direttamente nei punti
   in index.html, dato che non hanno uno stroke da poter allargare via CSS. */
.ricezioni-court-svg .court-arrow-line {
  stroke-width: 0.285;
}

/* evidenziazione più marcata al passaggio del mouse: oltre a opacità piena, uno spessore
   nettamente superiore (non solo proporzionale al +50% di base) così la freccia risalta di più */
.ricezioni-court-svg .court-arrow-group:hover .court-arrow-line {
  stroke-width: 0.44;
  opacity: 1;
}
.ricezioni-court-svg .court-arrow-group:hover .court-arrow-poly {
  opacity: 1;
}

/* titolo ("Direzioni ricezione") e legenda della card, molto più grandi del default
   .mstb-overlay-label/.mstb-overlay-sublabel (pensati per le card più piccole e decorative delle
   altre sezioni) dato che qui sono la spiegazione del grafico interattivo, non un dettaglio.
   Titolo centrato sulla larghezza della colonna sinistra (.ricezioni-court-info è un flex
   column, quindi lo span si stira già a piena larghezza: basta text-align). */
.ricezioni-overlay-court .mstb-overlay-label {
  font-size: 0.82rem;
  text-align: center;
}

/* due voci per riga (flex-basis 50% invece del wrap "naturale"): con un carattere più piccolo
   (sotto) le quattro voci stanno comode in due colonne anche nella colonna sinistra, più stretta
   di quando la legenda stava sull'intera larghezza della card. */
.ricezioni-court-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 8px;
  padding: 2px 2px 0;
}

.ricezioni-legend-item {
  flex: 0 0 calc(50% - 4px);
  display: inline-flex;
  align-items: center;
  /* centra il pallino+etichetta nella propria metà colonna, invece di restare appoggiati al
     bordo sinistro con spazio vuoto a destra (inline-flex, di base, impacchetta il contenuto
     all'inizio del proprio box) — vale sia su desktop che da telefono, nessun media query. */
  justify-content: center;
  gap: 5px;
  font-size: 0.8rem;
  font-weight: 600;
  color: rgba(0, 0, 0, 0.6);
  white-space: nowrap;
}

.ricezioni-legend-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* Sezione "Genera automaticamente gli studi partita": stessa struttura outer/inner di
   -video-media/-video-crop altrove (es. .attacchi-video-media/.attacchi-video-crop). .studio-box
   (outer) è solo l'ancora di posizionamento — nessun overflow, altrimenti taglierebbe via la metà
   "fuori" del pulsante "Genera studio" (sotto) — mentre .studio-box-inner (inner) porta
   aspect-ratio/bordo arrotondato/ombra/overflow:hidden e ospita le due "viste" alternative
   (picker delle 4 partite / mini studio partita in sola lettura), gestite in js/main.js
   aggiungendo/togliendo l'attributo HTML "hidden" — :not([hidden]) invece di un semplice
   "display:flex" sulla classe, altrimenti quella dichiarazione (stessa specificità dello UA
   stylesheet che imposta display:none su [hidden], ma successiva nell'ordine di cascata perché è
   nel foglio dell'autore) vincerebbe SEMPRE, anche quando l'attributo è presente. */
.studio-box {
  position: relative;
}

.studio-box-inner {
  position: relative;
  aspect-ratio: 32 / 27;
  overflow: hidden;
  border-radius: var(--radius);
  box-shadow: 0 20px 45px rgba(11, 30, 61, 0.18);
  background: #fff;
  display: flex;
  flex-direction: column;
}

.studio-picker-view,
.studio-viewer-view {
  flex-direction: column;
  min-height: 0;
}

.studio-picker-view:not([hidden]),
.studio-viewer-view:not([hidden]) {
  display: flex;
  flex: 1 1 auto;
  width: 100%;
}

/* ── Vista 1: scelta della partita ── */
.studio-picker-view {
  padding: clamp(14px, 3vw, 28px);
}

/* Le 4 partite, disposte "a quadrato" (griglia 2x2, non più una riga) da quando sono diventate 4
   invece di 3 — riempiono per intero lo spazio disponibile (niente aspect-ratio fisso sulla
   thumbnail: la forma segue quella che risulta dal riquadro, non necessariamente quadrata). */
.studio-matches {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: clamp(8px, 1.6vw, 16px);
  flex: 1;
  min-height: 0;
}

.studio-match {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-height: 0;
  min-width: 0;
  padding: 2px;
  transition: transform 0.15s;
}

.studio-match:hover {
  transform: translateY(-2px);
}

/* Il contorno di selezione va sulla sola thumbnail (non sull'intera cella, etichetta compresa):
   bordo trasparente di base (riserva lo spazio, non un vero bordo grigio) così comparire non
   sposta il layout. flex:1 (non aspect-ratio): l'altezza segue quella che resta nella cella della
   griglia dopo l'etichetta sotto, qualunque essa sia — non è detto sia quadrata. */
/* Bordo E raggio sullo STESSO elemento che ritaglia l'immagine (overflow:hidden qui, non un
   border-radius separato sull'immagine): la causa del disallineamento non era il classico
   "angolo interno più stretto di quello esterno" di un bordo spesso (quello è normale, la stessa
   tecnica di qualunque avatar con cornice) — era che prima bordo e raggio di selezione stavano
   su .studio-match (l'intera cella, etichetta compresa, raggio 10px) mentre la thumbnail aveva un
   raggio suo proprio e diverso (6px): due elementi, due valori scollegati. Qui invece c'è un solo
   raggio dichiarato una volta sola, che governa sia il bordo sia il ritaglio dell'immagine sotto
   — l'angolo interno dell'immagine risulta quindi sempre concentrico e coerente con quello del
   bordo, qualunque sia lo spessore di quest'ultimo. */
.studio-match-thumb-wrap {
  display: block;
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  border-radius: 16px;
  background: var(--grey-50);
  border: 4px solid transparent;
  transition: border-color 0.15s;
}

.studio-match.is-selected .studio-match-thumb-wrap {
  border-color: var(--blue);
}

/* Unico elemento cliccabile per selezionare la partita (sostituisce il vecchio <button
   class="studio-match">, che non poteva più contenere anche .studio-generate-btn-mobile sotto —
   un <button> non può annidarne un altro): riempie per intero .studio-match-thumb-wrap, reset
   completo dello stile nativo del <button> perché resti visivamente identico a prima. */
.studio-match-select {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
  background: none;
  border: none;
  cursor: pointer;
}

.studio-match-thumb {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Pulsante "Genera studio" sovrapposto alla thumbnail — sostituisce da telefono quello unico sotto
   la griglia (nascosto lì sotto i 600px, vedi sotto): nascosto di default (anche su PC, dove non
   deve mai comparire) e mostrato solo dentro .studio-match.is-selected nel blocco @media più in
   basso. display:none qui va scritto DOPO .btn nel foglio di stile (che dichiara
   "display: inline-block" senza condizioni): a parità di specificità vince l'ultima regola
   dichiarata, e .btn comparirebbe prima in ordine di sorgente. */
.studio-generate-btn-mobile {
  display: none;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  white-space: nowrap;
  /* più compatto della dimensione di default di .btn (pensata per pulsanti a piena riga come
     "Scarica per Windows"): qui deve stare dentro una singola thumbnail della griglia 2x2. */
  padding: 6px 10px;
  font-size: clamp(0.6rem, 3vw, 0.72rem);
}

/* Stesso motivo dell'override già presente su .studio-generate-btn: .btn-primary:hover
   sostituirebbe (non sommerebbe a) il transform di centratura qui sopra. */
.studio-generate-btn-mobile:hover {
  transform: translate(-50%, -50%) translateY(-1px);
}

.studio-match-label {
  flex: 0 0 auto;
  font-size: clamp(0.7rem, 1.6vw, 0.85rem);
  font-weight: 700;
  color: var(--navy);
  text-align: center;
}

/* A cavallo del bordo inferiore di .studio-box-inner, centrato in orizzontale — stessa tecnica di
   .mstb-overlay-stats/.spike-speed-bar/.ricezioni-overlay-court (bottom:0 + translate(-50%,50%)
   mette il CENTRO del pulsante esattamente sul bordo, sempre metà dentro/metà fuori). Ancorato a
   .studio-box (l'outer SENZA overflow:hidden, sopra), non a .studio-box-inner: se fosse dentro
   quest'ultimo la sua metà "fuori" verrebbe ritagliata via insieme al resto del contenuto. */
.studio-generate-btn {
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translate(-50%, 50%);
  z-index: 2;
  white-space: nowrap;
}

/* .btn (sopra) dichiara "display: inline-block" senza condizioni: un attributo HTML "hidden"
   (impostato/tolto in js/main.js entrando/uscendo dallo studio) non basterebbe a farlo sparire,
   perché quella regola d'autore vince SEMPRE sul "display:none" del solo foglio di stile dello
   user agent per [hidden], a prescindere dalla specificità — serve quindi questa regola esplicita. */
.studio-generate-btn[hidden] {
  display: none;
}

/* .btn-primary:hover (sopra) imposta anche lui "transform", per il piccolo effetto di
   sollevamento al passaggio del mouse: sullo stesso elemento vince solo l'ultima dichiarazione,
   quindi senza questo override qui il transform di :hover SOSTITUIREBBE (non si sommerebbe a)
   quello di centratura/sporgenza sopra, facendo "saltare" il pulsante fuori posizione appena
   sfiorato. Stesso translate(-50%,50%) più lo stesso translateY(-1px) di :hover, in un'unica
   dichiarazione. */
.studio-generate-btn:hover {
  transform: translate(-50%, 50%) translateY(-1px);
}

.studio-generate-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Vista 2: mini studio partita in sola lettura ── */
.studio-viewer-topbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px clamp(10px, 2.5vw, 18px);
  border-bottom: 1px solid var(--grey-200);
  flex: 0 0 auto;
}

.studio-viewer-exit {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--blue);
  font-weight: 700;
  font-size: 0.78rem;
  padding: 4px 6px 4px 2px;
}

.studio-viewer-exit svg {
  width: 16px;
  height: 16px;
}

.studio-viewer-name {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--navy);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.studio-tabs {
  display: flex;
  gap: 4px;
  padding: 8px clamp(10px, 2.5vw, 18px) 0;
  flex: 0 0 auto;
  overflow-x: auto;
}

.studio-tab {
  background: var(--grey-50);
  border: none;
  border-radius: 999px;
  padding: 6px 12px;
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--grey-600);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s;
}

.studio-tab.is-active {
  background: var(--blue);
  color: #fff;
}

.studio-tab-panel {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain; /* vedi .mv-rot-list */
  padding: clamp(10px, 2.5vw, 18px);
  /* barra di scorrimento azzurro tenue invece del grigio di sistema — scrollbar-color/-width
     (Firefox, e ormai anche Chrome/Edge recenti) più ::-webkit-scrollbar* sotto per Safari e i
     Chrome/Edge che non supportano ancora scrollbar-color. */
  scrollbar-color: rgba(59, 130, 246, 0.35) transparent;
  scrollbar-width: thin;
}

.studio-tab-panel::-webkit-scrollbar {
  width: 8px;
}
.studio-tab-panel::-webkit-scrollbar-track {
  background: transparent;
}
.studio-tab-panel::-webkit-scrollbar-thumb {
  background-color: rgba(59, 130, 246, 0.35);
  border-radius: 999px;
}
.studio-tab-panel::-webkit-scrollbar-thumb:hover {
  background-color: rgba(59, 130, 246, 0.55);
}

.studio-empty {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(0, 0, 0, 0.4);
  font-size: 0.8rem;
  text-align: center;
}

/* Griglia dei grafici per giocatore (tab Attacchi/Battute), stesso principio di
   .sv-charts-grid nell'app (StudioViewer.razor.css) ma con colonne più strette, tarate sulla
   larghezza di .studio-box invece che su una finestra intera. */
/* 3 colonne fisse da PC (non auto-fill, che su un riquadro largo come .studio-box-inner
   arriverebbe a 4): sotto gli 860px torna auto-fill (vedi il blocco @media più sotto), dove il
   riquadro è più stretto e 3 colonne fisse sarebbero già strette di loro. */
.studio-chart-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

.studio-chart-card {
  background: #fff;
  border: 1px solid var(--grey-200);
  border-radius: 8px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.studio-chart-player {
  font-size: 0.6rem;
  font-weight: 700;
  color: var(--navy);
  line-height: 1.15;
}

.studio-chart-count {
  font-size: 0.52rem;
  color: rgba(0, 0, 0, 0.45);
}

.studio-chart-mini {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.48rem;
  table-layout: fixed;
}

.studio-chart-mini th,
.studio-chart-mini td {
  padding: 1px 0;
  text-align: center;
  font-weight: 700;
  color: rgba(0, 0, 0, 0.55);
}

.studio-chart-mini th {
  font-weight: 600;
  color: rgba(0, 0, 0, 0.4);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.studio-stat-kill { color: #2563eb; }
.studio-stat-error { color: #dc2626; }

.studio-chart-court-wrap svg {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 4px;
}

.studio-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 6px;
}

.studio-chart-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 0.46rem;
  font-weight: 600;
  color: rgba(0, 0, 0, 0.5);
}

.studio-chart-legend-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* Griglia distribuzioni per rotazione (tab Distribuzioni), stesso principio di .sv-dist-grid */
/* Stessa scelta di .studio-chart-grid sopra: 3 colonne fisse da PC, auto-fill sotto gli 860px. */
.studio-dist-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

.studio-dist-card {
  background: #fff;
  border: 1px solid var(--grey-200);
  border-radius: 8px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.studio-dist-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 0.56rem;
  font-weight: 700;
  color: var(--navy);
}

.studio-dist-count {
  font-weight: 600;
  color: rgba(0, 0, 0, 0.45);
}

.studio-dist-card svg {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 4px;
}

/* Tabelle statistiche (tab Statistiche), stesso principio di .sv-stats-table ma più compatta */
.studio-stats-label {
  font-size: 0.68rem;
  font-weight: 800;
  color: var(--navy);
  margin: 14px 0 6px;
}

.studio-stats-label:first-child {
  margin-top: 0;
}

.studio-stats-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.6rem;
}

.studio-stats-table th,
.studio-stats-table td {
  padding: 4px 3px;
  text-align: center;
  white-space: nowrap;
}

.studio-stats-table th:first-child,
.studio-stats-table td:first-child {
  text-align: left;
}

.studio-stats-table thead th {
  background: #f0f4ff;
  color: rgba(0, 0, 0, 0.45);
  font-size: 0.5rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.studio-stats-table tbody td {
  border-top: 1px solid rgba(0, 0, 0, 0.06);
  color: #1a1a2e;
  font-variant-numeric: tabular-nums;
}

.studio-stats-pct {
  font-weight: 400;
  color: rgba(0, 0, 0, 0.4);
  font-size: 0.9em;
}

.split-media img {
  border-radius: var(--radius);
  box-shadow: 0 20px 45px rgba(11, 30, 61, 0.18);
}

.split-media video {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: 0;
  box-shadow: 0 20px 45px rgba(11, 30, 61, 0.18);
}

/* Rotellina di caricamento inserita da js/main.js come fratello di ogni <video> (dentro il suo
   contenitore -video-crop/.mv-preview-video, già position:relative) — nascosta di default,
   .is-visible attivata/disattivata dagli eventi nativi "loadstart"/"waiting"/"canplay"/"playing"
   del video stesso. z-index:2 per stare sopra il video (senza serve nulla su nessun altro
   elemento della pagina, quindi nessun conflitto di stacking altrove). box-shadow sull'anello
   (invece di uno sfondo pieno dietro) per restare leggibile sia su fotogrammi chiari che scuri
   del poster/video sottostante, senza coprirlo con un riquadro. */
.video-spinner {
  display: none;
  position: absolute;
  inset: 0;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 2;
}
.video-spinner.is-visible {
  display: flex;
}
.video-spinner::after {
  content: "";
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  box-shadow: 0 0 0 6px rgba(11, 30, 61, 0.25);
  animation: video-spinner-rotate 0.8s linear infinite;
}
@keyframes video-spinner-rotate {
  to {
    transform: rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .video-spinner::after {
    animation: none;
  }
}

/* Sezione "Analisi dettagliata": stesso riquadro (aspect-ratio 32:27) di .opposto-video-crop
   ("Visualizza velocemente ogni evento"), così i due player risultano identici a dimensione.
   Ritaglio sull'angolo in alto a sinistra del video sorgente (1244x820): object-fit:cover con
   object-position:left top riempie il riquadro senza deformarlo mostrando tutta l'altezza (source
   più "largo" del riquadro: l'altezza combacia esattamente, l'eccedenza in larghezza viene
   tagliata a destra). scale(1.1) aggiuntivo sul video (transform-origin di default, al centro
   dell'inquadratura già ritagliata) applica uno zoom del 10%, tagliando in eccesso anche in
   verticale (voluto, a differenza del semplice cover) grazie a overflow:hidden sul contenitore. */
.spike-video-media {
  position: relative;
}

.spike-video-crop {
  position: relative;
  overflow: hidden;
  aspect-ratio: 32 / 27;
  border-radius: var(--radius);
  box-shadow: 0 20px 45px rgba(11, 30, 61, 0.18);
}

.spike-video-media .spike-video-crop video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: left top;
  transform: scale(1.1);
  border-radius: 0;
  box-shadow: none;
}

/* Selettore di velocità/frame-per-frame a cavallo del bordo inferiore del player, centrato in
   orizzontale: bottom:0 + translateY(50%) mette il CENTRO verticale del box sul bordo (metà
   dentro, metà fuori dal video), left:50% + translateX(-50%) lo centra in orizzontale — stessa
   tecnica di .attacchi-traj-legend e di .mstb-overlay-stats ("Visualizza velocemente ogni
   evento"). Largo un terzo del riquadro video da desktop (33.333% di .spike-video-media, che ha
   la stessa larghezza di .spike-video-crop essendo quest'ultimo width:100% al suo interno) — da
   telefono resta 66.667% (vedi @media max-width:600px più sotto), troppo stretto altrimenti per
   restare leggibile/toccabile. Stessa identità grafica di .mv-tabs/.mv-tab (tab
   Punti/Azioni/Rotazioni di "Rimozione dei tempi morti") ma su sfondo bianco pieno (invece che
   grigio) per restare leggibile sopra il video. Comportamento gestito in js/main.js. */
.spike-speed-bar {
  position: absolute;
  left: 50%;
  bottom: 0;
  z-index: 2;
  transform: translate(-50%, 50%);
  width: 33.333%;
  display: flex;
  flex-direction: column;
  gap: 5px;
  background: #fff;
  border: 1px solid var(--grey-200);
  border-radius: var(--radius);
  padding: 7px;
  box-shadow: 0 10px 22px rgba(11, 30, 61, 0.22);
}

.spike-speed-label {
  font-size: 0.62rem;
  font-weight: 700;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #000;
  padding: 0 2px;
}

.spike-speed-row {
  display: flex;
  gap: 4px;
}

.spike-speed-btn {
  flex: 1;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--grey-600);
  font-size: 0.75rem;
  font-weight: 700;
  font-family: inherit;
  padding: 0.4rem 0.3rem;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s;
}

.spike-speed-btn:hover  { background: rgba(5, 39, 103, 0.06); color: var(--navy); }
.spike-speed-btn.active { background: var(--navy); color: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); }

.spike-frame-row {
  display: flex;
  gap: 4px;
}

.spike-frame-btn {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border: 1px solid var(--grey-200);
  border-radius: 7px;
  background: #fff;
  color: var(--navy);
  font-size: 0.72rem;
  font-weight: 600;
  font-family: inherit;
  padding: 0.35rem 0.3rem;
  cursor: pointer;
  transition: background 0.15s;
}

.spike-frame-btn:hover { background: rgba(5, 39, 103, 0.06); }
.spike-frame-btn svg   { flex-shrink: 0; }

.split-text .kicker {
  color: var(--blue);
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 12px;
  display: block;
}

.split-text h2 {
  font-size: clamp(1.5rem, 2.8vw, 2rem);
  margin: 0 0 16px;
  font-weight: 800;
}

.split-text p {
  color: var(--grey-600);
  margin: 0 0 16px;
}

.split-text ul {
  margin: 0;
  padding-left: 20px;
  color: var(--grey-600);
}

.split-text li { margin-bottom: 8px; }

/* Sezione "Rimozione dei tempi morti": ricostruzione (sola navigazione) del player+sidebar
   Punti/Azioni/Rotazioni di MatchViewer.razor nell'app — vedi index.html/js/main.js. Sfondo
   bianco (niente .alt), a differenza delle sezioni precedenti.
   .mv-container ha anche la classe .reveal-split (stesso sistema di comparsa in scroll delle
   altre sezioni: setRevealVisible in js/main.js, parte dello scroll a container, cerca
   .reveal-split nella sezione appena diventata attiva e le mette/toglie is-visible). Non essendo
   una vera griglia a due colonne, si riscrivono qui align-items/
   max-width per neutralizzare le regole pensate per .split-media/.split-text-col (altrimenti
   .mv-container si restringerebbe a 900px e i suoi figli non si stirerebbero più a piena
   larghezza) — l'animazione vera e propria è sotto, su .mv-head/.mv-preview invece che su
   .split-media/.split-text-col. */
.mv-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  /* max-width dimensionato esattamente sulla somma video + gap + .mv-sidebar (larghezza fissa
     calcolata dall'aspect-ratio, vedi .mv-preview-video) così la riga non lascia spazio vuoto
     a destra della sidebar.
     width:100% è necessario perché .container gli dà margin:0 auto — dentro un flex-parent in
     colonna (.screen-section) i margini auto sul cross-axis fanno "collassare" l'elemento al
     contenuto (shrink-to-fit) invece di stirarlo, vanificando il max-width qui sotto. */
  width: 100%;
  max-width: 1022px;
}

/* comparsa in scroll granulare (a differenza delle altre sezioni, qui tre pezzi indipendenti
   invece di due): il titolo entra dall'alto, il video da sinistra, la sidebar Punti/Azioni/
   Rotazioni da destra — l'animazione va quindi sui due figli di .mv-preview (non su .mv-preview
   stesso, che resta un contenitore di layout puro) oltre che su .mv-head. */
.mv-container .mv-head,
.mv-container .mv-preview-video,
.mv-container .mv-sidebar {
  opacity: 0;
  transition: opacity 0.7s ease, transform 0.7s ease;
}
.mv-container .mv-head {
  transform: translateY(-40px);
}
.mv-container .mv-preview-video {
  transform: translateX(-60px);
  transition-delay: 0.2s;
}
.mv-container .mv-sidebar {
  transform: translateX(60px);
  transition-delay: 0.35s;
}
.mv-container.is-visible .mv-head,
.mv-container.is-visible .mv-preview-video,
.mv-container.is-visible .mv-sidebar {
  opacity: 1;
  transform: translate(0, 0);
}

.mv-head {
  max-width: 720px;
  margin: 0 auto 26px;
  text-align: center;
}

.mv-head h2 {
  font-size: clamp(1.6rem, 3vw, 2.3rem);
  margin: 0 0 14px;
  font-weight: 800;
  color: var(--blue);
}

.mv-head p {
  color: var(--grey-600);
  font-size: 1.25rem;
  margin: 0;
}

/* testo alternativo per il telefono (vedi @media max-width:600px più sotto): nascosto qui,
   sopra i 600px resta invariato il paragrafo normale */
.mv-head-mobile-text {
  display: none;
}

/* stesso meccanismo di .mv-head-mobile-text sopra, per il testo di "Tracciamento accurato di
   ogni giocatore": la versione desktop invita a scrollare con la rotellina del mouse sul
   grafico (gesto che da telefono non esiste), quella mobile invita invece a toccare
   direttamente una freccia — vedi @media max-width:600px più sotto. */
.ricezioni-lead-mobile {
  display: none;
}

/* aspetto: .btn.btn-primary (vedi HTML), pulsante blu pieno invece del vecchio link inline
   sottolineato — nascosto qui, come .mv-head-mobile-text sopra, compare solo sotto i 600px (vedi
   @media più sotto) */
.mv-reveal-btn {
  display: none;
}

/* "Prova"/"Esci" delle quattro sezioni con box/tabelle sovrapposte al video ("Visualizza
   velocemente ogni evento", "Analisi dettagliata", "Ogni alzata con la sua traiettoria",
   "Tracciamento accurato di ogni giocatore"): da telefono quei box partono nascosti (un video
   "pulito" di default, vedi ciascuno più sotto in @media max-width:600px) — "Prova" li rivela
   aggiungendo .mtry-open al ".split" della sezione (gestito in js/main.js, stesso meccanismo
   generico per tutte e quattro), "Esci" li nasconde di nuovo. Nascosti qui di default (solo da
   desktop/tablet non esistono affatto): compaiono solo sotto i 600px, dove è visibile solo uno
   dei due alla volta in base a .mtry-open (vedi override lì). Stesso aspetto blu pieno di
   .mv-reveal-btn sopra per "Prova" (.btn.btn-primary in HTML); "Esci" ha invece HTML .btn-ghost
   (contorno, senza sfondo) come base ma qui sotto viene ricolorato di rosso pieno — stesso
   rosso/hover di ".mv-exit-btn" ("Rimozione dei tempi morti", unico altro pulsante "Esci" del
   sito) per restare coerente ovunque compaia un'uscita. */
.mtry-btn,
.mtry-exit-btn {
  display: none;
  margin: 18px auto 0;
}

.mtry-exit-btn {
  background: #ef4444;
  border-color: #ef4444;
  color: #fff;
}

.mtry-exit-btn:hover {
  background: #dc2626;
  border-color: #dc2626;
  color: #fff;
}

/* Altezza della riga FISSA (a differenza delle altre sezioni ritagliate, che la lasciano
   determinare dall'aspect-ratio): qui .mv-sidebar ha una lista che può crescere parecchio
   (fino a 12 punti coi loro eventi), e in una riga flex senza altezza propria è lei — non il
   video — a decidere quanto alta viene tutta la riga (stretch degli item flex usa il PIÙ ALTO
   contenuto "naturale" tra i due, non quello del video). Con l'altezza fissata qui, invece,
   .mv-preview-video calcola la propria LARGHEZZA dall'aspect-ratio (sotto), e .mv-sidebar scrolla
   il proprio contenuto internamente invece di spingere in basso il bordo della card.
   justify-content:center: su finestre più basse (60vh < 540px, oppure quando .mv-preview viene
   compressa in altezza perché testo+video non ci stanno in .screen-section) il video si restringe
   ma .mv-sidebar resta al suo max-width — senza centrare la riga, lo spazio che avanza finirebbe
   tutto a destra della sidebar invece che ripartito ai due lati, facendo sembrare il blocco
   spostato rispetto al centro di .mv-container (che invece è sempre centrato sulla pagina). */
.mv-preview {
  display: flex;
  justify-content: center;
  gap: 22px;
  height: min(540px, 60vh);
}

/* il video sorgente è 1280x720: ritaglia 1/9 a sinistra e 2/9 a destra (rimane la fascia
   centrale 6/9 = 2/3), stessa tecnica/frazioni di .ricezioni-video-crop — infatti l'aspect-ratio
   è lo stesso 32:27. flex:0 0 auto (non "1 1 62%" come si potrebbe pensare): la larghezza NON è
   una frazione della riga, è quella che l'aspect-ratio calcola dall'altezza fissa qui sopra —
   .mv-sidebar prende poi tutto lo spazio che resta (flex:1 1 auto, sotto). */
.mv-preview-video {
  flex: 0 0 auto;
  height: 100%;
  aspect-ratio: 32 / 27;
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 20px 45px rgba(11, 30, 61, 0.18);
}

.mv-preview-video video {
  position: absolute;
  top: 0;
  left: 0;
  width: 150%;
  max-width: none;
  height: 100%;
  /* scale(1.02) aggiuntivo: senza, il bordo vero del video sorgente può cadere esattamente sul
     confine del ritaglio — un filo di sotto-pixel dove compositing/decodifica GPU e overflow:hidden
     non si allineano perfettamente lascia intravedere quel bordo (bande nere/bianche di 1px,
     sfarfallanti da un frame all'altro, vedi stesso commento su .attacchi-video-crop). Zoomando
     dell'ulteriore 2% attorno al centro si guadagna ~1% di margine per lato senza spostare
     percettibilmente l'inquadratura. */
  transform: translateX(-11.111%) scale(1.02);
  display: block;
}

.mv-sidebar {
  flex: 1 1 264px;
  max-width: 312px;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--grey-200);
  border-radius: var(--radius);
  background: #fff;
  overflow: hidden;
}

/* .mv-rail avvolge .mv-tabs + il pulsante Esci (mv-exit-btn, sotto): su desktop/tablet resta
   invisibile come contenitore (display:contents) così .mv-tabs si comporta esattamente come
   prima (figlio diretto di .mv-sidebar). Diventa una barra verticale vera sotto i 600px quando
   la tabella è aperta (mv-table-visible, vedi il blocco @media più sotto), col pulsante Esci
   ancorato in fondo. */
.mv-rail {
  display: contents;
}

/* Pulsante "Esci" (chiude la vista tabella da telefono, vedi mvExitBtn in js/main.js): nascosto
   ovunque tranne che nella barra verticale mobile, dove .mv-rail lo mostra in rosso. */
.mv-exit-btn {
  display: none;
}

/* ── Tab bar (Punti/Azioni/Rotazioni) — stessa grafica di .rot-team-toggle nell'app ── */
.mv-tabs {
  display: flex;
  gap: 3px;
  background: var(--grey-50);
  border-bottom: 1px solid var(--grey-200);
  padding: 8px;
  flex-shrink: 0;
}

.mv-tab {
  flex: 1;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--grey-600);
  font-size: 0.82rem;
  font-weight: 700;
  font-family: inherit;
  padding: 0.45rem 0.5rem;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}

.mv-tab:hover { background: rgba(5, 39, 103, 0.06); color: var(--navy); }
.mv-tab.active { background: var(--navy); color: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); }

.mv-panel {
  flex: 1;
  min-height: 0;
}

/* .mv-panel (Punti/Azioni) e .mv-panel-rotazioni (Rotazioni): entrambi diventano una colonna
   flex con la barra tab "Set N"/"Rot. N" FISSA in cima (.mv-set-tab-bar, vedi sotto — più i
   toggle squadra/situazione per Rotazioni, .mv-rot-controls) e una lista sotto che scrolla per
   conto suo (.mv-scroll-list/.mv-rot-list). La barra sta quindi FUORI dall'area che scorre
   (non in "position: sticky" dentro di essa, come nella vecchia barra pillola): i punti non
   possono più "intravedersi" scorrendo dietro o sopra di essa. :not([hidden]): un display
   esplicito qui batterebbe sempre — qualunque specificità — il display:none di [hidden] nello UA
   stylesheet, restando visibile anche sulle altre tab; qui infatti lo era, bug segnalato e
   corretto. */
.mv-panel:not([hidden]),
.mv-panel-rotazioni:not([hidden]) {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0;
}

.mv-scroll-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain; /* vedi .mv-rot-list */
  padding: 10px;
  box-sizing: border-box;
  background: #fff;
}

.mv-rot-controls { padding: 10px 10px 8px; flex-shrink: 0; }
/* overscroll-behavior: contain — quando la lista arriva a fondo corsa lo scorrimento NON viene
   passato alla pagina sotto ("scroll chaining"), che a tabella aperta deve restare ferma. Il
   caso normale è già gestito in js/main.js (scrollableAt nel listener touchmove), ma se la lista
   consuma l'inizio del gesto e finisce a metà swipe la decisione è ormai del browser: serve
   questa proprietà. */
.mv-rot-list { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 10px; box-sizing: border-box; background: #fff; }

/* ── Toggle squadra (tab Rotazioni) — stessa grafica di .rot-team-toggle nell'app ── */
.mv-rot-team-toggle {
  display: flex;
  gap: 3px;
  background: rgba(0, 0, 0, 0.06);
  border-radius: 8px;
  padding: 3px;
}

.mv-rot-team-btn {
  flex: 1;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: #777;
  font-size: 0.78rem;
  font-weight: 600;
  font-family: inherit;
  padding: 0.28rem 0.5rem;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mv-rot-team-btn:hover { background: rgba(0, 0, 0, 0.07); color: #333; }
.mv-rot-team-btn.active { background: #fff; color: var(--navy); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); }

/* toggle "Situazione" (Tutte/Battuta/Ricezione), stessa grafica del toggle squadra sopra di lui */
.mv-rot-situation-toggle { margin-top: 6px; }

/* .mv-rot-won/.mv-rot-lost (V/P, Vinti/Persi, tra parentesi — vedi renderRotazioni in
   js/main.js): colore sempre esplicito (verde/rosso), non ereditato dal testo della tab, ma più
   smorzato del solito verde/rosso pieno usato altrove nel sito (es. .mv-plus1.shown) — dentro la
   tab, accanto al numero della rotazione, un colore troppo acceso distrarrebbe dall'etichetta
   principale. Leggibili sia da tab attiva (sfondo bianco) che inattiva (sfondo grigio-azzurro). */
.mv-rot-stats { font-size: 0.68rem; font-weight: 700; flex-shrink: 0; }
.mv-rot-won { color: #6b9e7e; }
.mv-rot-lost { color: #c47a76; }

/* ── Barra tab "Set N" (Punti/Azioni) / "Rot. N" (Rotazioni) per cambiare set/rotazione — stessa
   grafica di ".filt-tab-bar"/".filt-tab" nell'app (TabFilters.razor: le due sotto-tab "Filtri"/
   "Risultati" della tab Filtri), stile "browser" (Chrome): angoli superiori arrotondati, tab
   attiva bianca che si fonde SENZA alcuna linea di separazione col contenuto sotto (stesso
   bianco, niente bordo/padding tra i due — esattamente come in un vero browser), tab inattive su
   sfondo grigio-azzurro. Fissa fuori dall'area che scorre (non "position: sticky" al suo interno,
   come nella vecchia barra pillola): resta quindi sempre uguale a se stessa, indipendentemente da
   come scorre la lista sotto — niente più punti che si "intravedono" dietro o sopra di essa.
   overflow:hidden (non "auto"): con min-width:0 sotto le tab si restringono sempre per stare
   tutte in riga (fino a 3-4, mai il contrario), quindi non c'è mai davvero altro da scrollare —
   "auto" mostrava comunque una barra di scorrimento appena il contenuto (a causa del min-width
   implicito "auto" dei figli flex) superava anche di un pixel la larghezza disponibile. */
.mv-set-tab-bar {
  display: flex;
  flex-direction: row;
  flex-shrink: 0;
  padding: 6px 8px 0;
  gap: 3px;
  background: #f0f3fb;
  overflow: hidden;
}

.mv-set-tab {
  flex: 1;
  min-width: 0;
  padding: 0.3rem 0.4rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  border: 1.5px solid transparent;
  border-radius: 6px 6px 0 0;
  cursor: pointer;
  color: #888;
  background: transparent;
  font-family: inherit;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
}
.mv-set-tab:hover:not(.active) { background: #e4e9f4; color: #555; }
.mv-set-tab.active {
  background: #fff;
  color: var(--navy);
  font-weight: 700;
}

/* ── Punto (condiviso da Punti/Rotazioni) — stessa grafica di .point-box nell'app ── */
.mv-point {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.2rem;
  width: 100%;
  box-sizing: border-box;
  border: 1.5px solid var(--grey-200);
  border-radius: 10px;
  background: #fff;
  padding: 0.45rem 0.9rem;
  margin-bottom: 0.5rem;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  transition: border-color 0.15s, background 0.15s;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

.mv-point:hover { border-color: var(--navy); background: #f0f4ff; }

.mv-point.is-current {
  border-color: var(--blue);
  background: rgba(59, 130, 246, 0.07);
  box-shadow: inset 3px 0 0 var(--blue), 0 1px 3px rgba(0, 0, 0, 0.04);
}

.mv-point-num {
  font-size: 0.65rem;
  color: #aaa;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mv-point-score {
  display: grid;
  grid-template-columns: 1fr auto auto;
  column-gap: 0.45rem;
  row-gap: 0.06rem;
  align-items: center;
  width: 100%;
}

.mv-team-name {
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--navy);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mv-team-score {
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--navy);
  text-align: right;
  font-variant-numeric: tabular-nums;
  min-width: 1.6ch;
}

.mv-plus1 {
  font-size: 0.62rem;
  font-weight: 700;
  color: transparent;
  min-width: 1.5rem;
  text-align: left;
}
.mv-plus1.shown { color: #22a55e; }

/* ── Lista eventi (tab Azioni) — stessa grafica di .event-list/.event-box nell'app ── */
.mv-event-list {
  border-left: 2px solid var(--grey-200);
  margin-left: 14px;
  padding-left: 6px;
  padding-bottom: 2px;
  margin-bottom: 0.5rem;
}

.mv-event {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 0.24rem 0.4rem;
  border-radius: 6px;
  border: none;
  background: transparent;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.12s;
}

.mv-event:hover { background: rgba(0, 0, 0, 0.05); }

.mv-event.is-current {
  background: rgba(59, 130, 246, 0.09);
  box-shadow: inset 2.5px 0 0 var(--blue);
}

.mv-event-label {
  font-size: 0.75rem;
  font-weight: 500;
  color: #444;
}

.mv-empty {
  color: var(--grey-600);
  font-size: 0.8rem;
  padding: 8px 4px;
}

/* Banner introduttivo della pagina tutorial: testo a sinistra, "collage" di tre screenshot reali
   dell'app sovrapposti a destra (stessa idea delle card sovrapposte in index.html — .mstb-overlay-
   card e affini — qui applicata a screenshot interi invece che a piccoli grafici d'accento). */
/* Alta quanto lo schermo (meno la toolbar in alto, --header-h — impostata da updateHeaderHeightVar
   in js/main.js, indipendente dal sistema di scroll-snap più sotto in questo file, che qui non è
   attivo: niente .screen-section su questa pagina, solo la stessa variabile CSS). min-height (non
   height) e nessun overflow:hidden: su schermi molto stretti/bassi o con testo più lungo del solito
   il banner può comunque crescere oltre lo schermo invece di tagliare il contenuto. */
/* Prima schermata di tutorial.html: foto del campo come sfondo, con sopra lo stesso velo scuro
   in gradiente usato dagli hero di index.html e download.html (il testo diventa quindi chiaro,
   vedi le due regole del titolo e del sommario più sotto). Da telefono la foto cambia: quella da
   PC è orizzontale e, ritagliata in "cover" su uno schermo stretto e alto, mostrerebbe solo una
   fetta centrale del campo — "campo cellulare.jpg" è la versione verticale della stessa scena
   (vedi il blocco @media qui sotto). */
.tutorial-intro {
  background: linear-gradient(180deg, rgba(11, 30, 61, 0.78) 0%, rgba(11, 30, 61, 0.7) 45%, rgba(11, 30, 61, 0.86) 100%),
    url('../images/stock/campo.jpg') center / cover no-repeat;
  padding-top: 40px;
  padding-bottom: 40px;
  min-height: calc(100vh - var(--header-h, 76px));
  min-height: calc(100dvh - var(--header-h, 76px));
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* Rapporto 2:3 (come .step-body) così le tre immagini occupano 3/5 della riga invece di metà.
   align-items:center (il default ereditato da .split) centra il testo sull'altezza della riga,
   più alta di lui perché dettata dalla card del collage. */
.tutorial-intro .split {
  grid-template-columns: 2fr 3fr;
  gap: 64px;
  align-items: center;
}

.tutorial-intro-text h1 {
  font-size: clamp(1.7rem, 3.4vw, 2.5rem);
  margin: 0 0 18px;
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.2;
  /* chiari sul velo scuro della foto di sfondo (vedi .tutorial-intro) */
  color: #fff;
}

.tutorial-intro-lead {
  font-size: 1.15rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.88);
  margin: 0 0 18px;
}

/* Su schermi stretti la foto orizzontale lascerebbe vedere solo una striscia centrale del campo:
   si passa alla versione verticale della stessa scena. Cambia solo l'immagine, il velo scuro
   resta identico. */
@media (max-width: 720px) {
  .tutorial-intro {
    background-image: linear-gradient(180deg, rgba(11, 30, 61, 0.78) 0%, rgba(11, 30, 61, 0.7) 45%, rgba(11, 30, 61, 0.86) 100%),
      url('../images/stock/campo%20cellulare.jpg');
  }
}

/* Riquadro che contiene le tre card assolute: l'aspect-ratio è calcolata sulle posizioni delle
   card qui sotto in modo che il bordo inferiore della card in primo piano (quella più in basso,
   top:42% + width:90%) coincida esattamente con il fondo del riquadro, senza margine residuo —
   vedi il commento su .tutorial-intro .split più sopra. Nessuna rotazione sulle card: solo
   posizione e dimensione, per non deformarne la lettura — ogni screenshot è ridotto in modo
   lineare (stessa proporzione larghezza/altezza dell'originale), mai stirato. */
.tutorial-intro-media {
  position: relative;
  width: 100%;
  aspect-ratio: 1.14;
}

.tintro-card {
  position: absolute;
  /* l'attributo HTML height="715" (messo per evitare layout shift) resterebbe altrimenti fisso in
     px: senza "height:auto" qui, la larghezza in percentuale sotto scala ma l'altezza no, deformando
     l'immagine. */
  height: auto;
  border-radius: var(--radius);
  border: 6px solid #fff;
  box-shadow: 0 14px 30px rgba(11, 30, 61, 0.16);
}

/* Sullo sfondo, spostata verso sinistra rispetto alla card centrale. */
.tintro-card-back {
  left: -4%;
  top: 0;
  width: 78%;
  z-index: 1;
}

/* Card centrale, spostata verso destra rispetto a quella di sfondo. */
.tintro-card-middle {
  left: 18%;
  top: 24%;
  width: 82%;
  z-index: 2;
}

/* La card in primo piano è la più grande e ha l'ombra più marcata delle altre due, per leggersi
   chiaramente come quella davanti. */
.tintro-card-front {
  left: 0;
  top: 42%;
  width: 90%;
  z-index: 3;
  box-shadow: 0 22px 50px rgba(11, 30, 61, 0.24);
}

/* Comparsa in ingresso del banner (al caricamento della pagina, non in scroll: il banner è alto
   quanto lo schermo, quindi è già tutto visibile da subito — stesso meccanismo di ".hero-reveal"
   in index.html, classe "is-visible" aggiunta da js/main.js con un doppio requestAnimationFrame).
   Il testo entra da sinistra, le tre card da destra una alla volta (transition-delay scaglionato
   sulle tre, dalla più lontana/sfondo alla più vicina/primo piano). */
.tutorial-hero-reveal .tutorial-intro-text {
  opacity: 0;
  transform: translateX(-50px);
  transition: opacity 1.1s ease, transform 1.1s ease;
}

.tutorial-hero-reveal .tintro-card {
  opacity: 0;
  transform: translateX(50px);
  transition: opacity 1.1s ease, transform 1.1s ease;
}

.tutorial-hero-reveal .tintro-card-back   { transition-delay: 0.15s; }
.tutorial-hero-reveal .tintro-card-middle { transition-delay: 0.35s; }
.tutorial-hero-reveal .tintro-card-front  { transition-delay: 0.55s; }

.tutorial-hero-reveal.is-visible .tutorial-intro-text,
.tutorial-hero-reveal.is-visible .tintro-card {
  opacity: 1;
  transform: translateX(0);
}

@media (max-width: 860px) and (orientation: portrait) {
  /* .tutorial-intro .split ha specificità più alta della regola generica ".split" più sotto in
     questo file (quella che normalmente collassa tutti gli split a una colonna da telefono): va
     quindi ripetuta qui esplicitamente, altrimenti vincerebbe il 2fr/3fr da desktop anche sotto
     gli 860px. */
  .tutorial-intro .split {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }
  .tutorial-intro-text {
    text-align: center;
  }
  .tutorial-intro-media {
    margin-top: 8px;
    max-width: 420px;
    margin-left: auto;
    margin-right: auto;
  }
}

/* Steps (tutorial) */
.steps-section {
  padding-top: 40px;
}

.steps {
  counter-reset: step;
  display: flex;
  flex-direction: column;
  gap: 0;
}

.step {
  padding: 36px 0;
  border-bottom: 1px solid var(--grey-200);
}

/* Il primo step non ha bisogno del proprio spazio in più sopra: lo spazio dopo il banner lo dà
   già .steps-section (unico punto da cui regolare il distacco dal banner). */
.steps .step:first-child { padding-top: 0; }

.step:last-child { border-bottom: none; }

/* Titolo e numero sulla stessa riga (il tag categoria è stato tolto: il numero fa già capire
   che è uno step di una sequenza). */
.step-title-row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 10px;
}

.step-num {
  counter-increment: step;
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--navy);
  color: var(--blue-light);
  font-weight: 800;
  font-size: 0.95rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.step-num::before { content: counter(step); }

/* Testo a sinistra, player a destra: stessa struttura a due colonne di .split, qui scoperta
   sul contenuto di ogni step invece che su un'intera sezione. Rapporto 2:3 così il player
   occupa 3/5 della riga. */
.step-body {
  display: grid;
  grid-template-columns: 2fr 3fr;
  gap: 32px;
  align-items: center;
}

.step h3 {
  margin: 0;
  font-size: 1.2rem;
}

.step p {
  margin: 0 0 14px;
  color: var(--grey-600);
}

.step-video {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 14px 30px rgba(11, 30, 61, 0.12);
}

.step-video iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Ingresso in scroll di ogni step: il testo entra da sinistra, il player da destra, ma non con
   una transizione che scatta a una soglia — la loro posizione è una funzione continua di quanto
   si è scorso, quindi scorrendo all'indietro tornano indietro. L'avanzamento (0 = fuori, 1 =
   arrivato) lo scrive js/main.js su ogni .step in --step-tp (testo) e --step-vp (player, un po'
   più in ritardo). Niente transition: il valore cambia a ogni frame ed è già lui l'animazione;
   una transizione sopra non farebbe che introdurre un ritardo rispetto al dito/rotella.
   I valori di default (1) valgono se il JS non gira: tutto visibile e al suo posto. */
.step-text {
  opacity: var(--step-tp, 1);
  transform: translateX(calc(-40px * (1 - var(--step-tp, 1))));
  will-change: opacity, transform;
}

.step-video {
  opacity: var(--step-vp, 1);
  transform: translateX(calc(40px * (1 - var(--step-vp, 1))));
  will-change: opacity, transform;
}

/* CTA band */
.cta-band {
  background: linear-gradient(120deg, var(--navy), var(--navy-mid));
  color: #fff;
  text-align: center;
  padding: 70px 24px;
  border-radius: var(--radius);
}

.cta-band h2 {
  font-size: clamp(1.5rem, 3vw, 2.1rem);
  margin: 0 0 14px;
}

.cta-band p {
  color: #cfd6e6;
  margin: 0 0 30px;
}

/* Footer */
footer {
  background: var(--navy);
  color: #a9b2c6;
  padding: 46px 0 28px;
  font-size: 0.9rem;
}

.footer-grid {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 24px;
  padding-bottom: 24px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  margin-bottom: 20px;
}

footer a { text-decoration: none; color: #a9b2c6; }
footer a:hover { color: #fff; }

.footer-links {
  display: flex;
  gap: 22px;
}

/* Pulsanti dell'ultima schermata ("Scarica Spike Net" + "Vedi i tutorial"): centrati, fianco a
   fianco quando c'è spazio, impilati altrimenti (telefono stretto) — stesso .btn-primary/
   .btn-ghost usati altrove, .cta-band qui sotto li ricolora per restare leggibili sul suo sfondo
   scuro. */
.cta-actions {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 16px;
}

/* .btn-ghost di base (bordo grigio chiaro/testo blu navy, pensati per uno sfondo bianco) sarebbe
   quasi illeggibile sullo sfondo scuro di .cta-band — qui riletto in negativo: bordo/testo
   bianchi, hover con un velo bianco leggero al posto del grigio chiaro di base (che sparirebbe
   sul navy). */
.cta-band .btn-ghost {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.4);
}
.cta-band .btn-ghost:hover {
  background: rgba(255, 255, 255, 0.12);
}

/* Responsive */
/* "and (orientation: portrait)" su questi tre breakpoint: un telefono ruotato in orizzontale ha
   spesso una larghezza (CSS px) superiore a questi breakpoint pensati per lo schermo stretto in
   verticale, ma non sempre — senza il vincolo di orientamento, un telefono più piccolo in
   landscape (es. ~700px) attiverebbe comunque l'impilamento mobile pur avendo lo spazio per il
   layout desktop a due colonne. Con orientation:portrait, il landscape usa sempre il layout da
   PC indipendentemente dalla larghezza esatta del dispositivo. */
@media (max-width: 860px) and (orientation: portrait) {
  /* Indicatore di posizione nella pagina: solo da PC, vedi .page-dots più sopra. */
  .page-dots {
    display: none;
  }

  /* .mstb-wrap ha già overflow-x:auto (scroll interno voluto per .mstb-table, troppo larga per
     stare in una sola schermata): ma alcuni browser mobile, nel decidere quanto allargare il
     viewport di layout, non tengono conto di quello scroll interno e allargano comunque l'intera
     pagina per "fare stare" quel contenuto — risultato: tutta la pagina scorre in orizzontale,
     non solo la tabella. overflow-x:hidden qui blocca lo scroll orizzontale a livello di pagina
     (senza toccare .mstb-wrap, che scorre comunque al suo interno normalmente). */
  html, body { overflow-x: hidden; }

  /* Le 3 colonne fisse di .studio-chart-grid/.studio-dist-grid (sopra) sono pensate per la
     larghezza di .studio-box-inner da PC: sotto gli 860px (box più stretto, spesso a piena
     larghezza dello schermo — vedi .studio-media più sotto) tornano ad auto-fill, che sceglie da
     sola quante colonne stanno comode invece di stringerle forzatamente a 3. */
  .studio-chart-grid {
    grid-template-columns: repeat(auto-fill, minmax(108px, 1fr));
  }
  .studio-dist-grid {
    grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  }

  /* .mstb-overlay-dist/.mstb-overlay-court ("Statistiche di squadra") sporgono di proposito
     oltre il bordo del riquadro (right/left negativi, vedi i commenti sopra) — un effetto voluto
     in desktop, dove il riquadro ha ampi margini attorno. Sotto 860px il riquadro arriva quasi al
     bordo dello schermo, quindi quella sporgenza esce dalla viewport e causa scroll orizzontale
     sulla pagina intera. Qui si azzera solo l'offset (le card restano identiche, semplicemente a
     filo invece che a cavallo del bordo). (".ricezioni-overlay-court" non è più tra queste: è
     centrata in orizzontale, non sporge lateralmente — vedi sopra.) */
  .mstb-overlay-dist { right: 0; }
  .mstb-overlay-court { left: 0; }

  /* Il riquadro "Direzioni ricezione (S1)" più compatto (width/max-width ridotte a 58%/300px,
     padding-top/bottom dimezzato a 2.5px) e il campo un ulteriore 5% più piccolo
     (transform:scale(0.95) sull'SVG) sono richiesti solo per "lo schermo largo" — qui, sotto gli
     860px in verticale (compreso un telefono, mai "PC"), si torna ai valori della versione
     precedente: width/max-width 72%/380px, padding-top/bottom 5px, nessuno scale aggiuntivo sul
     campo (resta solo il 10% di riduzione universale via viewBox, invariato a qualunque
     risoluzione — vedi il commento sopra .ricezioni-court-svg in index.html). */
  .ricezioni-overlay-court {
    width: 72%;
    max-width: 380px;
    padding-top: 5px;
    padding-bottom: 5px;
  }
  .ricezioni-court-svg {
    transform: none;
  }

  /* la height fissa della riga desktop (sopra) non ha senso impilata in colonna: qui il video
     torna a calcolare la propria altezza dall'aspect-ratio in base alla larghezza (piena, quella
     della colonna) invece che il contrario. */
  .mv-preview { flex-direction: column; height: auto; }
  .mv-preview-video { flex: none; height: auto; max-width: none; }
  .mv-sidebar { height: 360px; flex: none; max-width: none; }
  /* minmax(0, 1fr) e non semplicemente "1fr": una colonna 1fr ha un minimo implicito "auto" (il
     max-content dei suoi elementi) — con .mstb-table che ha min-width:460px dentro, il grid
     intero si allargherebbe fino a quella larghezza invece di stare negli ~342px disponibili su
     mobile, causando lo scroll orizzontale di tutta la pagina invece che il solo scroll interno
     già previsto su .mstb-wrap (overflow-x:auto). minmax(0, 1fr) toglie quel minimo, lasciando
     la colonna libera di restringersi alla larghezza reale dello schermo. */
  .split, .split.reverse { grid-template-columns: minmax(0, 1fr); }
  .split.reverse .split-media,
  .split.reverse .split-text { order: initial; }
  .step-body { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .step-text { text-align: center; }
  /* Da telefono il cerchio numerato torna sopra al titolo (non più a lato, come da desktop),
     centrato insieme al resto del testo. */
  .step-title-row {
    flex-direction: column;
    align-items: center;
    gap: 8px;
  }
  .reveal-split,
  .reveal-split.reveal-reverse {
    grid-template-columns: minmax(0, 1fr);
  }
  /* il wrapper "sparisce" dal layout: titolo e paragrafo diventano elementi indipendenti,
     così il titolo può salire sopra il video mantenendo il paragrafo sotto */
  .reveal-split .split-text-col {
    display: contents;
  }
  .reveal-split .reveal-title {
    order: -1;
  }
  /* ordine esplicito (indipendente dalla posizione nel DOM): titolo, poi video/immagine, poi testo */
  .reveal-split .split-media {
    order: 0;
  }
  .reveal-split .split-text {
    order: 1;
  }
  /* "Statistiche di squadra": testo subito dopo il titolo, prima della tabella (vedi anche
     @media max-width:600px più sotto, stesso motivo) */
  section.stats-alt .split-text {
    order: 0;
  }
  section.stats-alt .split-media {
    order: 1;
  }
  /* comparsa uniforme anche da stretti: stessa direzione per entrambe le sezioni, anche quella speculare */
  .reveal-split .split-media,
  .reveal-split.reveal-reverse .split-media {
    transform: translateX(-60px);
  }
  .reveal-split.is-visible .split-media,
  .reveal-split.reveal-reverse.is-visible .split-media {
    transform: translateX(0);
  }
  /* il wrapper con display:contents non genera più una sua "scatola" da animare:
     l'effetto di comparsa va riapplicato ai due elementi rimasti indipendenti */
  .reveal-split .reveal-title,
  .reveal-split .split-text {
    opacity: 0;
    transform: translateX(60px);
    transition: opacity 0.7s ease, transform 0.7s ease;
    transition-delay: 0.25s;
  }
  .reveal-split.is-visible .reveal-title,
  .reveal-split.is-visible .split-text {
    opacity: 1;
    transform: translateX(0);
  }
}

/* Su telefono (sotto i 600px — sopra, su tablet/PC, questo blocco non si applica e nulla
   cambia) ogni player video della pagina diventa "a tutta larghezza": tocca i bordi sinistro
   e destro dello schermo invece di fermarsi al padding di 24px di .container, come invece
   resta per titoli/testo. Tecnica di "breakout": width:100vw fa uscire l'elemento dalla
   larghezza della sua colonna, margin-left/right con un calc() in vw (non in %) lo ricentrano
   esattamente sul viewport indipendentemente da quanto sia annidato/paddato il contenitore —
   il calcolo si autocompensa (50% è relativo alla larghezza della colonna che lo contiene,
   50vw è sempre metà schermo: la differenza tra i due è sempre e solo il padding da annullare,
   qualunque esso sia). Va sui contenitori ESTERNI (-video-media/.mv-preview-video, non i
   riquadri -video-crop più interni) perché le card sovrapposte al video (tabella "Battuta
   opposto", traiettorie "Ogni alzata", card altezza/velocità e legenda della stessa sezione,
   frecce "Direzioni ricezione", selettore velocità "Analisi dettagliata") sono posizionate in
   percentuale rispetto a questi stessi contenitori: allargandoli tutti insieme (invece del
   solo riquadro video interno) restano agganciate agli angoli del player come in origine,
   solo più grandi — non serve quindi alcun aggiustamento separato sulle card.
   L'altezza dei riquadri segue sempre dall'aspect-ratio già dichiarato sui -video-crop, quindi
   ora cresce (video piena larghezza invece che limitato al 40% dell'altezza schermo come nella
   versione precedente di questa regola): la regola su .screen-section subito sotto passa da
   altezza fissa a minima apposta per non tagliare il contenuto quando serve più spazio. */
@media (max-width: 600px) and (orientation: portrait) {
  .opposto-video-media,
  .spike-video-media,
  .attacchi-video-media,
  .ricezioni-video-media,
  .mv-preview-video,
  .studio-media {
    width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
  }

  /* Angoli squadrati da telefono (arrotondati invece da PC, vedi le regole base sopra): i player
     video toccano già i bordi sinistro/destro dello schermo qui sotto (breakout, sopra) e un
     angolo arrotondato in quel contesto — a filo con lo schermo, non più dentro un riquadro con
     margini attorno come su desktop — risulterebbe fuori posto. */
  .opposto-video-crop,
  .attacchi-video-crop,
  .ricezioni-video-crop,
  .spike-video-crop,
  .mv-preview-video,
  .studio-box-inner {
    border-radius: 0;
  }

  .reveal-split .reveal-title {
    font-size: 1.25rem;
    margin: 0 0 8px;
  }

  .reveal-split .lead-text {
    font-size: 0.9rem;
    line-height: 1.4;
  }

  /* .screen-section (sopra) ha altezza FISSA (100dvh meno la barra del menu): con i video ora
     a piena larghezza (quindi anche più alti, vedi sopra) il contenuto di alcune sezioni può
     non starci più. Qui l'altezza fissa diventa un minimo, così se serve più spazio la sezione
     cresce invece di tagliare video/testo. Lo scroll a container in js/main.js non ne risente:
     la posizione di ogni sezione viene ricalcolata al momento dello scatto
     (sectionTargetY → getBoundingClientRect), non è un valore fisso salvato in anticipo. */
  .screen-section {
    height: auto;
    min-height: calc(100vh - var(--header-h, 76px));
    min-height: calc(100dvh - var(--header-h, 76px));
  }

  /* Sezione "Rimozione dei tempi morti": il video ora a tutta larghezza (sopra) lascia poco
     spazio per la sidebar Punti/Azioni/Rotazioni accanto — qui resta quindi nascosta finché
     l'utente non tocca "qui" nel testo alternativo mobile (.mv-head-mobile-text, mostrato al
     posto di quello desktop). Il tocco (mvRevealBtn in js/main.js) aggiunge .mv-table-visible
     a .mv-container: titolo e testo spariscono e la tabella compare sotto al player, unica
     cosa rimasta nella sezione. */
  .mv-head-desktop-text {
    display: none;
  }
  /* Font massimo ridotto e troncamento a tre righe di sicurezza (-webkit-line-clamp), stessa
     tecnica e stesso identico clamp usati per ".lead-text" nelle quattro sezioni con box/tabelle
     sul video più sotto (".reveal-split:has(.mtry-btn) .lead-text" più sotto — tenerli allineati
     se uno dei due cambia): mai il testo spinge il pulsante "Prova"/il video fuori dallo spazio
     che gli resta.
     ".mv-head .mv-head-mobile-text" (non solo ".mv-head-mobile-text"): serve la specificità in
     più (classe+classe invece di una sola classe) per battere ".mv-head p" più sopra (classe+
     elemento, dichiarata fuori da qualunque media query) — quella regola, pensata per il
     paragrafo desktop a dimensione fissa, ha specificità maggiore di una singola classe e senza
     questo aggancio in più vinceva comunque anche qui sotto i 600px, imponendo il suo font-size
     fisso (1.25rem) al posto del clamp qui sotto: il font non risultava mai responsive, e restava
     sempre più grande del clamp delle altre sezioni a schermi piccoli.
     NOTA: un tentativo di aggiungere "overflow-wrap: break-word" qui (per evitare che una parola
     più larga del box venga tagliata invece di andare a capo) ha causato la scomparsa del testo
     su mobile — probabile incompatibilità con "display: -webkit-box" su alcuni browser — ed è
     stato rimosso. Il taglio delle parole lunghe resta quindi un problema noto non risolto. */
  .mv-head .mv-head-mobile-text {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
    font-size: clamp(0.95rem, 4.2vw, 1.3rem);
  }
  .mv-reveal-btn {
    display: inline-block;
  }

  /* "Prova"/"Esci" (vedi .mtry-btn/.mtry-exit-btn sopra per il meccanismo generale): solo uno
     dei due visibile alla volta, in base a .mtry-open su ".split" (aggiunta/tolta in
     js/main.js). ".mtry-exit-btn" sta dentro ".split-media" (sotto il box, vedi HTML) invece che
     insieme a "Prova" nel testo: da attivo il testo sparisce (vedi più sotto), "Esci" deve
     restare raggiungibile. */
  .mtry-btn {
    display: block;
  }
  .split.mtry-open .mtry-btn {
    display: none;
  }
  .split.mtry-open .mtry-exit-btn {
    display: block;
    margin: 0;
  }

  /* "Visualizza velocemente ogni evento" (battuta opposto): la card statistiche
     (.mstb-overlay-stats, dentro .mstb-overlay) parte nascosta, la rivela "Prova". */
  .opposto-video-media .mstb-overlay {
    display: none;
  }

  /* "Analisi dettagliata": il selettore di velocità/frame (.spike-speed-bar) parte nascosto, lo
     rivela "Prova". */
  .spike-speed-bar {
    display: none;
  }

  /* "Ogni alzata, con la sua traiettoria": le due card informative (altezza/velocità e legenda
     colori) partono nascoste, le rivela "Prova" — le traiettorie stesse (.attacchi-traj-svg,
     disegnate direttamente sopra il video, non un box a parte) restano invece sempre visibili:
     sono il contenuto del video demo, non un'informazione aggiuntiva sovrapposta. */
  .attacchi-stats-overlay,
  .attacchi-traj-legend {
    display: none;
  }

  /* "Tracciamento accurato di ogni giocatore": il grafico "Direzioni ricezione"
     (.ricezioni-overlay-court, dentro .mstb-overlay) parte nascosto, lo rivela "Prova". */
  .ricezioni-video-media .mstb-overlay {
    display: none;
  }

  /* "Tracciamento accurato di ogni giocatore": stesso toggle desktop/mobile di .mv-head sopra
     (la versione mobile invita a toccare una freccia invece di scrollare con la rotellina). */
  .ricezioni-lead-desktop {
    display: none;
  }
  .ricezioni-lead-mobile {
    display: block;
  }
  .mv-sidebar {
    display: none;
  }
  .mv-container.mv-table-visible .mv-head {
    display: none;
  }
  .mv-container.mv-table-visible .mv-sidebar {
    display: flex;
  }

  /* Stato di default (tabella non ancora aperta): stessa griglia a spaziatori elastici usata
     dallo "schema comune titolo/testo/video" più sotto (bordo superiore→titolo, titolo→testo,
     testo→video, video→bordo inferiore, tutti 1x tranne titolo→testo che è 0,5x) — qui riscritta
     per .mv-container invece che riusata da .split.reveal-split perché .mv-container non ha la
     classe .split (struttura diversa, tab/sidebar). .mv-container è già lei stessa sia il
     ".container" (ha quella classe) sia l'equivalente di ".split.reveal-split" (contiene
     .mv-head/.mv-preview come .split-text-col/.split-media altrove), quindi le due regole che
     altrove servono su due elementi separati qui stanno su un solo elemento.
     .mv-head diventa display:contents (stesso trucco di .split-text-col) per promuovere titolo,
     testo e pulsante "Prova" (#mvRevealBtn, sostituisce la vecchia frase con link inline "Premi
     qui per...") a righe indipendenti della grid — l'animazione di comparsa in scroll, che prima
     stava su .mv-head intero, si sposta di conseguenza sui tre elementi (altrimenti non
     avrebbero più nessuna scatola su cui applicarsi). Nove righe invece di sette: lo spazio
     testo→pulsante è 0,5x come titolo→testo (stesso gruppo "di testa"), poi un intero spazio 1x
     prima del video — stessa idea dei "5 spazi" dell'hero mobile più sotto (che ha anch'essa un
     pulsante in fondo al testo). */
  /* Niente più riga elastica finale (video→bordo inferiore): come le altre sezioni con
     ".mtry-btn" (".split.reveal-split:has(.mtry-btn)" più sotto), il video sta quindi a filo con
     il margine inferiore dello schermo invece che con lo stesso spazio "1fr" riservato sopra. */
  .mv-container:not(.mv-table-visible) {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: 1fr auto 0.5fr auto 0.5fr auto 1fr auto;
    row-gap: 0;
    flex: 1;
    min-height: 0;
  }
  .mv-container:not(.mv-table-visible) .mv-head {
    display: contents;
  }
  .mv-container:not(.mv-table-visible) .mv-head h2 {
    grid-row: 2;
    width: 100%;
    text-align: center;
    margin: 0;
  }
  .mv-container:not(.mv-table-visible) .mv-head-mobile-text {
    grid-row: 4;
    width: 100%;
    text-align: center;
    margin: 0;
  }
  .mv-container:not(.mv-table-visible) .mv-reveal-btn {
    grid-row: 6;
    justify-self: center;
  }
  .mv-container:not(.mv-table-visible) .mv-preview {
    grid-row: 8;
  }
  .mv-container:not(.mv-table-visible) .mv-head h2,
  .mv-container:not(.mv-table-visible) .mv-head-mobile-text,
  .mv-container:not(.mv-table-visible) .mv-reveal-btn {
    opacity: 0;
    transition: opacity 0.7s ease, transform 0.7s ease;
    transform: translateY(-40px);
  }
  .mv-container.is-visible:not(.mv-table-visible) .mv-head h2,
  .mv-container.is-visible:not(.mv-table-visible) .mv-head-mobile-text,
  .mv-container.is-visible:not(.mv-table-visible) .mv-reveal-btn {
    opacity: 1;
    transform: translate(0, 0);
  }

  /* Con la tabella visibile: il video sta a filo con la cima dello schermo (coerente con la
     toolbar nascosta in quello stato, vedi js/main.js — sectionTargetY riallinea lo scroll di
     conseguenza), e sotto la tabella riempie lo spazio che resta invece di avere un'altezza
     fissa (360px, riga ~1723: su schermi bassi bastava a farla uscire dal fondo, con scroll
     verticale dell'intera pagina invece che solo della lista al suo interno) — così resta
     sempre "contenuta" nello schermo, con due margini identici sopra e sotto di essa (16px). Lo
     scroll della LISTA di punti/azioni resta comunque interno a .mv-panel (overflow-y:auto, già
     esistente), non cambia: cambia solo il contenitore attorno, che ora si adatta invece di
     avere una misura fissa. :has() applica questo SOLO quando .mv-table-visible è presente,
     lasciando invariato lo stato di default (sidebar nascosta, titolo/testo centrati come le
     altre sezioni).
     .screen-section stesso passa da altezza MINIMA (regola generica sopra, riga ~1831) ad
     altezza FISSA qui: senza un'altezza definita sull'antenato, la catena flex:1/min-height:0
     sotto non ha nulla da cui sottrarre lo spazio del video, quindi .mv-sidebar finiva alto
     quanto il contenuto della lista (anche oltre lo schermo) invece di ricevere lo spazio che
     resta — la tabella "usciva" dalla pagina invece di restarci contenuta. */
  .screen-section:has(.mv-container.mv-table-visible) {
    height: 100vh;
    height: 100dvh;
    min-height: 0;
  }
  .screen-section:has(.mv-container.mv-table-visible) > .container {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
  }
  .mv-container.mv-table-visible {
    justify-content: flex-start;
    flex: 1;
    min-height: 0;
  }
  .mv-container.mv-table-visible .mv-preview {
    flex: 1;
    height: auto;
    min-height: 0;
    flex-direction: column;
    gap: 16px;
  }
  .mv-container.mv-table-visible .mv-preview-video {
    flex: none;
  }
  .mv-container.mv-table-visible .mv-sidebar {
    flex: 1;
    height: auto;
    min-height: 0;
    margin-bottom: 16px;
    /* riga (non più colonna): barra verticale Punti/Azioni/Rotazioni/Esci a sinistra, pannello
       a destra — invece della vecchia barra orizzontale sopra il pannello, per lasciare più
       altezza alla lista. */
    flex-direction: row;
  }

  /* Barra verticale: .mv-rail torna un contenitore vero (su desktop/tablet è display:contents,
     vedi riga ~1327) largo quanto basta per le etichette dei tab, con Punti/Azioni/Rotazioni +
     Esci impilati e (sotto) tutti della stessa altezza. */
  .mv-container.mv-table-visible .mv-rail {
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    width: 78px;
    gap: 6px;
    padding: 8px;
    box-sizing: border-box;
    background: var(--grey-50);
    border-right: 1px solid var(--grey-200);
  }
  /* .mv-tabs si "appiattisce" (display:contents, invece di restare lei stessa un contenitore
     flex): i tre .mv-tab diventano così figli diretti di .mv-rail esattamente come .mv-exit-btn,
     tutti e quattro allo stesso livello — necessario perché tutti e quattro (i tre tab più Esci)
     abbiano le stesse dimensioni: con .mv-tabs ancora di mezzo, il flex:1 sarebbe stato diviso in
     due sole parti (i tre tab insieme da un lato, Esci dall'altro), rendendo Esci molto più alto
     dei singoli tab invece che uguale. */
  .mv-container.mv-table-visible .mv-tabs {
    display: contents;
  }
  /* .mv-tab ha già flex:1 dalla regola base (riga ~1345): ora diretto figlio di .mv-rail (anch'essa
     flex:1, quindi alta quanto tutto lo spazio disponibile nella barra) insieme a .mv-exit-btn
     (anch'esso flex:1, sotto), i quattro pulsanti si dividono quello spazio in parti UGUALI,
     riempiendo interamente la barra invece di restare alti quanto il loro solo contenuto.
     Contorno sempre visibile (anche da non selezionati, a differenza della versione desktop/
     tablet senza border): blu quando non selezionato; da selezionato il testo resta bianco (come
     da .mv-tab.active di base) e il bordo passa a var(--navy), stesso colore dello sfondo attivo —
     resta quindi disegnato ma "invisibile" perché si confonde con lo sfondo, senza salto di
     dimensione nel passaggio tra i due stati (stessa larghezza di bordo in entrambi). Il colore
     del testo va ripetuto qui (non basta quello di base): questa stessa regola sotto, con
     specificità maggiore di ".mv-tab.active" per via delle classi in più sul selettore, altrimenti
     vincerebbe anche da selezionato lasciando il testo blu invece che bianco. */
  .mv-container.mv-table-visible .mv-tab {
    flex: 1;
    font-size: 0.72rem;
    padding: 0.5rem 0.25rem;
    border: 1.5px solid var(--blue);
    color: var(--blue);
    box-sizing: border-box;
  }
  .mv-container.mv-table-visible .mv-tab.active {
    border-color: var(--navy);
    color: #fff;
  }
  /* flex:1 (non più margin-top:auto): stessa dimensione dei tab, invece di restare piccolo quanto
     il proprio contenuto e solo ancorato in fondo. */
  .mv-container.mv-table-visible .mv-exit-btn {
    display: block;
    flex: 1;
    border: none;
    border-radius: 7px;
    background: #ef4444;
    color: #fff;
    font-size: 0.78rem;
    font-weight: 700;
    font-family: inherit;
    padding: 0.55rem 0.25rem;
    cursor: pointer;
    transition: background 0.15s;
  }
  .mv-container.mv-table-visible .mv-exit-btn:hover {
    background: #dc2626;
  }
  .mv-container.mv-table-visible .mv-panel,
  .mv-container.mv-table-visible .mv-panel-rotazioni {
    flex: 1;
    min-width: 0;
  }

  /* Schema comune a TUTTE le sezioni "titolo, testo, player video" (Visualizza velocemente ogni
     azione / Analisi dettagliata / Ogni alzata / Tracciamento accurato, più Statistiche di
     squadra che però ha un ultimo spazio diverso, vedi sotto) — QUATTRO spazi (bordo
     superiore→titolo, titolo→testo, testo→video, video→bordo inferiore), tutti uguali tranne
     titolo→testo che è 0,5 volte gli altri. Impossibile con justify-content:space-evenly (spazi
     sempre identici) — si usa quindi una grid a 7 righe: 4 righe "vuote" con altezza in frazioni
     (fr, proporzionali fra loro: 1/0.5/1/1) che fanno da spaziatori elastici, alternate alle 3
     righe di contenuto vero (altezza auto, assegnate esplicitamente sotto via grid-row). Una riga
     vuota in una grid occupa comunque la sua quota di spazio anche senza alcun elemento dentro,
     quindi non serve nessun div "spaziatore" fittizio nell'HTML. flex:1 (ereditato da .container,
     reso anch'esso flex:1 dentro .screen-section "alto quanto lo schermo") dà alla grid l'altezza
     totale su cui applicare le frazioni; row-gap:0 azzera il gap ereditato da .split (riga ~291,
     "gap: 56px"), che altrimenti si sommerebbe alle righe elastiche.
     :has() nel primo selettore prende solo i .container che contengono davvero un
     .split.reveal-split, per non toccare altre sezioni senza questo schema (es. "Pronto a
     provarlo...", niente video) né .mv-container ("Rimozione dei tempi morti": non ha la classe
     .split, struttura del tutto diversa con tab/sidebar — trattata a parte). */
  .screen-section > .container:has(> .split.reveal-split) {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
  }
  .split.reveal-split {
    display: grid;
    grid-template-rows: 1fr auto 0.5fr auto 1fr auto 1fr;
    row-gap: 0;
    flex: 1;
    min-height: 0;
  }

  /* Le quattro sezioni con box/tabelle sul video (quelle con ".mtry-btn", vedi sopra) non hanno
     l'ultima riga elastica (video→bordo inferiore): il video sta quindi a filo con il margine
     inferiore dello schermo invece che con lo stesso spazio "1fr" delle altre sezioni sopra e
     sotto — su richiesta esplicita, per lasciargli più spazio possibile essendo l'elemento
     centrale della demo in questo stato. Selettore a tre "componenti" (2 classi + :has()) per
     battere in specificità ".split.reveal-split" appena sopra (2 classi), che altrimenti
     vincerebbe per essere dichiarato dopo. */
  .split.reveal-split:has(.mtry-btn) {
    grid-template-rows: 1fr auto 0.5fr auto 1fr auto;
  }

  /* Stato attivo (dopo "Prova"): titolo/testo spariscono, ".split" (una grid nelle due regole
     appena sopra) diventa una colonna flex — non serve più la grid a spaziatori elastici,
     pensata per la proporzione titolo/testo/video ora non più tutta visibile. ".split-media"
     (video + box, vedi sotto) prende tutto lo spazio e distribuisce i suoi figli con
     justify-content:space-between: video a filo in alto, "Esci" a filo in basso, il box in mezzo
     — esattamente "video in alto, box al centro, Esci sotto" richiesto. Dichiarato DOPO le due
     regole grid appena sopra (stessa specificità di ".split.reveal-split:has(.mtry-btn)": tre
     "componenti" ciascuna) apposta, per vincere il pareggio di specificità grazie all'ordine nel
     foglio di stile — se venisse prima, la grid vincerebbe e lo stato attivo non avrebbe mai
     effetto. padding-top:0 (invece di un valore fisso) apposta: il bordo superiore di ".split"
     coincide già con il bordo inferiore della toolbar "Spike Net" (stesso posizionamento di
     scroll di ogni sezione), quindi senza alcun padding qui il video parte esattamente da lì —
     nessuno spazio vuoto in mezzo. */
  .split.reveal-split.mtry-open {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
  }
  .split.reveal-split.mtry-open .reveal-title,
  .split.reveal-split.mtry-open .split-text {
    display: none;
  }
  .split.reveal-split.mtry-open .split-media {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    flex: 1;
    min-height: 0;
    gap: 16px;
    padding: 0 0 16px;
  }

  /* I box, normalmente sovrapposti al video (position:absolute, vedi ciascuno più sopra in
     questo file): qui tornano "in linea" dentro ".split-media" sopra, sotto al video invece che
     sovrapposti — position:static disattiva automaticamente left/right/top/bottom/z-index (si
     applicano solo a elementi posizionati), transform va invece annullato esplicitamente
     (altrimenti resterebbe lo spostamento pensato per l'ancoraggio al bordo del video).
     align-self:center li centra in orizzontale come singoli figli flex di ".split-media" senza
     toccarne l'"align-items" di default (stretch): -video-crop, l'unico altro figlio diretto,
     deve invece restare largo quanto ".split-media" (già a piena larghezza, vedi la regola
     "breakout" più sopra) come prima di "Prova" — un align-items:center qui lo avrebbe ristretto
     alla larghezza intrinseca (il video dentro è position:absolute, non ne stabilisce una). */
  .split.reveal-split.mtry-open .mstb-overlay {
    position: static;
    pointer-events: auto;
    display: flex;
    justify-content: center;
  }
  .split.reveal-split.mtry-open .mstb-overlay-stats,
  .split.reveal-split.mtry-open .ricezioni-overlay-court {
    position: static;
    transform: none;
  }
  .split.reveal-split.mtry-open .spike-speed-bar {
    position: static;
    transform: none;
    display: flex;
    align-self: center;
  }
  .split.reveal-split.mtry-open .attacchi-stats-overlay {
    position: static;
    transform: none;
    display: block;
    align-self: center;
  }
  .split.reveal-split.mtry-open .attacchi-traj-legend {
    position: static;
    transform: none;
    display: flex;
    align-self: center;
  }
  .split.reveal-split.mtry-open .mtry-exit-btn {
    align-self: center;
  }

  /* Azzera il margin-bottom "di compensazione" per la sporgenza del box (--overlay-half, vedi
     .opposto-video-media/.spike-video-media/.ricezioni-video-media più sotto): da attivo il box
     non sovrasta più il video (è un figlio flex a parte, vedi sopra), quindi non sporge più da
     nessuna parte — quel margine, qui, sarebbe solo spazio vuoto in fondo senza motivo. */
  .split.reveal-split.mtry-open .opposto-video-media,
  .split.reveal-split.mtry-open .spike-video-media,
  .split.reveal-split.mtry-open .ricezioni-video-media {
    margin-bottom: 0;
  }

  /* "Genera automaticamente gli studi partita": qui non c'è un video separato dal box (il
     riquadro partite/studio, .studio-box, è l'unico elemento di ".studio-media"), quindi
     "Prova" non sposta niente in alto — semplicemente ingrandisce il box stesso (da
     aspect-ratio 32:27 a un'altezza fissa, due terzi dello schermo) e fa comparire "Esci" sotto.
     Tre margini uguali richiesti esplicitamente: bordo superiore→box, box→"Esci", "Esci"→bordo
     inferiore. justify-content:space-evenly con esattamente due figli flex (box ed "Esci") crea
     proprio questo — spazio identico PRIMA del primo figlio, TRA i due, e DOPO l'ultimo — mentre
     gap/padding (diversi da zero nella regola generica sopra, per le altre quattro sezioni: qui
     azzerati) si sommerebbero in più a uno solo dei tre margini, rompendo l'uguaglianza. Stessa
     specificità (4 "componenti" ciascuna) della regola generica sopra: dichiarata dopo, vince il
     pareggio per ordine nel foglio di stile. */
  .split.reveal-split.mtry-open .studio-media {
    justify-content: space-evenly;
    gap: 0;
    padding: 0;
  }
  .split.reveal-split.mtry-open .studio-box-inner {
    aspect-ratio: auto;
    height: 66vh;
    height: 66dvh;
  }

  /* Titolo e testo centrati (width:100% sul titolo perché il testo si centri sull'intera riga,
     non solo sulla larghezza del proprio contenuto) e con dimensione fluida (clamp: cresce con
     la larghezza dello schermo tra un minimo e un massimo) invece di un singolo valore fisso,
     così restano proporzionati sia su un telefono piccolo che su uno grande — stessa dimensione
     in tutte le sezioni. grid-row li piazza nelle 3 righe "auto" della grid sopra (2ª, 4ª, 6ª) —
     l'ordine di comparsa (titolo, testo, video) è quindi lo stesso indipendentemente dall'ordine
     nel DOM (alcune sezioni hanno il video PRIMA del testo nel markup, es. reveal-reverse). */
  .reveal-split .reveal-title {
    grid-row: 2;
    width: 100%;
    text-align: center;
    margin: 0;
    font-size: clamp(1.3rem, 7vw, 2rem);
  }
  .reveal-split .lead-text {
    text-align: center;
    font-size: clamp(1.05rem, 5vw, 1.5rem);
    line-height: 1.45;
  }

  /* Nelle quattro sezioni con box/tabelle sul video (".mtry-btn", vedi sopra), col video ora a
     filo col bordo inferiore (regola ":has(.mtry-btn)" più sopra) il testo ha meno margine di
     manovra sotto di sé: font massimo ridotto rispetto al resto del sito, e un troncamento a tre
     righe (con "…") come garanzia — mai il testo, per quanto lungo o con lo zoom di sistema
     ingrandito, spinge il video fuori dalla porzione di schermo che gli resta. Stessa tecnica
     (-webkit-box/line-clamp) già usata per il titolo di ".ricezioni-overlay-court" più sotto, e
     stesso identico clamp di ".mv-head-mobile-text" più sopra ("Rimozione dei tempi morti", che
     ha lo stesso pulsante "Prova"/margine ridotto pur con una struttura HTML diversa non basata
     su ".reveal-split"/".lead-text") — tenerli allineati se uno dei due cambia.
     ":not(.ricezioni-lead-desktop)" esclude il paragrafo desktop di "Tracciamento accurato"
     (nascosto con display:none poco sopra, vedi .ricezioni-lead-desktop): senza, "display:
     -webkit-box" qui vincerebbe per specificità e lo farebbe ricomparire.
     NOTA: "overflow-wrap: break-word" era stato aggiunto qui per evitare il taglio delle parole
     più larghe del box, ma ha causato la scomparsa del testo su mobile (probabile incompatibilità
     con "display: -webkit-box") ed è stato rimosso — il taglio delle parole lunghe resta quindi
     un problema noto non risolto. */
  .reveal-split:has(.mtry-btn) .lead-text:not(.ricezioni-lead-desktop) {
    font-size: clamp(0.95rem, 4.2vw, 1.3rem);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
  }
  .reveal-split .split-text {
    grid-row: 4;
    width: 100%;
  }
  .reveal-split .split-media {
    grid-row: 6;
  }

  /* .mstb-overlay-stats sporge sempre sotto il video per metà della propria altezza (bottom:0 +
     translate(...,50%) sopra): senza compensazione, quella sporgenza "mangerebbe" parte dello
     spazio dell'ultima riga elastica (video→bordo inferiore, riga 7), rendendo il margine
     card→bordo più piccolo di quello header→titolo e testo→video. .opposto-video-media (riga 6,
     "auto") riceve quindi un margin-bottom pari a metà dell'altezza della card, così la riga 7
     riparte da dove finisce visivamente la card invece che dal bordo del video, e il margine
     finale torna a essere lo stesso 1fr delle altre righe — proporzionale allo schermo come loro,
     visto che qui si aggiunge solo il "correttivo" fisso dovuto all'altezza della card (quella sì
     non fluida, essendo la tabella compatta a font fissi).
     --overlay-half è impostata in js/main.js (ResizeObserver su .mstb-overlay-stats, che
     rimisura ogni volta che la card cambia dimensione per qualunque motivo — non solo il
     ridimensionamento della finestra) invece di un singolo pixel scelto a mano una volta per
     tutte: il fallback qui dopo la virgola è usato solo se ResizeObserver non è disponibile. */
  .opposto-video-media {
    margin-bottom: var(--overlay-half, 46px);
  }

  /* Stessa identica logica di .opposto-video-media sopra, applicata a ".spike-speed-bar"
     ("Analisi dettagliata"): sporge sempre a metà sotto il video (bottom:0 + translate(...,50%),
     vedi sopra), quindi .spike-video-media (riga 6 di QUESTA sezione) riceve lo stesso
     margin-bottom "di compensazione", con --overlay-half impostata dallo stesso meccanismo in
     js/main.js (un ResizeObserver separato, su .spike-speed-bar) — così anche qui il margine
     finale (box→bordo inferiore) torna a essere lo stesso 1fr delle altre righe invece di venire
     "mangiato" dalla sporgenza del box. */
  .spike-video-media {
    margin-bottom: var(--overlay-half, 52px);
  }

  /* Da telefono la tabella velocità/frame-per-frame (.spike-speed-bar, vedi sopra) resta larga
     due terzi del video invece di un terzo come da desktop: a un terzo i pulsanti diventerebbero
     troppo stretti per restare leggibili/toccabili comodamente su schermi piccoli. */
  .spike-speed-bar {
    width: 66.667%;
  }

  /* Stessa identica logica ancora, applicata a ".ricezioni-overlay-court" ("Tracciamento
     accurato di ogni giocatore", il grafico "Direzioni ricezione", ora anche lui sempre a
     cavallo del bordo inferiore invece che sovrapposto all'angolo — vedi sopra):
     .ricezioni-video-media (riga 6 di QUESTA sezione) riceve lo stesso margin-bottom di
     compensazione, con --overlay-half impostata da un terzo ResizeObserver in js/main.js (su
     .ricezioni-overlay-court). Qui il fallback statico (usato solo senza ResizeObserver) è
     ancora più approssimativo che negli altri due: questo box contiene un SVG la cui altezza
     dipende dalla propria larghezza resa (aspect-ratio dal viewBox), che a sua volta dipende
     dallo schermo — non più un'altezza fissa calcolabile a mano come le tabelle a font fissi
     sopra. */
  .ricezioni-video-media {
    margin-bottom: var(--overlay-half, 90px);
  }

  /* Il riquadro "Direzioni ricezione (S1)" eredita 72%/380px dal blocco 860px sopra: su un
     telefono stretto (~360px o meno) la colonna titolo+legenda a sinistra (metà di quella
     larghezza, essendo .ricezioni-court-info/.ricezioni-court-svg due flex:1 affiancati) diventa
     troppo stretta per le 4 etichette "Errore/Scarsa/Buona/Ottima" su due colonne, che si
     accavallano o vanno a capo in modo confuso. width qui sostituita con un clamp() invece di
     un'altra percentuale fissa, così scala in continuo con la larghezza reale dello schermo (in
     vw, equivalente a una % del contenitore dato che il video a questo breakpoint è già a piena
     larghezza, 100vw — vedi .ricezioni-video-media in index.html) invece di un unico valore
     identico su tutta la fascia 320-600px: 280px sui telefoni più stretti (SE/mini), fino allo
     stesso 380px di prima su quelli vicini alla soglia dei 600px. */
  .ricezioni-overlay-court {
    width: clamp(280px, 86vw, 380px);
  }

  /* .ricezioni-court-svg (quadrato: la sua altezza segue la propria larghezza, dal viewBox)
     riceve una quota della riga maggiore del 50/50 di base (flex:1 su entrambi) — e maggiore di
     quanto le servirebbe per un riquadro semplicemente "meno stretto" (0.7 vs 1.3, motivo
     originale di questi due valori): quota 0.7→1.05 (52,5% della riga, prima 35%) apposta per
     rendere il disegno del campo il 50% più grande (1.05/0.7 = 1,5×) di prima — .ricezioni-court-
     info compensa scendendo da 1.3 a 0.95 (stesso totale 2, così la larghezza complessiva della
     riga/card non cambia). */
  .ricezioni-court-info {
    flex: 0.95;
  }
  .ricezioni-overlay-court .ricezioni-court-svg {
    flex: 1.05;
  }

  /* Titolo e legenda ridotti e resi fluidi allo stesso modo (clamp invece di un rem fisso), per
     restare leggibili sia sui telefoni più stretti che su quelli più vicini alla soglia. Il
     titolo "Direzioni ricezione (S1)" non va mai oltre due righe: line-clamp lo tronca con "…"
     nel caso limite in cui, nonostante il clamp sul font, non ci stesse comunque (es. testo di
     sistema ingrandito dall'utente). NOTA: "overflow-wrap: break-word" era stato aggiunto qui
     contro il taglio delle parole più larghe del box, ma ha causato la scomparsa del testo su
     mobile (probabile incompatibilità con "display: -webkit-box") ed è stato rimosso — il taglio
     delle parole lunghe resta quindi un problema noto non risolto. */
  .ricezioni-overlay-court .mstb-overlay-label {
    font-size: clamp(0.68rem, 3.4vw, 0.82rem);
    line-height: 1.15;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .ricezioni-legend-item {
    font-size: clamp(0.62rem, 2.9vw, 0.78rem);
    gap: 4px;
  }

  .ricezioni-legend-dot {
    width: 8px;
    height: 8px;
  }

  /* "Genera automaticamente gli studi partita" da telefono: "Partita 1/2/3/4" scritto in bianco
     direttamente sopra la thumbnail (position:absolute, ancorata a .studio-match) invece che come
     etichetta sotto, per lasciare più spazio verticale alle 4 thumbnail nella griglia 2x2 stretta
     di un telefono. .studio-match diventa l'ancora di posizionamento: portando l'etichetta fuori
     dal flusso normale (position:absolute), .studio-match-thumb-wrap (l'unico figlio rimasto in
     flusso, flex:1) si riprende automaticamente anche lo spazio che l'etichetta occupava sotto. */
  .studio-match {
    position: relative;
  }
  .studio-match-label {
    position: absolute;
    left: 6px;
    right: 6px;
    bottom: 8px;
    color: #fff;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85), 0 0 8px rgba(0, 0, 0, 0.5);
  }

  /* Da telefono "Genera studio" nasce direttamente dentro la thumbnail selezionata (vedi
     .studio-generate-btn-mobile in index.html/js/main.js) invece che come pulsante unico sotto
     la griglia: quest'ultimo (#studioGenerateBtn, selettore per ID: batte ".btn" a prescindere
     dall'ordine nel foglio di stile) va quindi nascosto qui. */
  #studioGenerateBtn {
    display: none;
  }
  /* "Genera studio" (sulla thumbnail selezionata) compare solo in modalità "Prova" (.mtry-open
     sul ".split" della sezione, vedi .mtry-btn/.mtry-exit-btn più sopra): senza, selezionare una
     partita evidenzia la thumbnail ma non basta a generare nulla — bisogna prima premere
     "Prova". */
  .split.mtry-open .studio-match.is-selected .studio-generate-btn-mobile {
    display: inline-block;
  }

  /* "Statistiche di squadra" fa eccezione solo sull'ultimo spazio (tabella→bordo inferiore),
     1,5 volte gli altri invece di 1 — vince su ".split.reveal-split" sopra per specificità
     (section.stats-alt ha una classe in più), le altre righe restano invariate. */
  section.stats-alt .reveal-split {
    grid-template-rows: 1fr auto 0.5fr auto 1fr auto 1.5fr;
  }

  /* La tabella ha 13 colonne (Ruolo + 3 Battuta + 5 Ricezione + 4 Attacco), troppe per stare
     leggibili su uno schermo da telefono senza rimpicciolire il testo all'illeggibile. Invece di
     stringere tutto, si nasconde il gruppo "Ricezione" (il più largo, 5 colonne) via nth-child:
     colgroup/th/td hanno tutti la stessa struttura a 13 colonne su ogni riga, quindi le stesse
     posizioni (3ª del gruppo, 5ª-9ª della singola colonna) valgono ovunque. Nascondere anche i
     <col> (non solo le celle) è necessario con table-layout:fixed, altrimenti lo spazio della
     colonna resterebbe comunque riservato pur essendo le celle vuote. Il divisore verticale tra
     Battuta e Attacco resta automaticamente (la cella "Tot" di Attacco ha già la sua classe
     mstb-vsep, indipendente da quella di Ricezione che scompare). Restano quindi 8 colonne, che
     stanno larghe anche senza font minuscoli. */
  section.stats-alt .mstb-table colgroup col:nth-child(n+5):nth-child(-n+9) {
    display: none;
  }
  section.stats-alt .mstb-table thead tr:first-child th:nth-child(3) {
    display: none;
  }
  section.stats-alt .mstb-table thead tr:nth-child(2) th:nth-child(n+5):nth-child(-n+9),
  section.stats-alt .mstb-table tbody tr > :nth-child(n+5):nth-child(-n+9) {
    display: none;
  }

  /* .mstb-table ha min-width:460px (pensato per lo scroll orizzontale interno di .mstb-wrap su
     desktop/tablet) — su telefono lo si toglie: con solo 8 colonne visibili la tabella torna a
     stare larga quanto il contenitore (width:100%, niente più scroll) con un font solo
     leggermente ridotto rispetto al desktop, non minuscolo. */
  section.stats-alt .mstb-table {
    min-width: 0;
    font-size: 0.66rem;
  }
  section.stats-alt .mstb-th-group,
  section.stats-alt .mstb-th-sub {
    padding: 0.3rem 0.15rem;
    font-size: 0.56rem;
  }
  section.stats-alt .mstb-td-player,
  section.stats-alt .mstb-td {
    padding: 0.35rem 0.2rem;
  }

  /* .stats-table-media ha aspect-ratio:620/492 (riga ~409), tarato per il desktop: con il
     carattere ingrandito qui sopra la tabella non ci stava più per intero in quell'altezza e
     .mstb-wrap (overflow-y:auto) mostrava una barra di scorrimento verticale, tagliando l'ultima
     riga. Rapporto più alto qui = più altezza a parità di larghezza. */
  section.stats-alt .stats-table-media {
    aspect-ratio: 620 / 580;
  }

  /* Le due card "Distribuzione attacchi"/"Direzioni attacco" sporgono di proposito sotto il
     bordo del contenitore (bottom:-8%/-10%, riga ~480-494) — un effetto voluto in desktop. Su
     mobile lo spazio prima del bordo inferiore della pagina è calcolato su .split-media (il
     contenitore, non le card), quindi quella sporgenza faceva sembrare quel margine più corto
     degli altri tre: qui le card tornano a filo (bottom:0) così il loro bordo visivo coincide
     con quello del contenitore già usato per lo spazio equidistante. */
  section.stats-alt .mstb-overlay-dist,
  section.stats-alt .mstb-overlay-court {
    bottom: 0;
  }

  /* Hero iniziale su telefono: il titolo in cima (subito sotto la barra del menu, che è fissa e
     gli si sovrapporrebbe: da qui il padding superiore calcolato su --header-h) e, appoggiati al
     bordo inferiore, il sommario, il pulsante "Scarica" e l'invito a scorrere. L'unico spazio
     elastico è quello tra i due gruppi (riga 2, 1fr): cresce e si stringe con l'altezza dello
     schermo, mentre gli stacchi dentro il gruppo in basso restano fissi perché sono tre elementi
     legati tra loro. .hero-media/.hero-content diventano display:contents (come .split-text-col
     altrove) così titolo/testo/pulsante — normalmente annidati dentro di loro — risultano item
     diretti della grid sulla section. Selettori con "section.hero.hero-home"/"section.hero-home"
     (invece del semplice ".hero.hero-home p.lead" usato altrove) apposta più specifici delle
     regole equivalenti nel blocco @media max-width:720px più sotto: quel blocco viene DOPO nel
     file, quindi a parità di specificità vincerebbe lui nonostante sia il breakpoint più largo. */
  section.hero.hero-home {
    overflow: hidden;
    display: grid;
    grid-template-rows: auto 1fr auto 18px auto 18px auto;
    row-gap: 0;
    background: #0b1e3d;
    /* margini laterali stretti (16px invece di 24): il titolo deve arrivare da un bordo
       all'altro dello schermo, vedi la sua font-size in vw più sotto. */
    padding: calc(var(--header-h, 76px) + 16px) 16px 28px;
  }
  .hero-media,
  .hero-content {
    display: contents;
  }

  /* Stessa foto della versione da PC, ma agganciata al giocatore che schiaccia invece che al
     pixel 350: il suo centro (430px da sinistra e 350px dall'alto su 1199x800, cioè 35,86% e
     43,75%) finisce al centro dello schermo. La larghezza tiene conto dell'aggancio spostato a
     sinistra: serve almeno 100vw / (2 x 0,3586) = 140vw perché il bordo destro resti coperto
     (vedi il commento esteso su .hero-bg-home). */
  .hero-bg-home,
  .hero-chart-layer {
    --hero-photo-w: max(140vw, 172dvh);
    /* i -50px in più alzano tutta la foto di altrettanto: il centro del giocatore non cade più
       esattamente a metà schermo ma una cinquantina di pixel più in alto, come richiesto. */
    transform: translate(-35.86%, calc(-43.75% - 50px));
  }

  /* Titolo in cima e, in basso, testo/pulsante/invito: tutto centrato e su tutta la larghezza
     dello schermo (niente più banda riservata a destra).
     La font-size del titolo è in vw pura, senza clamp: la riga più lunga ("Dal video alle
     statistiche,", 27 caratteri, il "a capo" è esplicito nell'HTML) è larga all'incirca 14 volte
     la dimensione del carattere, quindi 6,4vw la porta praticamente da un bordo all'altro dello
     schermo a qualsiasi larghezza di telefono. Con il clamp del blocco 720px (8vw, minimo
     1,8rem) la riga non ci stava e andava a capo da sola, lasciando il titolo corto e addossato a
     sinistra. */
  section.hero.hero-home h1 {
    grid-row: 1;
    text-align: center;
    margin: 0;
    padding-right: 0;
    font-size: 6.4vw;
  }
  section.hero.hero-home p.lead {
    grid-row: 3;
    text-align: center;
    margin: 0;
    padding-right: 0;
    /* tre righe esatte (gli "a capo" sono i <br class="hero-lead-br"> dell'HTML, visibili solo
       qui): la riga più lunga è di 43 caratteri, quindi il carattere è in vw per starci intera. */
    font-size: 3.8vw;
    line-height: 1.45;
  }
  .hero-lead-br {
    display: inline;
  }
  section.hero-home .hero-actions {
    grid-row: 5;
    margin-left: 0;
    width: auto;
    justify-content: center;
  }
  /* invito a scorrere: riga propria nella grid, non annidato dentro .hero-actions (il gap di un
     flex interno, con .hero-actions a sua volta figlio di questa grid, non produceva un margine
     visibile). È lui il "Vedi come funziona" da telefono — stesso testo e stesso link del pulsante
     omonimo, che qui viene infatti nascosto — con in più le frecce animate. */
  .hero-scroll-hint {
    display: none;
  }
  /* "Scarica" e "Vedi come funziona" affiancati (l'invito con le frecce è nascosto): padding e
     font ridotti perché due pulsanti di larghezza piena non ci starebbero in una riga. */
  section.hero-home .hero-actions {
    gap: 10px;
  }
  section.hero-home .hero-actions .btn {
    padding: 14px 12px;
    font-size: 1rem;
    text-align: center;
    white-space: nowrap;
  }
}

@media (max-width: 720px) and (orientation: portrait) {
  nav.nav-links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: #fff;
    border-bottom: 1px solid var(--grey-200);
    box-shadow: 0 8px 16px rgba(5, 39, 103, 0.08);
    flex-direction: column;
    align-items: stretch;
    padding: 18px 24px;
    gap: 16px;
    display: none;
  }
  nav.nav-links.open { display: flex; }
  .menu-toggle { display: block; }
  .hero-content { padding: 56px 24px 60px; }

  /* Sotto i 720px la hero non deve mai "tagliare" logo/titolo/testo: l'altezza
     diventa un minimo (non più un valore fisso) così, se il contenuto ha bisogno
     di più spazio di quanto lo schermo ne offra, il container cresce invece di
     nascondere ciò che eccede; font e padding vengono inoltre ridotti e resi
     più proporzionali alla larghezza (vw) così si restringono col restringersi
     della pagina invece di fermarsi al minimo del clamp() usato da desktop. */
  .hero.hero-home {
    height: auto;
    min-height: 100vh;
    min-height: 100dvh;
  }
  .hero-logo {
    flex-wrap: wrap;
    padding: 32px 16px 20px;
    gap: 12px;
  }
  .hero-logo img {
    height: 56px;
  }
  .hero-logo span {
    font-size: clamp(1.6rem, 8vw, 3.6rem);
  }
  .hero.hero-home h1 {
    font-size: clamp(1.8rem, 8vw, 4.2rem);
  }
  .hero.hero-home p.lead {
    font-size: clamp(0.95rem, 4vw, 1.7rem);
  }
  .hero-logo,
  .hero.hero-home h1,
  .hero.hero-home p.lead {
    text-align: center;
  }
}

/* Blocco orizzontale da telefono: il layout mobile (blocchi @media sopra) è pensato solo per
   verticale — "and (orientation: portrait)" sui breakpoint sopra fa sì che un telefono ruotato in
   orizzontale riceva comunque il layout da PC a due colonne, che su uno schermo così basso (poca
   altezza CSS in landscape) risulta illeggibile/troppo compresso, invece di un vero layout
   landscape dedicato (non ne vale la pena per un solo orientamento raro su un sito di solo
   marketing). Un overlay a schermo intero copre quindi il sito e chiede di ruotare il telefono.
   "(hover: none) and (pointer: coarse)" restringe la regola ai touchscreen (telefoni/tablet):
   senza, basterebbe restringere la finestra di un browser desktop sotto max-height per far
   comparire l'overlay, bloccando l'uso normale del sito da PC. "max-height: 500px" copre i
   telefoni comuni in landscape (altezza CSS residua dopo la barra degli indirizzi, di solito
   sotto i 450px) restando sotto l'altezza landscape dei tablet più piccoli (~600px e oltre),
   quindi questi ultimi non vengono bloccati. */
.orientation-lock {
  display: none;
}

@media (orientation: landscape) and (hover: none) and (pointer: coarse) and (max-height: 500px) {
  .orientation-lock {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 9999;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 20px;
    background: var(--navy);
    color: #fff;
    padding: 24px;
    text-align: left;
  }
  .orientation-lock-icon {
    flex: none;
    width: 44px;
    height: 44px;
    animation: orientation-lock-rotate 1.6s ease-in-out infinite;
  }
  .orientation-lock p {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    max-width: 320px;
  }
  /* Eccezione: video.html (body.video-page). Il viewer di una partita condivisa è l'unica
     pagina del sito fatta apposta per il telefono in orizzontale — video a sinistra, azioni a
     destra — e chiede lei stessa di girarlo quando è in verticale. Senza questa esclusione
     girando il telefono si otteneva una pagina bianca: qui dentro non c'è nessun
     .orientation-lock da mostrare al posto del contenuto, quindi spariva tutto. */
  body:not(.video-page) > :not(.orientation-lock) {
    display: none !important;
  }
}

@keyframes orientation-lock-rotate {
  0%, 15%   { transform: rotate(-90deg); }
  50%, 65%  { transform: rotate(0deg); }
  100%      { transform: rotate(-90deg); }
}

@media (prefers-reduced-motion: reduce) {
  .orientation-lock-icon {
    animation: none;
  }
}


/* Grafico attacchi S2 attorno al giocatore dell'hero: stesso aggancio/scala della foto
   (.hero-bg-home, condivide le regole sopra), disegnato sopra il velo e sotto testi/pulsanti.
   L'altezza segue il viewBox 3:2 della foto. */
.hero-chart-layer {
  height: auto;
  aspect-ratio: 3 / 2;
  pointer-events: none;
  overflow: visible;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
}

.hero-chart-arrow {
  opacity: 0;
  animation: hero-chart-in 0.6s ease-out forwards;
  animation-delay: calc(0.4s + var(--i) * 0.09s);
}

@keyframes hero-chart-in {
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .hero-chart-arrow { animation: none; opacity: 1; }
}

/* Tabella di efficienza di S2, separata dal grafico: in basso a sinistra dell'hero. */
.hero-eff-card {
  position: absolute;
  z-index: 1;
  /* centrata sotto il giocatore: 530px dal bordo sinistro della foto (1536x1024), cioè
     530/1536 della larghezza resa; il bordo superiore della foto sta a 50% - 0,4375 x altezza. */
  --hero-photo-w: max(100vw, 172dvh);
  left: calc(50% - 0.5 * var(--hero-photo-w) + 0.345052 * var(--hero-photo-w));
  /* 150px (di foto) sotto la rete del grafico (525px) = 675px dall'alto della foto; il min() la
     tiene comunque dentro l'hero (che ritaglia) sugli schermi larghi e bassi, dove 675px di foto
     cadrebbero sotto il bordo inferiore. */
  top: min(calc(50% + 0.147786 * var(--hero-photo-w)), calc(100% - 130px));
  transform: translateX(-50%);
  padding: 10px 14px 12px;
  border-radius: 12px;
  background: rgba(11, 30, 61, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.18);
  backdrop-filter: blur(6px);
  color: #fff;
  font-size: 0.85rem;
}

.hero-eff-title {
  font-weight: 700;
  margin-bottom: 6px;
}

.hero-eff-table {
  border-collapse: collapse;
}

.hero-eff-table th,
.hero-eff-table td {
  padding: 2px 10px;
  text-align: center;
  white-space: nowrap;
}

.hero-eff-table th {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: rgba(255, 255, 255, 0.6);
}

.hero-eff-table td { font-weight: 700; }
.hero-eff-table small { font-weight: 500; opacity: 0.7; }
.hero-eff-table .is-kill { color: #93c5fd; }
.hero-eff-table .is-err { color: #fca5a5; }


/* Da PC il campo è ridotto al 70% nell'SVG
   (vedi index.html, con la rete a 525px dall'alto della FOTO intera, non del banner ritagliato);
   lo scarto orizzontale --chart-dx è calcolato da js/main.js perché il bordo sinistro del campo
   coincida con quello della tabella (la cui larghezza dipende dal testo). */
@media (min-width: 601px) {
  .hero-chart-layer {
    transform: translate(calc(-50% + var(--chart-dx, 0px)), -43.75%);
  }
}

/* Telefono: stessa composizione della versione da PC, agganciata alla foto come lo sfondo
   (.hero-bg-home: centro giocatore al 35,86% x / 43,75% y, alzata di 50px, larghezza
   max(140vw, 172dvh)). Ritaglio e campo condividono già quelle regole; qui il campo aggiunge solo
   --chart-dx (bordo sinistro allineato a quello della tabella, calcolato da js/main.js) e la
   tabella riprende le stesse coordinate della foto (530px da sinistra, 675px dall'alto su
   1536x1024). */
@media (max-width: 600px) {
  .hero-chart-layer {
    transform: translate(calc(-35.86% + var(--chart-dx, 0px)), calc(-43.75% - 50px));
  }
  /* Tabella ridotta del 20% (scale) e allineata a destra con 12px dal bordo dello schermo; il
     bordo superiore sta 30px sotto il bordo inferiore del campo (la rete, y=520 nell'SVG, che
     con la scala 0,7 e l'ancoraggio a 525 cade a 525px dall'alto della foto = 0,341797 x
     larghezza).
     Il campo del grafico resta dov'era: js/main.js su telefono lo allinea alla vecchia
     posizione della tabella (centrata sotto il giocatore), non a quella attuale. */
  .hero-eff-card {
    --hero-photo-w: max(140vw, 172dvh);
    left: auto;
    right: 12px;
    top: calc(50% - 0.291667 * var(--hero-photo-w) - 50px + 0.341797 * var(--hero-photo-w) + 30px);
    transform: scale(0.8);
    transform-origin: top right;
    font-size: 0.7rem;
    padding: 8px 10px 10px;
  }
  .hero-eff-table th, .hero-eff-table td { padding: 2px 6px; }
}


/* Schermata "Dalla partita all'analisi in tre passi" (#process, prima di "Statistiche di squadra"):
   tre card numerate. Da PC sono una riga da sinistra a destra, con una freccia nello spazio tra
   l'una e l'altra; da telefono (max-width:720px) una colonna dall'alto in basso, card compatte
   con icona a sinistra e testo a destra. Comparsa: ".proc-reveal.is-visible" (js/main.js). */
/* Container che riempie la schermata (flex:1 nella colonna di .screen-section): i tre margini
   automatici (sopra il titolo, tra titolo e card, sotto le card) si dividono lo spazio libero in
   parti uguali, da PC e da telefono; "gap" fissa un minimo tra titolo e card. */
.proc-section .proc-reveal {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-top: 0;
  padding-bottom: 0;
}

.proc-section .proc-title {
  margin-top: auto;
}

.proc-section .proc-grid {
  margin-top: auto;
  margin-bottom: auto;
}

/* PC: le card sono alte il 55% della schermata. */
@media (min-width: 721px) {
  .proc-section .proc-grid {
    height: 55%;
    flex-shrink: 0;
  }
  .proc-card {
    justify-content: center;
  }
}

.proc-title {
  text-align: center;
  font-size: clamp(1.5rem, 2.8vw, 2rem);
  font-weight: 800;
  color: var(--blue);
  margin: 0;
}

.proc-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 56px;
  max-width: 1000px;
  margin: 0 auto;
}

.proc-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 44px 24px 32px;
  background: var(--grey-50);
  border: 1px solid var(--grey-200);
  border-radius: 16px;
  box-shadow: 0 6px 20px rgba(5, 39, 103, 0.08);
  opacity: 0;
  transform: translateY(30px);
  transition: opacity 0.6s ease, transform 0.6s ease;
  transition-delay: calc(var(--i) * 0.18s);
}

.proc-reveal.is-visible .proc-card {
  opacity: 1;
  transform: translateY(0);
}

.proc-num {
  position: absolute;
  top: -20px;
  left: 50%;
  transform: translateX(-50%);
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--navy);
  color: #fff;
  font-weight: 800;
  font-size: 1.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 0 5px #fff;
}

.proc-icon {
  width: 84px;
  height: 84px;
  padding: 18px;
  border-radius: 50%;
  background: rgba(59, 130, 246, 0.12);
  color: var(--blue);
  margin-bottom: 20px;
  box-sizing: border-box;
  flex-shrink: 0;
}

.proc-body h3 {
  margin: 0 0 10px;
  font-size: 1.25rem;
  color: var(--navy);
}

.proc-body p {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.55;
  color: var(--grey-600);
}

/* freccia (un chevron) nello spazio tra due card */
.proc-card:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 50%;
  right: -35px;
  width: 14px;
  height: 14px;
  transform: translateY(-50%) rotate(-45deg);
  border-right: 4px solid var(--blue);
  border-bottom: 4px solid var(--blue);
  border-radius: 2px;
  opacity: 0.8;
}

@media (max-width: 720px) {
  .proc-title {
    font-size: 1.35rem;
  }
  .proc-grid {
    grid-template-columns: 1fr;
    gap: 30px;
  }
  .proc-card {
    flex-direction: row;
    text-align: left;
    gap: 14px;
    padding: 16px 16px 16px 30px;
  }
  .proc-num {
    top: 50%;
    left: 0;
    transform: translate(-50%, -50%);
    width: 34px;
    height: 34px;
    font-size: 1.05rem;
  }
  .proc-icon {
    width: 60px;
    height: 60px;
    padding: 12px;
    margin-bottom: 0;
  }
  .proc-body h3 {
    font-size: 1.02rem;
    margin-bottom: 4px;
  }
  .proc-body p {
    font-size: 0.85rem;
    line-height: 1.4;
  }
  /* chevron verso il basso nello spazio tra due card */
  .proc-card:not(:last-child)::after {
    top: auto;
    bottom: -18px; /* centrato otticamente nei 30px tra le card: stesso spazio sopra e sotto */
    right: auto;
    left: 50%;
    transform: translateX(-50%) rotate(45deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .proc-card {
    transition: none;
    transform: none;
    opacity: 1;
  }
}


/* Tasto "Scopri le funzionalità" + frecce blu animate, come ultimo elemento della colonna (da PC e
   da telefono): margini automatici uguali agli altri, al posto dell'invito standard in basso. */
.proc-section .proc-grid {
  margin-bottom: 0;
}
.proc-section .section-scroll-hint {
  display: none;
}
.proc-more {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin-top: auto;
  margin-bottom: auto;
  color: var(--blue);
  text-decoration: none;
}
.proc-more .btn {
  padding: 12px 20px;
  font-size: 0.95rem;
  text-align: center;
}
@media (min-width: 721px) {
  .proc-more .btn {
    padding: 14px 28px;
    font-size: 1.05rem;
  }
}


/* frecce sotto "Scopri le funzionalità": blu (la regola base .hero-scroll-arrow le fa bianche) */
.proc-more .hero-scroll-arrow {
  color: var(--blue);
}

/* "Genera automaticamente gli studi partita": da telefono il riquadro delle partite (#studioBox)
   occupa quasi tutta la schermata e gli swipe che partono da lì non cambiano container (servono
   a scorrere il pannello dello studio), quindi l'unico modo di arrivare all'ultima schermata è
   l'invito a scorrere in basso: le frecce bianche di base sparivano sullo sfondo chiaro. */
.screen-section:has(#studioBox) .section-scroll-hint .hero-scroll-arrow {
  color: var(--blue);
}

/* Telefono: tutte le frecce d'invito a scorrere verso il basso (hero, ogni schermata, tasto
   "Scopri le funzionalità") sono blu invece che bianche. */
@media (max-width: 600px) {
  .hero-scroll-arrow {
    color: var(--blue);
  }
}

/* Telefono: alone bianco semitrasparente dietro le frecce, così restano leggibili sopra video e
   foto senza un riquadro pieno. */
@media (max-width: 600px) {
  .hero-scroll-arrows {
    padding: 8px 16px 10px;
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.55);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
  }
}

/* Riga piccola sopra lo slogan dell'hero della home. Sta DENTRO l'<h1> apposta: lo slogan da
   solo non contiene "pallavolo" né "scout", cioè le parole che si cercano su Google, e l'h1 è il
   testo a cui Google dà più peso. In rem fissi (non in em) perché da telefono la font-size
   dell'h1 è in vw: la riga non deve ingrandirsi insieme al titolo. */
.hero.hero-home h1 .hero-kicker {
  display: block;
  margin-bottom: 0.6rem;
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--blue-light, #93c5fd);
}
@media (max-width: 600px) {
  .hero.hero-home h1 .hero-kicker { font-size: 0.8rem; margin-bottom: 0.4rem; }
}

/* ── "Confronta le due squadre" (cmpx-*) ──
   Tre box della tab Confronto (TabMatchStats.razor nell'app, .mstats-cmp-* in css/video.css)
   sovrapposti a una foto di gioco, stesso schema delle card su tabella/video delle altre sezioni
   (.mstb-overlay-card): sporgono oltre il bordo della foto, entrano con un ritardo dopo di lei.
   Grafica dei box copiata da .mstats-cmp-* e rimpicciolita: verde la squadra messa meglio, rossa
   l'altra; il box squilibrio ha il bordo sinistro del colore della squadra (arancio = B). */
.cmpx-media {
  position: relative;
}

/* più spazio fra testo e foto (come section.stats-alt): la card "Efficienza in attacco" sporge
   a sinistra della foto, verso il testo */
section.cmpx-section .reveal-split {
  column-gap: 72px;
}

.cmpx-photo {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  aspect-ratio: 3 / 2;
  box-shadow: 0 20px 45px rgba(11, 30, 61, 0.18);
}

/* selettore più specifico di ".split-media img" (raggio e ombra li porta già .cmpx-photo) */
.cmpx-media .cmpx-photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 0;
  box-shadow: none;
}

/* credito della foto (CC BY 4.0 lo richiede), in alto a sinistra sulla zona scura del pubblico */
.cmpx-credit {
  position: absolute;
  top: 8px;
  left: 10px;
  font-size: 0.62rem;
  color: rgba(255, 255, 255, 0.75);
  text-decoration: none;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}
.cmpx-credit:hover { color: #fff; text-decoration: underline; }

.cmpx-cards {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.cmpx-card {
  position: absolute;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.06);
  border-radius: 10px;
  padding: 10px 12px 11px;
  box-shadow: 0 16px 32px rgba(11, 30, 61, 0.22);
  opacity: 0;
  transition: opacity 0.6s ease, transform 0.6s ease;
  transition-delay: 0.55s;
}

.cmpx-card-block {
  top: -8%;
  right: -7%;
  width: 36%;
  transform: translateY(18px) rotate(4deg) scale(0.92);
}

.cmpx-card-eff {
  left: -7%;
  bottom: -11%;
  width: 40%;
  z-index: 3;
  transition-delay: 0.7s;
  transform: translateY(18px) rotate(-3deg) scale(0.92);
}

.cmpx-card-imb {
  right: 3%;
  bottom: -7%;
  width: 37%;
  border-left: 4px solid #e07b2a;
  transition-delay: 0.85s;
  transform: translateY(18px) rotate(2deg) scale(0.92);
}

.reveal-split.is-visible .cmpx-card { opacity: 1; }
.reveal-split.is-visible .cmpx-card-block { transform: translateY(0) rotate(4deg) scale(1); }
.reveal-split.is-visible .cmpx-card-eff { transform: translateY(0) rotate(-3deg) scale(1); }
.reveal-split.is-visible .cmpx-card-imb { transform: translateY(0) rotate(2deg) scale(1); }

.cmpx-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}

.cmpx-cat {
  align-self: flex-start;
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgb(5, 39, 103);
  background: #e8ecf5;
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
}
.cmpx-head .cmpx-cat { align-self: center; }

.cmpx-chip {
  font-size: 0.6rem;
  font-weight: 700;
  color: #fff;
  background: #e07b2a;
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
  white-space: nowrap;
}

.cmpx-title {
  font-size: 0.86rem;
  font-weight: 800;
  line-height: 1.2;
  color: #1a1a2e;
}

.cmpx-desc {
  font-size: 0.66rem;
  line-height: 1.35;
  color: rgba(0, 0, 0, 0.55);
}

.cmpx-sides { display: flex; flex-direction: column; gap: 6px; margin-top: 2px; }
.cmpx-side-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 6px;
}
.cmpx-team {
  font-size: 0.66rem;
  font-weight: 700;
  color: rgba(0, 0, 0, 0.7);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cmpx-val {
  font-size: 0.95rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.cmpx-bar {
  height: 5px;
  border-radius: 999px;
  background: #edf0f6;
  overflow: hidden;
  margin-top: 2px;
}
.cmpx-bar-fill { height: 100%; border-radius: 999px; }
.cmpx-detail {
  font-size: 0.6rem;
  color: rgba(0, 0, 0, 0.45);
  margin-top: 2px;
}
.cmpx-side.better .cmpx-val      { color: #2d8a4e; }
.cmpx-side.better .cmpx-bar-fill { background: #2d8a4e; }
.cmpx-side.worse  .cmpx-val      { color: #c0392b; }
.cmpx-side.worse  .cmpx-bar-fill { background: #e07a6f; }

.cmpx-big-row { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.cmpx-big {
  font-size: 1.35rem;
  font-weight: 800;
  color: #1a1a2e;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.cmpx-big-row .cmpx-detail { margin-top: 0; }

@media (prefers-reduced-motion: reduce) {
  .cmpx-card { transition: none; opacity: 1; }
}

/* Telefono e tablet in verticale: le card sporgenti uscirebbero dallo schermo e tre box sopra
   una foto così piccola la coprirebbero tutta. Restano i due box "differenza", in riga sotto la
   foto e accavallati sul suo bordo inferiore (margin-top negativo, in flusso: niente
   compensazione da calcolare per la sporgenza come per gli altri box a cavallo del bordo); senza
   descrizione e senza rotazione. */
@media (max-width: 860px) and (orientation: portrait) {
  .cmpx-cards {
    position: relative;
    inset: auto;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin-top: -44px;
    padding: 0 10px;
  }
  .cmpx-card,
  .cmpx-card-block,
  .cmpx-card-eff {
    position: static;
    width: auto;
    transform: translateY(18px) scale(0.96);
  }
  .reveal-split.is-visible .cmpx-card-block,
  .reveal-split.is-visible .cmpx-card-eff {
    transform: none;
  }
  .cmpx-card-imb,
  .cmpx-desc,
  .cmpx-detail {
    display: none;
  }
}

/* Telefono: foto a piena larghezza come i video delle altre sezioni (stesso breakout, angoli
   squadrati). */
@media (max-width: 600px) and (orientation: portrait) {
  .cmpx-media {
    width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
  }
  .cmpx-photo {
    border-radius: 0;
  }
}
