/* =========================================================================
   LUNA MINIMAL — il livello di movimento.

   Le comparse di base (data-reveal) restano in main.css: qui c'è tutto
   quello che le sta sopra — coreografia della hero, transizioni fra le
   pagine, animazioni legate allo scorrimento, micro-interazioni.

   Tre regole che valgono per ogni riga di questo foglio:

   1. Nessuna libreria. Dove serve JavaScript è solo per aggiungere una
      classe o un nome: se non parte, resta tutto visibile e cliccabile.
   2. Si animano solo `transform`, `opacity` e `clip-path`. Mai larghezze,
      altezze o margini: quelli fanno rifare il layout a ogni fotogramma.
   3. Il movimento è dentro `prefers-reduced-motion: no-preference`. Chi
      chiede meno movimento vede il sito fermo, non il sito rotto.
   ========================================================================= */

:root {
	/* Fuori entra più lento di quanto esce: è la curva che fa sembrare le
	   cose pesanti al punto giusto. */
	--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
	--ease-inout: cubic-bezier(0.65, 0, 0.35, 1);
	/* Un filo di rimbalzo, solo su elementi piccoli */
	--ease-molla: cubic-bezier(0.34, 1.4, 0.64, 1);

	--dur-micro: 200ms;
	--dur-media: 420ms;
	--dur-scena: 760ms;

	--passo: 70ms; /* distanza fra un elemento e il successivo in fila */
}

/* =========================================================================
   1 · TRANSIZIONI FRA LE PAGINE
   Il browser tiene una foto della pagina che esce e la incrocia con quella
   che entra. Dove non è supportato non succede niente: si naviga come
   sempre, senza codice di ripiego.
   ========================================================================= */

/* L'adesione sta al primo livello del foglio, non dentro una media query:
   il browser la legge prestissimo, prima di sapere cosa vogliamo animare, e
   annidata veniva ignorata — `pageswap` scattava con `viewTransition` a
   null, cioè nessuna transizione creata. Chi chiede meno movimento non la
   disattiva: gliela si azzera in fondo al foglio, dove si spengono le
   animazioni. */
@view-transition {
	navigation: auto;
}

@media (prefers-reduced-motion: no-preference) {
	/* Il fondo si limita a scambiarsi: niente scorrimenti, o si muoverebbero
	   due cose insieme e la foto che vola smetterebbe di essere il soggetto. */
	::view-transition-old(root) {
		animation: sfuma-via 260ms var(--ease-inout) both;
	}

	::view-transition-new(root) {
		animation: sfuma-dentro 420ms 120ms var(--ease-out) both;
	}

	/* La testata non deve partecipare al dissolvenza: sta ferma mentre il
	   contenuto cambia, e la navigazione sembra un'app invece che un
	   ricaricamento. */
	.testata {
		view-transition-name: testata;
	}

	::view-transition-group(testata) {
		animation-duration: 0ms;
	}

	/* Il gioiello su cui si clicca vola dalla griglia alla sua scheda.

	   Sulla pagina in arrivo il nome si dà QUI, non dal JavaScript: il
	   browser fotografa la pagina nuova alla prima occasione utile, e i
	   nostri script stanno in fondo al documento. Assegnandolo da lì il
	   nome arrivava dopo lo scatto, la foto in arrivo non veniva agganciata
	   e restava solo la dissolvenza — che è esattamente quello che si
	   vedeva. Nel CSS il nome c'è già al primo calcolo degli stili.

	   Sulla pagina che si lascia serve invece il JavaScript, perché il nome
	   dev'essere unico e va messo solo sulla scheda su cui si è cliccato:
	   lì lo scatto avviene dopo il clic, quindi si fa in tempo.

	   FIGLIO DIRETTO, non discendente: dentro la galleria ci sono anche le
	   miniature, e col selettore discendente il nome finiva su tutte. Un
	   nome duplicato non degrada la transizione: la ANNULLA — il volo
	   funzionava solo sui prodotti con una foto sola. */
	.gioiello__pista > .gioiello__slide:first-child img {
		view-transition-name: gioiello;
	}

	/* Il volo è la cosa da guardare: dura quasi il doppio del resto e si
	   prende la scena. Il fondo si limita a scambiarsi sotto. */
	::view-transition-group(gioiello) {
		animation-duration: 800ms;
		animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
	}

	/* Le due foto si incrociano con la dissolvenza di sistema. Avevo provato
	   a toglierla — sono quasi la stessa immagine — ma spegnere l'animazione
	   qui vale anche quando la foto in arrivo NON esiste: tornando indietro
	   col browser, la scheda che si lascia ha il suo nome e la griglia no,
	   quindi la vecchia restava ferma senza uscita finché la transizione non
	   finiva. Da qui l'immagine che «rimane un po' prima di andare via».
	   La dissolvenza di sistema copre tutti e due i casi. */
	::view-transition-old(gioiello),
	::view-transition-new(gioiello) {
		height: 100%;
		object-fit: contain;
	}

	/* La dissolvenza è breve mentre il volo resta lungo: incrociandosi in
	   fretta le due foto sembrano una sola che si sposta, e nel caso senza
	   arrivo — il tasto indietro — la vecchia se ne va subito invece di
	   restare appesa per tutta la durata del volo. */
	::view-transition-old(gioiello) {
		animation-duration: 300ms;
	}

	::view-transition-new(gioiello) {
		animation-duration: 420ms;
	}
}

