/* ══════════════════════════════════════════════════════════
   v5 — foglio di stile condiviso da tutte le pagine.
   Principi (misurati su igloo.inc e adattati):
     · niente backdrop-filter: e' il costo di compositing #1
     · si animano SOLO opacity e transform (lavoro del compositor)
     · nessuna animazione legata allo scroll frame-per-frame
   ══════════════════════════════════════════════════════════ */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{
  --ink:#eef2ff; --ink-dim:#98a4c4; --blue:#0066ff; --cyan:#00ccff; --teal:#2affd5;
  /* Il tono piu' tenue del sito. Non e' scelto a occhio: e' il piu' scuro che
     su questo fondo tiene 4.5:1, la soglia sotto la quale un testo piccolo
     smette di essere leggibile. Prima qui c'erano quattro grigi diversi
     (var(--ink-fio), var(--ink-fio), var(--ink-fio), var(--ink-fio)), tutti fra 3.5 e 4.3. */
  --ink-fio:#8a97bb;
  /* Il tono del sottotitolo: piu' acceso di --ink-dim, ma sempre subordinato
     al titolo. Prima era un esadecimale fisso (var(--ink-forte)) senza variante
     chiara: sul tema chiaro faceva 1.24 di contrasto sul fondo vero, cioe'
     spariva. */
  --ink-forte:var(--ink-forte);
  --bg:#04050a; --line:rgba(255,255,255,.09);
  --font:'Inter',-apple-system,BlinkMacSystemFont,system-ui,"Segoe UI",Roboto,sans-serif;
  --pad:clamp(1.5rem,6vw,7rem);
  /* Il marchio e' il passaggio fra i tre colori, non uno dei tre. */
  --marchio:linear-gradient(105deg,var(--blue),var(--cyan) 45%,var(--teal));
  /* Sul testo piccolo lo stesso passaggio, ma con l'estremita' blu spinta
     FUORI dall'elemento: il blu su fondo scuro fa 2.9:1 di contrasto e una
     scritta di sei lettere spaziate diventa illeggibile, mentre il ciano fa
     9:1. I colori restano tre, comincia solo piu' avanti. */
  --marchio-min:linear-gradient(100deg,var(--blue) -45%,var(--cyan) 40%,var(--teal));
}

/* ─── Tema chiaro ─────────────────────────────────────────────────────────
   Non e' lo scuro con i colori girati: su fondo chiaro un testo tenue
   sparisce e le ombre vanno tenute morbide. I valori sono scelti per
   mantenere lo stesso CONTRASTO, non le stesse tinte.
   Vetro e particelle cambiano anche nel motore (vedi app.js): in additivo,
   su bianco, la luce sommata non si vede.                                */
:root[data-tema="chiaro"]{
  --ink:#0d1424; --ink-dim:#4d5875; --bg:#f4f6fb; --ink-fio:#545f7d; --ink-forte:#232c44;
  /* Sul chiaro il gradiente del testo piccolo va SCURITO: ciano e verde
     acqua su bianco fanno 3.34 e 2.75 di contrasto, cioe' illeggibili.
     Questi tre tengono 7.99, 5.17 e 5.11 — stessa famiglia, luminosita'
     abbassata quanto serve. Il gradiente grande resta quello vivo: li' il
     testo e' enorme e la soglia e' 3.0, non 4.5. */
  --marchio-min:linear-gradient(100deg,#0043b0 -45%,#006f9c 40%,#00775f);
  --blue:#0055dd; --cyan:#0090c8; --teal:#00a98c;
  --line:rgba(10,20,40,.11);
}
/* Il velo chiaro non sostituisce piu' quello scuro: sta sopra e compare
   sfumando (vedi #veil::after). Qui resta solo il fondo, che serve quando la
   transizione e' spenta. */
/* Stessa lastra, ma su fondo chiaro il filo scuro dei fianchi va tenuto
   morbido: qui a staccarla dal fondo basta l'ombra. */
:root[data-tema="chiaro"] nav,:root[data-tema="chiaro"] #snd,:root[data-tema="chiaro"] #tema{
  background:rgba(255,255,255,.58);border-color:rgba(10,20,40,.08);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.95),
             inset 0 -1px 0 rgba(10,20,40,.05),
             inset 1px 0 0 rgba(10,20,40,.045),
             inset -1px 0 0 rgba(10,20,40,.045),
             0 12px 28px -18px rgba(10,20,40,.4)}
:root[data-tema="chiaro"] .tag{border-color:rgba(0,144,200,.35);color:#0a6c93}
:root[data-tema="chiaro"] .hint,:root[data-tema="chiaro"] .voce .patroc .lbl{color:var(--ink-fio)}

/* Anche su <html>, non solo su <body>: quando il body e' alto quanto lo
   schermo con overflow nascosto, quello che sta FUORI dal body — le zone di
   sicurezza sopra e sotto su iPhone — prende il colore di <html>. Senza,
   restano del colore predefinito. */
html{-webkit-text-size-adjust:100%;background:var(--bg)}
body{background:var(--bg);color:var(--ink);font-family:var(--font);
     overflow-x:hidden;-webkit-font-smoothing:antialiased}

/* ─── Passaggio fra chiaro e scuro ────────────────────────────────────────
   Le variabili CSS non si possono animare: cambiano di scatto e con loro
   tutto quello che le usa. Quindi si animano le proprieta' che le LEGGONO,
   una per una, sulle superfici che contano. Mezzo secondo, la stessa durata
   con cui il motore fa scendere e risalire la luce delle particelle (vedi
   applicaTema in app.js): le due cose devono sembrare un solo movimento. */
body,#veil,nav,#snd,#tema,.vetro,.sk,.tag,.serv .ico,#tip,.bottone,
#scrivi input,#scrivi textarea,.prev .lastra,.mockup .schermo,.mockup .telefono{
  transition:background-color 1.9s cubic-bezier(.45,0,.25,1),
             color 1.9s cubic-bezier(.45,0,.25,1),
             border-color 1.9s cubic-bezier(.45,0,.25,1),
             box-shadow 1.9s cubic-bezier(.45,0,.25,1),
             background 1.9s cubic-bezier(.45,0,.25,1)}
@media (prefers-reduced-motion:reduce){
  body,#veil,nav,#snd,#tema,.vetro,.sk,.tag,.serv .ico,#tip,.bottone,
  #scrivi input,#scrivi textarea,.prev .lastra,.mockup .schermo,.mockup .telefono{transition:none}
}

/* Niente width/height nel CSS: le mette il renderer, uguali al disegno.
   Con 100vw/100vh il canvas veniva STIRATO — su iOS 100vh e' l'altezza con la
   barra nascosta, mentre il disegno e' alto innerHeight, cioe' l'altezza vera
   del momento. Uno stiramento verticale di qualche punto percentuale: al
   centro dello schermo non si nota, verso i bordi tutto quel che sta nel
   canvas (vetro compreso) risulta spostato rispetto al DOM. Ed e' per questo
   che il vetro sembrava scollarsi allontanandosi dal centro.
   inset:0 e' diventato top/left: con tutti e quattro i lati fissati
   l'elemento verrebbe stirato lo stesso, ignorando le dimensioni. */
#gl{position:fixed;top:0;left:0;display:block;z-index:0;pointer-events:none}
#veil{position:fixed;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(120% 90% at 50% 40%,transparent 35%,rgba(4,5,10,.55) 75%,rgba(4,5,10,.9) 100%)}
/* Il velo copre tutto lo schermo, quindi e' LUI a dare il lampo: cambia da
   quasi nero a quasi bianco su ogni pixel. Un gradiente non si interpola bene
   fra due valori, quindi non basta la transizione: si sovrappone il velo
   dell'altro tema e si fa comparire quello, sfumando. Due strati che si danno
   il cambio invece di uno che salta. */
#veil::after{content:"";position:absolute;inset:0;opacity:0;
  transition:opacity 1.9s cubic-bezier(.45,0,.25,1);
  background:radial-gradient(120% 90% at 50% 40%,transparent 40%,rgba(244,246,251,.5) 78%,rgba(244,246,251,.85) 100%)}
:root[data-tema="chiaro"] #veil::after{opacity:1}
@media (prefers-reduced-motion:reduce){#veil::after{transition:none}}

main{position:relative;z-index:2}

/* Scorrimento gestito da noi (vedi app.js): la pagina non scorre, scorre
   questo contenitore. Serve perche' contenuto e vetro vengano spostati dallo
   stesso numero nello stesso fotogramma — con lo scorrimento del browser i
   due percorsi sono diversi e il vetro resta indietro.
   Senza JavaScript la classe non viene messa e la pagina scorre normalmente. */
html.js-scroll,html.js-scroll body{height:100%;overflow:hidden;overscroll-behavior:none}
#scorri{position:relative;z-index:2;will-change:transform}
/* Su uno schermo molto largo il contenuto non deve continuare ad allargarsi:
   il titolo finisce a sinistra, il resto a un metro di distanza, e non si
   legge piu' niente come un blocco unico. Oltre il limite le sezioni restano
   larghe cosi' e si centrano.
   Il limite sta sulla SEZIONE e non sui figli: cosi' vale per tutto quello che
   c'e' dentro — titoli, paragrafi, griglie — senza doverlo ripetere. */
/* Le sezioni erano alte uno schermo ciascuna. Con dentro quattrocento pixel
   di contenuto restavano duecento pixel di niente sopra e altrettanti sotto,
   e scorrendo si attraversavano stanze mezze vuote. Adesso ogni sezione e'
   alta quanto quello che contiene, con la sua aria intorno. La prima resta
   uno schermo intero: quella e' l'apertura, e li' il vuoto e' voluto. */
section{min-height:0;display:flex;flex-direction:column;justify-content:center;
        padding:9vh var(--pad);
        width:100%;max-width:calc(1560px + var(--pad) * 2);margin-inline:auto}
main > section:first-child{min-height:100svh;padding-top:12vh;padding-bottom:12vh}
/* Qui c'era content-visibility:auto con contain-intrinsic-size:100svh. Fa
   risparmiare lavoro saltando il layout delle sezioni fuori schermo, ma
   proprio per questo le loro altezze diventano un'IPOTESI (100svh) invece
   della misura vera. Il vetro pero' ricava la posizione delle card da
   offsetTop, che su quelle ipotesi e' sbagliato: le lastre finivano centinaia
   di pixel piu' in basso, e tornavano al loro posto solo passandoci sopra col
   puntatore — perche' li' si legge il rettangolo vero.
   Con lo scorrimento gestito da noi il risparmio non serve piu': disegniamo
   solo quel che e' in vista comunque.                                      */
section.auto{min-height:0}

/* Reveal governato da IntersectionObserver, mai dallo scroll. */
.rv{opacity:0;transform:translate3d(0,26px,0);
    transition:opacity .9s cubic-bezier(.16,1,.3,1),transform .9s cubic-bezier(.16,1,.3,1)}
.rv.in{opacity:1;transform:none}
.rv:nth-child(2){transition-delay:.07s} .rv:nth-child(3){transition-delay:.14s}
.rv:nth-child(4){transition-delay:.21s} .rv:nth-child(5){transition-delay:.28s}
@media (prefers-reduced-motion:reduce){.rv{opacity:1;transform:none;transition:none}}

.eyebrow{font-size:.72rem;letter-spacing:.28em;text-transform:uppercase;
         margin-bottom:1.4rem;font-weight:600}
/* ─── Il badge del hero ───────────────────────────────────────────────────
   Nel sito vecchio l'occhiello del hero non era una scritta e basta: era una
   pastiglia con un pallino che pulsa. E' un dettaglio da tre righe, ed e'
   quello che fa capire in mezzo secondo che il sito e' vivo.
   Vale SOLO nel hero: sulle altre sezioni l'occhiello resta una scritta,
   altrimenti sei pastiglie identiche diventano rumore.                     */
/* La pastiglia NON puo' essere il fondo dell'elemento: l'occhiello ha gia' un
   fondo, ed e' il gradiente ritagliato sulle lettere. Mettendocene un altro
   veniva ritagliato pure quello — pastiglia invisibile e testo sparito.
   Quindi la pastiglia e' uno strato a parte, dietro. */
/* ─── Gli occhielli sono pastiglie di VETRO ───────────────────────────────
   Sono etichette di sfondo — "Generative · Product · Reality", "Lavori
   recenti" — e il vetro e' il materiale del sito: tanto vale che lo siano.
   Il vetro lo disegna il motore (data-glass), quindi qui il CSS deve solo
   dare forma e spazio; il fondo lo mette la lastra.
   Due scatole, due mestieri: la pastiglia e' il <p>, il gradiente e' lo
   <span> dentro. Con background-clip:text il testo E' lo sfondo
   dell'elemento, quindi mettendone un altro sull'elemento stesso si ritaglia
   pure quello e il testo sparisce — e' costato tre tentativi. */
.eyebrow{position:relative;display:inline-block;width:fit-content;
  padding:.5rem 1.05rem;border-radius:999px;
  -webkit-background-clip:border-box;background-clip:border-box;color:var(--ink);
  animation:none}
.eyebrow span{background:var(--marchio-min);background-size:230% 100%;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:marchio-scorre 9s ease-in-out infinite}
/* Senza il vetro del motore (nessun WebGL) la pastiglia se lo disegna da se'. */
html:not(.gl-vetro) .eyebrow{background:rgba(8,11,20,.5);border:1px solid rgba(255,255,255,.10);
  backdrop-filter:blur(12px) saturate(1.4);-webkit-backdrop-filter:blur(12px) saturate(1.4)}
:root[data-tema="chiaro"] html:not(.gl-vetro) .eyebrow{background:rgba(255,255,255,.6)}
@media (prefers-reduced-motion:reduce){.eyebrow span{animation:none}}
/* Qui c'era un pallino che pulsava. Tolto: e' il tic che si vede su meta'
   dei siti generati, e bastava quello a far sembrare fatto in serie tutto il
   resto. La pastiglia di vetro dice gia' abbastanza da sola. */

@media (prefers-reduced-motion:reduce){#hero .eyebrow::before{animation:none}}

/* ─── Il filo luminoso fra una sezione e l'altra ──────────────────────────
   Nel vecchio sito le sezioni erano separate da una riga che scorre. Senza,
   il contenuto e' un elenco continuo e non si capisce dove finisce una cosa e
   comincia l'altra — e' meta' del "manca qualcosa".
   Sta sul bordo ALTO: la prima sezione non ne ha bisogno.                  */
section{position:relative}
section + section::before{content:"";position:absolute;top:0;left:var(--pad);right:var(--pad);
  height:1px;pointer-events:none;
  background:linear-gradient(90deg,transparent 0%,rgba(0,102,255,.28) 22%,
             rgba(42,255,213,.34) 46%,rgba(0,204,255,.26) 72%,transparent 100%);
  background-size:220% 100%;animation:filo-scorre 11s linear infinite}
@keyframes filo-scorre{0%{background-position:180% 0}100%{background-position:-180% 0}}
@media (prefers-reduced-motion:reduce){section + section::before{animation:none}}
h1{font-size:clamp(2.6rem,9vw,7rem);line-height:.94;font-weight:800;letter-spacing:-.03em}
h2{font-size:clamp(1.9rem,5.2vw,3.6rem);line-height:1.06;font-weight:800;letter-spacing:-.02em;margin-bottom:1.4rem}
h3{font-size:1.02rem;font-weight:700}
/* ─── L'accento del marchio e' il GRADIENTE ───────────────────────────────
   Non il verde acqua e non il blu: quelli sono due estremi di una cosa sola.
   Dove prima c'era una tinta piatta ora c'e' il passaggio intero, ritagliato
   sul testo. Restano in tinta piatta solo i posti dove il gradiente farebbe
   danno: i collegamenti dentro ai paragrafi (sottolineati all'hover, e un
   testo trasparente con la sottolineatura colorata si legge male) e i
   messaggi di esito del modulo, che devono dire una cosa sola e subito.   */
.grad{background:var(--marchio)}
.voce > .anno,.portale .go,.cat > h3,nav .lingue a[aria-current]{
  background:var(--marchio-min)}
.grad,.voce > .anno,.portale .go,.cat > h3,nav .lingue a[aria-current]{
  -webkit-background-clip:text;background-clip:text;color:transparent}

/* ─── Il gradiente si muove ───────────────────────────────────────────────
   Fermo e' una tinta; che scorre piano e' una cosa viva, ed e' come stava sul
   sito vecchio. Il trucco e' un fondo piu' largo dell'elemento che si sposta
   avanti e indietro: si animano solo le coordinate del disegno, niente
   layout.
   Lento apposta — nove secondi per andare e tornare. Piu' veloce si nota, e
   quel che si nota su un occhiello di sei lettere e' fastidio.
   Con "riduci movimento" si ferma.                                        */
@keyframes marchio-scorre{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}
@media (prefers-reduced-motion:reduce){html.grad-uno *{animation-name:none!important}}
/* Con il motore acceso il gradiente non e' piu' un'animazione per elemento ma
   una rampa sola distesa su tutta la pagina: la posizione gliela passa il
   JavaScript in --gp (vedi `gradienti` in app.js). L'animazione qui sopra
   resta come rete di sicurezza per chi apre il sito senza JavaScript. */
html.grad-uno .grad,html.grad-uno .voce > .anno,html.grad-uno .portale .go,
html.grad-uno .cat > h3,html.grad-uno main a:not([class]),
html.grad-uno footer a:not([class]),html.grad-uno .tag,html.grad-uno #scrivi button,
html.grad-uno .eyebrow span,html.grad-uno nav .logo span,
html.grad-uno .piede .marchio-piede span,
html.grad-uno .ss-barra i,html.grad-uno .bottone.primario,
html.grad-uno .scelta3d button[aria-current],
html.grad-uno .invito,html.grad-uno .ss-ico,html.grad-uno .serv .ico{
/* ── Come si muove ──────────────────────────────────────────────────────
   Con un'animazione del browser, non con una posizione riscritta a ogni
   fotogramma dal JavaScript: quello costava quaranta ricalcoli di stile per
   fotogramma (gli scatti) e per non farne troppi c'era una soglia che
   fermava proprio il movimento lento.
   Il PUNTO da cui ognuna parte glielo dice il JavaScript una volta sola, con
   animation-delay: e' la sua posizione nella pagina. Da lontano si legge
   come una rampa sola distesa su tutto il sito; da vicino ogni scritta
   respira.
   Lo sfondo al 205% perche' a 135% lo spostamento era del trentacinque per
   cento della larghezza: su un collegamento di cinquanta pixel, due pixel.  */
  animation:marchio-scorre 14s linear infinite;background-size:205% 100%}
.grad,.voce > .anno,.portale .go,.cat > h3,
main a:not([class]),footer a:not([class]),.tag,#scrivi button{
  background-size:230% 100%;
  animation:marchio-scorre 9s ease-in-out infinite}
/* La lingua attiva no: e' due lettere, il movimento non si legge e in cambio
   fa lampeggiare l'unico elemento che dice dove sei. */
@media (prefers-reduced-motion:reduce){
  .grad,.voce > .anno,.portale .go,.cat > h3,
  main a:not([class]),footer a:not([class]),.tag,#scrivi button{animation:none}
}
p{font-size:clamp(1rem,1.55vw,1.18rem);line-height:1.72;color:var(--ink-dim);max-width:52ch}
/* ─── L'alone del testo libero ────────────────────────────────────────────
   Il testo che NON sta dentro a una scheda si trova sopra al campo di
   particelle, e li' il fondo cambia da un pixel all'altro: nessun colore di
   testo puo' andare bene su tutti e due. Un alone del colore della PAGINA
   attorno alle lettere risolve senza toccare ne' il colore del testo ne' la
   scena — le particelle continuano a vedersi, fra una lettera e l'altra.
   Sul chiaro l'alone e' bianco, sullo scuro nero: e' la stessa variabile. */
main > section > p,main > section > h1,main > section > h2,
.lead,.hint,#hero .eyebrow,.azioni,.piede p,.chiusa,.riga-firma{
  text-shadow:0 0 8px var(--bg),0 0 16px var(--bg),0 0 30px var(--bg),0 1px 3px var(--bg)}
