/* ==========================================================================
   MOTION — il sistema di rivelazione e i motivi animati
   ==========================================================================

   PERCHE' L'INNESCO E' IN JS MA IL MOVIMENTO E' IN CSS

   Si potrebbe fare tutto in CSS puro con `animation-timeline: view()`.
   Non si fa, per un motivo preciso: quella tecnica AGGANCIA l'animazione alla
   posizione di scorrimento. Tornando indietro l'elemento si ri-nasconde, e
   mentre lo si legge resta a mezza opacita'. Il testo deve comparire una
   volta e restare.

   Quindi: IntersectionObserver decide QUANDO, il CSS decide COME.

   --------------------------------------------------------------------------
   LEGGERO, DAL 2026-10-13
   --------------------------------------------------------------------------
   Il sito deve scorrere bene anche su un computer poco potente. Da quel
   giorno qui si anima SOLO opacita' e transform, che la scheda grafica
   compone senza ridisegnare:
     - gli ingranaggi dietro la pagina sono usciti (37 livelli sfocati e una
       maschera ricalcolata a ogni fotogramma; stanno in
       ~/Desktop/ingranaggi-sfondo/ e in git, bf0bfc8);
     - la rivelazione non sfoca piu': entra salendo e schiarendosi;
     - la grana sopra la pagina e' uscita: era un livello grande quattro
       finestre, ricomposto in continuazione;
     - niente piu' cursore personalizzato, titoli accesi parola per parola,
       ritardi elastici: erano tutti calcoli fatti mentre si scorre.
   L'unica sfocatura rimasta e' quella delle FAQ (§ 8), solo dopo un clic.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Rivelazione a scorrimento
   -------------------------------------------------------------------------- */

/* SOLO DISSOLVENZA dal 2026-10-14: a salire adesso e' il testo, ognuna delle
   sue righe dentro la propria maschera (§ 3c). Se salisse anche il
   contenitore, le righe farebbero due movimenti insieme. */
@keyframes rivela {
	from {
		/* Non zero: un elemento a opacita' esattamente 0 puo' essere scartato
		   dalla composizione, e alla ripresa lampeggia. */
		opacity: var(--reveal-seed);
	}
	to {
		opacity: 1;
	}
}

/* Stato di partenza. Si applica SOLO quando il livello animato e' attivo:
   se engine.js non parte, .motion-on non viene mai messa e il contenuto
   resta visibile e leggibile. Non scrivere mai regole che nascondono
   contenuto fuori da .motion-on. */
.motion-on .reveal {
	opacity: var(--reveal-seed);
	will-change: opacity, transform;
}

.motion-on .reveal.is-visible {
	animation: rivela var(--dur-reveal) var(--ease-out) both;
}

/* Finita l'animazione non serve piu' promuovere il livello alla GPU. */
.motion-on .reveal.is-settled {
	will-change: auto;
}

/* --------------------------------------------------------------------------
   2. Scaglionamento
   --------------------------------------------------------------------------
   I gruppi non entrano tutti insieme: 65ms tra un elemento e il successivo,
   e mai oltre l'ottavo — sei elementi fanno 390ms in tutto.
   -------------------------------------------------------------------------- */

.motion-on .reveal.is-visible > * {
	animation: rivela var(--dur-reveal) var(--ease-out) both;
	animation-delay: calc(var(--stagger) * var(--i, 0));
}

/* Il contenitore, quando scaglione i figli, non si anima a sua volta:
   altrimenti il movimento si somma e il gruppo scivola due volte. */
.motion-on .reveal.is-visible:has(> *) {
	animation: none;
	opacity: 1;
}

.motion-on .reveal > *:nth-child(1) { --i: 0; }
.motion-on .reveal > *:nth-child(2) { --i: 1; }
.motion-on .reveal > *:nth-child(3) { --i: 2; }
.motion-on .reveal > *:nth-child(4) { --i: 3; }
.motion-on .reveal > *:nth-child(5) { --i: 4; }
.motion-on .reveal > *:nth-child(6) { --i: 5; }
.motion-on .reveal > *:nth-child(7) { --i: 6; }
.motion-on .reveal > *:nth-child(n + 8) { --i: 7; }

/* Un paragrafo o un titolo NON si scaglionano per figli: dentro un <p> i
   figli sono <strong> e <em>, e farli entrare a scaletta sarebbe assurdo. */
.motion-on p.reveal.is-visible > *,
.motion-on h2.reveal.is-visible > *,
.motion-on h3.reveal.is-visible > * {
	animation: none;
}

.motion-on p.reveal.is-visible,
.motion-on h2.reveal.is-visible,
.motion-on h3.reveal.is-visible {
	animation: rivela var(--dur-reveal) var(--ease-out) both;
	opacity: 1;
}