@keyframes sfuma-via {
	to {
		opacity: 0;
	}
}

@keyframes sfuma-dentro {
	from {
		opacity: 0;
	}
}

/* =========================================================================
   2 · LA HERO ENTRA IN SCENA
   Non tutto insieme: prima l'occhiello, poi il titolo parola per parola,
   poi il sottotitolo, il bottone, la riga dati. Chi arriva legge nello
   stesso ordine in cui gli elementi compaiono.
   ========================================================================= */

@media (prefers-reduced-motion: no-preference) {
	.js .hero__box > div > *:not(h1),
	.js .hero__specs li {
		animation: sali-dentro var(--dur-scena) var(--ease-out) both;
	}

	/* Tre classi ciascuno, non due: la riga qui sopra usa `:not(h1)`, che
	   porta con sé la specificità del suo argomento, e un selettore più
	   leggero si vedrebbe azzerare il ritardo dalla scorciatoia. */
	.js .hero .occhiello {
		animation-delay: 80ms;
	}
	.js .hero .hero__sub {
		animation-delay: 420ms;
	}
	.js .hero .btn {
		animation-delay: 540ms;
	}

	/* La riga dati arriva per ultima, una voce dietro l'altra */
	.js .hero__specs li {
		animation-delay: calc(620ms + var(--i, 0) * var(--passo));
	}

	/* Il titolo: ogni parola sale da sotto una feritoia. Senza JavaScript
	   le parole non vengono avvolte e il titolo resta lì, fermo e intero. */
	.parola {
		display: inline-block;
		overflow: hidden;
		vertical-align: bottom;
		/* La feritoia taglierebbe le code di g, p e q: si allarga sotto e
		   si riprende lo spazio col margine, così la riga non si muove. */
		padding-bottom: 0.14em;
		margin-bottom: -0.14em;
	}

	.parola > span {
		display: inline-block;
		animation: parola-su 900ms var(--ease-out) both;
		animation-delay: calc(140ms + var(--i, 0) * 55ms);
	}
}

@keyframes sali-dentro {
	from {
		opacity: 0;
		transform: translateY(14px);
	}
}

/* 100% + 0.2em, non 105%: la feritoia è allargata sotto di 0.14em per non
   tagliare le code di g e q, e il 5% extra (~0.054em a line-height 1.08)
   non bastava a coprire l'allargamento — alla taglia hero spuntavano ~6px
   di maiuscole dalla fessura prima che l'animazione partisse. */
@keyframes parola-su {
	from {
		transform: translateY(calc(100% + 0.2em));
	}
}

/* =========================================================================
   2b · LA SCHEDA DEL GIOIELLO SI APRE
   Prima si posa la foto, poi arriva il testo. Non è vezzo: la foto è
   l'elemento più grande e più pesante da caricare, e se il testo compare
   mentre lei si sta ancora sistemando si legge sopra una cosa che si
   muove. Un attimo di attesa e ognuno arriva al suo posto.
   ========================================================================= */

/* Foto e testi passano dal sistema delle comparse, non da un'animazione a
   fotogrammi. Il motivo è una regola di questo progetto: nessun contenuto
   può restare invisibile perché qualcosa non è partito. Un'animazione che
   comincia da `opacity: 0` è al sicuro solo finché il suo orologio gira —
   e basta una scheda in secondo piano, o un'anteprima che non disegna, per
   scoprire che non girava. Le comparse hanno l'uscita anticipata, il
   controllo allo scorrimento e la rete di sicurezza a tre secondi.

   Il ritardo di partenza glielo dà `data-reveal-delay` sul gruppo. */
.js .gioiello__galleria[data-reveal] {
	transform: translateY(12px);
}