/* Il testo ritagliato sul gradiente NON prende l'alone: li' il testo e' lo
   sfondo dell'elemento, e l'ombra gli finisce SOPRA — le lettere si
   spengono. Si vedeva su "& clienti" del titolo, diventato quasi nero. */
/* E nemmeno il testo dentro a un bottone: il bottone ha il suo fondo, quindi
   l'alone non serve — e su quello pieno diventa un contorno nero attorno
   alle lettere bianche. */
.grad,.eyebrow span,.ss-dati b,.firma .firma-sigla,.bottone,.bottone *,.invito,.invito *,
main a:not([class]),footer a:not([class]),.tag,.voce > .anno,.portale .go,.cat > h3{
  text-shadow:none}
.lead{font-size:clamp(1.05rem,1.9vw,1.35rem);color:var(--ink-forte);max-width:46ch;margin-top:1.6rem}
a{color:var(--cyan);text-decoration:none}
a:hover{text-decoration:underline}

/* I collegamenti del contenuto prendono il gradiente come tutto il resto.
   Solo quelli SENZA classe: nella barra, sui portali e sulle anteprime il
   colore serve a distinguere lo stato, non a fare marchio.
   La sottolineatura non puo' restare quella del browser: con il testo
   ritagliato sul gradiente il colore del testo e' trasparente, e la riga
   eredita proprio quello — cioe' sparisce. Qui e' una barretta a parte, con
   lo stesso gradiente, che compare all'hover. */
main a:not([class]),footer a:not([class]){
  position:relative;background:var(--marchio-min);
  -webkit-background-clip:text;background-clip:text;color:transparent;
  text-decoration:none}
main a:not([class])::after,footer a:not([class])::after{
  content:"";position:absolute;left:0;right:0;bottom:-2px;height:1px;
  background:var(--marchio-min);opacity:0;transition:opacity .28s}
main a:not([class]):hover::after,footer a:not([class]):hover::after,
main a:not([class]):focus-visible::after{opacity:.85}
main a:not([class]):hover,footer a:not([class]):hover{text-decoration:none}

#hero{justify-content:flex-end;padding-bottom:16vh}
/* I due collegamenti in fondo alla vetrina: bottoni, non righe di testo. */
#vetrina .azioni{margin-top:2.4rem}
/* ─── I due bottoni del hero ──────────────────────────────────────────────
   Erano spariti nel passaggio a v5, e sono la cosa che porta al lavoro: da
   qui si va ai contatti o si guardano i lavori. Il primo e' pieno, il secondo
   e' solo un contorno — c'e' una gerarchia, non due bottoni pari. */
.azioni{display:flex;flex-wrap:wrap;gap:.7rem;margin-top:2.2rem;max-width:none}
.bottone{display:inline-flex;align-items:center;gap:.45rem;
  padding:.85rem 1.5rem;border-radius:999px;font:600 .88rem/1 var(--font);
  color:var(--ink);border:1px solid rgba(255,255,255,.16);text-decoration:none!important;
  background:rgba(8,11,20,.5);
  backdrop-filter:blur(14px) saturate(1.5);-webkit-backdrop-filter:blur(14px) saturate(1.5);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.13),0 12px 30px -18px rgba(0,0,0,.9);
  transition:transform .45s cubic-bezier(.16,1,.3,1),border-color .35s,background .35s,box-shadow .35s}
.bottone:hover{transform:translateY(-3px);border-color:rgba(0,119,255,.42);
  background:rgba(0,119,255,.09);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 8px 30px rgba(0,119,255,.2)}
:root[data-tema="chiaro"] .bottone:hover{background:rgba(0,119,255,.10)}
/* ── Perche' il bottone pieno NON usa il gradiente del marchio ──────────
   Perche' finisce sul verde acqua, e bianco su verde acqua fa 1.28:1 di
   contrasto — illeggibile. Sul blu del marchio fa 4.83:1, sul blu piu' cupo
   dell'estremita' 5.65. Il sito vecchio lo sapeva gia': il suo bottone pieno
   e' un gradiente di BLU, non il marchio intero.
   Il marchio resta ovunque il testo sia colorato su fondo scuro, dove il
   verde acqua e' il colore piu' leggibile che ci sia. */
.bottone.primario{color:#fff;border-color:transparent;
  background:linear-gradient(135deg,#0b7bff,#0048c4);
  background-size:180% 180%;animation:marchio-scorre 9s ease-in-out infinite;
  box-shadow:0 4px 25px rgba(0,119,255,.35),inset 0 1px 0 rgba(255,255,255,.18);
  backdrop-filter:blur(18px) saturate(1.8);-webkit-backdrop-filter:blur(18px) saturate(1.8)}
/* ── Il passaggio sul bottone ────────────────────────────────────────────
   Provate due strade e scartate: la lama di luce che attraversa (si nota
   piu' del bottone) e l'alone che cresce dal basso. Questa e' quella del
   sito vecchio, che sta li' da mesi e funziona: il bottone si solleva di
   tre pixel, cresce del tre per cento e la luce blu sotto di lui si allarga.
   Niente che passi, niente che lampeggi.                                  */
.bottone{position:relative;isolation:isolate}
.bottone.primario:hover{transform:translateY(-3px) scale(1.03);
  border-color:rgba(255,255,255,.25);background:linear-gradient(135deg,#0b7bff,#0048c4);
  box-shadow:0 10px 45px rgba(0,119,255,.55),inset 0 1px 0 rgba(255,255,255,.2)}
@media (prefers-reduced-motion:reduce){.bottone::after{display:none}}
:root[data-tema="chiaro"] .bottone{background:rgba(255,255,255,.6);border-color:rgba(10,20,40,.12);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 12px 26px -18px rgba(10,20,40,.4)}
:root[data-tema="chiaro"] .bottone.primario{color:#fff;border-color:transparent;
  background:linear-gradient(135deg,#0b7bff,#0048c4);background-size:180% 180%}
@media (prefers-reduced-motion:reduce){.bottone.primario{animation:none}}
.hint{margin-top:3.5rem;font-size:.7rem;letter-spacing:.3em;text-transform:uppercase;color:var(--ink-dim)}

/* ─── Portali: le "deviazioni" verso le destinazioni ─────────────────── */
.portali{display:grid;gap:.9rem;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));
         margin-top:2.6rem;max-width:1180px}
.portale{display:flex;flex-direction:column;gap:.4rem;padding:1.5rem 1.4rem;border-radius:18px;
         text-decoration:none!important;color:var(--ink);
         transition:transform .5s cubic-bezier(.16,1,.3,1),border-color .4s,background .4s}
.portale:hover{transform:translateY(-5px);border-color:rgba(0,204,255,.45);background:rgba(14,20,38,.72)}
.portale .n{font-size:.66rem;letter-spacing:.24em;text-transform:uppercase;color:var(--ink-fio)}
.portale .t{font-size:1.32rem;font-weight:700;letter-spacing:-.01em}
.portale .d{font-size:.9rem;line-height:1.55;color:var(--ink-dim)}
.portale .go{margin-top:.5rem;font-size:.78rem}

/* ─── Servizi: cosa faccio ────────────────────────────────────────────────
   Tre colonne su schermo largo, due sul medio, una sul telefono. Le schede
   non hanno un'immagine e non ne vogliono: qui conta la frase, e una figura
   generica accanto a "Consulenza & Security" toglierebbe credibilita' invece
   di darne.                                                               */
.servizi{display:grid;gap:.9rem;grid-template-columns:repeat(auto-fit,minmax(min(290px,100%),1fr));
         margin-top:2.4rem;max-width:1180px}
.serv{padding:1.5rem 1.4rem;border-radius:18px;display:flex;flex-direction:column;gap:.55rem}
/* L'icona sta in un quadrato con gli angoli tondi, come nel sito vecchio. Il
   tratto prende il gradiente del marchio: e' l'unica grafica della scheda,
   quindi tanto vale che sia quella giusta. */
/* Al passaggio il quadratino si riempie del gradiente e il tratto diventa
   bianco: e' come si comporta di la'. Il gradiente sta su uno pseudo-elemento
   che sfuma in opacita' — un gradiente non si interpola, l'opacita' si. */
.serv .ico{position:relative;isolation:isolate;
  width:46px;height:46px;border-radius:14px;display:flex;align-items:center;justify-content:center;
  margin-bottom:.5rem;background:rgba(0,102,255,.10);border:1px solid rgba(0,204,255,.18);
  color:var(--cyan);
  transition:transform .5s cubic-bezier(.16,1,.3,1),border-color .4s,color .4s,box-shadow .4s}
.serv .ico::after{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;
  background:linear-gradient(135deg,var(--blue),var(--cyan) 45%,var(--teal));
  background-size:230% 230%;animation:marchio-scorre 9s ease-in-out infinite;
  opacity:0;transition:opacity .5s}
.serv .ico svg{width:22px;height:22px}
.serv:hover .ico{transform:translateY(-3px) scale(1.06);border-color:transparent;color:#fff;
  box-shadow:0 12px 26px -12px rgba(0,102,255,.75)}
.serv:hover .ico::after{opacity:1}
/* La scheda si alza col puntatore. Il vetro la segue — glass.build ascolta le
   transizioni proprio per questo — quindi si alza la lastra, non solo il
   testo. */
.serv{transition:transform .55s cubic-bezier(.16,1,.3,1)}
.serv:hover{transform:translateY(-5px)}
:root[data-tema="chiaro"] .serv .ico{background:rgba(0,85,221,.08);border-color:rgba(0,144,200,.28)}
.serv h3{font-size:1.06rem;letter-spacing:-.01em}
.serv p{font-size:.92rem;line-height:1.6;max-width:none}
.invito{margin-top:2.2rem;max-width:60ch}
.invito a{white-space:nowrap;font-weight:600}

/* ─── Liste di contenuto (lavori, progetti, skill) ───────────────────── */
/* Fra una voce e l'altra ci vuole aria vera: le anteprime debordano dal
   loro riquadro — e' il modo in cui galleggiano — e con un rem di distanza
   quelle di due schede vicine arrivavano a toccarsi. */
.lista{display:grid;gap:2.6rem 1.6rem;margin-top:2.4rem;max-width:1180px}
/* Due colonne, non tre. A tre l'anteprima e' larga trecentottanta pixel e lo
   schermo dentro ne prende trecento: si intuisce cosa c'e' ma non si legge.
   A due ne prende cinquecento, ed e' li' che l'anteprima comincia a valere
   quello che costa. */
.lista.due{grid-template-columns:repeat(auto-fit,minmax(min(460px,100%),1fr))}
/* Con una voce sola auto-fit le da' tutta la riga, e una scheda larga
   milleduecento pixel con dentro tre righe di testo non e' un'anteprima:
   e' un manifesto. Le voci restano larghe quanto in una riga da due. */
.lista.due > .voce{max-width:600px;width:100%;justify-self:start}
/* ── Perche' le voci si allineano ────────────────────────────────────────
   L'anteprima di un sito e' alta trecentoventicinque pixel, quella di un
   filmato duecento, quella di una coppia col modello duecentoquaranta: le
   schede sotto partivano ognuna a un'altezza diversa e la riga sembrava
   storta. Qui ogni anteprima occupa la stessa altezza — quello che c'e'
   dentro resta della sua misura, centrato — e le schede partono in riga.
   Poi le schede si tirano fino in fondo, cosi' anche i piedi combaciano. */
.lista .voce{height:100%}
/* Altezza UGUALE per tutte, e quello che c'e' dentro si misura su di lei:
   il filmato, i due mezzi della Scopa, il modello e la sua anteprima. Cosi'
   le schede sotto partono tutte alla stessa riga. */
.lista .voce > .mockup{height:325px;min-height:0;flex:0 0 auto}
.lista .voce > .mockup.sito{height:auto}
/* Frida's si misura da se' (e' una griglia). Arduino no: e' un'altezza
   fissa con il filmato al centro e le schede intorno, e lasciandogli
   "auto" il filmato prendeva la sua altezza naturale — mille pixel di
   pagina di codice, con le schede sparse sopra. */
.lista .voce > .mockup.fridas{height:auto}
.lista .voce > .mockup.arduino{height:320px}
.lista .voce > .scheda{flex:1 1 auto}
.mockup.solo .cornice,.mockup.app .cornice-tel{height:100%;width:auto;max-width:100%}
.mockup.doppio .cornice-meta{height:100%;width:auto;max-width:46%}
.mockup.telefoni-due .telefoni{height:100%}
.mockup.telefoni-due .tel-uno{width:auto;height:88%;display:flex;align-items:center}
.mockup.telefoni-due .tel-schermo{width:auto;height:100%}
.lista .voce > .mockup.paio{align-items:stretch}
.lista .voce > .mockup.paio .paio-3d{aspect-ratio:auto;height:100%;min-height:0}
.lista .voce > .mockup.paio .cornice-paio{align-self:center;height:auto;max-height:100%;
  width:100%;max-width:100%}
@media (max-width:760px){
  .lista .voce > .mockup{height:auto;min-height:0}
  .mockup.solo .cornice,.mockup.app .cornice-tel{height:auto;width:min(100%,calc(320px * var(--vw,16) / var(--vh,9)))}
  .mockup.doppio .cornice-meta{height:auto;width:46%;max-width:46%}
  .mockup.telefoni-due .tel-uno{width:26%;height:auto;display:block}
  .mockup.telefoni-due .tel-schermo{width:100%;height:auto}
  .lista .voce > .mockup.paio .paio-3d{height:auto;aspect-ratio:1.6}}
/* Schede di solo testo: due colonne larghe, non quattro strette. A tutta
   larghezza il paragrafo si ferma a 52 caratteri e resta mezza scheda vuota —
   con il vetro dietro quella meta' diventa una finestra sul campo di stelle,
   e la scheda sembra incompiuta. */
/* min(430px,100%): senza, su un telefono da 393 px il minimo della colonna e'
   piu' largo dello schermo e la griglia sfonda — misurato, le schede di Chi
   sono arrivavano a 454. Vale per tutte le griglie del sito. */
/* Chi sono: colonne VERE, non una griglia. In griglia ogni riga e' alta
   quanto la scheda piu' alta, e sotto alle altre resta un buco — su schede di
   testo, che hanno lunghezze molto diverse, i buchi erano enormi. A colonne
   le schede si impilano riempiendo lo spazio.
   break-inside:avoid impedisce che una scheda venga spezzata a meta' fra due
   colonne. */
.lista.testi{display:block;columns:2;column-gap:1rem}
.lista.testi > .voce{break-inside:avoid;margin:0 0 1rem;display:block}
@media (max-width:820px){.lista.testi{columns:1}}
.voce{display:flex;flex-direction:column;gap:.7rem}
.voce .scheda{border-radius:16px;padding:1.5rem 1.4rem}
/* L'anno sta FUORI dalla scheda, sopra l'anteprima, come nella timeline del
   sito attuale: e' la prima cosa che si legge, prima ancora del titolo. */
.voce > .anno{font-size:.68rem;letter-spacing:.2em;font-weight:600}
.voce h3{margin-bottom:.45rem}
.voce .testa{margin-bottom:.45rem}
.voce .fatto{margin:.9rem 0 0;padding-left:1.05rem;list-style:none}
.voce .fatto li{position:relative;font-size:.88rem;line-height:1.6;color:var(--ink-dim);margin-top:.3rem}
.voce .fatto li::before{content:'';position:absolute;left:-1.05rem;top:.62em;width:5px;height:5px;
                        border-radius:50%;background:var(--marchio-min);opacity:.65}
.voce .vai{margin-top:.9rem;font-size:.86rem}
.voce .patroc{margin-top:1rem;padding-top:.8rem;border-top:1px solid var(--line);
              display:flex;flex-direction:column;gap:.25rem}
.voce .patroc .lbl{font-size:.62rem;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-fio)}
/* Marchi di clienti e patrocini — stesso trattamento del sito attuale.
   Le placchette chiare erano una mia idea e non convincevano: qui i marchi
   stanno sul fondo, come sono stati disegnati.
   Ognuno ha la sua misura (un marchio testuale lungo e un emblema quadrato
   non possono avere la stessa altezza) e chi e' nero su trasparente viene
   invertito, ma solo nel tema in cui sparirebbe. NASA e Space Camp non si
   toccano mai: il filtro appiattirebbe l'emblema in un disco. */
.voce .chi{display:inline-flex;align-items:center;gap:.42rem;vertical-align:middle}
.voce .marchio{height:24px;width:auto;max-width:110px;object-fit:contain;
  filter:drop-shadow(0 0 4px rgba(0,119,255,.25))}
.voce .marchio.pic{height:18px;max-width:90px}
.voce .marchio.gra{height:34px;max-width:150px}
:root[data-tema="chiaro"] .voce .marchio{filter:drop-shadow(0 0 4px rgba(0,0,0,.08))}

.voce .patroc .loghi{display:flex;flex-wrap:wrap;align-items:center;gap:1rem 1.5rem;margin-top:.55rem}
.voce .patroc .loghi a{display:inline-flex;align-items:center;justify-content:center;
  transition:transform .3s cubic-bezier(.16,1,.3,1),filter .3s}
.voce .patroc .loghi a:hover{transform:translateY(-2px) scale(1.04);
  filter:drop-shadow(0 4px 14px rgba(0,119,255,.45))}
.voce .patroc .loghi img{height:32px;width:auto;max-width:100px;object-fit:contain;
  display:block;opacity:.9;transition:opacity .3s,filter .3s}
.voce .patroc .loghi a:hover img{opacity:1}
.voce .patroc .loghi a.medio img{height:46px;max-width:130px}
.voce .patroc .loghi a.grande img{height:72px;max-width:260px}
.voce .patroc .loghi a.acceso img{filter:brightness(1.6) saturate(1.15)}
:root[data-tema="scuro"] .voce .marchio.inv-scuro,
:root[data-tema="scuro"] .voce .patroc .loghi a.inv-scuro img{
  filter:invert(1) hue-rotate(180deg) drop-shadow(0 0 4px rgba(0,224,198,.2))}
:root[data-tema="chiaro"] .voce .marchio.inv-chiaro,
:root[data-tema="chiaro"] .voce .patroc .loghi a.inv-chiaro img{
  filter:invert(1) hue-rotate(180deg)}


.voce .meta{font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-fio);margin-bottom:.6rem}
.voce p{font-size:.93rem;line-height:1.62}
/* Le etichette arrivavano a filo del titolo: con due righe di etichette la
   prima lettera del titolo ci finiva quasi sotto. */