/* --------------------------------------------------------------------------
   3. L'hero
   --------------------------------------------------------------------------
   Non aspetta lo scorrimento: parte al caricamento, appena i font sono
   pronti. Occhiello subito, poi le cinque righe del titolo da dietro la loro
   maschera, poi sottotitolo e bottoni.
   -------------------------------------------------------------------------- */

/* LA MISURA AMPIA, condivisa fra l'hero e i contatori: sulle cose grandi il
   gesto di base non si vede, e va rifatto in scala. */
@keyframes rivela-ampia {
	from {
		opacity: var(--reveal-seed);
		transform: translate3d(0, var(--reveal-lift-hero), 0);
	}
	to {
		opacity: 1;
		transform: translate3d(0, 0, 0);
	}
}

.motion-on .hero__apertura > *,
.motion-on .hero__chiusura > * {
	opacity: var(--reveal-seed);
	will-change: opacity, transform;
}

.motion-on .hero.is-visible .hero__apertura > *,
.motion-on .hero.is-visible .hero__chiusura > * {
	animation: rivela-ampia 1200ms var(--ease-out) both;
	animation-delay: calc(90ms * var(--i, 0));
}

.motion-on .hero.is-settled .hero__apertura > *,
.motion-on .hero.is-settled .hero__chiusura > * {
	will-change: auto;
}

/* L'ordine di entrata. 11 e 12 per 90ms fanno 0.99s e 1.08s: sottotitolo e
   bottoni entrano mentre sale l'ultima riga, non durante la frase. */
.motion-on .hero__apertura > *              { --i: 0; }
.motion-on .hero__chiusura > *:nth-child(1) { --i: 11; }
.motion-on .hero__chiusura > *:nth-child(2) { --i: 12; }

/* IL TITOLO SALE DA DIETRO UNA MASCHERA, come in karolinahess.com
   (2026-10-10). Ogni riga e' la maschera e il testo dentro di lei parte del
   115% piu' in basso. Nessuna dissolvenza: le lettere sono piene, le svela il
   bordo. Padding e margine negativo si annullano nel layout ma allargano la
   maschera, o taglierebbe le gambe della g e della p. */
.motion-on .hero__riga {
	overflow: hidden;
	padding-block: 0.12em;
	margin-block: -0.12em;
}

@keyframes sale-in-maschera {
	from { transform: translate3d(0, 115%, 0); }
	to   { transform: translate3d(0, 0, 0); }
}

.motion-on .hero__riga-testo {
	transform: translate3d(0, 115%, 0);
	will-change: transform;
}

.motion-on .hero.is-visible .hero__riga-testo {
	animation: sale-in-maschera var(--dur-maschera) var(--ease-maschera) both;
	animation-delay: calc(var(--passo-maschera) * var(--r));
}

.motion-on .hero.is-settled .hero__riga-testo {
	will-change: auto;
}

.motion-on .hero__riga:nth-child(1) { --r: 1; }
.motion-on .hero__riga:nth-child(2) { --r: 2; }
.motion-on .hero__riga:nth-child(3) { --r: 3; }
.motion-on .hero__riga:nth-child(4) { --r: 4; }
.motion-on .hero__riga:nth-child(5) { --r: 5; }

/* --------------------------------------------------------------------------
   3a. Le maschere di tutto il sito
   --------------------------------------------------------------------------
   Dal 2026-10-14 ogni segmento di testo sale come il titolo dell'hero:
   maschere.js lo spezza nelle sue righe vere, e ogni riga e' una maschera da
   cui il testo sale dal 115% a zero, con la curva e la durata del titolo. I
   titoli tengono il passo dell'hero fra una riga e l'altra (200ms), il testo
   corrente uno piu' stretto (80ms). Nessuna dissolvenza.

   Il padding e il margine negativo allargano la maschera senza spostare
   niente, sopra e sotto per le gambe della g e della p, ai lati per il
   corsivo che sporge.
   -------------------------------------------------------------------------- */

/* UNA COLONNA FLEX, non dei blocchi uno sotto l'altro: fra blocchi fratelli i
   margini negativi delle maschere si fonderebbero invece di sommarsi, e ogni
   riga allungherebbe il testo di 0,12em (misurato: 787px su tutta la pagina).
   In una colonna flex i margini non si fondono, come nelle righe dell'hero. */
.mv-righe {
	display: flex;
	flex-direction: column;
}

.mv-riga,
.mv-riga__testo {
	display: block;
}

/* Durante la misura l'involucro e' un blocco normale, e il testo ci scorre
   dentro come scorreva nell'elemento. */
.mv-righe.is-misura {
	display: block;
}

.mv-riga {
	overflow: hidden;
	padding: 0.12em 0.1em;
	margin: -0.12em -0.1em;
}

.motion-on .mv-maschera {
	--passo: var(--passo-righe);
}

.motion-on .mv-maschera--titolo {
	--passo: var(--passo-maschera);
}

.motion-on .mv-maschera .mv-riga__testo {
	transform: translate3d(0, 115%, 0);
}