.js .gioiello__galleria[data-reveal].is-revealed {
	transform: none;
}

/* =========================================================================
   3 · ANIMAZIONI LEGATE ALLO SCORRIMENTO
   Niente listener: è il browser a legare l'avanzamento dell'animazione alla
   posizione dell'elemento. Costo in JavaScript: zero. Dove non c'è
   supporto, `@supports` lascia tutto com'era.
   ========================================================================= */

@supports (animation-timeline: view()) {
	@media (prefers-reduced-motion: no-preference) {

		/* Il filo di avanzamento sopra la testata: dice quanto manca alla
		   fine della pagina senza occupare spazio né chiedere attenzione.
		   Base a scaleX(0): su una pagina che non scorre la timeline è
		   inattiva, l'animazione non applica nessun fotogramma, e senza
		   base resterebbe una riga nera piena che dice «letta al 100%». */
		.testata::after {
			content: "";
			position: absolute;
			inset: auto 0 -1px 0;
			height: 1px;
			background: var(--nero);
			transform: scaleX(0);
			transform-origin: 0 50%;
			animation: avanzamento linear both;
			animation-timeline: scroll(root block);
		}

		/* Le foto dei gioielli respirano mentre scorrono: partono appena
		   più grandi e si posano. Due punti percentuali, non di più: deve
		   sentirsi, non vedersi.

		   Qui si anima `scale`, non `transform`, e non è un dettaglio: le
		   stesse foto si ingrandiscono al passaggio del mouse con un
		   `transform`, e un'animazione batte sempre una dichiarazione
		   normale. Animando `transform` avrei ucciso l'hover su ogni
		   browser dove questa timeline funziona — cioè ovunque tranne che
		   nell'anteprima in cui stavo guardando. Sono proprietà distinte e
		   si moltiplicano fra loro: la foto si posa E si ingrandisce. */
		.pezzo__media img,
		.occasione__media img {
			animation: posa-foto linear both;
			animation-timeline: view();
			animation-range: entry 10% cover 45%;
		}

		/* I numeri di sezione arrivano da sinistra. Qui si sposta soltanto:
		   niente opacità. Se un domani la timeline risultasse inattiva su
		   qualche browser, il peggio che può capitare è un'etichetta spostata
		   di dieci pixel — mai un testo invisibile. */
		.indice {
			animation: indice-entra linear both;
			animation-timeline: view();
			animation-range: entry 5% entry 60%;
		}

		/* Inganno della scorciatoia `animation`: riporta la durata al suo
		   valore iniziale, 0s. Con una timeline di scorrimento la durata
		   dev'essere `auto` — cioè «quanto dura lo scorrimento» — altrimenti
		   l'animazione risulta avviata ma ferma sul primo fotogramma, e
		   `getAnimations()` la dà per «running» senza che si muova niente.
		   Va riscritta DOPO ogni scorciatoia, o se la rimangiano. */
		.testata::after,
		.pezzo__media img,
		.occasione__media img,
		.indice {
			animation-duration: auto;
		}
	}
}

@keyframes avanzamento {
	from {
		transform: scaleX(0);
	}
	to {
		transform: scaleX(1);
	}
}

/* `scale` e non `transform`: vedi la nota sopra. Sono due proprietà
   distinte e il browser le moltiplica, così la foto può posarsi mentre
   l'hover la ingrandisce, senza che una spenga l'altra. */
@keyframes posa-foto {
	from {
		scale: 1.06;
	}
	to {
		scale: 1;
	}
}

@keyframes indice-entra {
	from {
		transform: translateX(-10px);
	}
	to {
		transform: none;
	}
}

/* =========================================================================
   4 · MICRO-INTERAZIONI
   Tutto quello che risponde al dito o al mouse. Gli stati importanti non
   dipendono mai dal solo hover: su un telefono non esiste.
   ========================================================================= */

/* --- il bottone pieno: si alza, e il nero scorre da sotto --- */

.btn {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	transition: transform var(--dur-micro) var(--ease-molla),
		background var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}

.btn::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--bianco);
	transform: scaleY(0);
	transform-origin: 50% 100%;
	transition: transform var(--dur-media) var(--ease-out);
}

/* Il velo che sale prende il colore opposto della variante: sul bottone
   vuoto un velo bianco copriva il fondo nero chiesto dall'hover e
   l'inversione si annullava da sola. Unico padrone dell'hover: questo
   blocco — main.css non dichiara più :hover sui bottoni. */
.btn--vuoto::before {
	background: var(--nero);
}