.tags{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem;margin-top:.9rem}
.voce > .anno{margin-bottom:.55rem}
.voce .tags{margin:0 0 .9rem}
.voce .tags + .testa{margin-top:0}
/* Il titolo di un lavoro puo' essere lungo: va a capo per parole intere,
   senza spezzarle, e le due righe restano vicine. */
.voce .testa h3{line-height:1.22;text-wrap:balance;overflow-wrap:anywhere;hyphens:none}
/* La pastiglia era un elemento in linea con del padding: il testo si
   appoggiava alla linea di base e restava alto, e con due righe di etichette
   le pastiglie non erano nemmeno allineate fra loro. Adesso e' una scatola
   con il testo centrato dentro, e tutte hanno la stessa altezza. */
.tag{display:inline-flex;align-items:center;justify-content:center;
     height:24px;padding:0 .65rem;border-radius:20px;
     font-size:.68rem;line-height:1;letter-spacing:.04em;
     border:1px solid rgba(0,204,255,.28);background:var(--marchio-min);
     -webkit-background-clip:text;background-clip:text;color:transparent}

/* ─── LIQUID GLASS ───────────────────────────────────────────────────────
   Vetro vero = rifrazione + sfocatura + bordo neutro sottilissimo.
   NIENTE gradienti colorati, riflessi diagonali o bordi arcobaleno: sono
   quelli a far sembrare il vetro finto, roba da interfacce di vent'anni fa.
   La curvatura la fa feDisplacementMap (vedi filtro #liquid nell'HTML),
   la sfocatura sta DENTRO lo stesso filtro, dopo la rifrazione — cosi' e'
   la luce gia' piegata a essere sfocata, come nel vetro reale.
   Su WebKit i filtri SVG nel backdrop non esistono: li' interviene il
   vetro WebGL (vedi app.js), che funziona ovunque.                        */
/* ── La velatura del testo ──────────────────────────────────────────────
   Il contrasto non lo deve dare il vetro. Finche' ci provava, l'unico modo
   era assorbire tanta luce da spegnere anche le particelle: la lastra
   diventava un pannello e il vetro non si vedeva piu'.
   Qui la velatura sta DENTRO alla scheda, dietro al solo blocco di testo, e
   sfuma verso i bordi. Il vetro resta limpido dove non c'e' niente da
   leggere — cioe' proprio dove le particelle si devono vedere passare. */
html.gl-vetro .vetro::before,html.gl-vetro .serv::before,
html.gl-vetro .dato::before,html.gl-vetro .modulo::before{
  content:"";position:absolute;inset:1px;border-radius:inherit;pointer-events:none;z-index:-1;
  background:radial-gradient(125% 105% at 38% 45%,rgba(4,6,14,.84),rgba(4,6,14,.5) 52%,rgba(4,6,14,.14) 82%,rgba(4,6,14,0) 100%)}
html.gl-vetro .vetro,html.gl-vetro .serv,html.gl-vetro .dato,html.gl-vetro .modulo{isolation:isolate}
/* html.gl-vetro[data-tema="chiaro"], NON :root[...] html.gl-vetro: :root E'
   <html>, quindi quel selettore cercava un <html> dentro a un altro <html> e
   non poteva combaciare con niente. La velatura scura restava anche sul tema
   chiaro — ed e' quello che si vedeva. */
html.gl-vetro[data-tema="chiaro"] .vetro::before,
html.gl-vetro[data-tema="chiaro"] .serv::before,
html.gl-vetro[data-tema="chiaro"] .dato::before,
html.gl-vetro[data-tema="chiaro"] .modulo::before{
  background:radial-gradient(125% 105% at 38% 45%,rgba(250,251,255,.92),rgba(250,251,255,.6) 52%,rgba(250,251,255,.2) 82%,rgba(250,251,255,0) 100%)}
/* Gli occhielli no: sono pastiglie piccole, li' la velatura coprirebbe tutto
   e il vetro tornerebbe a essere una pastiglia opaca. */
html.gl-vetro .eyebrow::before{display:none}
/* Anche i bottoni "vuoti" sono lastre del motore: sono piccoli, e su un
   pezzo piccolo la rifrazione si vede piu' che su una scheda. Quello pieno
   no — ha il suo fondo blu, e il motore glielo cancellerebbe. */
html.gl-vetro .bottone::before{display:none}
html.gl-vetro .bottone[data-glass]:not([data-vetro-css]){backdrop-filter:none;-webkit-backdrop-filter:none}

.vetro{position:relative;border-radius:22px;
  background:rgba(255,255,255,.045);
  border:1px solid rgba(255,255,255,.13);
  box-shadow:0 18px 50px -28px rgba(0,0,0,.85);
  backdrop-filter:blur(3px) saturate(1.25);
  -webkit-backdrop-filter:blur(3px) saturate(1.25)}