.motion-on .mv-maschera.is-su .mv-riga__testo {
	animation: sale-in-maschera var(--dur-maschera) var(--ease-maschera) both;
	animation-delay: calc(var(--attesa, 0ms) + var(--passo) * var(--r, 0));
}

/* Gia' salito prima che la finestra cambiasse larghezza: le righe nuove sono
   gia' al loro posto, senza rifare il giro. */
.motion-on .mv-maschera.is-gia .mv-riga__testo {
	transform: none;
	animation: none;
}

/* DENTRO UN .reveal NON ANCORA COMPARSO il testo aspetta: salirebbe dentro un
   contenitore ancora trasparente, e non lo vedrebbe nessuno. Quando il
   contenitore compare, l'animazione ha un nome e parte. */
.motion-on .reveal:not(.is-visible) .mv-maschera.is-su .mv-riga__testo {
	animation-name: none;
}

/* Un testo spezzato non si dissolve anche: o e' un .reveal lui stesso, o e'
   figlio di uno. Le lettere sono piene, le svela il bordo. */
.motion-on .reveal.mv-maschera,
.motion-on .reveal.is-visible.mv-maschera,
.motion-on .reveal.is-visible > .mv-maschera {
	animation: none;
	opacity: 1;
}

/* NELL'HERO occhiello e sottotitolo salgono come il titolo, al loro turno:
   l'occhiello subito, il sottotitolo quando l'ultima riga del titolo sta
   arrivando (0,99s, come prima). */
.motion-on .hero__apertura > .mv-maschera,
.motion-on .hero__chiusura > .mv-maschera,
.motion-on .hero.is-visible .hero__apertura > .mv-maschera,
.motion-on .hero.is-visible .hero__chiusura > .mv-maschera {
	animation: none;
	opacity: 1;
}

.motion-on .hero__sub {
	--attesa: 990ms;
}

/* --------------------------------------------------------------------------
   3b. I contatori
   --------------------------------------------------------------------------
   Quattro numeri grandi: il gesto nella misura ampia dell'hero, e lo
   scaglionamento piu' largo (110ms) perche' si contino.
   -------------------------------------------------------------------------- */

.motion-on .stats.is-visible > * {
	animation: rivela-ampia 1100ms var(--ease-out) both;
	animation-delay: calc(110ms * var(--i, 0));
}

.motion-on .stats.is-settled > * {
	will-change: auto;
}

/* --------------------------------------------------------------------------
   4. I blocchi che entrano ed escono
   --------------------------------------------------------------------------
   blocchi.js mette .is-dentro quando un blocco arriva dal basso e .is-uscito
   quando ne resta solo la coda nel terzo alto della finestra. Qui il come:
   entrando sale di 40px, cresce di un soffio e si schiarisce; uscendo
   sbiadisce. Risalendo, tutto al contrario.

   TRANSIZIONI E NON KEYFRAMES: un blocco puo' entrare e uscire due volte in
   un secondo scorrendo avanti e indietro, e una transizione riparte da dove si
   trova invece di ricominciare.

   Tutto sotto .con-blocchi, che mette il modulo: se il modulo non parte, i
   blocchi restano visibili.
   -------------------------------------------------------------------------- */

/* Il blocco cresce e cala attorno al suo bordo basso, dove la linea guida ne
   esce: al centro, o dove guida.js scrive --guida-origine per un blocco che
   la linea attraversa sopra. Cosi', quando il blocco sbiadisce, il tratto
   dentro di lui e quello nello stacco sotto restano allineati. */
.con-blocchi main > .section {
	opacity: 0;
	transform-origin: var(--guida-origine, 50%) 100%;
	transform: translate3d(0, var(--blocco-lift), 0) scale(var(--blocco-scala));
	transition: opacity var(--dur-blocco) var(--ease-out),
	            transform var(--dur-blocco) var(--ease-out);
}

.con-blocchi main > .section.is-dentro {
	opacity: 1;
	transform: none;
}

.con-blocchi main > .section.is-dentro.is-uscito {
	opacity: var(--blocco-uscito);
	transform: scale(var(--blocco-scala));
}

/* --------------------------------------------------------------------------
   4b. La linea guida
   --------------------------------------------------------------------------
   Copiata da auxia.io il 2026-10-14 (guida.js): tratti dritti e curve da
   24px, una traccia chiara sempre visibile e il percorso scuro che si allunga
   mentre si scorre. Corre accanto, sopra o sotto i blocchi, secondo il loro
   data-guida, e attraversa la pagina negli stacchi. Lo strato della pagina
   e' dipinto sotto i blocchi; il tratto che passa SOPRA un blocco e' uno
   strato dentro di lui (.mv-guida--blocco).

   Il percorso lo scrive guida.js nel tratteggio (pathLength="1",
   stroke-dasharray "quanto 2"), senza transizione: la linea e' dove e' lo
   scorrimento, come nel riferimento. Cappucci piatti, cosi' un tratto lungo
   zero non lascia un puntino.
   -------------------------------------------------------------------------- */