@media (hover: hover) {
	.btn:hover {
		color: var(--nero);
		transform: translateY(-2px);
	}

	.btn--vuoto:hover {
		color: var(--bianco);
	}

	.btn--bianco:hover {
		color: var(--nero);
	}

	.btn:hover::before {
		transform: scaleY(1);
	}
}

/* Il dito non fa hover: gli si risponde alla pressione */
.btn:active {
	transform: translateY(0) scale(0.985);
	transition-duration: 90ms;
}

/* --- il collegamento sottolineato --- */

/* A riposo la riga C'È: è l'unica cosa che dice «questo è un link» a un
   micro-testo maiuscolo, e su touch — dove l'hover non esiste — partire
   da scaleX(0) la toglieva per sempre. Al passaggio del mouse la riga si
   ridisegna da sinistra: stesso gesto di prima, ma come animazione che
   riparte, non come stato nascosto. Unico padrone: questo blocco. */
.linea {
	position: relative;
	background-image: none;
}

.linea::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -2px;
	height: 1px;
	background: currentColor;
	transform-origin: 0 50%;
}

@media (hover: hover) {
	.linea:hover::after {
		animation: linea-ridisegna 420ms var(--ease-out);
	}
}

.linea:focus-visible::after {
	animation: linea-ridisegna 420ms var(--ease-out);
}

@keyframes linea-ridisegna {
	from {
		transform: scaleX(0);
	}
	to {
		transform: scaleX(1);
	}
}

/* --- le voci del menu: la riga esce dal centro --- */

@media (min-width: 900px) and (hover: hover) {
	.nav a {
		position: relative;
	}

	.nav a::after {
		content: "";
		position: absolute;
		left: 0;
		right: 0;
		bottom: -4px;
		height: 1px;
		background: currentColor;
		transform: scaleX(0);
		transition: transform var(--dur-media) var(--ease-out);
	}

	.nav a:hover::after {
		transform: scaleX(1);
	}
}

/* --- la scheda del gioiello --- */

/* L'ingrandimento al passaggio del mouse vale ovunque compaia una scheda:
   nella selezione in home, nella griglia dei prodotti e fra i correlati in
   fondo alla scheda, che usano tutte le stesse classi.

   700ms erano troppi: il movimento partiva dopo che il mouse era già
   arrivato. Mezzo secondo scarso resta elegante e risponde subito. */
.pezzo__media img,
.occasione__media img {
	transition: transform 480ms var(--ease-out);
}

/* Il margine non è estetica, è quello che rende visibile l'ingrandimento.

   Le foto arrivano dal master con proporzioni diverse: alcune verticali
   (882×1102), altre quadrate (882×882). Dentro un riquadro quadrato con
   `contain`, le verticali lasciano una trentina di pixel vuoti ai lati e
   crescendo si vedono crescere; la quadrata riempisce tutto, quindi
   l'ingrandimento le taglia i bordi contro l'`overflow: hidden` e sembra
   che non si muova. È esattamente quello che succedeva alla scheda in
   mezzo ai correlati.

   Col padding in percentuale il riquadro resta identico — `box-sizing`
   è border-box — ma l'immagine si posa dentro un'area più piccola, uguale
   per tutte: così ognuna ha il suo spazio in cui crescere, quale che sia
   la proporzione della foto. */
.pezzo__media img {
	padding: 6%;
}

/* Al passaggio del mouse si muove SOLO la foto, dentro la sua cornice:
   la scheda sta ferma. Le righe della griglia sono il fondo del
   contenitore che traspare da fessure di un pixel, e una scheda bianca
   che si alza copre la riga sopra di sé — non era uno z-index da
   sistemare, era il sollevamento a essere sbagliato in questo impianto.
   Lo spostamento vero ce l'ha il clic: la foto vola verso la sua scheda. */

/* 1.12, non 1.06 — misurato su tutte le 17 foto del catalogo: al 6% il
   soggetto cresceva di 8-10px, e su un anello sottile in oro bianco quel
   movimento sta sotto la soglia dell'occhio. Al 12% cresce di 16-21px,
   visibile anche sul soggetto meno contrastato. Il padding del 6% lascia
   comunque il fotogramma dentro la cornice.

   Un'unica regola per prodotti e occasioni: la stessa foto non può
   muoversi in un modo in una griglia e in un altro in un'altra.

   La hero ha lo stesso linguaggio ma metà della scala: la foto è quattro
   volte più grande, e il 12% lì sarebbe un balzo, non una risposta. */