@supports (backdrop-filter: url(#liquid)){
  .vetro{backdrop-filter:url(#liquid) saturate(1.25)}
}
/* Quando al vetro ci pensa la GPU (classe messa da app.js) il backdrop-filter
   del browser diventa un doppione, e su Safari e' un doppione CARO: il
   compositore ri-sfoca lo sfondo a ogni frame sopra un canvas che cambia
   sempre. E' da li' che veniva lo scatto "solo sul vetro". Qui si spegne. */
/* Con il vetro in WebGL la card NON deve disegnare nulla di suo: ne' fondo,
   ne' bordo, ne' ombra. Erano tre superfici piatte sovrapposte a una che
   invece si deforma, e si leggevano come strati staccati. Il fondo che tiene
   leggibile il testo ora sta dentro al vetro (assorbimento lungo lo
   spessore), e il bordo e' il riflesso sulla molatura. */
/* :not([data-vetro-css]) — app.js segna cosi' gli elementi a cui NON disegna
   la lastra, perche' stanno dentro a un'altra (niente vetro dentro al vetro).
   Quelli devono tenersi il vetro del browser, se no restano senza niente. */
html.gl-vetro .vetro:not([data-vetro-css]),
html.gl-vetro [data-glass]:not([data-vetro-css]){backdrop-filter:none;-webkit-backdrop-filter:none;
  background:transparent;border-color:transparent;box-shadow:none}

/* ─── Anteprima: un blocco a se', sopra la scheda ────────────────────────
   Stessa struttura del sito attuale: l'anteprima non sta DENTRO al vetro, sta
   sopra, ed e' un link — e' il modo piu' diretto per arrivare alla cosa vera.
   Le proporzioni e le inclinazioni sono quelle di li'.                     */
/* Niente fondo sull'area dell'anteprima. C'era una velatura chiara, e sopra
   al vetro si vedeva come un rettangolo piu' chiaro attorno al mockup: due
   superfici sovrapposte che non combaciano, ed e' proprio la cosa che si
   nota. Il mockup deve galleggiare, non stare dentro a una cornice. */
/* Le misure, le inclinazioni e la cornice sono quelle del sito vecchio,
   prese dal suo CSS una per una: schermo grande a sinistra largo l'82%,
   telefono in basso a destra largo il 22% che gli finisce leggermente
   sopra, e la cornice fatta di due anelli d'ombra invece che di un bordo. */
.mockup{position:relative;aspect-ratio:16/9;min-height:248px;overflow:visible;
  text-decoration:none!important;background:transparent;perspective:1200px}

/* La cornice: uno spessore scuro e un filo chiaro appena fuori. Non e' un
   bordo, sono due anelli di ombra — cosi' non ruba spazio all'immagine e
   segue l'angolo senza doppioni. */
.cornice,.mockup .schermo,.mockup .telefono,.tel-schermo{
  --bezel:0 0 0 6px rgba(20,22,30,.95),0 0 0 7px rgba(255,255,255,.08);
  --posa:translateZ(0);
  position:relative;display:block;border-radius:6px;background:#0a0c14;overflow:hidden;
  box-shadow:var(--bezel),0 22px 50px -14px rgba(0,0,0,.65)}
:root[data-tema="chiaro"] .cornice,:root[data-tema="chiaro"] .mockup .schermo,
:root[data-tema="chiaro"] .mockup .telefono,:root[data-tema="chiaro"] .tel-schermo{
  --bezel:0 0 0 5px rgb(230,230,240),0 0 0 6px rgba(10,20,40,.10);
  box-shadow:var(--bezel),0 20px 44px -10px rgba(10,20,40,.25)}
.cornice > img,.cornice > video,
.mockup .schermo img,.mockup .schermo video,
.mockup .telefono img,.mockup .telefono video{
  display:block;width:100%;height:100%;object-fit:cover;object-position:top;background:inherit}
@keyframes galleggia{0%,100%{transform:var(--posa,none) translateY(0)}
                     50%{transform:var(--posa,none) translateY(-6px)}}
@media (prefers-reduced-motion:reduce){.mockup *{animation:none!important}}

/* ── Sito: schermo e telefono, sovrapposti ─────────────────────────────── */
.mockup.sito .schermo{position:absolute;top:2%;left:0;width:78%;
  aspect-ratio:var(--ar,16/10);
  --posa:translateZ(-25px) perspective(1200px) rotateY(-5deg) rotateX(3deg);
  transform:var(--posa);animation:galleggia 7s ease-in-out infinite;
  transition:transform .7s cubic-bezier(.16,1,.3,1)}
/* Il telefono e' piu' basso dello schermo, non piu' alto: appoggiato al
   fondo com'era, scendeva sessanta pixel sotto allo schermo e i due
   sembravano due oggetti staccati invece che una coppia. */
.mockup.sito .telefono{position:absolute;right:4%;bottom:9%;width:21%;
  aspect-ratio:var(--ar,402/874);border-radius:13px;z-index:2;background:#111;
  --bezel:0 0 0 3px rgba(20,22,30,.95),0 0 0 4px rgba(255,255,255,.12);
  --posa:translateZ(25px) perspective(800px) rotateY(5deg) rotateX(-2deg);
  transform:var(--posa);animation:galleggia 8.6s ease-in-out infinite -2.4s}
:root[data-tema="chiaro"] .mockup.sito .telefono{
  --bezel:0 0 0 3px rgb(230,230,240),0 0 0 4px rgba(10,20,40,.12)}
.mockup.sito .telefono img{object-position:center top}

/* ── Due telefoni: iOS e Android ───────────────────────────────────────── */
/* Girati leggermente uno verso l'altro, con l'etichetta dello store sotto.
   Ognuno passa fra le sue cinque schermate da solo: sono immagini
   sovrapposte e a girare e' l'opacita', quindi al cambio non si carica
   niente e non si ridisegna niente. */
.mockup.telefoni-due{aspect-ratio:auto;min-height:0;display:flex;
  align-items:center;justify-content:center;margin:0 0 1.4rem}
.telefoni{display:flex;align-items:center;justify-content:center;gap:6%;width:100%}
.tel-uno{--posa:translateZ(0);position:relative;display:block;width:26%;text-decoration:none!important;
  color:inherit;filter:drop-shadow(0 18px 30px rgba(0,0,0,.5));transition:filter .3s}
.tel-uno:hover{filter:drop-shadow(0 22px 40px rgba(42,255,213,.35))}
.tel-a{--posa:rotateY(-12deg) rotateX(3deg);animation:galleggia 6.5s ease-in-out infinite}
.tel-b{--posa:rotateY(12deg) rotateX(-3deg);animation:galleggia 7.2s ease-in-out infinite -2.6s}
.tel-a,.tel-b{transform:var(--posa)}
.tel-schermo{width:100%;aspect-ratio:var(--ar,402/874);border-radius:13px;background:#111;
  --bezel:0 0 0 3px rgba(20,22,30,.95),0 0 0 4px rgba(255,255,255,.12)}
:root[data-tema="chiaro"] .tel-schermo{--bezel:0 0 0 3px rgb(230,230,240),0 0 0 4px rgba(10,20,40,.12)}
.tel-schermo img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:top;
  opacity:0;animation:passa-schermate 25s linear infinite}
.tel-schermo img:nth-child(1){animation-delay:0s}
.tel-schermo img:nth-child(2){animation-delay:-20s}
.tel-schermo img:nth-child(3){animation-delay:-15s}
.tel-schermo img:nth-child(4){animation-delay:-10s}
.tel-schermo img:nth-child(5){animation-delay:-5s}
@keyframes passa-schermate{0%,16%{opacity:1}20%,96%{opacity:0}100%{opacity:1}}
.tel-nome{position:absolute;bottom:-1.7rem;left:50%;transform:translateX(-50%);
  font-size:.62rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;
  color:var(--ink-fio);white-space:nowrap}
@media (prefers-reduced-motion:reduce){
  .tel-schermo img{animation:none;opacity:0}
  .tel-schermo img.su{opacity:1}}

/* ── Il modello 3D accanto alla sua anteprima ──────────────────────────── */
/* Sul sito vecchio il modello non SOSTITUISCE l'immagine: le sta accanto,
   libero, senza riquadro, e deborda dal suo posto. Qui e' la stessa cosa. */
.mockup.paio{aspect-ratio:auto;min-height:0;display:grid;gap:.8rem;align-items:center;
  grid-template-columns:1.05fr 1.3fr;position:relative;margin:0}
.mockup.paio-destra{grid-template-columns:1.3fr 1.05fr}
.paio-3d{position:relative;aspect-ratio:1.05;min-height:180px;background:transparent;
  overflow:visible;z-index:5;cursor:grab;touch-action:pan-y}
.paio-3d:active{cursor:grabbing}
.paio-3d model-viewer{background:transparent;--poster-color:transparent;z-index:6}
.paio-3d .vuoto{position:absolute;inset:0;background:transparent;box-shadow:none;border-radius:0}
/* ── La fotografia e il modello devono inquadrare uguale ─────────────────
   Le pose sono rese con lo STESSO visualizzatore e la STESSA macchina che
   poi usa il sito, su una tela quadrata. Perche' combacino davvero devono
   pero' anche stare nello stesso riquadro: un quadrato centrato, per tutte e
   due. Prima la fotografia veniva stirata sul riquadro — spesso largo — e il
   modello si inquadrava da se': due misure diverse, e al passaggio l'oggetto
   saltava. */
/* Il quadrato piu' grande che ci sta dentro, per tutti e due. Con height al
   cento per cento e aspect-ratio il browser tiene l'altezza e stringe solo la
   larghezza: veniva fuori un rettangolo, e la posa — che e' quadrata — ci
   entrava rimpicciolita mentre il modello vivo si inquadrava sul rettangolo.
   Le unita' del contenitore danno il quadrato vero. */
.tremd{container-type:size}
/* ── Perche' la finestra sborda dalla sua casella ────────────────────────
   Girando il modello, quello che era fuori inquadratura entra: con la
   finestra grande quanto la casella l'oggetto veniva tagliato appena lo si
   ruotava. La finestra sborda del 12%, e le distanze in data.js sono tarate
   perche' la sagoma piu' larga che il modello fa girando occupi il 71% della
   finestra: in casella sono l'80%, la stessa proporzione del sito vecchio.
   La posa e' resa con la STESSA macchina, quindi combaciano. */
.tremd{overflow:visible}
.tremd .mod-posa,.tremd model-viewer,.tremd .mv-fuori{
  position:absolute;inset:auto;top:50%;left:50%;transform:translate(-50%,-50%);
  width:min(112cqw,112cqh);height:min(112cqw,112cqh);max-width:none}
.mod-posa{object-fit:contain;display:block;pointer-events:none;z-index:7;
  filter:drop-shadow(0 14px 26px rgba(0,0,0,.5));
  transition:opacity .5s ease}
.mod-posa.esce{opacity:0}
.mv-fuori{border:0;background:transparent;z-index:6}
.tremd model-viewer.entra{animation:mv-entra .5s ease both}
@keyframes mv-entra{from{opacity:0}to{opacity:1}}
/* Il bottone del 3D: uno per anteprima, in basso a destra. */
.mockup .apri3d{position:absolute;right:.4rem;bottom:.2rem;z-index:12}
.mockup.paio .apri3d{bottom:-.2rem}
.mockup .apri3d .lbl{white-space:nowrap}
.mockup .apri3d.acceso{opacity:.62}
.mockup .apri3d.in-corso{opacity:.62;pointer-events:none}
.cornice-paio{width:100%;aspect-ratio:var(--ar,16/9);border-radius:8px}
@media (max-width:760px){
  .mockup.paio,.mockup.paio-destra{grid-template-columns:1fr;gap:.4rem}
  .mockup.paio .cornice-paio{order:1}
  .mockup.paio .paio-3d{order:2;aspect-ratio:1.6;min-height:150px}}

/* ── Lo stesso filmato, due volte, una meta' per parte ─────────────────── */
.mockup.doppio{aspect-ratio:auto;min-height:0;display:flex;align-items:center;
  justify-content:center;gap:28px;margin:0}
.cornice-meta{flex:0 0 auto;width:46%;aspect-ratio:var(--ar-meta,616/1052);border-radius:6px}
.cornice-meta video,.cornice-meta img{transform-origin:center}

/* ── Una cornice sola ──────────────────────────────────────────────────── */
.mockup.solo,.mockup.app{aspect-ratio:auto;min-height:0;display:flex;
  align-items:center;justify-content:center;margin:0}
/* L'altezza e' la stessa per tutte le anteprime semplici, come sul sito
   vecchio: la larghezza segue la forma del filmato, non il contrario. Cosi'
   un filmato verticale non diventa una colonna alta il doppio degli altri. */
.mockup.solo .cornice{width:min(100%,calc(320px * var(--vw,16) / var(--vh,9)));
  aspect-ratio:var(--ar,16/9);border-radius:12px;
  animation:galleggia 6s ease-in-out infinite}
.mockup.app .cornice-tel{width:min(46%,230px);aspect-ratio:var(--ar,402/874);border-radius:16px;
  background:#111;animation:galleggia 8.2s ease-in-out infinite}

/* ── Frida's: tutto quello che gira intorno al filmato ─────────────────── */
/* Non e' un lavoro con un'anteprima, e' un lavoro fatto di tante cose: due
   vasi modellati, le grafiche che si alternano, il filmato, il biglietto da
   visita che si gira. La disposizione e' quella del sito vecchio — filmato al
   centro, il resto ai due lati, tutto spostato un po' verso di lui e un po'
   piu' in basso, cosi' non sembra una griglia ma un tavolo. */
.mockup.fridas{aspect-ratio:auto;min-height:0;display:grid;
  grid-template-columns:.72fr 2fr .72fr;grid-template-rows:1fr 1fr;gap:.7rem;
  align-items:stretch;margin:1.2rem 0 2.4rem;padding:0 .4rem}
.mockup.fridas .apri3d{left:50%;right:auto;transform:translateX(-50%);bottom:-2rem}
.fr-vaso-1{grid-column:1;grid-row:1;transform:translate(-10px,-6px)}
.fr-grafiche{grid-column:1;grid-row:2;transform:translate(-18px,20px)}
.fr-video{grid-column:2;grid-row:1/3;position:relative;aspect-ratio:16/9}
.fr-carta{grid-column:3;grid-row:1;transform:translate(-26px,6px)}
.fr-vaso-2{grid-column:3;grid-row:2;transform:translate(-26px,10px)}
.fr-vaso{position:relative;align-self:center;justify-self:center;aspect-ratio:1;
  height:158%;width:auto;z-index:20;background:transparent}
.fr-vaso-2{height:124%}
.fr-vaso model-viewer{background:transparent;--poster-color:transparent;
  pointer-events:none;z-index:10}
.fr-video .fr-cornice{display:block;width:100%;height:100%;border-radius:22px;
  animation:galleggia 6s ease-in-out infinite}
/* Il bollo: piu' piccolo, e il dondolio piu' morbido — prima scattava fra
   due estremi, adesso passa dal centro e rallenta agli angoli. */
.fr-bollo{position:absolute;top:-11px;left:-13px;width:48px;height:48px;z-index:10;
  pointer-events:none;animation:bollo 8s cubic-bezier(.45,0,.55,1) infinite;
  filter:drop-shadow(0 5px 14px rgba(0,0,0,.55))}
.fr-bollo img{width:100%;height:100%;object-fit:contain;display:block}
@keyframes bollo{0%,100%{transform:rotate(-4deg) translateY(0)}
                 50%{transform:rotate(4deg) translateY(-3px)}}
.fr-grafiche{position:relative;align-self:center;justify-self:center;aspect-ratio:1;
  height:205%;width:auto;background:transparent}
.fr-grafiche img{position:absolute;inset:4%;width:92%;height:92%;object-fit:contain;
  opacity:0;animation:passa-grafiche 21s linear infinite}
.fr-grafiche img:nth-child(1){animation-delay:0s}
.fr-grafiche img:nth-child(2){animation-delay:-18s}
.fr-grafiche img:nth-child(3){animation-delay:-15s}
.fr-grafiche img:nth-child(4){animation-delay:-12s}
.fr-grafiche img:nth-child(5){animation-delay:-9s}
.fr-grafiche img:nth-child(6){animation-delay:-6s}
.fr-grafiche img:nth-child(7){animation-delay:-3s}
@keyframes passa-grafiche{0%,13%{opacity:1}16%,97%{opacity:0}100%{opacity:1}}
/* Il biglietto si gira al passaggio: davanti, retro, e torna. */
.fr-carta{align-self:center;justify-self:center;aspect-ratio:1;height:108%;width:auto;
  perspective:900px;z-index:15}
.fr-carta-dentro{position:relative;width:100%;height:100%;transform-style:preserve-3d;
  transition:transform 1.1s cubic-bezier(.16,1,.3,1)}
.fr-carta:hover .fr-carta-dentro{transform:rotateY(360deg)}
.fr-fronte,.fr-retro{position:absolute;inset:0;backface-visibility:hidden;
  border-radius:10px;overflow:hidden;box-shadow:0 14px 30px -14px rgba(0,0,0,.8)}
.fr-retro{transform:rotateY(180deg)}
.fr-fronte img,.fr-retro img{width:100%;height:100%;object-fit:cover;display:block}
@media (max-width:900px){
  .mockup.fridas{grid-template-columns:1fr 1fr;grid-template-rows:auto auto auto}
  .fr-video{grid-column:1/3;grid-row:1}
  .fr-vaso-1{grid-column:1;grid-row:2;transform:none}
  .fr-carta{grid-column:2;grid-row:2;transform:none;height:120%}
  .fr-grafiche{grid-column:1;grid-row:3;transform:none;height:120%}
  .fr-vaso-2{grid-column:2;grid-row:3;transform:none;height:120%}
  .fr-vaso{height:130%}}

/* ── Arduino: le cinque schede intorno al filmato ──────────────────────── */
.mockup.arduino{aspect-ratio:auto;min-height:0;position:relative;display:flex;
  align-items:center;justify-content:center;margin:0;height:320px}
.ar-video{display:block;height:100%;width:auto;aspect-ratio:.55;flex:0 0 auto;
  border-radius:8px;animation:galleggia 6s ease-in-out infinite}
.ar-video video,.ar-video img{width:100%;height:100%;object-fit:cover}
.ar-lato{position:absolute;top:50%;display:flex;flex-direction:column;
  justify-content:center;align-items:center;gap:2px;z-index:5;width:172px}
/* Le schede cominciano appena FUORI dal filmato — meta' della sua larghezza
   piu' un margine — se no gli finiscono sopra e non si legge ne' l'una cosa
   ne' l'altra. */
.ar-sx{right:50%;margin-right:96px;transform:translate(0,-50%) rotateY(8deg)}
.ar-dx{left:50%;margin-left:96px;transform:translate(0,-50%) rotateY(-8deg)}
.ar-scheda{position:relative;width:172px;aspect-ratio:1;flex:0 0 auto;background:transparent}
/* Tre da una parte e due dall'altra: quelle di sinistra si sovrappongono di
   piu' perche' sono una in piu' e devono stare nella stessa altezza. */
.ar-sx .ar-scheda + .ar-scheda{margin-top:-96px}
.ar-dx .ar-scheda + .ar-scheda{margin-top:-76px}
.ar-scheda model-viewer{background:transparent;--poster-color:transparent;pointer-events:none}
@media (max-width:900px){
  .mockup.arduino{height:auto;flex-direction:column;gap:.6rem}
  .ar-video{height:auto;width:min(70%,260px)}
  .ar-lato{position:static;width:auto;transform:none;flex-direction:row;margin:0}
  .ar-scheda{width:33%;max-width:120px}
  .ar-sx .ar-scheda + .ar-scheda,.ar-dx .ar-scheda + .ar-scheda{margin-top:0;margin-left:-18px}}
@media (max-width:620px){.ar-lato{display:none}}

.mockup .piatta{position:absolute;inset:0;display:block}
.mockup video{background-repeat:no-repeat;background-size:cover;background-position:top center}
a.mockup:hover .schermo{transform:var(--posa,none) translateY(-4px) scale(1.02);animation-play-state:paused}
a.mockup:hover .telefono{transform:var(--posa,none) translateY(-3px)}
/* L'invito compare in hover, come nel sito attuale. */
/* L'invito e' un bottone pieno come gli altri: stesso fondo, stessa ombra,
   e niente alone nero attorno alle lettere bianche — quello serve al testo
   che sta sulle particelle, non a quello che ha il suo fondo sotto. */
.mockup .invito,.cornice .invito{position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%) scale(.9);
  display:inline-flex;align-items:center;gap:.45rem;padding:.6rem 1.1rem;border-radius:999px;
  font:700 .76rem/1 var(--font);letter-spacing:.02em;color:#fff;z-index:9;
  background:linear-gradient(135deg,#0b7bff,#0048c4);
  border:1px solid rgba(255,255,255,.18);
  box-shadow:0 4px 25px rgba(0,119,255,.45),inset 0 1px 0 rgba(255,255,255,.18);
  opacity:0;pointer-events:none;
  transition:opacity .35s cubic-bezier(.16,1,.3,1),transform .4s cubic-bezier(.16,1,.3,1),box-shadow .4s cubic-bezier(.16,1,.3,1)}
.mockup .invito svg,.cornice .invito svg{width:13px;height:13px}
a.mockup:hover .invito,a.cornice:hover .invito{opacity:1;
  transform:translate(-50%,-50%) scale(1.03);
  box-shadow:0 10px 45px rgba(0,119,255,.55),inset 0 1px 0 rgba(255,255,255,.2)}
.mockup model-viewer{--poster-color:transparent;background:transparent}

/* ─── Modello 3D a richiesta ──────────────────────────────────────────────
   Finche' non lo si chiede c'e' l'anteprima, e in un angolo il bottone. Il
   bottone e' piccolo e sta in basso a destra: e' un'offerta, non un invito a
   cui non ci si puo' sottrarre.                                           */
.tremd{position:relative}
.apri3d{position:absolute;right:.6rem;bottom:.6rem;z-index:6;display:flex;align-items:center;gap:.4rem;
  padding:.42rem .7rem;border-radius:999px;cursor:pointer;
  font:600 .68rem/1 var(--font);letter-spacing:.04em;color:var(--ink);
  background:rgba(8,11,20,.62);border:1px solid rgba(255,255,255,.14);
  backdrop-filter:blur(10px) saturate(1.4);-webkit-backdrop-filter:blur(10px) saturate(1.4);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.14),0 8px 20px -12px rgba(0,0,0,.9);
  transition:background .3s,border-color .3s,transform .3s}
.apri3d:hover{background:rgba(16,22,38,.75);border-color:rgba(255,255,255,.24);transform:translateY(-2px)}
.apri3d svg{width:13px;height:13px}
:root[data-tema="chiaro"] .apri3d{background:rgba(255,255,255,.72);border-color:rgba(10,20,40,.12);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 8px 20px -14px rgba(10,20,40,.45)}
/* Acceso: il modello ha bisogno di posarsi su qualcosa. Senza un piano sotto
   galleggia sul campo di stelle e sembra ritagliato male. */
.tremd.acceso{background:radial-gradient(120% 100% at 50% 100%,rgba(0,204,255,.10),transparent 62%),
  linear-gradient(180deg,rgba(255,255,255,.035),rgba(255,255,255,.012));
  border:1px solid rgba(255,255,255,.10);border-radius:16px;overflow:hidden}
:root[data-tema="chiaro"] .tremd.acceso{
  background:radial-gradient(120% 100% at 50% 100%,rgba(0,144,200,.10),transparent 62%),
  linear-gradient(180deg,rgba(255,255,255,.7),rgba(255,255,255,.35));
  border-color:rgba(10,20,40,.10)}
/* Il modello accanto alla sua anteprima non ha riquadro: sta libero e
   deborda dal suo posto, come sul sito vecchio. Il piano sotto serve solo
   quando il modello E' l'anteprima, cioe' quando e' da solo. */
.tremd.paio-3d.acceso,:root[data-tema="chiaro"] .tremd.paio-3d.acceso,
.tremd.fr-vaso.acceso,:root[data-tema="chiaro"] .tremd.fr-vaso.acceso,
.tremd.ar-scheda.acceso,:root[data-tema="chiaro"] .tremd.ar-scheda.acceso{
  background:none;border:0;border-radius:0;overflow:visible}
.paio-3d .gira,.fr-vaso .gira,.ar-scheda .gira{display:none}
/* La fila per cambiare modello: sta sotto, e' piccola, e non deve sembrare
   una barra di navigazione — sono varianti della stessa cosa. */
.paio-3d .scelta3d{bottom:-1.5rem;z-index:8}
.mockup.paio{padding-bottom:1.4rem}
.mockup.paio:not(:has(.scelta3d)){padding-bottom:0}
.scelta3d{position:absolute;left:0;right:0;bottom:.5rem;z-index:7;
  display:flex;flex-wrap:wrap;justify-content:center;gap:.3rem;padding:0 .6rem}
.scelta3d button{padding:.32rem .6rem;border-radius:999px;cursor:pointer;
  font:600 .64rem/1 var(--font);letter-spacing:.02em;color:var(--ink-dim);
  background:rgba(8,11,20,.6);border:1px solid rgba(255,255,255,.10);
  backdrop-filter:blur(10px) saturate(1.4);-webkit-backdrop-filter:blur(10px) saturate(1.4);
  transition:color .3s,border-color .3s,background .3s}
.scelta3d button:hover{color:var(--ink);border-color:rgba(255,255,255,.22)}
.scelta3d button[aria-current]{color:#fff;border-color:transparent;
  background:linear-gradient(135deg,#0b7bff,#0048c4);
  background-size:180% 180%;animation:marchio-scorre 9s ease-in-out infinite}
:root[data-tema="chiaro"] .scelta3d button:not([aria-current]){background:rgba(255,255,255,.7);border-color:rgba(10,20,40,.12)}
/* Finche' il modello non e' stato chiesto la fila non serve a niente —
   tranne dove i pezzi sono otto e la fila serve a scegliere QUALE guardare:
   li' cambia la fotografia, e il modello e' solo un di piu'. */
.tremd:not(.acceso) .scelta3d{display:none}
.setup-3d:not(.acceso) .scelta3d{display:flex}
/* ─── Le versioni del sito ────────────────────────────────────────────────
   Quattro schermetti in fila, ognuno con la sua sigla e il suo anno. Stessa
   cornice delle anteprime dei progetti, in piccolo: e' la stessa cosa —
   uno schermo con dentro un sito.                                        */
/* Anche qui il telefono e' un oggetto a se', accanto al desktop: e' la stessa
   coppia delle anteprime dei progetti, in piccolo. */
/* Le anteprime delle versioni sono il pezzo piu' raccontabile della pagina:
   qui si vede in un colpo d'occhio quanta strada. A 150 px erano francobolli.
   Due per riga, larghe. */
/* Le versioni del sito: la stessa anteprima di tutte le altre — schermo e
   telefono che si sovrappongono — solo in piccolo. Prima era una cornice
   diversa dalle altre e si vedeva che era un'altra cosa. */
/* Una per riga: cosi' l'anteprima e' larga quanto la scheda e la schermata
   si legge davvero. In due colonne erano due francobolli. */
.versioni{display:grid;gap:1.8rem;grid-template-columns:1fr;margin-top:1.4rem}
.versione{margin:0}
/* E' uno <span>: senza display:block resta in linea, e su una scatola in
   linea aspect-ratio e min-height non fanno niente — il riquadro restava
   alto zero e le immagini dentro non venivano nemmeno chieste. */
.mockup.sito.piccolo{display:block;min-height:0;aspect-ratio:16/10;margin:0}
.mockup.sito.piccolo .schermo{width:87%}
.mockup.sito.piccolo .telefono{width:18%;right:1%;bottom:7%}
.mockup.sito.piccolo .schermo{border-radius:5px;
  --bezel:0 0 0 4px rgba(20,22,30,.95),0 0 0 5px rgba(255,255,255,.08)}
.mockup.sito.piccolo .telefono{border-radius:9px;
  --bezel:0 0 0 2px rgba(20,22,30,.95),0 0 0 3px rgba(255,255,255,.12)}
:root[data-tema="chiaro"] .mockup.sito.piccolo .schermo{--bezel:0 0 0 4px rgb(230,230,240),0 0 0 5px rgba(10,20,40,.10)}
:root[data-tema="chiaro"] .mockup.sito.piccolo .telefono{--bezel:0 0 0 2px rgb(230,230,240),0 0 0 3px rgba(10,20,40,.12)}
.versione figcaption{margin-top:.7rem;font-size:.82rem;line-height:1.45;color:var(--ink-dim)}
.versione figcaption b{color:var(--ink);font-size:.95rem}
.versione .anno-v{color:var(--ink-fio)}

/* Sulla scheda del setup non c'e' un'anteprima da mostrare: il riquadro
   resta vuoto finche' non si chiede un modello.
   E qui la fila dei modelli NON sta sopra al modello: sono otto voci, in
   sovrimpressione coprivano meta' oggetto. Sta sotto, nel flusso. */
/* Gli attrezzi: la fotografia del pezzo scelto, la fila per cambiarlo sotto
   e il bottone che accende il modello vero. La fila sta NEL FLUSSO, non
   appoggiata sotto al riquadro: sono otto voci, vanno a capo su due righe, e
   appoggiate finivano tagliate dal bordo della scheda. */
.mockup.setup{aspect-ratio:auto;min-height:0;margin-top:1rem;display:block;
  position:relative}
.setup-3d{position:relative;height:300px;display:block}
.mockup.setup > .scelta3d{position:static;margin-top:1rem;padding:0;
  justify-content:flex-start;gap:.35rem;display:flex}
.mockup.setup .gira{display:none}
.mockup.setup .apri3d{right:.2rem;bottom:auto;top:.2rem}
.mockup.setup:not(.acceso){min-height:170px;position:relative}
.mockup .schermo.vuoto{height:100%;width:100%;max-width:100%;background:transparent;
  box-shadow:none;animation:none}
.tremd.acceso .schermo.vuoto{display:none}

.tremd .gira{position:absolute;left:0;right:0;bottom:.5rem;z-index:5;text-align:center;pointer-events:none;
  font:600 .62rem/1 var(--font);letter-spacing:.2em;text-transform:uppercase;color:var(--ink-fio);
  opacity:0;transition:opacity .6s}
.tremd.acceso .gira{opacity:1}
a.mockup:hover .invito,a.mockup:focus-visible .invito{opacity:1;transform:translate(-50%,-50%) scale(1)}
@media (max-width:520px){
  .mockup{min-height:170px}
  .mockup .telefono.grande{width:38%}
}

/* ─── Vetrina: anteprime che FLUTTUANO dentro lastre di vetro ────────────
   Vetro impilato ispirato a "Stackable Glass" (Spline Community, CC0):
   lastre traslucide sfalsate in profondita' — dove si sovrappongono il
   colore si somma e la luce si concentra. Reimplementato in CSS puro.
   Il galleggiamento riprende la ricetta del sito attuale: oscillazione
   sinusoidale + attrazione magnetica verso il cursore.
   Le trasformazioni passano da variabili CSS, cosi' JS (moto) e CSS
   (hover) non si contendono la proprieta' transform.                      */
.vetrina{display:grid;gap:1.5rem 1.1rem;grid-template-columns:repeat(auto-fill,minmax(min(215px,100%),1fr));
         margin-top:3rem;max-width:1180px;perspective:1400px}
.prev{position:relative;display:block;border-radius:22px;text-decoration:none!important;
      transform-style:preserve-3d;
      transform:translate3d(var(--fx,0px),var(--fy,0px),0)
                rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)) scale(var(--sc,1));
      transition:--sc .5s}
/* Le due lastre dietro: sporgono e si accumulano, come nello stack. */
.prev::before,.prev::after{content:'';position:absolute;inset:0;border-radius:26px;z-index:-1;
  pointer-events:none;transition:transform .6s cubic-bezier(.16,1,.3,1),opacity .5s}
.prev::before{transform:translate3d(-7%,-6%,-30px);
  background:linear-gradient(150deg,rgba(42,255,213,.20),rgba(0,204,255,.10) 50%,transparent);
  border:1px solid rgba(42,255,213,.22);opacity:.7}
.prev::after{transform:translate3d(7%,6%,-60px);
  background:linear-gradient(150deg,rgba(0,102,255,.22),rgba(0,204,255,.08) 55%,transparent);
  border:1px solid rgba(0,140,255,.20);opacity:.55}
.prev:hover{--sc:1.03}
.prev:hover::before{transform:translate3d(-11%,-9%,-34px);opacity:.95}
.prev:hover::after{transform:translate3d(11%,9%,-68px);opacity:.8}
/* La lastra in primo piano: il vetro che contiene l'immagine. */
/* La lastra deve avere un'altezza SUA: prima gliela dava l'immagine dentro,
   ora l'anteprima e' in posizione assoluta e senza proporzione dichiarata la
   lastra collassava a due pixel — le card della vetrina risultavano vuote. */
.prev .mini{position:absolute;inset:0;display:block;perspective:700px}
/* In vetrina lo schermo e' piu' piccolo e non galleggia: sei anteprime che
   ondeggiano insieme sono un acquario, non una vetrina. */
.prev .mini .schermo{height:84%;border-radius:9px;animation:none;
  box-shadow:0 14px 30px -14px rgba(0,0,0,.7)}
.prev .mini .telefono.grande{width:44%}
.prev .lastra{display:block;position:relative;border-radius:22px;overflow:hidden;
  border:1px solid rgba(255,255,255,.16);background:#0a0e1a;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3),
             inset 0 -12px 26px -22px rgba(0,204,255,.7),
             0 26px 50px -26px rgba(0,0,0,.9);
  transition:border-color .45s;aspect-ratio:4/5;position:relative}
.prev:hover .lastra{border-color:rgba(0,204,255,.5)}
.prev img{width:100%;height:auto;aspect-ratio:4/5;object-fit:cover;display:block;opacity:.88;
          transition:transform .8s cubic-bezier(.16,1,.3,1),opacity .45s}
.prev:hover img{transform:scale(1.07);opacity:1}
/* Riflesso che scorre sul vetro all'hover. */
.prev .lastra::after{content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(112deg,transparent 34%,rgba(255,255,255,.16) 47%,transparent 60%);
  transform:translateX(-110%);transition:transform .9s cubic-bezier(.16,1,.3,1)}
.prev:hover .lastra::after{transform:translateX(110%)}
.prev .cap{display:block;position:absolute;left:0;right:0;bottom:0;padding:1.9rem .85rem .7rem;z-index:2;
  font-size:.78rem;font-weight:600;color:var(--ink);
  background:linear-gradient(180deg,transparent,rgba(4,6,14,.94))}
@media (prefers-reduced-motion:reduce){.prev{transform:none}}

/* Skill: barre di livello (leggibili anche senza la scena 3D) */
/* Il vetro sta sotto l'intero gruppo, non sotto ogni singola riga: sei
   pannelli invece di ventiquattro, ed e' la stessa lastra a reggere sia il
   titolo della categoria sia le voci. Le righe restano leggere, altrimenti
   sarebbe vetro sopra vetro e il testo perderebbe contrasto. */
.cat{margin-top:2.6rem;padding:1.15rem 1.25rem 1.35rem;border-radius:22px}
.cat > h3{font-size:.72rem;letter-spacing:.24em;text-transform:uppercase;margin-bottom:.9rem}
/* ─── Le skill: una pastiglia per ognuna, con il suo marchio ──────────────
   Erano righe con nome, barra e numero — un foglio di calcolo. Nel sito
   vecchio ognuna e' un elemento suo con il logo, e una griglia di marchi la
   si legge a colpo d'occhio mentre un elenco di nomi va letto riga per riga.
   Il livello resta, ma come filo sotto al nome invece che come numero in
   fondo: l'informazione c'e' e smette di essere la cosa piu' vistosa.     */
/* Le categorie sono COLONNE affiancate, come nel sito vecchio: una colonna
   per ambito, con la sua intestazione e il suo conteggio, e dentro le
   pastiglie a due per riga. Prima erano fasce orizzontali a tutta larghezza —
   con undici pastiglie in fila l'ambito non si leggeva piu'. */
/* ─── La pagina di una tecnologia ─────────────────────────────────────────
   Non c'e' piu' un pannellino che si apre sopra: la pastiglia porta diritto
   qui. Una pagina si puo' mandare a qualcuno, la trova Google, e soprattutto
   ha lo spazio per la cosa che conta davvero — i lavori in cui quella
   tecnologia e' finita, con la loro anteprima.                            */
.sk-titolo{margin-bottom:1.6rem}
.sk-testa{border-radius:20px;padding:1.6rem 1.5rem;max-width:820px}
.sk-riga{display:flex;align-items:center;gap:1.2rem;flex-wrap:wrap;margin-bottom:1.1rem}
.sk-ruolo{font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-fio);
  margin-left:auto}