.mv-guida {
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
}

/* LO STRATO DENTRO UN BLOCCO (2026-10-17): il tratto che scende su un blocco
   marcato data-guida="sopra", nel suo margine, e la sua tappa. E' un figlio
   del blocco: entra, sbiadisce e si sposta con lui, e non ne esce. Prima era
   uno strato unico sopra tutti i blocchi, e quando un blocco era ancora in
   arrivo o stava sbiadendo il tratto restava li', fuori dai suoi bordi.
   Traccia e bordo della tappa prendono il grigio del tono del blocco. */
.mv-guida--blocco {
	z-index: 1;
	--tappa-traccia: var(--guida-sul-blocco);
}

.mv-guida--blocco .mv-guida__traccia {
	stroke: var(--guida-sul-blocco);
}

.mv-guida__disegno {
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	overflow: visible;
}

.mv-guida__traccia,
.mv-guida__percorso {
	fill: none;
	stroke-width: var(--guida-tratto);
	stroke-linecap: butt;
	stroke-linejoin: round;
}

.mv-guida__traccia {
	stroke: var(--guida-traccia);
}

.mv-guida__percorso {
	stroke: var(--guida-percorso);
}

/* La fine della linea, nello stacco sopra il piede. */
.mv-guida__fine {
	fill: var(--guida-traccia);
	transition: fill var(--dur-ui) var(--ease-hover);
}

.mv-guida__fine.is-raggiunta {
	fill: var(--guida-percorso);
}

/* LE TAPPE: una pillola con un ingranaggio, come quelle con il fulmine del
   riferimento. Ferma e' grigia; quando il percorso la raggiunge prende il
   colore della linea e l'ingranaggio si mette in moto, e gira finche' la tappa
   si vede. La posizione la scrive guida.js in left/top una volta per misura:
   non si anima. Il fondo e' quello della pagina, anche sopra un blocco nero:
   copre la linea sotto di lei, e niente nero negli ingranaggi.

   LA MISURA (2026-10-17, Pietro: "ingrandisci del doppio") la da'
   --tappa-larga, che segue la finestra: 96x68px dove la corsia e' larga, e
   sul telefono quanto la corsia di 44px permette, come prima. L'altezza e
   l'ingranaggio stanno nella stessa proporzione di quando era 48x34. */
.mv-tappa {
	position: absolute;
	display: flex;
	align-items: center;
	justify-content: center;
	width: var(--tappa-larga);
	height: max(1.75rem, var(--tappa-larga) * 0.71);
	/* Centrata sul punto che scrive guida.js. */
	translate: -50% -50%;
	border: var(--guida-bordo-tappa) solid var(--tappa-traccia, var(--guida-traccia));
	border-radius: var(--radius-pill);
	background-color: var(--pagina);
	color: var(--guida-ferma);
	transition: border-color var(--dur-ui) var(--ease-hover),
	            color var(--dur-ui) var(--ease-hover);
}

/* Raggiunta resta chiara e cambia solo colore: bordo e ingranaggio del colore
   della linea, niente nero sotto (Pietro, 2026-10-14). */
.mv-tappa.is-raggiunta {
	border-color: var(--guida-percorso);
	color: var(--guida-percorso);
}

@keyframes tappa-giro {
	to { transform: rotate(360deg); }
}

/* Un'animazione in pausa che riparte da dove si era fermata: l'ingranaggio
   non torna a zero, riprende a girare. */
.mv-tappa__ruota {
	display: block;
	width: max(0.9375rem, var(--tappa-larga) * 0.375);
	height: max(0.9375rem, var(--tappa-larga) * 0.375);
	animation: tappa-giro var(--dur-tappa) linear infinite;
	animation-play-state: paused;
}

.mv-tappa.is-raggiunta.is-vista .mv-tappa__ruota {
	animation-play-state: running;
}

.mv-tappa__ruota svg {
	display: block;
	width: 100%;
	height: 100%;
	fill: currentColor;
	fill-rule: evenodd;
}

/* --------------------------------------------------------------------------
   4c. La sigla della testata
   --------------------------------------------------------------------------
   sigla.js divide il nome in iniziali e resti; superato l'hero mette
   .is-sigla e i resti si chiudono, lasciando PGCG. Ogni resto e' una griglia
   da 1fr a 0fr (l'eccezione gia' ammessa per gli accordion), e
   `overflow-x: clip` invece di hidden non mozza la gamba della j.
   -------------------------------------------------------------------------- */

.mv-sigla {
	white-space: nowrap;
}

.mv-sigla__resto {
	display: inline-grid;
	grid-template-columns: 1fr;
	opacity: 1;
	transition: grid-template-columns var(--dur-sigla) var(--ease-out),
	            opacity var(--dur-sigla) var(--ease-out);
}