@media (hover: hover) {
	.pezzo:hover .pezzo__media img,
	.occasione:hover .occasione__media img {
		transform: scale(1.12);
	}

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

.hero__media img {
	transition: transform 480ms var(--ease-out);
}

.occasione__media img {
	padding: 6%;
}

.pezzo__nome {
	transition: opacity var(--dur-micro) var(--ease-out);
}

.pezzo__prezzo {
	display: inline-block;
	transition: transform var(--dur-media) var(--ease-out);
}

@media (hover: hover) {
	.pezzo:hover .pezzo__prezzo {
		transform: translateX(4px);
	}
}

.pezzo:active .pezzo__media img,
.occasione:active .occasione__media img,
.hero__media:active img {
	transform: scale(0.99);
	transition-duration: 120ms;
}

/* --- le schede dei contatti ---

   NIENTE sollevamento della cella: occasioni e schede contatti vivono
   nelle stesse griglie a fessure di 1px dei prodotti, e una cella bianca
   che si alza copre la riga sopra e scopre una banda grigia sotto — lo
   stesso identico difetto già eliminato per .pezzo. Il feedback delle
   occasioni è lo zoom della foto; qui, dove una foto non c'è, al
   passaggio sulla scheda si ridisegna la riga del suo link. */
@media (hover: hover) {
	.scheda-contatto:hover .linea::after {
		animation: linea-ridisegna 420ms var(--ease-out);
	}
}

/* --- le miniature della galleria --- */

.gioiello__thumbs button {
	transition: opacity var(--dur-micro) var(--ease-out),
		transform var(--dur-micro) var(--ease-molla);
}

@media (hover: hover) {
	.gioiello__thumbs button:hover {
		transform: translateY(-2px);
	}
}

/* La foto grande slitta E sfuma: mentre una slide esce dalla cornice la
   sua opacità scende, quella che entra risale — lo slittamento resta il
   gesto, il fade lo ammorbidisce. È legato allo scorrimento della pista
   (view sull'asse inline), non a un timer: a metà trascinamento le due
   foto sono entrambe a mezza luce, come deve essere.
   Base a opacità piena: dove la timeline non c'è, resta solo lo slide. */
@supports (animation-timeline: view(inline)) {
	@media (prefers-reduced-motion: no-preference) {
		.gioiello__slide img {
			animation: slide-luce linear both;
			animation-timeline: view(inline);
			/* la scorciatoia riporta la durata a 0s: con una timeline serve auto */
			animation-duration: auto;
		}
	}
}

@keyframes slide-luce {
	0% {
		opacity: 0.15;
	}
	28% {
		opacity: 1;
	}
	72% {
		opacity: 1;
	}
	100% {
		opacity: 0.15;
	}
}

/* --- il fuoco da tastiera si vede, e si muove con grazia --- */

:focus-visible {
	transition: outline-offset 120ms var(--ease-out);
}

/* =========================================================================
   5 · COMPARSE PIÙ FINI
   La fila di elementi di un gruppo entra a onda invece che tutta insieme.
   main.css assegna il ritardo via JavaScript; qui si aggiunge il verso.
   ========================================================================= */

@media (prefers-reduced-motion: no-preference) {
	.js [data-reveal-group] > * {
		transform: translateY(18px) scale(0.995);
	}

	/* Le schede dei gioielli salgono di più delle altre cose: sono blocchi
	   grandi, e con diciotto pixel il movimento si perdeva. Vale ovunque
	   compaia una griglia di schede — la selezione in home, i prodotti, e
	   la fascia dei correlati in fondo alla scheda. */
	.js [data-reveal-group] > .pezzo,
	.js [data-reveal-group] > .occasione {
		transform: translateY(34px) scale(0.97);
	}

	.js [data-reveal-group] > .is-revealed {
		transform: none;
	}
}

/* =========================================================================
   6 · CHI CHIEDE MENO MOVIMENTO
   Nessuna animazione decorativa, nessuna transizione fra le pagine. Il sito
   resta identico nella sostanza: cambia solo che sta fermo.
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
	.js .hero__box > div > *,
	.js .hero__specs li,
	.parola > span,
	.gioiello__galleria,
	.gioiello > div > * {
		animation: none !important;
		opacity: 1 !important;
		transform: none !important;
		scale: none !important;
	}

	.btn::before,
	.linea::after,
	.nav a::after {
		transition: none;
	}

	/* La transizione fra le pagine non si può disattivare da qui — l'adesione
	   sta al primo livello del foglio — ma si può togliere il movimento: le
	   due schermate si scambiano e basta. */
	::view-transition-group(*),
	::view-transition-old(*),
	::view-transition-new(*) {
		animation: none !important;
	}
}