.sk-dove{margin:3.4rem 0 0}
.sk-nav{display:flex;align-items:center;justify-content:space-between;gap:1rem;
  margin-top:3rem;padding-top:1.2rem;border-top:1px solid var(--line);flex-wrap:wrap}
.sk-nav a{display:inline-flex;align-items:center;gap:.5rem;text-decoration:none!important;
  font-size:.86rem;color:var(--ink-dim);transition:color .3s}
.sk-nav a:hover{color:var(--ink)}
.sk-nav svg{width:16px;height:16px;flex:0 0 auto}
.sk-tutte{font-weight:600}
/* ─── I comandi della pagina di una tecnologia ───────────────────────────
   Non in fondo alla pagina: addosso a quello che si sta guardando. Le due
   frecce ai lati, come si sfoglia; la X in alto a destra, dove si cerca
   un'uscita. Sono lastre di vetro: le disegna il motore come tutte le altre,
   quindi rifrangono le particelle e si vedono anche sul nero.            */
/* ── Perche' QUESTO vetro non e' quello del motore ───────────────────────
   Le lastre del motore vivono nel canvas, e il canvas sta DIETRO al
   contenuto: va benissimo per una scheda, che il contenuto non lo copre mai.
   Questi bottoni invece stanno sopra a tutto, e il contenuto ci scorre
   sotto: con la lastra dietro si vedeva il vetro finire sotto le schede.
   Qui il vetro e' quello del browser, che compone davanti — e' l'unico che
   puo' sfocare quello che gli passa sotto. */