.mv-sigla__resto > span {
	min-width: 0;
	overflow-x: clip;
	white-space: pre;
}

.mv-sigla.is-sigla .mv-sigla__resto {
	grid-template-columns: 0fr;
	opacity: 0;
}

/* Sul telefono il nome intero va a capo (main.css § 4), ma solo fra una
   parola e l'altra: iniziale e resto stanno insieme. */
.mv-sigla__parola {
	white-space: nowrap;
}

@media (max-width: 640px) {
	.mv-sigla {
		white-space: normal;
	}
}

/* --------------------------------------------------------------------------
   5. La pillola di posizione
   --------------------------------------------------------------------------
   Un ingranaggio e due cifre, in basso a destra. L'ingranaggio gira solo
   mentre si scorre: l'angolo lo scrive posizione.js, sul contenitore e non
   sull'SVG, cosi' la scheda grafica gira un livello gia' disegnato. NESSUNA
   transizione sulla rotazione: un easing aggiungerebbe un ritardo fra dove
   sei e dove la ruota dice che sei.

   NON PORTA PAROLE (V1): due cifre, la lettura di uno strumento.
   -------------------------------------------------------------------------- */

.mv-posizione {
	position: fixed;
	inset-block-end: var(--space-6);
	inset-inline-end: var(--space-6);
	z-index: 80;
	display: flex;
	align-items: center;
	gap: var(--space-3);
	padding: var(--space-2) var(--space-4) var(--space-2) var(--space-3);
	border: var(--hairline) solid var(--line);
	border-radius: var(--radius-pill);
	background-color: var(--bg);
	box-shadow: var(--shadow-md);
	font-family: var(--font-mono);
	font-size: var(--fs-micro);
	font-variant-numeric: tabular-nums;
	letter-spacing: var(--track-label);
	color: var(--text-muted);
	opacity: 0;
	pointer-events: none;
	transition: opacity var(--dur-panel) var(--ease-out);
}

/* Compare quando la pagina si stacca dall'inizio: nell'hero non serve. */
.mv-posizione.is-visible {
	opacity: 1;
}

.mv-posizione__ruota {
	display: block;
	flex: none;
	width: 1.625rem;
	height: 1.625rem;
	will-change: transform;
}

.mv-posizione__ruota svg {
	display: block;
	width: 100%;
	height: 100%;
	/* Grigio come l'ingranaggio di una tappa ferma: niente nero negli
	   ingranaggi (Pietro, 2026-10-14). */
	fill: var(--guida-ferma);
	fill-rule: evenodd;
}

/* Larghezza fissa: la stringa passa da 01/12 a 12/12, e senza cifre
   tabulari la pillola respirerebbe di un paio di pixel a ogni sezione. */
.mv-posizione__cifre {
	white-space: nowrap;
}

@media (max-width: 700px) {
	.mv-posizione {
		display: none;
	}
}

/* --------------------------------------------------------------------------
   5b. Il diagramma del metodo
   --------------------------------------------------------------------------
   Due tracciati e cinque tacche: il piano e' un filo grigio tratteggiato,
   l'andamento reale una linea piena. SI DISEGNA UNA VOLTA quando entra in
   vista (diagramma.js mette .is-disegnato) e resta: fino al 2026-10-13
   seguiva lo scorrimento pixel per pixel.

   Le tacche e la linea dell'intervento si accendono quando la punta le
   raggiunge: il momento, in frazione della durata, lo calcola diagramma.js
   e lo scrive in --quando.
   -------------------------------------------------------------------------- */

.mv-diagramma {
	margin-block: var(--space-8) var(--space-9);
}

.mv-diagramma svg {
	display: block;
	width: 100%;
	/* preserveAspectRatio: none piu' un'altezza fissa: il disegno si stira in
	   orizzontale e resta alto uguale. E' un grafico, non un logo. */
	height: clamp(9rem, 6rem + 9vw, 16rem);
	overflow: visible;
}

.mv-dg__asse {
	stroke: var(--line);
	stroke-width: 1;
}

.mv-dg__tacca {
	stroke: var(--line-strong);
	stroke-width: 1.5;
	opacity: 0.5;
	transition: opacity var(--dur-ui) var(--ease-hover) calc(var(--dur-disegno) * var(--quando, 0)),
	            stroke var(--dur-ui) var(--ease-hover) calc(var(--dur-disegno) * var(--quando, 0));
}

.is-disegnato .mv-dg__tacca {
	stroke: var(--text);
	opacity: 1;
}

.mv-dg__piano {
	fill: none;
	stroke: var(--line-strong);
	stroke-width: 1.5;
	stroke-dasharray: 6 7;   /* tratteggiato: e' una previsione, non un fatto */
	vector-effect: non-scaling-stroke;
}