.sk-lato,.sk-esci{
  background:rgba(8,11,20,.55);border:1px solid rgba(255,255,255,.14);
  backdrop-filter:blur(16px) saturate(1.6);-webkit-backdrop-filter:blur(16px) saturate(1.6);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.14),0 14px 34px -18px rgba(0,0,0,.95)}
:root[data-tema="chiaro"] .sk-lato,:root[data-tema="chiaro"] .sk-esci{
  background:rgba(255,255,255,.62);border-color:rgba(10,20,40,.12);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),0 14px 30px -18px rgba(10,20,40,.4)}
.sk-lato:hover,.sk-esci:hover{background:rgba(16,22,38,.7);border-color:rgba(0,204,255,.4)}
:root[data-tema="chiaro"] .sk-lato:hover,:root[data-tema="chiaro"] .sk-esci:hover{
  background:rgba(255,255,255,.8);border-color:rgba(0,144,200,.35)}
.sk-lato{position:fixed;top:50%;transform:translateY(-50%);z-index:30;
  display:flex;align-items:center;gap:.5rem;
  height:56px;padding:0 .9rem;border-radius:999px;
  color:var(--ink);text-decoration:none!important;
  transition:transform .45s cubic-bezier(.16,1,.3,1),color .3s,background .3s,border-color .3s}
.sk-prec{left:.7rem}
.sk-succ{right:.7rem;flex-direction:row-reverse}
.sk-lato svg{width:20px;height:20px;flex:0 0 auto}
/* Il contenuto della pagina lascia il posto alle frecce invece di
   sfiorarle: sotto ai mille pixel le frecce si stringono da sole. */
@media (min-width:1080px){.sk-pagina{padding-left:calc(var(--pad) + 26px);padding-right:calc(var(--pad) + 26px)}}
/* Il nome della prossima esce da sotto la freccia al passaggio: fermo
   sarebbe una colonna di testo in mezzo alla pagina. */
.sk-lato-nome{max-width:0;overflow:hidden;white-space:nowrap;opacity:0;
  font-size:.82rem;font-weight:600;
  transition:max-width .45s cubic-bezier(.16,1,.3,1),opacity .3s}
.sk-lato:hover .sk-lato-nome{max-width:180px;opacity:1}
.sk-prec:hover{transform:translateY(-50%) translateX(-4px)}
.sk-succ:hover{transform:translateY(-50%) translateX(4px)}
.sk-esci{position:fixed;top:calc(16px + 48px + 16px);right:var(--pad);z-index:30;
  display:flex;align-items:center;justify-content:center;width:48px;height:48px;
  border-radius:50%;color:var(--ink);text-decoration:none!important;
  transition:transform .4s cubic-bezier(.16,1,.3,1),color .3s}
.sk-esci:hover{transform:rotate(90deg)}
.sk-esci svg{width:20px;height:20px}
@media (max-width:760px){
  .sk-lato{height:52px;padding:0 .7rem}
  .sk-lato-nome{display:none}
  .sk-prec{left:.5rem}
  .sk-succ{right:.5rem}
  .sk-esci{top:auto;bottom:calc(16px + env(safe-area-inset-bottom));right:.9rem;
    width:44px;height:44px}}

@media (max-width:620px){.sk-nav span{display:none}}

.ss-testa{display:flex;align-items:center;gap:.9rem;margin-bottom:1.2rem}
.ss-ico{display:flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:56px;height:56px;border-radius:16px;
  background:linear-gradient(135deg,rgba(0,102,255,.16),rgba(42,255,213,.10));
  border:1px solid rgba(0,204,255,.20)}
.ss-logo{width:34px;height:34px;object-fit:contain;display:block}
#scheda-skill h3,.scheda-skill h1{font-size:1.32rem;letter-spacing:-.02em;margin:0;max-width:none}
.scheda-skill h1{font-size:1.7rem}
#scheda-skill .ss-ruolo,.scheda-skill .ss-ruolo{font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--ink-fio);margin:.25rem 0 0;max-width:none}

.ss-meta{display:flex;align-items:center;gap:1.1rem;margin-bottom:1.1rem}
.ss-anello{position:relative;width:78px;height:78px;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center}
.ss-anello svg{position:absolute;inset:0;width:100%;height:100%;transform:rotate(-90deg)}
.ss-pista{fill:none;stroke:rgba(255,255,255,.09);stroke-width:6}
:root[data-tema="chiaro"] .ss-pista{stroke:rgba(10,20,40,.1)}
.ss-fill{fill:none;stroke:url(#ss-grad);stroke-width:6;stroke-linecap:round;
  transition:stroke-dashoffset .9s cubic-bezier(.16,1,.3,1);
  filter:drop-shadow(0 0 4px rgba(42,255,213,.45))}
.ss-pct{position:relative;font-weight:800;font-size:1.05rem;letter-spacing:-.02em}
.ss-pct small{font-size:.62rem;opacity:.7;margin-left:1px}
.ss-meta-testo{display:flex;flex-direction:column;gap:.1rem}
.ss-meta-testo b{font-size:1.6rem;font-weight:800;letter-spacing:-.02em;line-height:1}
.ss-meta-testo i{font-style:normal;font-size:.68rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-fio)}
#scheda-skill .ss-d,.scheda-skill .ss-d{font-size:.94rem;line-height:1.62;max-width:none;margin:0}

.ss-vicine{margin-top:1.1rem;padding-top:.9rem;border-top:1px solid var(--line)}
.ss-vicine-t{font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--ink-fio);margin:0 0 .55rem;max-width:none}
.ss-vicine-l{display:flex;flex-wrap:wrap;gap:.35rem}
.ss-vicine-l button,.ss-vicine-l a.ss-tag{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;
  text-decoration:none!important;
  padding:.32rem .6rem;border-radius:999px;font:600 .72rem/1 var(--font);color:var(--ink-dim);
  background:rgba(255,255,255,.05);border:1px solid var(--line);
  transition:color .3s,border-color .3s,background .3s}
.ss-vicine-l button:hover,.ss-vicine-l a.ss-tag:hover{color:var(--ink);border-color:rgba(0,204,255,.4);background:rgba(0,102,255,.10)}
.ss-vicine-l img{width:18px;height:18px;object-fit:contain}
:root[data-tema="chiaro"] .ss-vicine-l button,:root[data-tema="chiaro"] .ss-vicine-l a.ss-tag{background:rgba(10,20,40,.04)}

.ss-nav{display:flex;align-items:center;justify-content:center;gap:.8rem;
  margin-top:1rem;padding-top:.9rem;border-top:1px solid var(--line)}
.ss-nav button,.ss-nav a{width:36px;height:36px;border-radius:50%;cursor:pointer;border:1px solid var(--line);
  text-decoration:none!important;
  display:flex;align-items:center;justify-content:center;color:var(--ink-dim);
  background:rgba(255,255,255,.05);transition:color .3s,border-color .3s,background .3s}
.ss-nav button:hover,.ss-nav a:hover{color:var(--ink);border-color:rgba(0,204,255,.4);background:rgba(0,102,255,.10)}
.ss-nav svg{width:17px;height:17px}
.ss-idx{font-size:.72rem;color:var(--ink-fio);font-variant-numeric:tabular-nums;min-width:4.4em;text-align:center}
:root[data-tema="chiaro"] .ss-nav button,:root[data-tema="chiaro"] .ss-nav a{background:rgba(10,20,40,.04)}
.ss-vai{margin-top:.9rem;font-size:.86rem;text-align:center}
.ss-usi{list-style:none;display:flex;flex-direction:column;gap:.4rem;font-size:.88rem}
/* Chi arriva da una pagina delle competenze cercava UN lavoro: per due
   secondi quello si accende, cosi' si sa su quale si e' atterrati. */
.voce.trovata > .scheda,.voce.trovata > .mockup{animation:trovata 2.4s ease-out both}
@keyframes trovata{
  0%{box-shadow:0 0 0 0 rgba(0,204,255,.55)}
  18%{box-shadow:0 0 0 4px rgba(0,204,255,.35)}
  100%{box-shadow:0 0 0 14px rgba(0,204,255,0)}}
@media (prefers-reduced-motion:reduce){.voce.trovata > .scheda,.voce.trovata > .mockup{animation:none}}
.ss-usi .anno-v{color:var(--ink-fio);font-size:.8rem}

/* ─── L'elenco delle categorie: a colonne, non a righe ───────────────────
   In griglia ogni riga e' alta quanto la scheda piu' alta: sotto a
   "Frontend & Mobile" restavano trecento pixel di niente perche' accanto
   c'erano quindici linguaggi. A colonne le schede si impilano e i vuoti
   si chiudono da soli — e' come sta sul sito vecchio a occhio, ma senza
   dover decidere a mano chi va sotto a chi. */
/* Il marchio grande sulla pagina della singola tecnologia. */
.sk-grande{width:64px;height:64px;object-fit:contain;display:block;margin-bottom:1rem;
  filter:drop-shadow(0 4px 12px rgba(0,0,0,.55))}
.ss-chiudi{position:absolute;top:.8rem;right:.8rem;width:36px;height:36px;border:0;cursor:pointer;
  text-decoration:none!important;
  display:flex;align-items:center;justify-content:center;border-radius:50%;
  background:rgba(255,255,255,.06);color:var(--ink-dim);transition:background .3s,color .3s}
.ss-chiudi:hover{background:rgba(255,255,255,.12);color:var(--ink)}
.ss-chiudi svg{width:17px;height:17px}
:root[data-tema="chiaro"] .ss-chiudi{background:rgba(10,20,40,.06)}
/* La barra piatta resta: la usa la pagina della singola tecnologia. */
.ss-barra{margin-top:1.3rem;height:4px;border-radius:3px;background:rgba(255,255,255,.08);overflow:hidden}
.ss-barra i{display:block;height:100%;border-radius:3px;
  background:linear-gradient(90deg,var(--blue),var(--cyan) 45%,var(--teal));
  background-size:230% 100%;animation:marchio-scorre 9s ease-in-out infinite;
  box-shadow:0 0 10px rgba(42,255,213,.45)}
@media (prefers-reduced-motion:reduce){.ss-barra i{animation:none}}

/* Le misure sono quelle del sito vecchio, prese una per una dal suo CSS:
   tre colonne esatte con 1.5rem di distanza, intestazione con 0.75rem fra
   icona e nome e un filo sotto, e dentro le pastiglie DUE per riga.
   "auto-fit" qui sarebbe sbagliato: con quattro colonne su schermo largo le
   pastiglie tornerebbero una per riga e si perderebbe la griglia. */
.categorie{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1.5rem;
  max-width:1180px;margin-top:2.6rem;align-items:start}
.cat-col{display:flex;flex-direction:column;gap:1.5rem}
@media (max-width:980px){.categorie{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:620px){.categorie{grid-template-columns:1fr}}
.cat-testa{display:flex;align-items:center;gap:.75rem;padding-bottom:1rem;margin-bottom:1.5rem;
  border-bottom:1px solid var(--line)}
.cat-ico{display:flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:32px;height:32px;border-radius:10px;color:var(--cyan);
  background:linear-gradient(135deg,rgba(0,102,255,.18),rgba(0,204,255,.12) 45%,rgba(42,255,213,.10));
  border:1px solid rgba(0,102,255,.2)}
.cat-ico svg{width:16px;height:16px}
.cat-testa h3{flex:1;font-size:1rem;letter-spacing:-.01em;margin:0;color:var(--ink)}
.cat-n{margin-left:auto;font-size:.72rem;font-weight:600;letter-spacing:1px;color:var(--ink-fio);
  font-variant-numeric:tabular-nums}
:root[data-tema="chiaro"] .cat-ico{background:linear-gradient(135deg,rgba(0,85,221,.12),rgba(0,169,140,.08));
  border-color:rgba(0,144,200,.3)}

.skills{display:grid;gap:.55rem;grid-template-columns:repeat(2,minmax(0,1fr))}
.sk{position:relative;display:flex;align-items:center;gap:.55rem;padding:.6rem .7rem;
    width:100%;text-align:left;font:inherit;cursor:pointer;color:var(--ink);
    text-decoration:none!important;
    border:1px solid rgba(255,255,255,.06);border-radius:14px;
    background:linear-gradient(135deg,rgba(255,255,255,.03),rgba(255,255,255,.01));
    transition:transform .45s cubic-bezier(.16,1,.3,1),border-color .35s,background .35s,box-shadow .35s}
.sk .testo{display:flex;flex-direction:column;min-width:0;flex:1}
.sk .nome{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Il numero: e' quello che dice quanto la conosco, e cliccandolo si apre la
   sua pagina come tutto il resto della pastiglia. */
/* Certi marchi sono neri: su fondo scuro non si vedono. Si rovesciano. */
:root:not([data-tema="chiaro"]) .marchio-scuro{filter:invert(1) brightness(1.12)}
.sk-liv{flex:0 0 auto;font-size:.68rem;font-weight:700;letter-spacing:.04em;
  color:var(--ink-fio);font-variant-numeric:tabular-nums;transition:color .3s}
.sk:hover .sk-liv{color:var(--cyan)}
/* Un filo di luce sul bordo alto, che compare solo al passaggio: e' il
   dettaglio che sul sito vecchio fa "accendere" la pastiglia. */
.sk::before{content:"";position:absolute;top:0;left:0;right:0;height:1px;border-radius:14px 14px 0 0;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.12),transparent);
  opacity:0;transition:opacity .35s}
.sk:hover::before{opacity:1}
.sk:hover{transform:translateY(-2px);border-color:rgba(42,255,213,.28);
  background:linear-gradient(135deg,rgba(0,102,255,.08),rgba(42,255,213,.04));
  box-shadow:0 10px 25px -10px rgba(0,102,255,.3)}
.sk img{width:30px;height:30px;object-fit:contain;flex-shrink:0;filter:brightness(1.05);
        transition:transform .35s cubic-bezier(.16,1,.3,1)}