.mv-dg__reale {
	fill: none;
	stroke: var(--text);
	stroke-width: 2.5;
	stroke-linecap: round;
	vector-effect: non-scaling-stroke;
	stroke-dasharray: var(--lunghezza, none);
	stroke-dashoffset: var(--lunghezza, 0);
	transition: stroke-dashoffset var(--dur-disegno) var(--ease-scan);
}

.is-disegnato .mv-dg__reale {
	stroke-dashoffset: 0;
}

.mv-dg__intervento {
	stroke: var(--line-strong);
	stroke-width: 1;
	stroke-dasharray: 3 5;
	opacity: 0;
	transition: opacity var(--dur-panel) var(--ease-out) calc(var(--dur-disegno) * var(--quando, 0));
}

.is-disegnato .mv-dg__intervento {
	opacity: 1;
}

/* Il segnalino arriva per ultimo, in fondo al tracciato. */
.mv-dg__segnalino {
	fill: var(--text);
	opacity: 0;
	transition: opacity var(--dur-panel) var(--ease-out) var(--dur-disegno);
}

.is-disegnato .mv-dg__segnalino {
	opacity: 1;
}

/* Movimento ridotto: tutto gia' disegnato, nessuna transizione. */
.mv-diagramma.is-fermo .mv-dg__reale,
.mv-diagramma.is-fermo .mv-dg__tacca,
.mv-diagramma.is-fermo .mv-dg__intervento,
.mv-diagramma.is-fermo .mv-dg__segnalino {
	transition: none;
}

@media (max-width: 900px) {
	.mv-diagramma {
		display: none;
	}
}

/* --------------------------------------------------------------------------
   6. Il cervello del logo
   --------------------------------------------------------------------------
   Le ruote girano di continuo, ognuna attorno al proprio centro, con il
   periodo che le scrive tools/logo-cervello.js in --periodo: proporzionale ai
   denti, verso alterno. Due ruote che partono ingranate restano ingranate.

   `transform-box: fill-box` fa girare ogni ruota attorno al centro del proprio
   riquadro; il riquadro e' tenuto centrato da un cerchio invisibile.

   Keyframe e non transizione: e' un giro continuo, non uno stato.
   -------------------------------------------------------------------------- */

@keyframes cervello-giro {
	to { transform: rotate(360deg); }
}

.motion-on .cervello__ruota {
	transform-box: fill-box;
	transform-origin: 50% 50%;
	animation: cervello-giro var(--periodo) linear infinite;
}

.motion-on .cervello__ruota--indietro {
	animation-direction: reverse;
}

/* --------------------------------------------------------------------------
   7. L'orologio dei contatti
   --------------------------------------------------------------------------
   Il quadrante che si disegna, resta e si scioglie, sotto il testo della
   sezione contatti. Tondo dal 2026-10-13: fino ad allora colava in basso in
   tre gocce. Il disegno lo costruisce vivo.js come SVG a runtime: nessuna
   immagine (V2).

   NESSUN COLORE SCRITTO: l'orologio legge i token del testo. Fino al
   2026-10-09 la sezione era nera e lui era chiaro; da quando la pagina e'
   tutta chiara e' scuro, senza che una riga di questo blocco sia cambiata.
   Contrasti sul bianco (2026-10-12): bordo e lancette in nero 18.88:1,
   indici minori e secondi in grigio scuro 7.46:1, l'ombra del quadrante in
   grigio chiaro 1.48:1 — che e' decorativa, non testo.

   GLI SPESSORI SONO QUELLI DEL BANCO DI PROVA e non vanno riscalati: il
   riquadro e' 400 unita' e il disegno si mostra a 416px, cioe' circa una unita'
   per pixel. E' la ragione per cui la larghezza massima e' 26rem e non meno.
   -------------------------------------------------------------------------- */

.mv-vivo {
	display: block;
	width: 100%;
	height: auto;

	/* Il tratto ha uno spessore, e a ridosso del bordo del riquadro verrebbe
	   tagliato a meta'. */
	overflow: visible;

	/* Decorativo: non deve prendersi il puntatore. Il campo cinetico ascolta
	   il mouse sulla finestra, quindi non gli serve. */
	pointer-events: none;
}

/* Un anello larghissimo e appena percettibile, che stacca il quadrante dal
   fondo senza disegnare un contorno in piu'. Non si anima mai. */
.mv-vivo__alone {
	fill: none;
	stroke: rgba(var(--text-rgb), 0.05);
	stroke-width: 18;
}

/* Il quadrante, sempre presente e appena accennato: durante la pausa del
   ciclo il bordo non c'e' piu' e senza di lui resterebbe un buco. */
.mv-vivo__ombra {
	fill: none;
	stroke: var(--line);
	stroke-width: 1.15;
	stroke-linecap: round;
	stroke-linejoin: round;
	opacity: 0.42;
}