.sk:hover img{transform:scale(1.12) rotate(-4deg)}
.sk .nome{display:block;font-size:.78rem;font-weight:700;letter-spacing:-.2px;
  margin-bottom:.35rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Il filo del livello sta SOTTO al nome, non sul bordo della pastiglia: nel
   sito vecchio e' li', ed e' corto — non arriva mai al bordo, cosi' si legge
   come un livello e non come una sottolineatura. */
.sk .bar{width:100%;height:3px;border-radius:2px;
  background:rgba(255,255,255,.06);overflow:hidden}
/* Il riempimento ha un alone: senza, tre pixel di gradiente su fondo scuro
   non si vedono proprio. E' cosi' anche di la'. */
/* La barretta NON si anima: e' alta quattro pixel, il movimento del
   gradiente non si vede, e quarantaquattro sfondi che si ridipingono a ogni
   fotogramma costavano nove millisecondi sulla pagina delle competenze
   (misurati: 25.6 ms per fotogramma con, 16.7 senza). Il gradiente ce l'ha,
   fermo. */
.sk .bar i{display:block;height:100%;border-radius:2px;
  background:linear-gradient(90deg,var(--blue),var(--cyan) 45%,var(--teal));
  box-shadow:0 0 8px rgba(42,255,213,.4)}
:root[data-tema="chiaro"] .sk{background:linear-gradient(135deg,rgba(0,0,0,.03),rgba(0,0,0,.015));
  border-color:rgba(0,0,0,.07)}
:root[data-tema="chiaro"] .sk .bar{background:rgba(10,20,40,.1)}

/* ─── Navigazione ────────────────────────────────────────────────────── */
/* La barra non tocca il bordo dello schermo: galleggia. E' il modo in cui
   Apple usa il vetro: nessun pezzo incollato ai lati. Il suo vetro sta piu'
   in basso, nella sezione dedicata. */
/* Le zone di sicurezza: con viewport-fit=cover il sito arriva sotto alle
   barre di Safari, e senza questo la barra ci finirebbe sotto. */
nav{position:fixed;top:calc(.75rem + env(safe-area-inset-top));left:var(--pad);right:var(--pad);z-index:20;
    display:flex;align-items:center;justify-content:space-between;
    padding:.68rem 1.15rem;border-radius:24px}
@media (max-width:700px){nav{top:.5rem;padding:.58rem .8rem;border-radius:20px}}
/* Marchio piu' scritta, come nel sito vecchio: il simbolo da solo su una
   barra alta quaranta pixel non si riconosce, la scritta da sola non e' un
   marchio. La scritta prende il gradiente, il simbolo no — e' gia' colorato
   di suo, e sovrapporgliene un altro lo sporcherebbe. */
nav .logo{display:flex;align-items:center;gap:.5rem;
  font-weight:800;letter-spacing:-.02em;font-size:1.05rem;text-decoration:none!important;
  transition:transform .4s cubic-bezier(.16,1,.3,1)}
nav .logo img{height:30px;width:auto;display:block;
  filter:drop-shadow(0 0 10px rgba(0,119,255,.35));
  transition:transform .45s cubic-bezier(.16,1,.3,1)}
nav .logo:hover img{transform:rotate(-8deg) scale(1.07)}
nav .logo span{background:var(--marchio);background-size:230% 100%;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:marchio-scorre 9s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){nav .logo span{animation:none}}
@media (max-width:760px){nav .logo img{height:26px}}
nav .voci{display:flex;gap:1.4rem}
nav .voci a{font-size:.8rem;color:var(--ink-dim);text-decoration:none!important;transition:color .3s}
nav .voci a:hover,nav .voci a[aria-current]{color:var(--ink)}
@media (max-width:700px){nav .voci{gap:.9rem}nav .voci a{font-size:.72rem}}
/* Selettore della lingua: sigle, non bandiere. Una bandiera indica un paese,
   non una lingua, e chi parla spagnolo fuori dalla Spagna non si riconosce
   in quella spagnola. */
nav .lingue{display:flex;gap:.5rem;margin-left:1.1rem;padding-left:1.1rem;
  border-left:1px solid var(--line)}
nav .lingue a{font-size:.68rem;letter-spacing:.06em;color:var(--ink-dim);
  text-decoration:none!important;transition:color .3s}
nav .lingue a:hover{color:var(--ink)}
nav .lingue a[aria-current]{font-weight:700}
@media (max-width:820px){nav .lingue{margin-left:.7rem;padding-left:.7rem;gap:.36rem}
  nav .lingue a{font-size:.62rem}}

/* ─── La barra sul telefono ───────────────────────────────────────────────
   A 393 px di larghezza cinque voci piu' cinque lingue non ci stanno: il logo
   e la prima voce si toccavano, le lingue sparivano e non c'era piu' modo di
   cambiarle. Sotto i 760 px la barra tiene solo il marchio e un bottone; il
   menu diventa un pannello che scende, con le destinazioni e le lingue.
   E' lo STESSO menu, non una copia: il contenitore cambia forma, i link sono
   quelli di sempre — cosi' non esiste un secondo posto da tenere allineato e
   il router continua a sostituirli come faceva.                            */
.menu{display:flex;align-items:center}
.apri-menu{display:none}

@media (max-width:760px){
  nav{padding:.55rem .7rem .55rem 1rem}
  .apri-menu{display:flex;flex-direction:column;justify-content:center;gap:5px;
    width:40px;height:34px;padding:0 9px;border:0;background:transparent;cursor:pointer;
    -webkit-tap-highlight-color:transparent}
  .apri-menu span{display:block;height:1.5px;border-radius:2px;background:var(--ink);
    transition:transform .35s cubic-bezier(.16,1,.3,1),opacity .25s,width .35s}
  .apri-menu span:first-child{width:20px}
  .apri-menu span:last-child{width:13px;align-self:flex-start;margin-left:9px}
  /* Aperto: le due righe diventano una croce. Non e' decorazione — dice che
     lo stesso bottone adesso chiude. */
  body.menu-aperto .apri-menu span:first-child{transform:translateY(3.2px) rotate(45deg)}
  body.menu-aperto .apri-menu span:last-child{width:20px;margin-left:0;
    transform:translateY(-3.2px) rotate(-45deg)}

  /* left/right a ZERO, non var(--pad): <nav> ha una transform, quindi e' lui
     il riquadro di riferimento anche per un elemento fisso. Con var(--pad) il
     margine si sommava due volte e il pannello usciva storto.
     E il fondo e' quasi pieno: a .72 il titolo del hero si leggeva attraverso
     il menu e le due scritte si sovrapponevano. Un menu deve coprire. */
  .menu{position:fixed;left:0;right:0;top:calc(100% + .5rem);
    flex-direction:column;align-items:stretch;gap:0;
    padding:.5rem;border-radius:20px;
    background:rgba(6,9,17,.94);border:1px solid rgba(255,255,255,.09);
    backdrop-filter:blur(26px) saturate(1.7);-webkit-backdrop-filter:blur(26px) saturate(1.7);
    box-shadow:inset 0 1px 0 rgba(255,255,255,.14),0 24px 50px -28px rgba(0,0,0,.95);
    opacity:0;transform:translateY(-10px) scale(.98);transform-origin:top right;
    pointer-events:none;visibility:hidden;
    transition:opacity .3s ease,transform .42s cubic-bezier(.16,1,.3,1),visibility .3s}
  body.menu-aperto .menu{opacity:1;transform:none;pointer-events:auto;visibility:visible}
  :root[data-tema="chiaro"] .menu{background:rgba(252,253,255,.96);border-color:rgba(10,20,40,.10)}

  nav .voci{flex-direction:column;gap:0}
  nav .voci a{padding:.82rem .9rem;border-radius:12px;font-size:.95rem;color:var(--ink)}
  nav .voci a[aria-current]{background:rgba(255,255,255,.06)}
  :root[data-tema="chiaro"] nav .voci a[aria-current]{background:rgba(10,20,40,.05)}
  /* Le lingue tornano tutte visibili: sul telefono erano l'unica cosa
     davvero irraggiungibile. */
  nav .lingue{margin:.35rem 0 0;padding:.6rem .3rem 0;gap:.15rem;
    border-left:0;border-top:1px solid var(--line);justify-content:space-between}
  nav .lingue a{display:block;padding:.5rem .55rem;border-radius:10px;font-size:.78rem}
  nav .lingue a:not([aria-current]){display:block}
}

/* ─── Agibilita' dei comandi ──────────────────────────────────────────────
   Tre cose che mancavano e che si sentono usandolo:
   1. un contorno visibile quando ci si arriva da tastiera. C'era
      outline:none su meta' dei comandi, e chi naviga col Tab non sapeva piu'
      dov'era;
   2. area toccabile piena. Il pallino del tema e' 36 px: sotto le dita si
      manca. Lo pseudo-elemento allarga la zona sensibile a 44 senza
      cambiare il disegno;
   3. il puntatore giusto e nessuna selezione accidentale del testo. */
:where(a,button,[role="button"]):focus-visible{
  outline:2px solid var(--cyan);outline-offset:3px;border-radius:8px}
#snd:focus-visible,#tema:focus-visible,.bottone:focus-visible,.apri-menu:focus-visible,
.apri3d:focus-visible,nav a:focus-visible{outline:2px solid var(--cyan);outline-offset:3px}
@media (pointer:coarse){
  #tema,.apri-menu,.apri3d{position:relative}
  #tema::after,.apri-menu::after,.apri3d::after{content:"";position:absolute;
    left:50%;top:50%;transform:translate(-50%,-50%);
    width:max(100%,44px);height:max(100%,44px)}
  nav .voci a,nav .lingue a{min-height:44px;display:flex;align-items:center}
}
button,.bottone{user-select:none;-webkit-user-select:none}

/* ─── Contatti: dati a sinistra, modulo a destra ──────────────────────────
   Le proporzioni sono quelle del sito vecchio: 1fr per i dati e 1.3fr per il
   modulo. Prima erano due schede pari, e il modulo — che e' la cosa per cui
   la pagina esiste — valeva quanto l'elenco degli indirizzi.             */
.contatti{display:grid;grid-template-columns:1fr 1.3fr;gap:1.4rem;
  margin-top:2.4rem;max-width:1180px;align-items:start}
@media (max-width:860px){.contatti{grid-template-columns:1fr}}
.dati{display:flex;flex-direction:column;gap:.9rem}
.dato{padding:1.15rem 1.3rem;border-radius:18px}
.dato h4{font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-fio);
  font-weight:600;margin-bottom:.45rem}
.dato p{font-size:.98rem;line-height:1.5;color:var(--ink);max-width:none;margin:0}
/* Solo i figli DIRETTI: dentro all'indirizzo di posta c'e' uno <span> che
   tiene la chiocciola (vedi posta() in build.mjs), e questa regola lo faceva
   diventare un blocco — "info", "@", "gpr.dev" finivano su tre righe. */
.dato > span{display:block;margin-top:.25rem;font-size:.85rem;color:var(--ink-dim)}
.modulo{padding:1.6rem 1.5rem;border-radius:22px}
/* I due bottoni sotto al modulo, come di la': il pieno manda il messaggio,
   l'altro apre la posta per chi preferisce scrivere dal suo programma. */
.azioni-modulo{display:flex;flex-wrap:wrap;gap:.6rem;margin-top:.4rem}
.azioni-modulo .bottone{padding:.78rem 1.3rem;font-size:.84rem}
/* La dedica: non e' una riga del racconto, e' una cosa a parte. Riquadro
   suo, filo verde acqua a lato, corsivo — il nome no, quello resta dritto.
   E' il formato del sito vecchio. */
.grazie{margin-top:1.4rem;padding:.9rem 1.1rem .9rem 1.4rem;
  border-left:3px solid var(--teal);border-radius:0 12px 12px 0;
  background:linear-gradient(90deg,rgba(42,255,213,.09),transparent 70%);
  font-size:.93rem;font-style:italic;color:var(--ink-dim);max-width:none}
.grazie strong{color:var(--ink);font-style:normal;font-weight:700}
:root[data-tema="chiaro"] .grazie{background:linear-gradient(90deg,rgba(0,144,120,.10),transparent 70%)}
.posta{margin-top:1rem;font-size:.86rem;color:var(--ink-fio)}
.posta a{font-weight:600}
/* L'indirizzo non va a capo. La chiocciola sta in un elemento a se' per non
   farsi mangiare da Cloudflare (vedi posta() in build.mjs), e quello apre
   due punti dove il testo puo' spezzarsi: "info", "@", "gpr.dev" su tre
   righe. Qui si tiene insieme. */
a[href^="mailto"],a[href^="/cdn-cgi/l/email-protection"]{white-space:nowrap}

/* ─── Il piede della pagina ───────────────────────────────────────────────
   Era una riga sola con la firma e l'indirizzo di posta, e su un sito che
   racconta sei ambiti e cinque lingue quella riga sembrava una dimenticanza.
   Qui ci sono le tre colonne che servono: chi, dove si va, come si scrive. */
/* Lo spazio in fondo tiene conto dei due comandi fissi in basso a sinistra:
   senza, l'ultima riga del piede ci finisce sotto e non si legge piu'. */
/* Il piede galleggiava sul campo di stelle come tutto il resto, e non si
   capiva dove finiva il sito. Qui il fondo scende piano fino a chiudere: non
   e' un pannello incollato, e' il buio che torna. Sopra ci sta lo stesso filo
   luminoso che separa le sezioni. */
/* Il piede e' quello del sito vecchio: quattro colonne nello stesso ordine —
   marchio, contatti, esplora, azienda — e sotto la riga di chiusura. Manca
   solo il richiamo grande in cima, che li' occupava mezzo schermo per
   ripetere una cosa che il sito dice gia'. E occupa meno spazio: prima
   sette centesimi di schermo sopra e settantaquattro pixel di aria sotto. */
footer{position:relative;z-index:2;color:var(--ink-dim);font-size:.9rem;
  padding:4vh var(--pad) calc(1.2rem + 68px + env(safe-area-inset-bottom));
  background:linear-gradient(180deg,transparent,rgba(4,6,14,.55) 22%,rgba(4,6,14,.88))}
:root[data-tema="chiaro"] footer{
  background:linear-gradient(180deg,transparent,rgba(244,246,251,.6) 22%,rgba(244,246,251,.92))}
footer::before{content:"";position:absolute;top:0;left:var(--pad);right:var(--pad);height:1px;
  pointer-events:none;
  background:linear-gradient(90deg,transparent 0%,rgba(0,102,255,.28) 22%,
             rgba(42,255,213,.34) 46%,rgba(0,204,255,.26) 72%,transparent 100%);
  background-size:220% 100%;animation:filo-scorre 11s linear infinite}
@media (prefers-reduced-motion:reduce){footer::before{animation:none}}
.piede{display:grid;gap:1.6rem 2.2rem;grid-template-columns:1.7fr 1fr 1fr 1fr;
  max-width:1180px;padding-bottom:1.5rem;border-bottom:1px solid var(--line)}
@media (max-width:980px){.piede{grid-template-columns:1fr 1fr;gap:1.6rem}
  .piede-marchio{grid-column:1/-1}}
@media (max-width:560px){.piede{grid-template-columns:1fr;gap:1.4rem}}
.piede-marchio p{margin-bottom:.9rem}
/* I social: cerchietti col marchio dentro, come li'. */
.piede-social{display:flex;gap:.5rem}
.piede-social a{display:flex;align-items:center;justify-content:center;
  width:34px;height:34px;border-radius:50%;color:var(--ink-dim);
  border:1px solid var(--line);background:rgba(255,255,255,.04);
  transition:color .3s,border-color .3s,background .3s,transform .3s}
.piede-social a:hover{color:var(--ink);border-color:rgba(0,204,255,.4);
  background:rgba(0,102,255,.12);transform:translateY(-2px)}
.piede-social svg{width:16px;height:16px}
:root[data-tema="chiaro"] .piede-social a{background:rgba(10,20,40,.04)}
/* Le voci con etichetta: "Sede", "P. IVA", "Codice ATECO". */
.piede-et{display:block;font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-fio);margin-bottom:.1rem}
.piede li{line-height:1.45}
.piede h5{font-size:.68rem;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-fio);
  font-weight:600;margin-bottom:.7rem}
.piede .marchio-piede{display:inline-flex;align-items:center;gap:.5rem;margin-bottom:.6rem;
  font-weight:800;font-size:1.02rem;letter-spacing:-.02em;text-decoration:none!important}