.mv-vivo__bordo {
	fill: none;
	stroke: var(--text);
	stroke-width: 1.85;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* Sessanta indici, e quelli delle cinque piu' marcati: senza, il quadrante
   diventa una corona di trattini uguali e si perde il verso. L'opacita' la
   scrive il modulo, uno per uno: entrano in giro, non tutti insieme. */
.mv-vivo__indice {
	stroke: var(--text-faint);
	stroke-width: 0.9;
	stroke-linecap: round;
	opacity: 0;
}

.mv-vivo__indice.is-grande {
	stroke: var(--text);
	stroke-width: 2.6;
}

/* La gerarchia e' quella di un orologio vero: ore corte e piene, minuti lunghi
   e piu' sottili, secondi un filo — e in acciaio, non in un accento: questa
   tavolozza non ne ha uno, ed e' una decisione presa. */
.mv-vivo__lancetta {
	fill: none;
	stroke-linecap: round;
}

.mv-vivo__lancetta--ore     { stroke: var(--text);       stroke-width: 7.5; }
.mv-vivo__lancetta--minuti  { stroke: var(--text);       stroke-width: 4.4; }
.mv-vivo__lancetta--secondi { stroke: var(--text-faint); stroke-width: 1.7; }

/* Il contrappeso dei secondi, dall'altra parte del perno. E' il dettaglio che
   fa leggere la lancetta come un pezzo montato invece che come una linea. */
.mv-vivo__coda {
	stroke: var(--text-faint);
	stroke-width: 2.4;
	stroke-linecap: round;
	opacity: 0.9;
}

/* Il perno arriva per ultimo: prima che le tre lancette ci siano tutte, non ha
   niente da tenere. L'opacita' la guida il modulo. */
.mv-vivo__perno {
	opacity: 0;
}

.mv-vivo__perno-fuori  { fill: var(--text); }
.mv-vivo__perno-dentro { fill: var(--bg); }
.mv-vivo__perno-punto  { fill: var(--text-faint); }

/* A movimento ridotto il modulo si monta e si ferma, disegnato: il perno non
   ha nessun ciclo che glielo accenda. */
.mv-vivo.is-ferma .mv-vivo__perno {
	opacity: 1;
}

/* --------------------------------------------------------------------------
   8. Le FAQ che si concentrano
   --------------------------------------------------------------------------
   Aprendo una domanda, le altre sfocano e sbiadiscono: resta nitida solo
   quella aperta, con la sua risposta. Il titolo della sezione NON sfoca, ed e'
   una scelta: e' l'ancora che dice dove sei nella pagina.

   NESSUN JAVASCRIPT. Lo stato c'e' gia' — main.js scrive data-open sull'item e
   apre una domanda per volta — e qui il CSS lo legge con :has(). E' la stessa
   divisione di tutto il sito: il JS governa lo stato, il CSS decide come si
   vede. Il pannello chiaro sotto la domanda aperta sta in main.css § 15,
   perche' quello e' il componente; questa e' la messa a fuoco, ed e' un gesto.

   --------------------------------------------------------------------------
   PERCHE' SFOCA IL BOTTONE E NON L'ITEM
   --------------------------------------------------------------------------
   Perche' sull'item non funzionerebbe, e non si capirebbe il motivo guardando.
   .faq-item e' figlio di .faq-list, che e' un .reveal: lo scaglionamento (§ 2)
   gli mette addosso `animation: rivela ... both`, e quel `both` TIENE
   applicato lo stato finale del keyframe — filter compreso — per tutta la vita
   della pagina. Un'animazione batte una dichiarazione normale nella cascata,
   quindi `filter: blur(3px)` sull'item veniva ignorato in silenzio: nessun
   errore, nessun avviso, solo un effetto che non c'era.

   E' la stessa trappola gia' pagata con GSAP e le transform. Il rimedio e' lo
   stesso: non contendersi la proprieta', ma spostarsi su un elemento che
   nessuno sta gia' animando — qui il bottone, che e' un nipote di .reveal.

   Sfocare solo il bottone e' anche piu' giusto a vedersi: i filetti fra una
   domanda e l'altra restano nitidi, quindi si continua a contare quante
   domande ci sono mentre si smette di poterle leggere. E la risposta chiusa
   non serve toccarla: e' gia' schiacciata a zero.
   -------------------------------------------------------------------------- */

@supports selector(:has(*)) {

	/* La transizione va riscritta per intero, incluse le due di main.css: una
	   lista di transition non si puo' allungare, si sostituisce. */
	.motion-on .faq-item__question {
		transition: color var(--dur-ui) var(--ease-hover),
		            transform var(--dur-press) var(--ease-out),
		            filter var(--dur-panel) var(--ease-out),
		            opacity var(--dur-panel) var(--ease-out);
	}

	/* Lo sbiadimento vale sempre: e' l'unico modo di fare gerarchia su questa
	   fascia, dove il token del testo secondario e' nero pieno. */
	.motion-on .faq-list:has(.faq-item[data-open="true"]) .faq-item:not([data-open="true"]) .faq-item__question {
		opacity: var(--faq-velo);
	}

	/* LA SFOCATURA NON ESISTE A MOVIMENTO RIDOTTO NE' A CONTRASTO ALTO, e non
	   e' attenuata: e' proprio assente. Sfocare del testo per chi ha gia'
	   difficolta' di lettura non ha una versione gentile — resta il solo
	   sbiadimento, che dice la stessa cosa senza togliere leggibilita'.

	   Il blocco e' scritto in positivo (`no-preference`) invece di spegnere
	   dopo: cosi' non serve nessun !important per vincere, che in questo
	   livello e' vietato. */
	@media (prefers-reduced-motion: no-preference) and (prefers-contrast: no-preference) {

		.motion-on .faq-list:has(.faq-item[data-open="true"]) .faq-item:not([data-open="true"]) .faq-item__question {
			filter: blur(var(--faq-sfocatura));

			/* Solo mentre qualcosa e' aperto. A riposo questo selettore non
			   corrisponde a niente, quindi non resta un livello acceso su
			   cinque elementi per tutta la vita della pagina. */
			will-change: filter;
		}
	}

	/* CHI PRENDE IL FUOCO TORNA NITIDO E LEGGIBILE. Senza questa riga, chi
	   naviga con il tabulatore mentre una domanda e' aperta si trova a
	   scegliere fra quattro macchie: l'effetto diventa una barriera.

	   Vale anche per il passaggio del mouse: sfocato vuol dire "non e' questo",
	   e avvicinandosi la domanda deve tornare a dire che si puo' aprire.

	   LA CATENA E' RIPETUTA PER INTERO, e non e' pigrizia nel copiare: e'
	   l'unico modo di vincere. Il selettore che sfoca pesa (0,7,0) — dentro
	   :has() la specificita' e' quella del suo argomento piu' pesante, e li'
	   dentro c'e' un attributo — quindi una scorciatoia tipo
	   `.faq-item:not([data-open]) .faq-item__question:hover` si ferma a (0,5,0)
	   e perde. Provato: con il fuoco da tastiera la domanda restava sfocata,
	   cioe' esattamente il caso che questa regola esiste per proteggere. */
	.motion-on .faq-list:has(.faq-item[data-open="true"]) .faq-item:not([data-open="true"]) .faq-item__question:focus-visible,
	.motion-on .faq-list:has(.faq-item[data-open="true"]) .faq-item:not([data-open="true"]) .faq-item__question:focus {
		filter: none;
		opacity: 1;
	}

	@media (hover: hover) and (pointer: fine) {
		.motion-on .faq-list:has(.faq-item[data-open="true"]) .faq-item:not([data-open="true"]) .faq-item__question:hover {
			filter: none;
			opacity: 1;
		}
	}
}


/* --------------------------------------------------------------------------
   9. Movimento ridotto
   --------------------------------------------------------------------------
   MENO E PIU' GENTILE, NON ZERO. Si toglie lo spostamento e si tiene la
   dissolvenza: azzerare tutto lascia la pagina senza feedback, e chi ha
   attivato l'impostazione voleva meno movimento, non meno informazione.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {

	@keyframes rivela {
		from { opacity: var(--reveal-seed); }
		to   { opacity: 1; }
	}

	@keyframes rivela-ampia {
		from { opacity: var(--reveal-seed); }
		to   { opacity: 1; }
	}

	.motion-on .reveal,
	.motion-on .reveal.is-visible,
	.motion-on .reveal.is-visible > *,
	.motion-on .hero__apertura > *,
	.motion-on .hero__chiusura > * {
		will-change: auto;
	}

	/* Il titolo non sale: compare in dissolvenza, gia' al suo posto. */
	.motion-on .hero__riga-testo,
	.motion-on .hero.is-visible .hero__riga-testo {
		transform: none;
		animation-name: rivela-ampia;
		will-change: auto;
	}

	/* Le righe di tutto il sito, come il titolo: compaiono in dissolvenza,
	   gia' al loro posto. */
	.motion-on .mv-maschera .mv-riga__testo,
	.motion-on .mv-maschera.is-su .mv-riga__testo {
		transform: none;
		animation-name: rivela-ampia;
	}

	/* I blocchi entrano ed escono in dissolvenza, fermi al loro posto. */
	.con-blocchi main > .section,
	.con-blocchi main > .section.is-dentro.is-uscito {
		transform: none;
	}

	/* Gli ingranaggi delle tappe stanno fermi: la tappa raggiunta si scurisce
	   e basta. La linea resta: segue lo scorrimento, non si muove da sola. */
	.mv-tappa__ruota {
		animation: none;
	}

	/* Il nome si chiude in dissolvenza, senza stringersi. */
	.mv-sigla__resto {
		transition: opacity var(--dur-ui) var(--ease-out);
	}

	/* Il cervello e' fermo: e' un logo, non deve chiedere attenzione. */
	.motion-on .cervello__ruota {
		animation: none;
	}
}