.piede .marchio-piede img{height:28px;width:auto;display:block}
.piede .marchio-piede span{background:var(--marchio);background-size:230% 100%;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:marchio-scorre 9s ease-in-out infinite}
.piede p{font-size:.88rem;line-height:1.55;max-width:34ch;color:var(--ink-dim)}
.piede ul{list-style:none;display:flex;flex-direction:column;gap:.45rem}
.piede a{font-size:.9rem}
.chiusa{display:flex;flex-wrap:wrap;gap:.5rem 1.4rem;justify-content:space-between;
  align-items:center;max-width:1180px;padding-top:1.1rem;font-size:.8rem;color:var(--ink-fio)}
.piede-sito a{font-weight:600}
/* Le lingue anche qui: chi arriva in fondo e vuole cambiarle non deve
   risalire fino alla barra. */
/* ─── La firma ────────────────────────────────────────────────────────────
   E' quella dei siti dei clienti, presa dal loro CSS: il marchio non e'
   un'immagine colorata ma una MASCHERA riempita col colore del testo, cosi'
   sta nella riga come una lettera; e "GPR" e' nascosto dietro, con larghezza
   zero, e scorre fuori al passaggio.
   La larghezza che si anima e' max-width e non width: su un elemento in linea
   width non fa niente.                                                     */
.riga-firma{color:var(--ink-fio)}
.firma{display:inline-flex;align-items:center;vertical-align:middle;
  text-decoration:none!important;color:var(--ink-fio);transition:color .3s ease}
.firma:hover{color:var(--ink)}
.firma .firma-marchio{display:inline-block;width:19px;height:19px;flex-shrink:0;
  background-color:currentColor;
  -webkit-mask:url(/assets/images/gpr-mark.png) no-repeat center / contain;
          mask:url(/assets/images/gpr-mark.png) no-repeat center / contain;
  transition:background-color .3s ease,transform .3s ease}
.firma .firma-sigla{display:inline-block;overflow:hidden;max-width:0;opacity:0;
  margin-left:0;white-space:nowrap;letter-spacing:.02em;font-weight:800;
  transform:translateX(-4px);
  transition:max-width .35s cubic-bezier(.4,0,.2,1),opacity .25s ease .05s,
             margin-left .35s cubic-bezier(.4,0,.2,1),transform .35s cubic-bezier(.4,0,.2,1)}
.firma:hover .firma-marchio{transform:scale(1.08)}
.firma:hover .firma-sigla{max-width:60px;opacity:1;margin-left:6px;transform:translateX(0)}
@media (prefers-reduced-motion:reduce){
  .firma .firma-sigla{transition:opacity .2s}
}
.piede-lingue{display:flex;gap:.7rem}
.piede-lingue a{font-size:.78rem;letter-spacing:.06em;color:var(--ink-fio)}
.piede-lingue a[aria-current]{color:var(--ink);font-weight:700}
@media (prefers-reduced-motion:reduce){.piede .marchio-piede span{animation:none}}

/* Transizione tra destinazioni: il contenuto sfuma, la scena 3D resta viva. */
main{transition:opacity .32s ease}
body.navigating main{opacity:0}
/* Cambio di lingua: un velo, non una dissolvenza. */
body.navigating.lingua main{opacity:.45;transition:opacity .17s ease}

/* ─── Puntatore personalizzato (solo mouse vero) ─────────────────────── */
@media (hover:hover) and (pointer:fine){
  /* Il puntatore e' il pallino blu: la freccia e la manina del sistema non
     si devono vedere da nessuna parte, nemmeno sui bottoni. Prima erano
     coperti solo body, a e button — bastava un'etichetta, un input o una
     lastra di vetro e la manina tornava fuori. */
  *,*::before,*::after{cursor:none!important}
  /* Nemmeno il visualizzatore 3D: dentro al suo shadow DOM mette
     cursor:grab e poi grabbing al pointerdown. Lo si spegne da fuori qui e
     da dentro con una regola iniettata nel suo shadow root (vedi app.js) —
     e' la stessa cosa che fa il sito vecchio. */
  model-viewer{cursor:none!important}
  #cdot,#cring{position:fixed;top:0;left:0;z-index:60;pointer-events:none;border-radius:50%;
               will-change:transform;opacity:0;
               transition:opacity .35s,width .28s cubic-bezier(.16,1,.3,1),
                          height .28s cubic-bezier(.16,1,.3,1),
                          margin .28s cubic-bezier(.16,1,.3,1),
                          border-color .3s,background .3s,box-shadow .3s}
  /* Uguale al sito attuale: blu, non verde acqua, e l'anello e' una goccia
     di vetro — sfocatura del fondo, non solo un cerchio colorato.        */
  /* il pallino sta DAVANTI all'anello */
  #cdot{z-index:61;width:9px;height:9px;margin:-4.5px 0 0 -4.5px;background:var(--blue);
        box-shadow:0 0 8px rgba(0,119,255,.75)}
  #cring{width:32px;height:32px;margin:-16px 0 0 -16px;
         border:1px solid rgba(0,119,255,.55);background:rgba(0,119,255,.22);
         backdrop-filter:blur(3px) saturate(1.4);-webkit-backdrop-filter:blur(3px) saturate(1.4)}
  body.cursor-ready #cdot,body.cursor-ready #cring{opacity:1}
  body.cursor-hot #cring{width:40px;height:40px;margin:-20px 0 0 -20px;
    border-color:rgba(0,119,255,.85);background:rgba(0,119,255,.3);
    box-shadow:0 0 20px rgba(0,119,255,.35)}
  /* Sopra a un modello il puntatore diventa il segno del "gira": l'anello
     si allarga e dentro ci compare una freccia circolare che ruota piano.
     Il pallino si toglie di mezzo, se no coprirebbe la freccia. */
  body.cursor-3d #cring{width:58px;height:58px;margin:-29px 0 0 -29px;
    border-color:rgba(0,119,255,.9);background:rgba(0,119,255,.18);
    box-shadow:0 0 28px rgba(0,119,255,.5)}
  body.cursor-3d #cdot{opacity:0}
  #cring::after{content:"\21BB";position:absolute;top:50%;left:50%;
    width:24px;height:24px;margin:-12px 0 0 -12px;
    display:flex;align-items:center;justify-content:center;
    color:rgba(0,119,255,1);font-size:18px;font-weight:700;
    text-shadow:0 0 10px rgba(0,119,255,.75);
    opacity:0;transition:opacity .3s;
    /* La proprieta' `rotate` e non `transform`: il transform dell'anello lo
       riscrive il JavaScript a ogni fotogramma, e i due si darebbero
       fastidio a vicenda. */
    rotate:0deg;animation:gira-freccia 2.4s linear infinite;will-change:rotate}
  body.cursor-3d #cring::after{opacity:1}
  @keyframes gira-freccia{from{rotate:0deg}to{rotate:360deg}}
  @media (prefers-reduced-motion:reduce){#cring::after{animation:none}}
}
@media (hover:none),(pointer:coarse){#cdot,#cring{display:none}}

/* ─── Interruttore audio ─────────────────────────────────────────────── */
/* Interruttore del tema: stessa pastiglia del suono, accanto ad essa. */
#tema{position:fixed;left:calc(var(--pad) + 118px);bottom:calc(2rem + env(safe-area-inset-bottom));z-index:20;
  display:flex;align-items:center;justify-content:center;width:36px;height:36px;
  padding:0;border-radius:50%;color:var(--ink-dim);cursor:pointer;
  transition:color .35s,border-color .35s,background .35s;-webkit-tap-highlight-color:transparent}
#tema:hover,#tema:focus-visible{color:var(--ink);outline:none}
#tema svg{width:18px;height:18px}
#tema .t-luna{display:none}
:root[data-tema="chiaro"] #tema .t-sole,
:root[data-tema="chiaro"] #tema .t-raggi{display:none}
:root[data-tema="chiaro"] #tema .t-luna{display:block}

/* ─── Vetro della barra e dei due bottoni ─────────────────────────────────
   Questi tre non sono lastre del motore, e non possono esserlo: il motore
   disegna sul canvas, che sta sotto all'intero documento, quindi il
   contenuto che scorre gli passava DAVANTI — il titolo del hero copriva la
   scritta GPR. L'unica cosa che vede il DOM dietro di se' e' il
   backdrop-filter del browser, e allora il vetro qui lo fa lui.
   Si perde la rifrazione (il browser sa sfocare e saturare, non piegare:
   provato anche il filtro SVG nel backdrop, Safari accetta la proprieta' e
   non applica lo spostamento) e si guadagna l'ordine giusto: tutto ci passa
   SOTTO, sfocandosi.
   I bordi rifanno a mano quello che sul motore esce dalla geometria: un filo
   chiaro sopra e uno piu' debole sotto, i fianchi scuri, un alone dentro al
   filo alto. Le ombre interne con solo offset seguono la curvatura da sole —
   quella con offset verticale si assottiglia verso i fianchi, quelle
   orizzontali verso l'alto e il basso: e' la stessa sfumatura che nello
   shader viene dalla normale del bordo.
   translateZ(0) li stacca su un layer loro: senza, Safari ri-sfoca l'intera
   pagina sotto a ogni fotogramma del canvas.                              */
nav,#snd,#tema{
  background:rgba(8,11,20,.55);
  border:1px solid rgba(255,255,255,.06);
  backdrop-filter:blur(26px) saturate(1.7);
  -webkit-backdrop-filter:blur(26px) saturate(1.7);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.15),
             inset 0 -1px 0 rgba(255,255,255,.055),
             inset 1px 0 0 rgba(0,0,0,.35),
             inset -1px 0 0 rgba(0,0,0,.35),
             inset 0 3px 9px -6px rgba(255,255,255,.16),
             0 18px 44px -26px rgba(0,0,0,.95);
  transform:translateZ(0)}
/* ?barra=3d — l'ottica la disegna il motore (vedi app.js). Qui il CSS deve
   togliersi di mezzo: niente fondo, niente bordi, niente ombra, e la
   sfocatura ridotta al minimo che serve a far affondare il testo. Piu' di
   cosi' e si sfoca anche l'ottica, che sta li' sotto. */
/* ?barra=puro — l'ottica del motore senza niente sopra. Il contenuto non ci
   passa sotto: si dissolve prima, dentro la finestra fissa che app.js mette
   attorno a quel che scorre. Le due fasce corrispondono alla barra in alto e
   ai due bottoni in basso, con un dito di margine perche' la dissolvenza
   deve essere finita PRIMA del bordo del vetro, non sopra. */
html.barrapura #finestra{position:fixed;inset:0;z-index:2;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,transparent 58px,#000 112px,
                     #000 calc(100% - 118px),transparent calc(100% - 64px),transparent 100%);
  mask-image:linear-gradient(180deg,transparent 0,transparent 58px,#000 112px,
             #000 calc(100% - 118px),transparent calc(100% - 64px),transparent 100%);
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-size:100% 100%;mask-size:100% 100%}
html.barra3d nav,html.barra3d #snd,html.barra3d #tema,
:root[data-tema="chiaro"].barra3d nav,:root[data-tema="chiaro"].barra3d #snd,
:root[data-tema="chiaro"].barra3d #tema{
  background:transparent;border-color:transparent;box-shadow:none;
  backdrop-filter:blur(5px) saturate(1.2);
  -webkit-backdrop-filter:blur(5px) saturate(1.2)}
/* Deve stare DOPO il blocco qui sopra: stesso peso, vince l'ultimo. Qui
   niente sfocatura del tutto — l'ottica del motore resta nitida. */
html.barrapura nav,html.barrapura #snd,html.barrapura #tema{
  backdrop-filter:none;-webkit-backdrop-filter:none}

#snd{position:fixed;left:var(--pad);bottom:calc(2rem + env(safe-area-inset-bottom));z-index:20;display:flex;align-items:center;gap:.55rem;
  padding:.6rem .95rem;font:600 .68rem/1 var(--font);letter-spacing:.18em;text-transform:uppercase;
  color:var(--ink-fio);border-radius:40px;
  cursor:pointer;transition:color .35s,border-color .35s,background .35s;-webkit-tap-highlight-color:transparent}
/* All'hover la lastra si schiarisce appena, come una superficie che prende
   piu' luce. Il bordo restava a .30 di bianco: contro i .06 di riposo era uno
   scatto, non un'accensione. */
#snd:hover,#snd:focus-visible,#tema:hover,#tema:focus-visible{
  color:var(--ink);border-color:rgba(255,255,255,.16);
  background:rgba(16,22,38,.6);outline:none}
:root[data-tema="chiaro"] #snd:hover,:root[data-tema="chiaro"] #snd:focus-visible,
:root[data-tema="chiaro"] #tema:hover,:root[data-tema="chiaro"] #tema:focus-visible{
  border-color:rgba(10,20,40,.14);background:rgba(255,255,255,.72)}
#snd .ico{width:9px;height:9px;border-radius:50%;background:#4d5878;transition:background .35s,box-shadow .35s}
#snd[aria-pressed="true"]{color:var(--ink)}
#snd[aria-pressed="true"] .ico{background:var(--marchio);box-shadow:0 0 10px rgba(0,204,255,.7)}

/* Etichetta della skill puntata nella costellazione 3D: UN solo elemento
   aggiornato, non uno per nodo. */
#tip{position:fixed;z-index:7;pointer-events:none;opacity:0;transform:translate(-50%,-140%);
  padding:.42rem .75rem;border-radius:9px;background:rgba(6,9,18,.9);border:1px solid rgba(0,204,255,.4);
  font:600 .78rem/1 var(--font);color:var(--ink);white-space:nowrap;transition:opacity .2s}
#tip.on{opacity:1}

#perf{position:fixed;top:8px;right:8px;z-index:99;font:11px/1.4 ui-monospace,Menlo,monospace;
  color:#0fa;background:rgba(0,0,0,.75);border:1px solid #0fa;border-radius:5px;padding:5px 7px;
  white-space:pre;display:none;pointer-events:none}

/* ─── Modulo dei contatti ────────────────────────────────────────────── */
#scrivi{display:flex;flex-direction:column;gap:.85rem;margin-top:.4rem}
#scrivi label{display:flex;flex-direction:column;gap:.32rem;
  font-size:.72rem;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-dim)}
#scrivi input,#scrivi textarea{font:inherit;font-size:.94rem;color:var(--ink);
  background:rgba(255,255,255,.05);border:1px solid var(--line);border-radius:12px;
  padding:.62rem .8rem;outline:none;transition:border-color .25s,background .25s;
  text-transform:none;letter-spacing:normal;resize:vertical}
#scrivi input:focus,#scrivi textarea:focus{border-color:var(--cyan);background:rgba(255,255,255,.08)}
:root[data-tema="chiaro"] #scrivi input,:root[data-tema="chiaro"] #scrivi textarea{
  background:rgba(10,20,40,.04)}
:root[data-tema="chiaro"] #scrivi input:focus,:root[data-tema="chiaro"] #scrivi textarea:focus{
  background:rgba(10,20,40,.06)}
/* Il bottone di invio E' un .bottone.primario: qui restano solo le misure.
   Aveva anche colore e fondo suoi, e siccome il selettore ha un ID vinceva
   sulla classe — testo quasi nero (#02101f) sul fondo blu. Il colore scuro
   era giusto ai tempi del gradiente verde acqua, non piu' da quando il
   bottone pieno e' blu. */
#scrivi button{font:inherit;font-size:.9rem;font-weight:600;cursor:pointer;
  padding:.85rem 1.5rem;align-self:flex-start}
#scrivi button:hover{transform:translateY(-2px);filter:brightness(1.08)}
#scrivi button[disabled]{opacity:.55;cursor:default;transform:none}
/* La trappola non deve essere raggiungibile ne' col dito ne' con Tab, ma
   nemmeno nascosta con display:none: cosi' i programmi automatici non la
   riconoscono come trappola e la riempiono lo stesso. */
#scrivi .esca{position:absolute;left:-9999px;width:1px;height:1px;opacity:0;pointer-events:none}
#scrivi .esito{font-size:.86rem;min-height:1.2em;margin:0}
/* L'esito resta in tinta piatta: deve dire una cosa sola e subito, e un
   testo ritagliato sul gradiente si legge peggio quando conta di piu'. */
#scrivi .esito.ok{color:var(--teal)}
#scrivi .esito.no{color:#ff8080}
