/* ============================================================
   FRANCESCO — XR ARCHIVE  ·  stylesheet
   Design system: Phantom Studios (strict)
   ------------------------------------------------------------
   INDICE (cerca l'etichetta per saltare alla sezione)
     1.  TOKENS & BASE ............ @font-face, :root (variabili), reset
     1b. DESIGN SYSTEM ........... tipografia h1–h6/body + griglia 12-col
     2.  PRELOADER
     3.  MODAL (generico)
     4.  PAGE FX ................... edge blur + vignette
     5.  TOP BAR .................. logo centrato
     6.  ARCHIVE / HUD ............ canvas griglia + caption hover
     7.  STATUS ................... fusi orari + audio
     8.  FILTERS .................. pannello filtri archivio
     9.  COOKIE BANNER
     10. SECTIONS (shell) ......... contenitore pagine interne
     11. ABOUT
     12. INDEX LIST ............... liste journal/work
     13. JOURNAL .................. griglia + hero
     14. CONTACT
     15. ARTICLE .................. lettura articolo
     16. PROJECT ................. case study
     17. LEGAL ................... privacy / cookie
     18. CTA / BUTTONS
     19. CASE ANATOMY ............ blocchi case study
     20. TITLES .................. normalizzazione pesi (ULTIMO blocco)
   Ogni sezione è marcata da un header di commento con il suo NOME.
   Le VARIABILI di design (colori, spaziature, type scale) stanno in :root,
   quindi per ritoccare il look parti da lì.
   ============================================================ */

/* ---- TIPOGRAFIA: Helvetica Neue LT Pro (webfont) ----
   UNA sola famiglia su tutto il sito — testo, etichette, titoli, canvas
   delle card. Niente font di sistema, niente secondo carattere: se serve un
   contrasto lo danno corpo, peso, maiuscolo e tracking, non un'altra faccia.

   Tre tagli in licenza, convertiti in woff2 (~22KB l'uno):
     45 Light  → 300
     55 Roman  → 400–500   ← il peso di lavoro del sito
     85 Heavy  → 700–900

   Il Roman copre un INTERVALLO 400–500 apposta: il design system chiede 500
   per i titoli (--w-semibold) e senza l'intervallo il browser lo
   risolverebbe sintetizzando o ripiegando, con un peso incerto fra i due.
   Dichiarandolo, un font-weight:var(--w-semibold) è esattamente il Roman, senza finte
   grassettature. Se un giorno vuoi i titoli più decisi, punta
   --w-semibold a 700 e prende l'Heavy: il file è già qui.

   `sans-serif` in coda NON è una seconda scelta tipografica: è la rete se
   un .woff2 non arriva, per non lasciare la pagina senza testo. */
/* ── ZURICH SANS — tre facce reali, tre pesi distinti ──
   I file dichiarano internamente usWeightClass 375 / 475 / 775, valori fuori
   scala che non significano niente per il CSS: qui li rimappo sui gradini
   standard 300 / 400 / 600, ed è questa mappatura a contare per il browser.
   NIENTE range di peso (il vecchio "400 500"): un range dice al browser che
   una faccia copre due gradini, ed è il motivo per cui prima ogni titolo a
   500 usciva identico al testo. Un peso, una faccia. */
@font-face{
  font-family:'ZurichSans';
  src:url('../assets/fonts/ZurichSans-Light.woff2') format('woff2'),
      url('../assets/fonts/ZurichSans-Light.ttf') format('truetype');
  font-weight:300;font-style:normal;font-display:swap;
}
@font-face{
  font-family:'ZurichSans';
  src:url('../assets/fonts/ZurichSans-Regular.woff2') format('woff2'),
      url('../assets/fonts/ZurichSans-Regular.ttf') format('truetype');
  font-weight:400;font-style:normal;font-display:swap;
}
@font-face{
  font-family:'ZurichSans';
  src:url('../assets/fonts/ZurichSans-SemiBold.woff2') format('woff2'),
      url('../assets/fonts/ZurichSans-SemiBold.ttf') format('truetype');
  font-weight:600;font-style:normal;font-display:swap;
}

:root{
  color-scheme:dark;
  /* ── colors ── */
  --bg:#000000;
  --ink:#ffffff;
  --border:rgba(255,255,255,0.1);
  --muted:#666666;
  --accent:#ff6347;

  /* ── type families ── */
  --font:'ZurichSans',sans-serif;
  /* --serif e --mono NON sono altre famiglie: sono alias della stessa, tenuti
     perché mezzo stylesheet li nomina. Le "etichette mono" restano etichette
     per maiuscolo + tracking + corpo, non per cambio di faccia. */
  --serif:var(--font);
  --mono:var(--font);

  /* ════ TYPE SYSTEM ════
     3 title sizes · 2 letter-spacings · 2 weights · 2 styles (uppercase/normal) */
  --fs-display:46px;  /* hero titles, big stats              */
  --fs-title:  24px;  /* section/card headings               */
  --fs-sub:    17px;  /* legal sections, HUD, list titles    */
  --fs-body:   16px;  /* body text                           */
  --fs-small:  14px;  /* nav, CTA, buttons                   */
  --fs-label:  12px;  /* etichette maiuscole con tracking      */

  --ls-title: -0.5px; /* titles, buttons, UI text            */
  --ls-label:  0.1em; /* uppercase mono labels               */

  /* ── pesi ──
     Tre facce vere, quindi tre gradini che si vedono davvero. Prima --w-regular
     e --w-semibold erano 400 e 500 ma puntavano allo STESSO file: la gerarchia
     stava in piedi solo sulle dimensioni. Ora 600 è una faccia a sé.
     USALI CON PARSIMONIA — la regola del sito è:
       400 regular  → tutto il testo. È il valore di default, non si dichiara.
       600 semibold → titoli, pulsanti, etichette che devono pesare.
       300 light    → SOLO sul display (46px), dove il chiaro fa eleganza e
                      non fragilità. Sotto i 30px non usarlo: si sfarina. */
  --w-light:300; --w-regular:400; --w-semibold:600;

  /* ── line-heights ── */
  --lh-tight:1.08; --lh-snug:1.25; --lh-normal:1.5; --lh-relaxed:1.65;

  /* ── legacy aliases (components still referencing old names) ── */
  --t-display:var(--fs-display);
  --t-hero:   var(--fs-display);
  --t-h:      var(--fs-title);
  --t-lg:     20px;           /* lead text — kept at 20px for reading comfort */
  --t-body:   var(--fs-body);
  --t-sm:     var(--fs-small);
  --t-cap:    12px;
  --t-mono:   var(--fs-label);
  --t-md:     var(--fs-body); /* was undefined; maps to body */

  /* ── spacing (base-8) ── */
  --s8:8px;--s12:12px;--s16:16px;--s24:24px;--s32:32px;--s40:40px;--s48:48px;--s62:62px;--s88:88px;
  /* ── fascia header ──
     --topbar-h è l'altezza della topbar; --rail-top è la riga su cui si
     appoggia TUTTO il resto della chrome fissa in alto (filtri, orologi,
     handtrack, tasto indietro). Prima erano tutti a top:24px, cioè DENTRO
     la topbar: si sovrapponevano al logo e alle azioni, e la topbar — che
     è larga quanto la finestra — si prendeva i loro click. */
  --topbar-h:62px;
  --rail-top:calc(var(--topbar-h) + var(--s16));
  /* ── margine orizzontale della chrome fissa ──
     UNA sola misura per header, menu, footer, banner e dock: 82px. Cambiala
     qui e tutta la cornice del sito si riallinea insieme. Su mobile scende a
     --grid-margin-sm (vedi le media query in fondo alle rispettive sezioni). */
  --pad-x:62px;
  /* dock in basso al centro: distanza dal fondo + altezza dei bottoni */
  --dock-bottom:62px;
  --dock-h:48px;
  /* DESIGN RULE: media & containers are square-cornered (0). Interactive pills
     (nav, CTA, chips) keep their own border-radius:999px on purpose. */
  --radius:0px;

  /* ════ LAYOUT GRID (Bootstrap-style, internal pages) ════
     12 columns, container up to 1440px, 16px gutter, 48px outer margin. */
  --grid-cols:12;
  --grid-gutter:16px;       /* gap between columns */
  --grid-margin:48px;       /* outer page margin (desktop) */
  --grid-margin-sm:24px;    /* tablet/mobile margin (still base-8) */
  --maxw:1440px;            /* container max width */

  --ease:cubic-bezier(.22,.61,.36,1);
  /* la curva del vetro: parte decisa e si posa lenta, come una massa che si
     ferma da sé. Serve una seconda curva perché --ease è tarata sulle entrate
     di pagina — su un hover di 400ms leggeva molle. */
  --ease-glass:cubic-bezier(1,0,.4,1);

  /* ═══════ LIQUID GLASS ═══════
     I comandi in vetro del sito (switch lingua, tondo XR, LinkedIn, banner
     cookie) prima erano un gradiente bianco al 16% più un bordo al 10%: da
     lontano è grigio, non vetro. Il vetro vero non si legge dal fondo, si
     legge dal BORDO — la luce che entra nello spessore e si accumula su due
     lati opposti mentre gli altri due restano in ombra.

     Da qui in poi il bordo lo fa una PILA di ombre interne, non un `border`.
     Un border è una cornice di spessore costante: gira tutto intorno con la
     stessa forza e per questo legge come contorno disegnato. Le ombre interne,
     invece, si possono spingere ognuna da una direzione diversa — ed è
     l'asimmetria fra loro (luce da sopra-sinistra, rientro da sotto-destra) a
     dare lo spessore.

     Le due manopole:
       --gl-light  quanto è forte la luce sui bordi accesi
       --gl-dark   quanto è profonda l'ombra sui bordi in ombra
     In chiaro si invertono di peso (vedi il blocco [data-theme="light"]):
     su fondo chiaro il vetro riceve meno luce di taglio e più ombra propria,
     e tenere gli stessi valori del tema scuro lo farebbe sparire nel fondo.

     color-mix() invece di rgba() letterali: così UN numero cambia tutta la
     pila invece di dover riscrivere dodici alfa a mano. */
  --gl-tint:#bfc2c8;        /* la tinta del vetro: grigio appena freddo, non bianco puro */
  --gl-light:#ffffff;
  --gl-dark:#000000;
  --gl-reflex-light:1;      /* moltiplicatore luce  */
  --gl-reflex-dark:1;       /* moltiplicatore ombra */
  --gl-fill:14%;            /* quanto la lastra vela il fondo */
  --gl-blur:14px;
  --gl-sat:180%;

  /* ───── ARCHIVE FX — tweak these freely ───── */
  --edge-blur:3px;          /* outer edge blur strength */
  --edge-blur-start:63%;    /* where the blur begins (higher = only the outer frame blurs) */
  --vignette-start:50%;     /* fin dove il centro resta pulito (↑ = vignetta più stretta) */
  --vignette-alpha:.26;     /* vignette darkness 0–1 — buio massimo agli angoli */
  --vignette-rgb:0,0,0;     /* vignette colour (RGB) */
}

/* ───── LIGHT THEME ───── */
:root[data-theme="light"]{
  color-scheme:light;
  --bg:#fbfbfb;
  --ink:#0b0b0b;
  --border:rgba(0,0,0,.16);
  --muted:#8a8a86;
  --accent:#ff6347;
  --vignette-rgb:120,118,112; /* soft light vignette instead of black */
  --vignette-alpha:.30;       /* sul chiaro serve un filo in più che sul nero */

  /* vetro in chiaro: si scambiano i pesi. Su fondo bianco un bordo bianco non
     esiste — quello che si vede di una lastra su carta è la sua OMBRA, non il
     suo colmo. Quindi la luce cala e l'ombra raddoppia. Il velo invece sale
     (14% → 22%): senza, la lastra su fondo chiaro non si stacca affatto. */
  --gl-tint:#ffffff;
  --gl-reflex-light:.55;
  --gl-reflex-dark:2;
  --gl-fill:22%;
}

*{margin:0;padding:0;box-sizing:border-box;}
html,body{height:100%;}
body{
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font);
  font-size:var(--fs-body);
  font-weight:var(--w-regular);
  line-height:var(--lh-normal);
  /* i tre pesi di Zurich Sans sono disegnati: se una regola ne chiede uno che
     non c'è, il browser deve scendere sulla faccia più vicina, non inventarne
     una ingrassando i contorni. */
  font-synthesis-weight:none;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow:hidden;            /* archive default */
}
body[data-view="about"],
body[data-view="journal"],
body[data-view="contact"],
body[data-view="project"],
body[data-view="article"],
body[data-view="legal"]{overflow-y:auto;overflow-x:hidden;}

a{color:inherit;text-decoration:none;}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer;}
.mono{font-family:var(--mono);font-size:var(--fs-label);line-height:1.1;letter-spacing:var(--ls-label);text-transform:uppercase;color:var(--muted);}
::selection{background:var(--accent);color:#000;}

/* ============================================================
   DESIGN SYSTEM — TYPOGRAPHY & 12-COL GRID (pagine interne)
   ------------------------------------------------------------
   • Gerarchia titoli: h1–h6  (o classi .t-h1 … .t-h6)
   • Body: .body-lg / .body-md / .body-sm / .body-xs
   • Pesi: .w-light (300) · .w-regular (400) · .w-semibold (600) — Zurich Sans
   • Layout: .container (boxed ≤1440, margine 48) + .grid (12 col, gap 16)
     con .col-1 … .col-12 ; .full-bleed per le hero a tutta viewport.
   ============================================================ */
/* — gerarchia titoli: 3 size (display · title · sub), 2 pesi, tracking stretto — */
h1,h2,h3,h4,h5,h6,
.t-h1,.t-h2,.t-h3,.t-h4,.t-h5,.t-h6{
  font-family:var(--font);font-weight:var(--w-semibold);
  line-height:var(--lh-tight);letter-spacing:var(--ls-title);
  text-transform:none;
}
/* il display è l'UNICO posto dove entra il Light: a 46px il chiaro legge come
   eleganza, e il contrasto col 600 dei titoli minori dà la gerarchia che prima
   mancava. Sotto i ~30px il Light si sfarina: non estenderlo. */
h1,.t-h1{font-size:var(--fs-display);font-weight:var(--w-light);}
h2,.t-h2{font-size:var(--fs-title);}
h3,.t-h3{font-size:var(--fs-title);line-height:var(--lh-snug);}
h4,.t-h4{font-size:var(--fs-sub);line-height:var(--lh-snug);}
h5,.t-h5{font-size:var(--fs-sub);line-height:var(--lh-snug);}
h6,.t-h6{font-size:var(--fs-small);line-height:var(--lh-snug);}
/* — body tiers — */
.body-lg{font-size:20px;line-height:var(--lh-relaxed);font-weight:var(--w-regular);}
.body-md{font-size:var(--fs-body);line-height:var(--lh-normal);font-weight:var(--w-regular);}
.body-sm{font-size:var(--fs-small);line-height:var(--lh-normal);font-weight:var(--w-regular);color:var(--muted);}
.body-xs{font-size:12px;line-height:var(--lh-normal);font-weight:var(--w-regular);color:var(--muted);}
/* — pesi — */
.w-light{font-weight:var(--w-light);}
.w-semibold{font-weight:var(--w-semibold);}
.w-regular{font-weight:var(--w-regular);}

/* — container: boxed fino a 1440, centrato, margine 48 (24 su mobile) — */
.container{width:100%;max-width:var(--maxw);margin-inline:auto;
  padding-inline:var(--grid-margin);}
/* — grid 12 colonne, gutter 16, contenuto a bandiera (allineato a sinistra) — */
.grid{display:grid;grid-template-columns:repeat(var(--grid-cols),minmax(0,1fr));
  gap:var(--grid-gutter);align-items:start;}
/* column-span helpers */
.col-1{grid-column:span 1}.col-2{grid-column:span 2}.col-3{grid-column:span 3}
.col-4{grid-column:span 4}.col-5{grid-column:span 5}.col-6{grid-column:span 6}
.col-7{grid-column:span 7}.col-8{grid-column:span 8}.col-9{grid-column:span 9}
.col-10{grid-column:span 10}.col-11{grid-column:span 11}.col-12{grid-column:span 12}
/* — full-bleed: rompe il box e va a tutta larghezza viewport (solo hero/immagini) — */
.full-bleed{width:100vw;margin-left:calc(50% - 50vw);}
/* tablet: la griglia collassa a 6, poi a 1 su mobile (resta base-8) */
@media (max-width:1000px){
  .grid{grid-template-columns:repeat(6,minmax(0,1fr));}
  [class*="col-"]{grid-column:span 6;}
}
@media (max-width:640px){
  .container{padding-inline:var(--grid-margin-sm);}
  .grid{grid-template-columns:1fr;gap:var(--grid-gutter);}
  [class*="col-"]{grid-column:span 1;}
}

/* ============================================================
   PHANTOM PATTERNS — pattern editoriali condivisi (project/article/about)
   ------------------------------------------------------------
   • .rule            divider orizzontale 1px
   • .spec            riga "specifica": label sx (col 1–3) / valore dx (col 4–12)
   • .lead-xl         caption editoriale sotto l'hero (24–32px)
   • .case-gal/.case-pair  galleria verticale singola/coppia
   • .sr/.sr-hero     scroll-reveal (IntersectionObserver, vedi main.js)
   • .subnav          tab secondarie (About)
   ============================================================ */
.rule{border:0;height:1px;background:var(--border);margin:0;width:100%;}

/* riga spec — il pattern label-sinistra/valore-destra che si ripete identico */
.spec{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--grid-gutter);
  padding:var(--s40) 0;text-align:left;}
.spec__label{grid-column:1/4;font-family:var(--mono);font-size:var(--fs-label);text-transform:uppercase;
  letter-spacing:var(--ls-label);color:var(--muted);font-weight:var(--w-regular);padding-top:6px;
  align-self:start;position:sticky;top:calc(var(--s88) + var(--s24));}
.spec__value{grid-column:4/13;}
/* variante prosa: piena larghezza del valore (4–12), testo secondario, highlight finale bold */
.spec__prose{grid-column:4/13;font-size:var(--fs-body);line-height:var(--lh-relaxed);
  color:color-mix(in srgb, var(--ink) 86%, transparent);}
.spec__prose p+p{margin-top:var(--s16);}
.spec__hl{display:block;margin-top:var(--s32);font-size:var(--fs-sub);font-weight:var(--w-semibold);
  line-height:var(--lh-snug);color:var(--ink);}
/* sub-griglia del valore: le 9 colonne 4→12 replicate 1:1 (stessi track, stesso gutter),
   così ogni blocco interno cade esatto sulle colonne della griglia madre */
.spec__value--grid{display:grid;grid-template-columns:repeat(9,minmax(0,1fr));
  gap:var(--grid-gutter);align-items:start;}
@media (max-width:1000px){
  .spec{grid-template-columns:1fr;gap:var(--s8);padding:var(--s32) 0;}
  .spec__label,.spec__value,.spec__prose{grid-column:auto;position:static;}
  .spec__value--grid{grid-template-columns:repeat(6,minmax(0,1fr));}
}
@media (max-width:640px){
  .spec__value--grid{grid-template-columns:1fr;}
}


/* galleria case: sequenza verticale, singole 16/9 + coppie 4/3 (boxed; solo l'hero è full-vw) */
.case-gal{display:flex;flex-direction:column;gap:var(--grid-gutter);margin:var(--s48) 0;}
.case-gal .plx{aspect-ratio:16/9;}
.case-pair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--grid-gutter);}
.case-pair .plx{aspect-ratio:4/3;}
@media (max-width:640px){.case-pair{grid-template-columns:1fr;}}

/* scroll-reveal — fade + rise all'ingresso in viewport (~85%), easing morbido */
.sr{opacity:0;transform:translateY(36px);transition:opacity .8s var(--ease),transform .8s var(--ease);}
.sr.is-in{opacity:1;transform:none;}
/* hero: fade + leggero scale-in (1.04 → 1) */
.sr-hero{opacity:0;transform:scale(1.04);transition:opacity 1s var(--ease),transform 1.2s var(--ease);}
.sr-hero.is-in{opacity:1;transform:none;}
/* stagger nei gruppi (pillole, coppie, card related): ritardo crescente sui figli */
.sr-stag>*:nth-child(2){transition-delay:.09s;}
.sr-stag>*:nth-child(3){transition-delay:.18s;}
.sr-stag>*:nth-child(4){transition-delay:.27s;}
.sr-stag>*:nth-child(5){transition-delay:.36s;}
.sr-stag>*:nth-child(6){transition-delay:.45s;}
@media (prefers-reduced-motion:reduce){.sr,.sr-hero{opacity:1;transform:none;transition:none;}}

/* ── TEXT ENTRANCE — l'ingresso del testo di pagina ──
   Titoli, paragrafi, liste e didascalie entrano tutti così: fade + rise di
   14px + micro-blur che si scioglie. initTextReveal() (main.js) mette la
   classe e poi .is-in quando il blocco entra in viewport, una volta sola.
   Non tocca il contenuto — funziona anche dove dentro ci sono link. */
.tr-fade{opacity:0;transform:translateY(14px);filter:blur(6px);
  transition:opacity .7s var(--ease),transform .9s cubic-bezier(.16,1,.3,1),filter .7s var(--ease);}
.tr-fade.is-in{opacity:1;transform:none;filter:none;}

@media (prefers-reduced-motion:reduce){
  .tr-fade{opacity:1;transform:none;filter:none;transition:none;}
}

/* ---------- PRELOADER ----------
   Solo due cose: il marchio 3D che gira e la parola "Welcome" sotto, che
   compare col fade gentile del resto del sito. Niente più colonne di frasi:
   il boot dura quanto la parola e non chiede di essere letto.
   USCITA: il nero sfuma e basta — niente sipario che scorre. Lo slide
   tradiva il trucco (si vedeva un pannello muoversi); il fade lascia solo
   il buio che si dirada mentre sotto il sito entra in zoom (enterZoom). */
.preloader{
  /* nero appena schiarito, non nero assoluto: è il fondo su cui si legge
     l'ombra del marchio. DEVE combaciare con `stageColor` in js/logo3d.js —
     è quello il colore con cui il canvas del logo pulisce il fotogramma, e
     se i due divergono si vede il quadrato del canvas. */
  position:fixed;inset:0;z-index:9999;background:#0d0d0f;
  display:flex;align-items:center;justify-content:center;
  transition:opacity .85s cubic-bezier(.4,0,.2,1);will-change:opacity;
}
.preloader.is-done{opacity:0;pointer-events:none;}
/* il contenuto lascia la scena un filo prima del nero, così non "galleggia" nel fade */
.preloader.is-done .preloader__stage{opacity:0;transition:opacity .35s var(--ease);}
.preloader__stage{
  display:flex;flex-direction:column;align-items:center;gap:var(--s32);
  padding:0 var(--s24);
}
.preloader__logo{
  display:block;width:120px;height:120px;
  /* il marchio entra per primo, la parola lo segue */
  animation:preMark .9s var(--ease) both;
}
@keyframes preMark{from{opacity:0;transform:scale(.9);}to{opacity:1;transform:none;}}
.preloader__welcome{
  margin:0;
  font-size:clamp(24px,4.4vw,var(--fs-display));font-weight:var(--w-semibold);
  line-height:var(--lh-tight);letter-spacing:var(--ls-title);color:var(--ink);
  /* segue il marchio: stesso fade + rise dei testi di pagina (.tr-fade) */
  opacity:0;transform:translateY(14px);filter:blur(6px);
  transition:opacity .7s var(--ease) .34s,
             transform .9s cubic-bezier(.16,1,.3,1) .34s,
             filter .7s var(--ease) .34s;
}
.preloader.is-ready .preloader__welcome{opacity:1;transform:none;filter:none;}

/* ---------- la barra di avanzamento ----------
   Sottile, larga poco, centrata sotto il marchio. Il binario è quasi
   invisibile (bianco al 10%): quello che si vede è il riempimento. */
.preloader__bar{
  position:relative;
  width:132px;height:2px;
  border-radius:999px;
  overflow:hidden;                       /* il riempimento non esce dagli angoli */
  background:rgba(255,255,255,.10);
  /* entra dopo il marchio, come faceva la parola: prima il soggetto, poi il
     servizio. Senza il ritardo comparirebbero insieme e la barra ruberebbe
     l'attenzione proprio mentre il marchio si sta presentando. */
  opacity:0;
  animation:preBarIn .6s var(--ease) .5s forwards;
}
@keyframes preBarIn{to{opacity:1;}}
.preloader__fill{
  position:absolute;inset:0;
  transform-origin:left center;
  border-radius:inherit;
  /* il gradiente ha un colmo più chiaro al bordo destro: è la TESTA della
     barra, il punto che avanza. Una barra di colore uniforme si legge come
     un rettangolo che si allunga; con la testa accesa si legge come qualcosa
     che corre. */
  background:linear-gradient(90deg,
    rgba(255,255,255,.35) 0%,
    rgba(255,255,255,.75) 82%,
    #ffffff 100%);
  /* scaleX e non `width`: la larghezza è una proprietà di layout e il browser
     rifà la geometria a ogni fotogramma; il transform lo gestisce il
     compositore. Su un preloader, dove nello stesso momento si compilano le
     shader di WebGL, è la differenza fra una barra fluida e una a scatti.
     La curva parte svelta e rallenta verso la fine — come un caricamento
     vero, che fa presto sul facile e si siede sull'ultimo pezzo. */
  animation:preFill 5.5s cubic-bezier(.35,.55,.45,1) both;
}
@keyframes preFill{
  from{transform:scaleX(0);}
  /* si ferma al 96%, non al 100%: l'ultimo 4% lo chiude la sparizione della
     barra stessa. Una barra che tocca il fondo e POI resta lì ferma per un
     istante è la cosa che fa sembrare un caricamento più lento di quanto sia. */
  to  {transform:scaleX(.96);}
}
/* in uscita la barra se ne va per prima, insieme al resto del contenuto */
.preloader.is-done .preloader__bar{opacity:0;transition:opacity .3s var(--ease);}

@media (max-width:720px){
  .preloader__stage{gap:var(--s24);}
  .preloader__logo{width:88px;height:88px;}
  .preloader__welcome{font-size:clamp(22px,7vw,32px);}
  .preloader__bar{width:104px;}
}
@media (prefers-reduced-motion:reduce){
  .preloader{transition:opacity .3s linear;}
  .preloader__logo{animation:none;}
  .preloader__welcome{opacity:1;transform:none;filter:none;transition:none;}
  /* la barra resta e resta INFORMATIVA — si riempie, senza la partenza
     scattante della curva. Toglierla del tutto lascerebbe chi ha il motion
     ridotto davanti a cinque secondi di nero senza spiegazione. */
  .preloader__bar{opacity:1;animation:none;}
  .preloader__fill{animation:preFill 5.5s linear both;}
}

/* ---------- MODAL (drone capability, generic) ---------- */
.modal{position:fixed;inset:0;z-index:9998;display:flex;align-items:center;justify-content:center;
  opacity:0;transition:opacity .3s var(--ease);}
.modal.is-open{opacity:1;}
.modal__backdrop{position:absolute;inset:0;background:rgba(0,0,0,.7);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);}
.modal__panel{position:relative;z-index:1;max-width:520px;width:calc(100% - var(--s48));
  background:var(--bg);border:1px solid var(--border);padding:var(--s40);
  transform:translateY(12px);transition:transform .3s var(--ease);}
.modal.is-open .modal__panel{transform:none;}
.modal__x{position:absolute;top:var(--s16);right:var(--s16);color:var(--muted);font-size:var(--fs-small);
  width:32px;height:32px;border:1px solid var(--border);border-radius:999px;cursor:pointer;transition:color .2s var(--ease),border-color .2s var(--ease);}
.modal__x:hover{color:var(--ink);border-color:var(--ink);}
.modal__eyebrow{color:var(--muted);}
.modal__title{font-size:var(--fs-title);font-weight:var(--w-semibold);line-height:1.05;letter-spacing:var(--ls-title);margin:var(--s16) 0 var(--s16);}
.modal__body{font-size:var(--t-body);line-height:1.6;color:var(--muted);margin-bottom:var(--s32);}
.modal__cta{display:flex;flex-wrap:wrap;gap:var(--s16);}

/* site entrance — il sito entra in ZOOM mentre il nero del preloader sfuma:
   parte appena rimpicciolito e si apre fino a riempire il viewport. Curva
   lenta in uscita (niente rimbalzo) — è il gesto che regge il "premium". */
@keyframes chromeRise{from{opacity:0;}to{opacity:1;}}
@keyframes enterZoom{
  from{opacity:0;transform:scale(.94);}
  to  {opacity:1;transform:none;}
}
body.is-entered .archive{animation:enterZoom 1.15s var(--ease) backwards;}
body.is-entered .topbar,
body.is-entered .dock{animation:chromeRise .8s .34s var(--ease) backwards;}
@media (prefers-reduced-motion:reduce){
  body.is-entered .archive{animation:chromeRise .5s linear backwards;}
}

/* ---------- PAGE FX: edge blur + vignette ----------
   both ON TOP of the UI (z 99/100) so the edge frame covers the chrome too;
   the radial falloff keeps the centre (cards) clear. pointer-events:none → clicks pass through. */
.edge-blur{
  position:fixed;inset:0;z-index:11;pointer-events:none;
  -webkit-backdrop-filter:blur(var(--edge-blur));backdrop-filter:blur(var(--edge-blur));
  -webkit-mask:radial-gradient(ellipse at 50% 50%,transparent var(--edge-blur-start),#000 100%);
          mask:radial-gradient(ellipse at 50% 50%,transparent var(--edge-blur-start),#000 100%);
}
/* Vignetta a gradiente, non box-shadow: lo spread dell'ombra creava una banda
   quasi netta: da qui l'effetto "marcato". La rampa a più stop (.14 → .40 →
   .72 → 1) approssima una smoothstep, così la caduta verso gli angoli è
   graduale e senza bordo visibile. Per dosarla tocca --vignette-alpha
   (buio agli angoli) e --vignette-start (dove comincia a scurire). */
.vignette{
  position:fixed;inset:0;z-index:12;pointer-events:none;
  background:
    radial-gradient(ellipse at 50% 50%,
      rgba(var(--vignette-rgb),0)                                  0%,
      rgba(var(--vignette-rgb),0)                                  var(--vignette-start),
      rgba(var(--vignette-rgb),calc(var(--vignette-alpha) * .14))  66%,
      rgba(var(--vignette-rgb),calc(var(--vignette-alpha) * .40))  81%,
      rgba(var(--vignette-rgb),calc(var(--vignette-alpha) * .72))  92%,
      rgba(var(--vignette-rgb),var(--vignette-alpha))             100%);
  /* il velo sotto la topbar sta in .top-distort, non qui: raddoppiarlo scuriva */
}

/* ---- EDGE DISTORTION (alto + basso) ----
   Stessa ricetta ai due bordi: il backdrop viene sfocato e increspato dal
   feTurbulence (#bottom-distort), poi una mask lo fa comparire in modo
   graduale e un velo scuro chiude il bordo. In BASSO ora è molto più corta e
   meno nera di prima (finiva a #000 pieno, mangiava una fascia di griglia).
   In ALTO serve a staccare header e menu dalle card che ci scorrono sotto. */
.top-distort,
.bottom-distort{
  position:fixed;left:0;right:0;z-index:88;pointer-events:none;
  -webkit-backdrop-filter:url(#bottom-distort) blur(7px);
          backdrop-filter:url(#bottom-distort) blur(7px);
}
/* --- basso: ridotta da 320px e non arriva più al nero pieno --- */
.bottom-distort{
  bottom:-2px;height:220px;
  -webkit-mask:linear-gradient(to bottom,transparent 0%,rgba(0,0,0,.18) 34%,rgba(0,0,0,.62) 62%,#000 88%);
          mask:linear-gradient(to bottom,transparent 0%,rgba(0,0,0,.18) 34%,rgba(0,0,0,.62) 62%,#000 88%);
}
.bottom-distort::after{
  content:"";
  position:absolute;inset:0;
  background:linear-gradient(to bottom,
    rgba(0,0,0,0)   0%,
    rgba(0,0,0,.05) 30%,
    rgba(0,0,0,.16) 50%,
    rgba(0,0,0,.34) 68%,
    rgba(0,0,0,.54) 84%,
    rgba(0,0,0,.68) 100%);
}
/* --- alto: copre i 62px della topbar + la coda di sfumatura --- */
.top-distort{
  top:0;height:150px;
  -webkit-mask:linear-gradient(to top,transparent 0%,rgba(0,0,0,.18) 32%,rgba(0,0,0,.62) 60%,#000 86%);
          mask:linear-gradient(to top,transparent 0%,rgba(0,0,0,.18) 32%,rgba(0,0,0,.62) 60%,#000 86%);
}
.top-distort::after{
  content:"";
  position:absolute;inset:0;
  background:linear-gradient(to top,
    rgba(0,0,0,0)   0%,
    rgba(0,0,0,.06) 32%,
    rgba(0,0,0,.20) 54%,
    rgba(0,0,0,.38) 74%,
    rgba(0,0,0,.52) 100%);
}

/* ---------- TOP BAR (mark + orologi a sinistra, azioni a destra) ----------
   z sits ABOVE the menu overlay on purpose: the mark and the Menu/Close
   toggle stay live while the full-screen menu is open.
   Il padding è --pad-x (82px): la stessa gabbia di menu, footer e banner. */
/* ---------- switch lingua ----------
   Sta in style.css e non in mvp.css perché deve restare al suo posto anche
   quando togli data-mvp e riaccendi il sito completo.
   In basso a destra: in alto ci sono già la barra di stato e la topbar, e il
   piede a sinistra è occupato dal blocco contatti. z-index 210 lo tiene sopra
   la vignettatura, come il pulsante primario. */
/* ═══════════ LA RICETTA DEL VETRO ═══════════
   Una classe sola, .glass, indossata da ogni comando in vetro: switch lingua,
   tondo XR, LinkedIn, bottoni del banner cookie. Prima ognuno riscriveva la
   propria pila di ombre — quattro ricette leggermente diverse, che è il
   motivo per cui l'insieme non sembrava fatto dello stesso materiale.

   Le dieci ombre non sono dieci decisioni: sono TRE gruppi.

     1. il filo (1ª riga)      — un capello di luce tutto intorno, che chiude
                                 la forma. È l'unica ombra simmetrica.
     2. i colmi (righe 2-4)    — la luce che entra nello spessore e si posa
                                 sopra-sinistra e sotto-destra. Raggi
                                 NEGATIVI: contraggono l'ombra fino a
                                 lasciarne solo il bordo, altrimenti sarebbe
                                 una macchia al centro invece di un filo.
     3. i rientri (righe 5-8)  — le stesse posizioni in ombra: dove il vetro
                                 si incurva via dalla luce. Sono loro a dare
                                 lo SPESSORE; senza, restano solo dei bordi
                                 chiari e la lastra torna piatta.
     4. le portate (ultime 2)  — l'unica coppia non-inset: staccano il pezzo
                                 dal fondo. Corta e stretta la prima (il
                                 contatto), lunga e larga la seconda (il peso).

   I decimali (1.8px, -6.5px, 2.5px) sono voluti: su valori interi i quattro
   colmi cadono esattamente sugli stessi pixel dei rientri e si annullano a
   vicenda, e il bordo torna piatto. Mezzo pixel di sfasamento basta perché
   ognuno resti visibile accanto all'altro.

   Deve stare su un elemento con un `border-radius` e SENZA `border`: lo
   spessore lo fanno le ombre, e una cornice vera ci passerebbe sopra
   coprendo proprio i colmi che fanno il lavoro. */
.glass{
  position:relative;
  border:0;
  background-color:color-mix(in srgb,var(--gl-tint) var(--gl-fill),transparent);
  -webkit-backdrop-filter:blur(var(--gl-blur)) saturate(var(--gl-sat));
          backdrop-filter:blur(var(--gl-blur)) saturate(var(--gl-sat));
  box-shadow:
    /* il contorno: mezzo pixel, non uno. È la differenza fra "questa forma
       finisce qui" e "questa forma ha una cornice". */
    inset 0 0 0 .5px       color-mix(in srgb,var(--gl-light) calc(var(--gl-reflex-light) * 16%),transparent),
    /* il colmo in alto e il rientro in basso: DUE, non otto. Sfocati (2px di
       blur) invece che netti, e senza componente orizzontale — un filo che
       sfuma legge come curvatura, un filo netto legge come linea disegnata.
       È qui che stava il peso di prima: quattro colmi e quattro rientri, tutti
       a fuoco, facevano un bordo sbalzato invece di una lastra. */
    inset 0 1px 2px -1px   color-mix(in srgb,var(--gl-light) calc(var(--gl-reflex-light) * 60%),transparent),
    inset 0 -1px 2px -1px  color-mix(in srgb,var(--gl-dark) calc(var(--gl-reflex-dark) * 14%),transparent),
    /* UNA portata sola, ampia e tenue: appoggia il pezzo sul fondo senza
       disegnargli sotto una seconda forma. Le due di prima (una corta e
       stretta, una lunga) si sommavano in un alone che si vedeva a colpo
       d'occhio prima del pulsante. */
    0 2px 10px -2px        color-mix(in srgb,var(--gl-dark) calc(var(--gl-reflex-dark) * 12%),transparent);
  transition:background-color .4s var(--ease-glass),
             box-shadow .4s var(--ease-glass),
             transform .4s var(--ease-glass),
             color .25s var(--ease-glass);
}

/* al passaggio il vetro si SCHIARISCE, non si muove e basta: sale il velo
   (+8 punti) e salgono le due portate, come se la lastra si alzasse di un
   millimetro dal fondo. Le ombre interne restano identiche — sono lo spessore
   del materiale, e il materiale non cambia perché ci passi sopra il mouse. */
.glass:hover{
  background-color:color-mix(in srgb,var(--gl-tint) calc(var(--gl-fill) + 8%),transparent);
}

/* pressione: la lastra torna a contatto col fondo. Spariscono le due portate
   e resta un solo alone corto — la scorciatoia visiva per "schiacciato". */
.glass:active{
  transform:translateY(1px) scale(.985);
}

/* Chrome e Safari non compongono `backdrop-filter` allo stesso modo: su Safari
   un elemento che lo usa crea un contesto di impilamento che TAGLIA le ombre
   portate dei figli. Isolandolo qui, il taglio non risale al genitore. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  /* niente sfocatura disponibile: il vetro diventa una lastra opaca, o il
     testo sopra finirebbe illeggibile su una griglia di immagini */
  .glass{background-color:color-mix(in srgb,var(--gl-tint) 72%,transparent);}
}

/* Riga dei comandi in alto a destra: lingua + modalità immersiva.
   In ALTO e non in basso: sul fondo ci sono .bottom-distort (250px di
   backdrop-filter) e il piede contatti, e i comandi finivano sepolti sotto
   entrambi — cliccabili in teoria, non in pratica.
   z-index 260 li porta sopra la topbar (210): devono restare raggiungibili
   da qualsiasi vista.
   align-items:center allinea i due elementi sulla stessa mezzeria anche se
   uno dei due cambia altezza. */
.topctl{
  /* UN numero solo per l'altezza dei due comandi: cambiarlo qui li muove
     insieme, invece di doverli tenere allineati a mano in due punti. */
  --ctl-h:44px;
  position:fixed;
  right:var(--pad-x,24px);
  top:calc(env(safe-area-inset-top,0px) + 32px);
  z-index:260;
  pointer-events:auto;
  display:flex;align-items:center;gap:10px;
}

.langswitch{
  /* pointer-events esplicito e non ridondante: se un giorno un antenato
     passa a none (come fa .topbar), i figli lo ereditano. */
  pointer-events:auto;
  /* riferimento per la pastiglia in ::after, che è in position:absolute */
  position:relative;
  display:inline-flex;align-items:center;
  /* altezza DICHIARATA e non dedotta dal padding: così combacia col pulsante
     tondo al pixel, invece di avvicinarcisi */
  height:var(--ctl-h,44px);
  padding:4px;border-radius:999px;
  /* niente gap: le due celle si toccano, e la pastiglia che scorre sotto
     passa dall'una all'altra senza un salto vuoto in mezzo. La distanza fra
     IT ed EN la fa il loro padding interno. */
  gap:0;
  /* --lang-w è la larghezza di UNA cella. La usano tre regole: la cella
     stessa, la pastiglia, e la corsa della pastiglia. Un numero solo, così
     non possono sfasarsi. */
  --lang-w:42px;
}
/* la pastiglia: il pezzo di vetro più denso che scorre sotto la lingua attiva.
   Non è un `background` sul bottone premuto — un fondo che si accende e si
   spegne non ha direzione, e qui la direzione è tutto: vedere la pastiglia
   ANDARE da IT a EN è ciò che dice che le due sono la stessa cosa in due
   stati, invece di due bottoni separati.
   z-index 0 con le etichette a 1: sta sotto il testo, sopra il fondo. */
.langswitch::after{
  content:'';
  position:absolute;
  left:4px;top:4px;
  width:var(--lang-w);
  height:calc(100% - 8px);
  border-radius:999px;
  z-index:0;
  background-color:color-mix(in srgb,var(--gl-tint) 38%,transparent);
  /* pila ridotta rispetto a .glass: la pastiglia è PICCOLA e dentro un altro
     vetro. Le dieci ombre della lastra grande, su 42px, si accavallerebbero
     fino a impastarsi in una macchia grigia. Restano il filo, due colmi e due
     rientri — quel tanto che basta a leggerla come un pezzo solido. */
  /* stessa grammatica ridotta della lastra: contorno, colmo, rientro, una
     portata. Su 42px anche solo sei ombre facevano una pastiglia bombata —
     qui deve leggersi come un pezzo di vetro più denso, non come un tasto. */
  box-shadow:
    inset 0 0 0 .5px      color-mix(in srgb,var(--gl-light) calc(var(--gl-reflex-light) * 18%),transparent),
    inset 0 1px 2px -1px  color-mix(in srgb,var(--gl-light) calc(var(--gl-reflex-light) * 55%),transparent),
    inset 0 -1px 2px -1px color-mix(in srgb,var(--gl-dark) calc(var(--gl-reflex-dark) * 12%),transparent),
    0 1px 4px -1px        color-mix(in srgb,var(--gl-dark) calc(var(--gl-reflex-dark) * 14%),transparent);
  /* `translate` e non `transform`: il transform su questo pseudo-elemento è
     già impegnato dallo scatto di scaleToggle, e le due proprietà separate
     non si sovrascrivono a vicenda. */
  translate:0 0;
  transition:translate .44s var(--ease-glass),
             background-color .4s var(--ease-glass),
             box-shadow .4s var(--ease-glass);
}
/* dove va la pastiglia lo decide aria-pressed, la STESSA fonte che lo dice
   allo screen reader: lo stato visivo non può divergere da quello dichiarato.
   :has() sul contenitore invece di una classe messa dal JS — nessuno deve
   ricordarsi di sincronizzare una classe in più ad ogni cambio lingua. */
.langswitch:has(button:nth-of-type(2)[aria-pressed="true"])::after{
  translate:var(--lang-w) 0;
}
/* lo scatto: mentre corre, la pastiglia si allunga nel verso del moto e poi
   rientra. È il dettaglio che la fa sembrare liquida invece che rigida —
   un solido che trasla resta un rettangolo che si sposta.
   Solo scaleX: allungare anche in altezza la farebbe uscire dal vetro. */
@keyframes lang-thumb-stretch{
  0%  {scale:1 1;}
  50% {scale:1.14 1;}
  100%{scale:1 1;}
}
.langswitch:has(button[aria-pressed="true"])::after{
  animation:lang-thumb-stretch .44s var(--ease-glass);
}
.langswitch button{
  position:relative;z-index:1;              /* sopra la pastiglia */
  font:inherit;font-size:11.5px;font-weight:var(--w-regular);letter-spacing:.06em;
  /* larghezza dichiarata e uguale per le due: la pastiglia si sposta di una
     misura fissa, e se una cella fosse più larga dell'altra la corsa la
     lascerebbe fuori registro. */
  width:var(--lang-w);
  line-height:1;padding:0;height:100%;
  border:0;border-radius:999px;cursor:pointer;
  background:transparent;color:rgba(255,255,255,.58);
  transition:color .3s var(--ease-glass);
}
.langswitch button:hover{color:rgba(255,255,255,.92);}
/* la lingua attiva è marcata da aria-pressed: lo stato accessibile e quello
   visivo vengono dalla STESSA fonte, così non possono divergere.
   Qui resta SOLO il colore: il fondo è la pastiglia che scorre. */
.langswitch button[aria-pressed="true"]{
  color:#fff;
  cursor:default;
}
.langswitch button:focus-visible{outline:2px solid rgba(255,255,255,.6);outline-offset:2px;}
.langswitch__sep{width:0.5px;height:12px;background:rgba(255,255,255,.18);}

/* chi non ha :has() (Firefox < 121) non vede la pastiglia muoversi: senza il
   selettore, resta ferma su IT e l'inglese sembrerebbe non selezionato mai.
   Meglio spegnerla del tutto e tornare al fondo acceso sul bottone premuto —
   meno bello, ma sempre corretto. */
@supports not selector(:has(*)){
  .langswitch::after{display:none;}
  .langswitch button[aria-pressed="true"]{
    background:color-mix(in srgb,var(--gl-tint) 38%,transparent);
  }
}

/* motion ridotto: la pastiglia c'è e sta al posto giusto, ci arriva
   istantaneamente invece di scorrere */
@media (prefers-reduced-motion:reduce){
  .langswitch::after{transition:none;animation:none;}
}

/* ---------- pulsante modalità immersiva ----------
   Stessa altezza dello switch lingua (36px) e larghezza uguale all'altezza:
   un cerchio esatto. Il valore è dichiarato e non dedotto dal contenuto —
   con l'icona dentro, un padding avrebbe dato un ovale. */
.xrbtn{
  /* 44px: la misura minima raccomandata per un bersaglio tattile, e la stessa
     del pulsante LinkedIn nel piede. Lo switch lingua ci si allinea da sé
     grazie a --ctl-h. */
  --xr-size:var(--ctl-h,44px);
  width:var(--xr-size);height:var(--xr-size);flex:none;
  display:inline-flex;align-items:center;justify-content:center;
  padding:0;border-radius:50%;cursor:pointer;
  color:rgba(255,255,255,.72);
  position:relative;
  /* fondo, bordo, ombre e transizione arrivano da .glass (vedi la ricetta
     sopra). Qui resta solo quello che è PROPRIO di questo pulsante: la
     misura, il cerchio e il colore dell'icona. Prima ognuno riscriveva la
     sua pila, ed è per questo che i comandi non sembravano lo stesso
     materiale. */
}
.xrbtn svg{display:block;flex:none;
  /* l'icona segue la lastra: al passaggio si scosta di un capello verso
     l'alto, come se galleggiasse dentro il vetro invece di esserci stampata
     sopra */
  transition:transform .4s var(--ease-glass);}
.xrbtn:hover{color:#fff;}

/* ── SIAMO SU UN VISORE ──
   La classe la mette il JS quando navigator.xr dichiara di poter aprire una
   sessione immersiva. Su un monitor questo stato non esiste mai, quindi qui
   si può spingere senza rischiare di gridare a chi non può farci niente.
   Tre segnali, in ordine di forza:
     1. il colore passa all'accent — è l'unico comando colorato in pagina
     2. un alone che pulsa piano dietro il tondo
     3. l'icona un filo più grande, come un pulsante già premuto a metà
   Niente scatti né rimbalzi: è un invito, non una notifica. */
.xrbtn.is-ready{
  /* PIENO, non tinto. Al 16% l'accent si leggeva come un'ombra rossastra
     sotto il vetro: da lontano restava un tondo grigio come gli altri.
     A questo punto il comando smette di essere vetro e diventa un pulsante
     colorato — che è esattamente ciò che serve quando è l'azione principale
     della pagina e sei sul dispositivo che può eseguirla. */
  color:#fff;
  background-color:color-mix(in srgb,var(--accent) 92%,transparent);
  /* il glifo bianco su arancione ha bisogno di un filo di peso in più */
  animation:xr-ready-pulse 2.4s var(--ease-glass) infinite;
}
/* un secondo anello, più largo e più lento del primo: due onde sfasate
   leggono come "sta chiamando", una sola come un bordo che lampeggia */
.xrbtn.is-ready::before{
  content:'';position:absolute;inset:0;border-radius:inherit;
  pointer-events:none;
  animation:xr-ready-ring 2.4s var(--ease-glass) .5s infinite;
}
@keyframes xr-ready-ring{
  0%  {box-shadow:0 0 0 0 rgba(255,99,71,.34);}
  70% {box-shadow:0 0 0 16px rgba(255,99,71,0);}
  100%{box-shadow:0 0 0 0 rgba(255,99,71,0);}
}
.xrbtn.is-ready:hover{
  color:#fff;
  /* più chiaro, non più scuro: su un fondo già pieno l'unico modo di dire
     "sei sopra" è schiarire. Scurendo sembrerebbe premuto. */
  background-color:color-mix(in srgb,#ff8566 100%,transparent);
  transform:scale(1.06);
  animation-play-state:paused;   /* al passaggio smette di chiamare: l'hai visto */
}
.xrbtn.is-ready:hover::before{animation-play-state:paused;}
.xrbtn.is-ready svg{transform:scale(1.06);}
/* L'alone è un box-shadow e NON un elemento sfocato: un filter:blur() su un
   elemento che anima viene rasterizzato in un layer e la sfocatura si taglia
   netta ai suoi bordi — si vedrebbe un quadrato attorno alla luce.
   Il colore è l'accent literal (#ff6347) perché rgba() non accetta una
   variabile: se un giorno cambi --accent, questi valori vanno rifatti. */
@keyframes xr-ready-pulse{
  0%,100%{box-shadow:0 0 0 0 rgba(255,99,71,.55), 0 4px 16px -2px rgba(255,99,71,.45);}
  50%    {box-shadow:0 0 0 10px rgba(255,99,71,0), 0 4px 20px -2px rgba(255,99,71,.65);}
}
/* il tooltip di un comando che invita resta aperto un attimo da solo, così
   l'invito si legge anche senza avvicinare il puntatore */
.xrbtn.is-ready::after{
  animation:xr-ready-tip .6s var(--ease-glass) 1.2s both;
}
@keyframes xr-ready-tip{
  0%  {opacity:0;transform:translateY(-4px);}
  30% {opacity:1;transform:none;}
  85% {opacity:1;transform:none;}
  100%{opacity:0;transform:translateY(-4px);}
}
@media (prefers-reduced-motion:reduce){
  /* resta l'evidenza (colore e alone fermo), sparisce il battito */
  .xrbtn.is-ready{animation:none;box-shadow:0 0 0 4px rgba(255,99,71,.30),0 4px 16px -2px rgba(255,99,71,.4);}
  .xrbtn.is-ready::before,
  .xrbtn.is-ready::after{animation:none;}
}
.xrbtn:hover svg{transform:translateY(-1px) scale(1.06);}
.xrbtn:focus-visible{outline:2px solid rgba(255,255,255,.6);outline-offset:2px;}

/* Tooltip su data-tip invece del `title` nativo: quello compare dopo oltre un
   secondo, non si può stilare e su touch non esiste. Qui la risposta è
   immediata e coerente col resto dell'interfaccia.
   Sta SOTTO il pulsante perché sopra c'è il bordo della finestra. */
.xrbtn::after{
  content:attr(data-tip);
  position:absolute;top:calc(100% + 8px);right:0;
  padding:6px 10px;border-radius:8px;white-space:nowrap;
  font-size:11.5px;line-height:1;letter-spacing:.01em;
  color:rgba(255,255,255,.92);
  background:rgba(20,20,23,.88);
  border:0.5px solid rgba(255,255,255,.14);
  -webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);
  opacity:0;transform:translateY(-4px);pointer-events:none;
  transition:opacity .2s var(--ease),transform .2s var(--ease);
}
.xrbtn:hover::after,
.xrbtn:focus-visible::after{opacity:1;transform:none;}
/* su touch il tooltip non ha senso: non c'è hover, e resterebbe attaccato
   dopo il tocco */
@media (hover:none){ .xrbtn::after{display:none;} }

/* in chiaro cambia SOLO il colore dell'icona: fondo, bordo e ombre li rifà da
   sé la ricetta, leggendo i token --gl-* che il tema ha già ribaltato. Prima
   qui c'era una seconda pila di ombre scritta a mano, che è il motivo per cui
   i due temi non sembravano lo stesso pulsante. */
:root[data-theme="light"] .xrbtn{color:rgba(0,0,0,.62);}
:root[data-theme="light"] .xrbtn:hover{color:#111;}
:root[data-theme="light"] .xrbtn::after{
  color:#111;background:rgba(255,255,255,.94);border-color:rgba(0,0,0,.1);
}

/* ---------- avviso "serve un visore" ---------- */
.xrmodal{
  position:fixed;inset:0;z-index:400;
  display:flex;align-items:center;justify-content:center;padding:24px;
  /* Velo più deciso di prima (era .22). La scheda ora è una FINESTRA, e una
     finestra ha bisogno che dietro ci sia stanza buia: è il contrasto col
     fondo a darle il distacco fisico. Al 22% la griglia restava vivace e la
     modale ci galleggiava sopra senza peso.
     Il blur resta alto: è lui a isolare, il nero serve solo a spegnere. */
  background:rgba(6,6,10,.58);
  -webkit-backdrop-filter:blur(34px) saturate(1.15) brightness(.62);
          backdrop-filter:blur(34px) saturate(1.15) brightness(.62);
  /* Il velo entra per primo e in fretta: è la stanza che si spegne, e deve
     essere già buia quando la finestra si materializza. Se i due partono
     insieme, la scheda arriva su un fondo ancora chiaro e si vede "attraverso"
     invece che davanti.
     La curva è quasi lineare in uscita (.4,0,.2,1): un buio che accelera
     sembra un taglio, non una dissolvenza. */
  animation:xrmodal-in .34s cubic-bezier(.4,0,.2,1) both;
}
/* `hidden` da solo non basta: display:flex della regola sopra lo
   sovrascriverebbe e la modale resterebbe visibile all'avvio */
.xrmodal[hidden]{display:none;}
@keyframes xrmodal-in{from{opacity:0;}to{opacity:1;}}

/* ── LA FINESTRA ──
   L'obiettivo non è più "una scheda di vetro" ma un OGGETTO con spessore,
   come una finestra di visionOS: qualcosa che sta a mezz'aria davanti al
   contenuto e proietta la propria ombra sulla stanza.
   Tre cose lo fanno leggere come fisico, e sono tutte e tre necessarie:
     · l'ombra portata lunga e morbida, che la stacca dal fondo
     · il bordo luminoso in alto e scuro in basso: è lo SPESSORE del vetro
       colpito dalla luce d'ambiente
     · l'ingresso in profondità (vedi xrcard-in), che le dà una posizione
       nello spazio invece di farla comparire e basta */
.xrmodal__card{
  width:min(400px,100%);
  /* niente padding qui: lo porta .xrmodal__body. Serve perché il video in
     cima deve toccare i bordi, e un padding sulla scheda lo rientrerebbe. */
  padding:0;
  text-align:center;
  border-radius:30px;                 /* raggio ampio: è la firma di visionOS */
  overflow:hidden;                    /* il video si taglia sugli angoli tondi */
  background:linear-gradient(180deg,rgba(255,255,255,.15) 0%,rgba(255,255,255,.055) 100%);
  -webkit-backdrop-filter:blur(60px) saturate(1.9) brightness(1.02);
          backdrop-filter:blur(60px) saturate(1.9) brightness(1.02);
  border:0;
  /* La pila che fa lo spessore. Il bordo NON è un `border` — una cornice di
     spessore costante legge come contorno disegnato; queste ombre interne
     spingono da direzioni diverse, ed è l'asimmetria a dare il volume.
     Le due portate hanno ruoli distinti: la corta è il contatto, la lunga è
     il peso della finestra sospesa nella stanza. */
  box-shadow:
    inset 0 0 0 .5px      rgba(255,255,255,.20),
    inset 0 1.5px 1px -1px rgba(255,255,255,.65),
    inset 0 -1.5px 2px -1px rgba(0,0,0,.35),
    0 2px 8px rgba(0,0,0,.30),
    0 40px 90px -20px rgba(0,0,0,.75);
  /* 0.72s e non 0.62, e soprattutto una curva diversa.
     La (.16,1,.3,1) di prima era troppo frontale: misurandola, in 200ms era
     già a scala 0.986 — cioè arrivava quasi subito e poi passava 400ms a
     non muoversi. Il risultato era uno scatto seguito da un'attesa.
     La (.34,1.06,.34,1) distribuisce il movimento su tutta la durata e
     supera di un soffio il valore finale (1.06) prima di rientrare: non è un
     rimbalzo — è l'assestamento di un oggetto che si ferma, la stessa cosa
     che fa una finestra di visionOS quando si posa.
     Il ritardo di 90ms la fa arrivare DOPO che la stanza si è spenta. */
  /* La curva è il punto. Misurando la precedente: scala 0.959 a 300ms, poi
     0.972 a 450ms — trecento millisecondi passati a non muoversi, che a
     occhio si leggono come "arriva e poi si impunta". Neutro, appunto.
     La (.2,.9,.25,1.14) fa il contrario: parte più decisa, arriva quasi in
     posizione, e SUPERA il valore finale (1.14) prima di rientrare. Quel
     sorpasso è l'assestamento — l'oggetto che si posa e si stabilizza — ed è
     tutto ciò che separa un movimento fisico da una dissolvenza con la scala. */
  animation:xrcard-in .68s cubic-bezier(.2,.9,.25,1.14) 60ms both;
  position:relative;isolation:isolate;
}
/* la scheda riceve il fuoco all'apertura ma non deve mostrarne l'anello:
   è un contenitore, non un comando. Il fuoco visibile ricompare al primo Tab,
   sul pulsante, dove serve. */
.xrmodal__card:focus{outline:none;}
.xrmodal__card::before{
  content:'';position:absolute;inset:0;border-radius:inherit;z-index:-1;
  /* Alleggerita (era .34/.52). Serve a garantire un fondo minimo al testo
     bianco quando la finestra capita sopra una card chiara, ma a quei valori
     rendeva la scheda quasi opaca: il backdrop-filter dietro non aveva più
     niente da mostrare e il vetro tornava lastra grigia.
     Più scura in basso che in alto: è sotto che sta il testo. */
  background:linear-gradient(180deg,
    rgba(0,0,0,.12) 0%, rgba(0,0,0,.30) 55%, rgba(0,0,0,.38) 100%);
}
/* L'ingresso: arriva da LONTANO, non dal basso.
   Prima saliva di 12px e scalava di .97 — un movimento da tooltip. Una
   finestra di visionOS si materializza in profondità: parte più piccola e
   dietro, e viene avanti fermandosi con una decelerazione lunga. Il blur che
   si dissolve è ciò che vende la distanza: quello che è lontano è fuori
   fuoco. La curva (.16,1,.3,1) non ha rimbalzo — un oggetto pesante non
   rimbalza, si posa. */
@keyframes xrcard-in{
  from{
    opacity:0;
    /* parte più piccola e un filo più in basso: la combinazione legge come
       "lontana", non come "spostata". La traslazione è piccola apposta —
       tanta traslazione è un pannello che scorre, poca traslazione con molta
       scala è un oggetto che viene avanti. */
    transform:translate3d(0,18px,0) scale(.78);
    filter:blur(14px) brightness(1.5);
  }
  /* Il fuoco si risolve PRIMA della geometria: a 45% la finestra è già
     leggibile mentre sta ancora arrivando. È come si comporta qualcosa che si
     avvicina, e toglie la sensazione di dissolvenza.
     `brightness` che scende da 1.5 a 1 è un colmo di luce che attraversa il
     vetro mentre si posa — il lampo che un materiale riflettente dà quando
     ruota nella luce. Costa nulla ed è la cosa che si nota di più. */
  45%{
    opacity:1;
    filter:blur(0) brightness(1.14);
  }
  to{
    opacity:1;
    transform:none;
    filter:blur(0) brightness(1);
  }
}

/* Il contenuto entra DOPO il contenitore, e appena appena da sotto.
   È il dettaglio che fa sembrare la finestra un oggetto invece che
   un'immagine: prima arriva il vetro, poi ci si posa dentro quello che
   contiene. 40ms di scarto fra i due blocchi bastano — di più si legge come
   ritardo, di meno non si legge affatto. */
@keyframes xrcontent-in{
  from{opacity:0;transform:translate3d(0,10px,0) scale(.985);}
  to  {opacity:1;transform:none;}
}

/* Motion ridotto: la finestra COMPARE, non arriva. Il movimento in
   profondità con blur è esattamente il tipo di animazione che dà fastidio a
   chi soffre di motion sickness — e qui non porta informazione, solo carattere.
   Il materiale, l'ombra e lo spessore restano: quelli non si muovono. */
@media (prefers-reduced-motion:reduce){
  .xrmodal{animation:xrmodal-in .2s linear both;}
  .xrmodal__card{animation:xrmodal-in .2s linear both;}
  /* niente scaglionamento e niente scorrimento: compaiono insieme al vetro */
  .xrmodal__media,
  .xrmodal__body{animation:none;}
}

/* ── il video di anteprima ──
   A filo: niente padding sopra e ai lati, il contenuto tocca la cornice.
   16:10 invece di 16:9: un filo più alto tiene la finestra compatta e
   assomiglia alle proporzioni delle finestre di sistema. */
.xrmodal__media{
  position:relative;
  animation:xrcontent-in .5s cubic-bezier(.16,1,.3,1) .20s both;
  /* 21:9 e non 16:10. A 16:10 su una scheda da 400px il video prendeva 250px,
     cioè metà finestra: l'anteprima diventava il soggetto e il messaggio un
     sottotitolo. Una fascia panoramica dice "ecco com'è" senza rubare la
     scena. */
  aspect-ratio:21/9;
  width:100%;
  /* il placeholder: un cielo da visore, coerente col logo 3D del preloader.
     Sostituendolo con un <video> vero questo fondo resta sotto e non si vede
     più — è anche la schermata d'attesa mentre il file carica. */
  background:
    radial-gradient(90% 70% at 72% 18%, rgba(255,168,86,.42) 0%, transparent 60%),
    radial-gradient(80% 80% at 20% 85%, rgba(96,124,224,.38) 0%, transparent 65%),
    linear-gradient(170deg, #2a3560 0%, #4a3a56 48%, #7a4a34 100%);
}
.xrmodal__media video,
.xrmodal__media img{
  display:block;width:100%;height:100%;object-fit:cover;
}
/* La sfumatura che lega il video alla scheda. Senza, il fotogramma finisce
   con un taglio netto e si legge come un'immagine incollata sopra il vetro.
   Con la dissolvenza verso il basso il media SI FONDE nel materiale — che è
   il modo in cui visionOS raccorda un contenuto alla finestra che lo tiene.
   Il gradiente è trasparente in cima (il video si vede pieno) e diventa opaco
   in fondo, dove comincia il testo. */
/* La dissolvenza del media.
   Prima era un velo NERO steso sopra: `rgba(10,10,16,.95)` in fondo, cioè una
   fascia scura dipinta sul vetro. Si vedeva come una banda, e soprattutto
   copriva il materiale della finestra proprio dove il vetro doveva tornare a
   respirare.
   Adesso non aggiungo colore: TOLGO il video. La maschera rende trasparente
   la propria metà bassa, quindi sotto ricompare la scheda — il suo vetro, il
   suo backdrop-filter, il fondo vero che ci passa attraverso. È la differenza
   fra "sfumare al nero" e "sfumare via". */
.xrmodal__media{
  -webkit-mask-image:linear-gradient(180deg,
    #000 0%, #000 38%, rgba(0,0,0,.72) 66%, rgba(0,0,0,.22) 88%, transparent 100%);
          mask-image:linear-gradient(180deg,
    #000 0%, #000 38%, rgba(0,0,0,.72) 66%, rgba(0,0,0,.22) 88%, transparent 100%);
}
/* il contenuto testuale: è QUI il padding della scheda */
.xrmodal__body{
  animation:xrcontent-in .5s cubic-bezier(.16,1,.3,1) .26s both;
  /* il top è ridotto (18 contro 30 ai lati): la sfumatura del video ha già
     creato lo stacco, e un padding pieno lascerebbe un vuoto sotto il media */
  padding:18px 30px 30px;
}

.xrmodal__title{
  margin:0 0 10px;font-size:20px;font-weight:var(--w-semibold);
  letter-spacing:-.01em;color:#fff;
  /* ombra appena percepibile: su vetro traslucido il testo può capitare
     sopra un'area chiara della griglia, e senza questa resterebbe illeggibile
     proprio lì */
  text-shadow:0 1px 3px rgba(0,0,0,.4);
}
.xrmodal__text{
  margin:0 0 26px;font-size:14.5px;line-height:1.55;
  color:rgba(255,255,255,.80);
  text-shadow:0 1px 3px rgba(0,0,0,.35);
}
.xrmodal__close{
  font:inherit;font-size:15px;font-weight:var(--w-regular);
  width:100%;padding:14px;border:0;border-radius:16px;cursor:pointer;
  /* Vetro chiaro anziché bianco pieno: in visionOS i pulsanti sono materiale
     traslucido, e un bianco opaco dentro una scheda di vetro romperebbe la
     coerenza — sembrerebbe incollato sopra invece che parte della stessa
     superficie. */
  /* più trasparente (era 26%): a quel livello il pulsante usciva come una
     lastra grigia piatta incollata sulla finestra. Sotto, il vetro della
     scheda si vede attraverso e il comando sembra ricavato NELLO stesso
     materiale invece che appoggiato sopra. */
  background-color:color-mix(in srgb,var(--gl-tint) 14%,transparent);
  color:#fff;
  border:0;
  /* stessa pila di .glass ma SENZA backdrop-filter: questo pulsante sta dentro
     .xrmodal__card, che sfoca già il fondo. Sfocare due volte lo stesso pixel
     lo impasta — e su Safari un secondo contesto di sfocatura annidato taglia
     anche le ombre. Qui serve solo il bordo: la lastra ce l'ha già sotto. */
  box-shadow:
    inset 0 0 0 .5px      rgba(255,255,255,.26),
    inset 0 1px 1px -.5px rgba(255,255,255,.60),
    inset 0 -1px 2px -1px rgba(0,0,0,.30),
    0 2px 12px -4px rgba(0,0,0,.40);
  transition:background-color .4s var(--ease-glass),box-shadow .4s var(--ease-glass),
             transform .3s var(--ease-glass);
}
.xrmodal__close:hover{
  background-color:color-mix(in srgb,var(--gl-tint) 26%,transparent);
  box-shadow:
    inset 0 0 0 .5px      rgba(255,255,255,.34),
    inset 0 1px 1px -.5px rgba(255,255,255,.75),
    inset 0 -1px 2px -1px rgba(0,0,0,.30),
    0 4px 16px -4px rgba(0,0,0,.45);
}
.xrmodal__close:active{transform:translateY(1px) scale(.985);}
.xrmodal__close:focus-visible{outline:2px solid rgba(255,255,255,.6);outline-offset:2px;}

/* ---------- pagina "spenta" durante la sessione immersiva ----------
   Su Vision Pro la finestra di Safari resta visibile nello spazio mentre sei
   immerso: una griglia che continua a muoversi lì accanto competerebbe con la
   stessa griglia vista in 3D. Nero pieno e opaco — uno spegnimento, non un
   velo. */
body.is-xr::after{
  content:'';position:fixed;inset:0;z-index:500;
  background:#000;pointer-events:none;
  animation:xr-sleep .5s var(--ease) both;
}
@keyframes xr-sleep{from{opacity:0;}to{opacity:1;}}


/* idem: in chiaro resta il solo colore del testo. La pastiglia e la lastra
   seguono i token. */
:root[data-theme="light"] .langswitch button{color:rgba(0,0,0,.5);}
:root[data-theme="light"] .langswitch button:hover{color:rgba(0,0,0,.85);}
:root[data-theme="light"] .langswitch button[aria-pressed="true"]{color:#111;}
:root[data-theme="light"] .langswitch__sep{background:rgba(0,0,0,.14);}

@media (max-width:720px){
  /* su schermo stretto la topbar si compatta: lo switch si stringe con lei */
  /* il `right` ora sta sul contenitore: lasciarlo sullo switch non avrebbe
     effetto, perché non è più lui a essere posizionato */
  /* una riga sola rimpicciolisce entrambi i comandi insieme, restando sopra
     i 40px di bersaglio comodo */
  .topctl{right:16px;gap:8px;--ctl-h:40px;}
  /* la cella si stringe e la pastiglia la segue da sola: la sua corsa è
     var(--lang-w), non un numero copiato. Prima qui c'erano due righe di
     padding sovrapposte (la seconda cancellava la prima) — con la larghezza
     dichiarata quel doppione non serve più. */
  .langswitch{--lang-w:38px;}
  .langswitch button{font-size:11px;}
}

.topbar{
  position:fixed;top:32px;left:0;right:0;z-index:210;
  height:var(--topbar-h);               /* fixed header, full body width */
  display:flex;align-items:center;justify-content:space-between;
  padding:0 var(--pad-x);
  /* la barra è larga quanto la finestra: senza questo il suo box vuoto
     intercetta i click di tutto ciò che le passa sotto (era il motivo per
     cui il tasto indietro non rispondeva). I figli se li riprendono. */
  pointer-events:none;
}
.topbar>*{pointer-events:auto;}
/* Cluster di sinistra: [indietro] + marchio + orologi.
   NIENTE gap: la casella dell'indietro è larga 0 quando è chiusa, ma un gap
   varrebbe lo stesso e sposterebbe il logo di 16px fuori griglia. Le
   distanze le mettono i singoli pezzi (margin dell'indietro e dell'orologio). */
.topbar__lead{display:flex;align-items:center;}
.wordmark{display:flex;flex-direction:column;align-items:center;gap:4px;line-height:1;text-align:center;}
.wordmark canvas{display:block;width:42px;height:42px;}
.wordmark__name{font-size:var(--t-cap);font-weight:var(--w-semibold);letter-spacing:var(--ls-title);}
.wordmark__role{font-family:var(--mono);font-size:var(--t-mono);letter-spacing:var(--ls-label);color:var(--ink);text-transform:uppercase;opacity:.7;}
/* right-hand cluster: contact CTA + menu toggle */
.topbar__actions{display:flex;align-items:center;gap:var(--s24);}
.topbar__cta{
  font-size:var(--fs-small);font-weight:var(--w-semibold);line-height:1;letter-spacing:var(--ls-title);
  color:var(--ink);padding:10px 20px;border:1px solid var(--border);border-radius:999px;
  transition:color .25s var(--ease),border-color .25s var(--ease);
}
.topbar__cta:hover{color:var(--accent);border-color:var(--accent);}
/* Menu ⇄ Close: two labels stacked in one masked box, swapped by is-menu-open */
.topbar__menu{
  position:relative;overflow:hidden;cursor:pointer;
  height:1.1em;min-width:4.5em;text-align:right;
  font-size:var(--fs-small);font-weight:var(--w-semibold);line-height:1.1;letter-spacing:var(--ls-title);
  color:var(--ink);background:none;border:0;padding:0;
}
.topbar__menu:hover{color:var(--accent);}
.topbar__menu-open,.topbar__menu-close{
  display:block;transition:transform .45s cubic-bezier(.76,0,.24,1);
}
.topbar__menu-close{position:absolute;inset:0;transform:translateY(100%);}
body.is-menu-open .topbar__menu-open{transform:translateY(-110%);}
body.is-menu-open .topbar__menu-close{transform:none;}

/* ---------- FULL-SCREEN MENU ----------
   Locomotive-style overlay: scrim wipes in, oversized links rise out of
   their own mask with a stagger, mono footer. The topbar (z 210) rides
   above it so the toggle keeps working as the Close control. */
.menu{position:fixed;inset:0;z-index:200;}
.menu[hidden]{display:none;}
.menu__backdrop{
  position:absolute;inset:0;
  background:rgba(0,0,0,.94);
  background:color-mix(in srgb,var(--bg) 94%,transparent);
  -webkit-backdrop-filter:blur(24px) saturate(1.2);backdrop-filter:blur(24px) saturate(1.2);
  opacity:0;transition:opacity .5s var(--ease);
}
.menu.is-open .menu__backdrop{opacity:1;}
.menu__panel{
  position:relative;height:100%;
  display:flex;flex-direction:column;justify-content:space-between;
  padding:calc(62px + var(--s48)) var(--pad-x) var(--s48);
}
.menu__nav{display:flex;flex-direction:column;align-items:flex-start;justify-content:center;flex:1;}
.menu__link{
  display:block;overflow:hidden;color:var(--ink);
  font-size:clamp(40px,8.5vw,96px);font-weight:var(--w-semibold);
  line-height:1.12;letter-spacing:var(--ls-title);
  padding-bottom:.1em;margin-bottom:-.02em;   /* la maschera non taglia le discendenti */
}
/* Le voci salgono dalla loro maschera (.menu__link ha overflow:hidden) con
   uno stagger crescente quando l'overlay prende .is-open. */
.menu__link>span{
  display:block;transform:translateY(115%);
  transition:transform .7s cubic-bezier(.22,1,.36,1),color .25s var(--ease);
}
.menu.is-open .menu__link>span{transform:none;}
.menu__link:nth-child(1)>span{transition-delay:.10s;}
.menu__link:nth-child(2)>span{transition-delay:.16s;}
.menu__link:nth-child(3)>span{transition-delay:.22s;}
.menu__link:nth-child(4)>span{transition-delay:.28s;}
/* in chiusura scendono tutte insieme — niente stagger al contrario */
.menu:not(.is-open) .menu__link>span{transition-delay:0s;transition-duration:.4s;}
.menu__link:hover>span{color:var(--accent);}
.menu__link.is-active>span{color:var(--muted);}
.menu__link.is-active:hover>span{color:var(--accent);}
.menu__foot{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s24);
  font-size:var(--fs-label);letter-spacing:var(--ls-label);text-transform:uppercase;
  color:var(--muted);
  opacity:0;transform:translateY(12px);
  transition:opacity .5s var(--ease) .34s,transform .5s var(--ease) .34s;
}
.menu.is-open .menu__foot{opacity:1;transform:none;}
/* while the menu is open the archive chrome steps back */
body.is-menu-open .dock,
body.is-menu-open .sitefoot,
body.is-menu-open .hud,
body.is-menu-open .cookie,
body.is-menu-open .top-distort,
body.is-menu-open .bottom-distort{opacity:0;pointer-events:none;transition:opacity .3s var(--ease);}
@media (max-width:720px){
  /* la gabbia a 82px è da desktop: su mobile si stringe sul margine di griglia */
  :root{--pad-x:var(--grid-margin-sm);--dock-bottom:var(--s24);}
  .menu__panel{padding:calc(62px + var(--s32)) var(--pad-x) var(--s32);}
  .menu__foot{flex-direction:column;align-items:flex-start;gap:var(--s8);}
  .topbar__cta{display:none;}
}
@media (prefers-reduced-motion:reduce){
  .menu__link>span{transform:none;opacity:0;transition:opacity .3s linear,color .25s var(--ease);}
  .menu.is-open .menu__link>span{opacity:1;}
  .menu__foot{transform:none;}
}

/* ============================================================
   ARCHIVE
   ============================================================ */
.archive{position:fixed;inset:0;z-index:10;
  opacity:0;pointer-events:none;transition:opacity .6s var(--ease);}
body[data-view="archive"] .archive{opacity:1;pointer-events:auto;}
.archive__canvas{
  display:block;width:100%;height:100%;cursor:grab;
  touch-action:none;              /* il gesto lo gestisce JS, non il browser */
  overscroll-behavior:none;       /* niente rimbalzo elastico iOS a fine trascinata */
  -webkit-user-select:none;user-select:none;
  -webkit-touch-callout:none;     /* niente menù "salva immagine" su pressione lunga */
}
.archive__canvas:active{cursor:grabbing;}

/* HUD */
.hud{position:fixed;z-index:95;pointer-events:none;transition:opacity .5s var(--ease);}
body:not([data-view="archive"]) .hud{opacity:0;pointer-events:none;visibility:hidden;}

.hud--focus{
  top:0;left:0;
  display:flex;flex-direction:column;align-items:flex-start;gap:4px;
  text-align:left;max-width:320px;
  /* glass pill dietro al titolo — stessa ricetta del CTA primary */
  padding:10px 18px;border-radius:999px;
  background:linear-gradient(to bottom,rgba(255,255,255,.14) 0%,rgba(255,255,255,.06) 100%);
  -webkit-backdrop-filter:blur(20px) saturate(1.8) brightness(1.08);
          backdrop-filter:blur(20px) saturate(1.8) brightness(1.08);
  border:0.5px solid rgba(255,255,255,.08);
  opacity:0;transform:scale(.96);transform-origin:0 50%;
  will-change:opacity,transform;transition:none;}
:root[data-theme="light"] .hud--focus{
  background:linear-gradient(to bottom,rgba(0,0,0,.07) 0%,rgba(0,0,0,.03) 100%);
  border-color:rgba(0,0,0,.12);}
body[data-view="archive"] .hud--focus.is-shown{
  opacity:1;transform:scale(1);
  /* rientro morbido, nessun overshoot: solo opacity+transform (composited, niente jank) */
  transition:opacity .32s cubic-bezier(.33,1,.68,1),transform .32s cubic-bezier(.33,1,.68,1);}
/* menu aperto → la HUD si toglie di mezzo */
body.is-menu-open .hud--focus.is-shown{
  opacity:0;transform:scale(.965);
  transition:opacity .26s cubic-bezier(.33,1,.68,1),transform .26s cubic-bezier(.33,1,.68,1);}
.hud__idx{color:var(--accent);}
/* il titolo entra ed esce dalla riga: la maschera è .hud__line */
.hud__line{overflow:hidden;}
.hud__title{font-size:var(--fs-sub);font-weight:var(--w-semibold);letter-spacing:var(--ls-title);display:block;
  white-space:nowrap;}
@keyframes hud-out{to{opacity:0;transform:translateY(-7px);}}
@keyframes hud-in {from{opacity:0;transform:translateY(7px);}}
.hud__title.is-out{animation:hud-out 110ms ease-in forwards;}
.hud__title.is-in {animation:hud-in  260ms cubic-bezier(.22,.61,.36,1) both;}
.hud__meta{color:var(--muted);}

/* ---------- STATUS: orologi, accanto al logo in topbar ----------
   Erano in alto a destra insieme alle preferenze; ora le preferenze stanno
   nel dock in basso e qui resta solo l'ora, appoggiata al marchio. Due righe
   compatte (mia · visitatore) alte quanto il logo. */
.status{
  display:flex;flex-direction:column;justify-content:center;gap:3px;
  margin-left:var(--s16);                 /* stacco dal logo (il lead non ha gap) */
  padding-left:var(--s16);border-left:1px solid var(--border);
  align-self:stretch;
}
.status .mono{font-size:var(--t-mono);color:var(--muted);}
.tz{display:flex;flex-direction:row;align-items:center;gap:var(--s8);line-height:1.15;
  white-space:nowrap;}
.tz__label{display:inline-flex;align-items:center;gap:var(--s8);color:var(--ink);}
.tz__time{color:var(--muted);}
.tz__led{width:8px;height:8px;flex:none;}
.tz__led .tz__day{fill:var(--accent);}
.tz__led .tz__night{fill:var(--muted);display:none;}
.tz.is-night .tz__day{display:none;}
.tz.is-night .tz__night{display:block;}
/* Le riduzioni stanno QUI e non nel blocco 720px più in alto: quello viene
   prima della definizione di .status e con pari specificità perderebbe. */
@media (max-width:720px){
  /* accanto al logo resta solo la mia ora: il suo fuso il visitatore lo sa già.
     !important perché updateClocks() scrive display inline su #tzVisitor. */
  .status{padding-left:var(--s12);}
  #tzVisitor{display:none !important;}
}
@media (max-width:480px){
  .status{display:none;}   /* col logo e il Menu non ci sta più nulla */
}

/* ---------- DOCK (navbar in basso al centro) ----------
   Filtri · controllo via mani · preferenze: tre controlli dello stesso tipo,
   raccolti in una sola barra invece di essere sparsi agli angoli. I pannelli
   si aprono verso l'ALTO (vedi .filters__panel / .prefs__panel): in basso non
   c'è spazio. Il contenitore non intercetta i click, li prendono i figli. */
.dock{
  position:fixed;left:50%;bottom:var(--dock-bottom);transform:translateX(-50%);
  /* sopra .bottom-distort (88): la distorsione è il fondale del dock, non un
     velo che glielo sfoca sopra — stesso rapporto che topbar (210) ha col
     .top-distort. Sotto la HUD (95) e il menu (200). */
  z-index:90;
  display:flex;align-items:center;gap:var(--s12);
  pointer-events:none;
  transition:opacity .4s var(--ease),visibility .4s var(--ease),transform .4s var(--ease);
}
.dock>*{pointer-events:auto;}
.dock__slot{display:flex;align-items:center;}
.dock__slot:empty{display:none;}   /* handtrack disattivato → niente spazio vuoto */
/* solo in home: sulle pagine interne la chrome dell'archivio si toglie */
body:not([data-view="archive"]) .dock{
  opacity:0;pointer-events:none;visibility:hidden;transform:translateX(-50%) translateY(8px);
}

/* preferences menu — one small control for theme + audio */
.prefs{position:relative;pointer-events:auto;}
/* ── ICON BUTTONS — round 48×48 glass primary (prefs · filters · back · handtrack) ── */
.prefs__btn,
.filters__btn,
.project__close,
.handtrack-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:48px;
  height:48px;
  border:0.5px solid rgba(255,255,255,.08);
  border-radius:999px;
  cursor:pointer;
  color:var(--ink);           /* icone piene: bianche in dark, nere in light */
  background:linear-gradient(to bottom,rgba(255,255,255,.14) 0%,rgba(255,255,255,.06) 100%);
  -webkit-backdrop-filter:blur(20px) saturate(1.8) brightness(1.08);
          backdrop-filter:blur(20px) saturate(1.8) brightness(1.08);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.35),
    inset 0 -1px 0 rgba(0,0,0,.15);
  transition:color .2s var(--ease),border-color .2s var(--ease),background .2s var(--ease);
}
.prefs__btn:hover,
.prefs.is-open .prefs__btn,
.filters__btn:hover,
.filters.is-open .filters__btn,
.project__close:hover,
.handtrack-btn:hover{
  color:var(--ink);
  background:linear-gradient(to bottom,rgba(255,255,255,.22) 0%,rgba(255,255,255,.10) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.5),
    inset 0 -1px 0 rgba(0,0,0,.15);
}
:root[data-theme="light"] .prefs__btn,
:root[data-theme="light"] .filters__btn,
:root[data-theme="light"] .project__close,
:root[data-theme="light"] .handtrack-btn{
  background:linear-gradient(to bottom,rgba(0,0,0,.07) 0%,rgba(0,0,0,.03) 100%);
  border-color:rgba(0,0,0,.12);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.6),inset 0 -1px 0 rgba(0,0,0,.08);
}
:root[data-theme="light"] .prefs__btn:hover,
:root[data-theme="light"] .prefs.is-open .prefs__btn,
:root[data-theme="light"] .filters__btn:hover,
:root[data-theme="light"] .filters.is-open .filters__btn,
:root[data-theme="light"] .project__close:hover,
:root[data-theme="light"] .handtrack-btn:hover{
  background:linear-gradient(to bottom,rgba(0,0,0,.12) 0%,rgba(0,0,0,.06) 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.7),inset 0 -1px 0 rgba(0,0,0,.08);
}

/* icone: i file in assets/icon montati come mask, non come <img>. La forma
   viene dall'SVG, il colore resta currentColor — così hover, tema chiaro e
   lo stato attivo (accent dell'handtrack) tingono l'icona da soli, senza
   una copia del file per ogni colore. Box 24×24 dentro il bottone da 48. */
.prefs__btn .icon,
.filters__btn .icon{display:none;}

.prefs__btn::before,
.filters__btn::before,
.project__close::before,
.handtrack-btn::before{
  content:'';
  display:block;
  width:24px;
  height:24px;
  flex:none;
  background:currentColor;
  -webkit-mask:var(--icon) center / 24px 24px no-repeat;
          mask:var(--icon) center / 24px 24px no-repeat;
}
.project__close::before{--icon:url(../assets/icon/arrow-left-02-sharp.svg);}                    /* indietro */
.handtrack-btn::before {--icon:url(../assets/icon/rotate-right-01.svg);}                        /* controllo via mani */
.prefs__btn::before    {--icon:url(../assets/icon/setting-02.svg);}                             /* tema + audio */
.filters__btn::before  {--icon:url(../assets/icon/arrow-data-transfer-vertical-sharp.svg);}     /* filtro */
/* Pannello preferenze — sale dal dock, ancorato al centro del bottone.
   Stessa ricetta di vetro del pannello filtri: nel dock i due stanno a 60px
   l'uno dall'altro, con due materiali diversi sembravano due componenti
   presi in prestito da siti diversi. */
.prefs__panel{position:absolute;left:50%;bottom:calc(100% + 8px);min-width:180px;
  display:flex;flex-direction:column;gap:4px;padding:8px;
  border-radius:24px;
  background:linear-gradient(to bottom,rgba(255,255,255,.14) 0%,rgba(255,255,255,.06) 100%);
  -webkit-backdrop-filter:blur(20px) saturate(1.8) brightness(1.08);
          backdrop-filter:blur(20px) saturate(1.8) brightness(1.08);
  border:0.5px solid rgba(255,255,255,.08);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.25),
    0 8px 32px rgba(0,0,0,.45),
    0 2px 8px rgba(0,0,0,.25);
  transform-origin:bottom center;
  animation:dock-panel-in .45s ease both;}
:root[data-theme="light"] .prefs__panel{
  background:linear-gradient(to bottom,rgba(0,0,0,.07) 0%,rgba(0,0,0,.03) 100%);
  border-color:rgba(0,0,0,.12);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.6),0 8px 32px rgba(0,0,0,.14);}
.prefs__panel[hidden]{display:none;}
/* righe come le voci del pannello filtri: testo pieno smorzato dall'opacity,
   così restano leggibili anche sopra una card chiara */
.prefs__row{display:flex;justify-content:space-between;gap:var(--s24);width:100%;
  padding:7px 10px;border-radius:8px;cursor:pointer;text-align:left;
  color:var(--ink);opacity:.6;
  font-size:var(--fs-small);font-weight:var(--w-semibold);text-transform:none;letter-spacing:var(--ls-title);
  transition:background .15s var(--ease),opacity .15s var(--ease);}
.prefs__row:hover{background:rgba(255,255,255,.07);opacity:.9;}
.prefs__row span:last-child{color:var(--accent);}

/* ---------- FILTERS (home / archive) ----------
   Vive dentro il dock: posizione relativa, il pannello sale sopra il bottone. */
.filters{position:relative;pointer-events:auto;}
/* tooltip panel — glass, border-radius 24, bounce in (verso l'alto) */
.filters__panel{
  position:absolute;bottom:calc(100% + 8px);left:50%;
  min-width:170px;
  display:flex;flex-direction:column;gap:4px;padding:8px;
  border-radius:24px;
  background:linear-gradient(to bottom,rgba(255,255,255,.14) 0%,rgba(255,255,255,.06) 100%);
  -webkit-backdrop-filter:blur(20px) saturate(1.8) brightness(1.08);
          backdrop-filter:blur(20px) saturate(1.8) brightness(1.08);
  border:0.5px solid rgba(255,255,255,.08);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.25),
    0 8px 32px rgba(0,0,0,.45),
    0 2px 8px rgba(0,0,0,.25);
  max-height:min(52vh,420px);overflow-y:auto;
  transform-origin:bottom center;
  animation:dock-panel-in .45s ease both;
}
.filters__panel[hidden]{display:none;}
/* i pannelli del dock crescono verso l'alto restando centrati sul bottone:
   il translateX(-50%) deve stare DENTRO i keyframe, o l'animazione lo azzera. */
@keyframes dock-panel-in{
  0%  {opacity:0;transform:translateX(-50%) scale(0.94) translateY(6px);}
  55% {opacity:1;transform:translateX(-50%) scale(1.015) translateY(-1px);}
  100%{opacity:1;transform:translateX(-50%) scale(1) translateY(0);}
}
/* ── PILL BUTTONS — testo mono + glass (filter-chip · jtoggle) ── */
.filter-chip,
.jtoggle{
  display:inline-flex;align-items:center;
  font-size:var(--fs-small);font-weight:var(--w-semibold);letter-spacing:var(--ls-title);
  color:var(--muted);
  background:rgba(255,255,255,.06);
  border:1px solid var(--border);
  border-radius:999px;
  cursor:pointer;
  -webkit-backdrop-filter:blur(0.5px) url(#cta-glass) blur(12px) brightness(1.1) saturate(1.5);
          backdrop-filter:blur(0.5px) url(#cta-glass) blur(12px) brightness(1.1) saturate(1.5);
  transition:color .2s var(--ease),border-color .2s var(--ease),background .2s var(--ease);
}
.filter-chip:hover,.jtoggle:hover{color:var(--ink);border-color:var(--ink);}

/* override padding per tipo */
.filter-chip{padding:7px 14px;pointer-events:auto;width:100%;justify-content:flex-start;}
.jtoggle{padding:9px 16px;}

/* stati attivi */
.filter-chip.is-active{background:rgba(255,99,71,.88);border-color:var(--accent);color:#000;}
.jtoggle.is-active{background:rgba(255,255,255,.18);border-color:rgba(255,255,255,.35);color:var(--ink);}

/* dentro il tooltip filtri: stile link (tertiary), niente pill */
.filters__panel .filter-chip{
  background:transparent;border:none;border-radius:8px;
  -webkit-backdrop-filter:none;backdrop-filter:none;
  padding:7px 10px;
  color:var(--ink);opacity:.6;
  font-size:var(--fs-small);font-weight:var(--w-semibold);text-transform:none;letter-spacing:var(--ls-title);
  text-align:left;justify-content:flex-start;
  white-space:nowrap;   /* "Emerging Technologies" su una riga: il pannello si allarga */
  position:relative;
}
.filters__panel .filter-chip:hover{
  opacity:.9;background:rgba(255,255,255,.07);border:none;
}
.filters__panel .filter-chip.is-active{
  opacity:1;background:transparent;border:none;font-weight:var(--w-semibold);
}
.filters__panel .filter-chip.is-active::after{
  content:'';position:absolute;left:10px;bottom:4px;
  width:calc(100% - 20px);height:1px;
  background:currentColor;opacity:.4;
}

/* chiusura tooltip con bounce inverso */
@keyframes dock-panel-out{
  0%  {opacity:1;transform:translateX(-50%) scale(1) translateY(0);}
  35% {opacity:.8;transform:translateX(-50%) scale(1.01) translateY(-1px);}
  100%{opacity:0;transform:translateX(-50%) scale(0.93) translateY(6px);}
}
.filters__panel.is-closing{
  animation:dock-panel-out .32s ease both;
  pointer-events:none;
}

/* ---------- SITE FOOTER (sottile, persistente in home) ---------- */
.sitefoot{
  position:fixed;right:var(--pad-x);bottom:var(--dock-bottom);z-index:90;
  height: 48px;
  display:flex;align-items:center;gap:14px;
  font-size:var(--t-mono);letter-spacing:var(--ls-label);text-transform:uppercase;
  color:var(--muted);
  transition:opacity .4s var(--ease),visibility .4s var(--ease);
}
.sitefoot__c{opacity:.7;}
.sitefoot__l{color:var(--muted);}
.sitefoot__l:hover{color:var(--accent);}
/* mostrato solo in home; nascosto sulle altre viste e finché il banner cookie è visibile */
body:not([data-view="archive"]) .sitefoot{opacity:0;visibility:hidden;pointer-events:none;}
#cookie:not([hidden]) ~ .sitefoot{opacity:0;visibility:hidden;pointer-events:none;}
/* Il footer condivide la riga col dock (centrato): sotto i ~1080px la riga
   non tiene entrambi e la firma andrebbe a sbattere sul tasto preferenze.
   Cade il copyright, restano i due link legali — che sono la parte utile. */
@media (max-width:1080px){ .sitefoot__c{display:none;} }
@media (max-width:640px){ .sitefoot{display:none;} }   /* niente clutter vicino alla nav mobile */

/* ---------- COOKIE BANNER ---------- */
/* ── BANNER COOKIE ──
   In basso a SINISTRA, non centrato: il centro in basso è occupato dalla CTA
   "Scrivimi" e dalla firma. Un banner centrato ci finirebbe sopra, ed è
   esattamente il difetto da evitare.
   Materiale: lo stesso vetro dei comandi (.glass), non il bianco pieno di
   prima — un rettangolo bianco opaco su una griglia di immagini è l'unica
   cosa in pagina che non appartiene al resto. */
.cookie{
  position:fixed;
  left:var(--pad-x);
  bottom:var(--dock-bottom);
  z-index:120;
  max-width:320px;
  display:flex;flex-direction:column;gap:16px;
  padding:24px;
  border-radius:20px;
  border:0;
  background-color:color-mix(in srgb,var(--gl-tint) calc(var(--gl-fill) + 6%),transparent);
  -webkit-backdrop-filter:blur(30px) saturate(1.8);
          backdrop-filter:blur(30px) saturate(1.8);
  /* stessa grammatica di bordo della lastra: contorno sottile, colmo sopra,
     rientro sotto, una portata sola. Vedi il commento su .glass. */
  box-shadow:
    inset 0 0 0 .5px       color-mix(in srgb,var(--gl-light) calc(var(--gl-reflex-light) * 18%),transparent),
    inset 0 1px 2px -1px   color-mix(in srgb,var(--gl-light) calc(var(--gl-reflex-light) * 60%),transparent),
    inset 0 -1px 2px -1px  color-mix(in srgb,var(--gl-dark) calc(var(--gl-reflex-dark) * 14%),transparent),
    0 8px 28px -6px        color-mix(in srgb,var(--gl-dark) calc(var(--gl-reflex-dark) * 34%),transparent);
  /* ENTRATA: sale da sotto e si posa. `both` tiene lo stato iniziale durante
     il ritardo, altrimenti si vedrebbe in posizione per un fotogramma.
     La curva senza rimbalzo è la stessa della modale: una cosa che ha peso
     non rimbalza, decelera. */
  animation:cookie-in .62s cubic-bezier(.16,1,.3,1) both;
}
/* `hidden` deve battere il display:flex qui sopra */
.cookie[hidden]{display:none;}

@keyframes cookie-in{
  from{opacity:0;transform:translateY(24px) scale(.96);filter:blur(6px);}
  to  {opacity:1;transform:none;filter:blur(0);}
}
/* USCITA: non sparisce, se ne va. La classe la mette il JS e la toglie dal DOM
   quando l'animazione finisce (animationend) — senza, `hidden` scatterebbe
   subito e l'uscita non si vedrebbe mai.
   Scende e si rimpicciolisce un filo più di quanto fosse entrata: un'uscita
   più rapida dell'entrata si legge come "chiuso", una più lenta come esitazione. */
.cookie.is-leaving{
  animation:cookie-out .34s cubic-bezier(.4,0,1,1) both;
  pointer-events:none;      /* nessun doppio click mentre esce */
}
@keyframes cookie-out{
  from{opacity:1;transform:none;filter:blur(0);}
  to  {opacity:0;transform:translateY(16px) scale(.94);filter:blur(4px);}
}
/* le varianti da mobile, dove il banner è ancorato in alto: entra ed esce
   verso l'ALTO. Stanno qui fuori e non dentro la media query — vedi il
   commento là sotto. */
@keyframes cookie-in-top{
  from{opacity:0;transform:translateY(-22px) scale(.96);filter:blur(6px);}
  to  {opacity:1;transform:none;filter:blur(0);}
}
@keyframes cookie-out-top{
  from{opacity:1;transform:none;filter:blur(0);}
  to  {opacity:0;transform:translateY(-16px) scale(.94);filter:blur(4px);}
}

.cookie__text{
  color:rgba(255,255,255,.86);
  line-height:1.5;text-transform:none;letter-spacing:0;
  font-size:13.5px;
  text-shadow:0 1px 3px rgba(0,0,0,.45);   /* regge anche su una card chiara */
}
.cookie__row{display:flex;gap:8px;}

/* I due comandi. Il primario è BIANCO PIENO: sul vetro serve un punto di
   contrasto vero, o le due scelte pesano uguale e non si capisce quale sia
   quella normale. Il secondario resta vetro sul vetro — visibile ma
   chiaramente subordinato.
   Prima erano tarati per una card bianca (nero pieno + bordo grigio) e su
   questo fondo sarebbero spariti. */
.cookie__btn{
  flex:1;
  display:inline-flex;align-items:center;justify-content:center;
  font:inherit;font-size:13px;font-weight:var(--w-regular);letter-spacing:0;
  min-height:40px;padding:10px 18px;
  border-radius:999px;cursor:pointer;border:0;
  background:linear-gradient(180deg,#ffffff 0%,#ececea 100%);
  color:#0b0b0b;
  box-shadow:
    inset 0 0 0 .5px      rgba(0,0,0,.06),
    inset 0 1px 1px       rgba(255,255,255,.9),
    inset 0 -1px 3px -1px rgba(0,0,0,.18),
    0 2px 10px -2px       rgba(0,0,0,.30);
  transition:background .3s var(--ease-glass),box-shadow .3s var(--ease-glass),
             transform .3s var(--ease-glass);
}
.cookie__btn:hover{
  background:linear-gradient(180deg,#ffffff 0%,#f6f5f4 100%);
  transform:translateY(-1px);
  box-shadow:
    inset 0 0 0 .5px      rgba(0,0,0,.06),
    inset 0 1px 1px       rgba(255,255,255,1),
    inset 0 -1px 3px -1px rgba(0,0,0,.18),
    0 4px 14px -3px       rgba(0,0,0,.35);
}
.cookie__btn:active{transform:translateY(0) scale(.985);}
.cookie__btn:focus-visible{outline:2px solid #fff;outline-offset:3px;}

.cookie__btn--ghost{
  background:color-mix(in srgb,var(--gl-tint) 14%,transparent);
  color:rgba(255,255,255,.88);
  box-shadow:
    inset 0 0 0 .5px      color-mix(in srgb,var(--gl-light) calc(var(--gl-reflex-light) * 24%),transparent),
    inset 0 1px 1px -.5px color-mix(in srgb,var(--gl-light) calc(var(--gl-reflex-light) * 50%),transparent),
    inset 0 -1px 2px -1px color-mix(in srgb,var(--gl-dark) calc(var(--gl-reflex-dark) * 22%),transparent);
}
.cookie__btn--ghost:hover{
  background:color-mix(in srgb,var(--gl-tint) 24%,transparent);
  color:#fff;
  box-shadow:
    inset 0 0 0 .5px      color-mix(in srgb,var(--gl-light) calc(var(--gl-reflex-light) * 32%),transparent),
    inset 0 1px 1px -.5px color-mix(in srgb,var(--gl-light) calc(var(--gl-reflex-light) * 65%),transparent),
    inset 0 -1px 2px -1px color-mix(in srgb,var(--gl-dark) calc(var(--gl-reflex-dark) * 22%),transparent);
}

/* accessibility: collapse all motion for users who ask for it */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;}
}

/* ── MOBILE ──
   Il vincolo vero. Su telefono la colonna centrale in basso è occupata dalla
   CTA "Scrivimi" (bottom:52px) e dalla firma (bottom:16px): un banner
   ancorato al fondo ci finirebbe sopra — che è precisamente il difetto da
   evitare.
   Quindi su schermo stretto NON sta in basso: si ancora in ALTO, sotto la
   fascia arancione, dove non c'è nient'altro. È l'unica zona libera, e in più
   un avviso di consenso in cima si legge prima.
   --wipbar-h è l'altezza reale della fascia, misurata da js/i18n.js: usarla
   invece di un numero fisso è ciò che tiene il banner al suo posto quando il
   testo va a capo un numero diverso di volte (lingua, rotazione, font). */
@media (max-width:720px){
  .cookie{
    left:12px;right:12px;
    max-width:none;                 /* prende la larghezza: a 320px una colonna
                                       da 320 non ci starebbe comunque */
    bottom:auto;
    /* sotto la fascia E sotto i comandi in alto a destra (lingua + visore),
       che stanno a top:--wipbar-h + 12 e sono alti --ctl-h (40px su mobile).
       Senza i +52 il banner ci finiva sopra: liberata la CTA in basso, si
       creava la stessa collisione dall'altra parte. */
    top:calc(var(--wipbar-h,48px) + 12px + var(--ctl-h,40px) + 12px);
    padding:15px 16px;
    gap:13px;
    border-radius:18px;
  }
  /* scendendo dall'alto invece che salendo dal basso: l'entrata deve venire
     dal bordo più vicino, o sembra che il pannello attraversi la pagina per
     arrivare al suo posto.
     Sono due @keyframes SEPARATI e non una ridefinizione di cookie-in dentro
     la media query: un @keyframes annidato dentro @media non è ridefinibile
     in modo affidabile — i parser lo accettano ma la regola vince o perde a
     seconda dell'ordine, e qui faceva cadere l'intero blocco. */
  .cookie{animation-name:cookie-in-top;}
  .cookie.is-leaving{animation-name:cookie-out-top;}
  .cookie__text{font-size:12.5px;}
  /* i due comandi restano affiancati (c'è spazio, sono corti) ma con il
     bersaglio tattile pieno */
  .cookie__btn{min-height:42px;font-size:12.5px;}
}

/* Fuori da MVP il banner convive con .sitefoot, che sta nello stesso angolo.
   Questa regola c'era già: la lascio, ma vale solo quando il footer del sito
   completo è acceso. */

/* Motion ridotto: compare e sparisce, senza scorrimenti né sfocature. */
/* i keyframe stanno FUORI dalla media query: annidarli dentro @media non è
   affidabile (vedi il commento sulle varianti -top qui sopra). */
@keyframes cookie-fade{from{opacity:0;}to{opacity:1;}}
@keyframes cookie-fade-out{from{opacity:1;}to{opacity:0;}}
@media (prefers-reduced-motion:reduce){
  .cookie{animation:cookie-fade .25s linear both;}
  .cookie.is-leaving{animation:cookie-fade-out .2s linear both;}
}

/* ============================================================
   EDITORIAL SECTIONS (about / journal / contact / project)
   ============================================================ */
.section{
  position:relative;z-index:20;min-height:100vh;background:var(--bg);
  padding:calc(var(--s88) + var(--grid-margin)) var(--grid-margin) var(--s88);
  opacity:0;transform:translateY(110px);
  transition:opacity .55s var(--ease), transform .7s cubic-bezier(.16,1,.3,1);
  will-change:opacity, transform;
}
.section[hidden]{display:none;}
.section.is-active{opacity:1;transform:none;}
.section.is-leaving{opacity:0;transform:translateY(-48px);}
/* project resolves as if zoomed-in from the clicked card */
/* project page wears the project's colour: a deep tint of --proj over the base bg
   (readable), with --accent (set inline) re-tinting eyebrows, chips and links */
.section--project{transform:scale(1.06);transform-origin:50% 30%;
  background:color-mix(in srgb, var(--proj, transparent) 14%, var(--bg));}
/* boxed content: container ≤1440, centrato; contenuto a bandiera (sinistra) */
.section__inner{max-width:var(--maxw);margin-inline:auto;text-align:left;}

@media (max-width:720px){
  .section{padding:calc(var(--s88) + var(--s24)) var(--grid-margin-sm) var(--s48);}
}

/* eyebrow + heading shared */
.eyebrow{display:flex;align-items:center;gap:var(--s16);margin-bottom:var(--s24);}
.eyebrow::after{content:"";flex:1;height:1px;background:var(--border);}
.lead-h{font-size:var(--t-h);font-weight:var(--w-semibold);line-height:.93;letter-spacing:var(--ls-title);margin-bottom:var(--s40);max-width:18ch;}

/* ---------- ABOUT (phantom agency-style) ----------
   Tutto vive sulle 12 colonne: l'hero occupa 1→9, la prosa la colonna di lettura
   4→11, i blocchi dentro .spec__value ricadono sulle 9 colonne 4→12.
   Testo sempre a bandiera: allineato a sinistra, margine destro libero. */
.ab-hero{margin-bottom:var(--s48);text-align:left;}
.ab-hero__eyebrow{grid-column:1/-1;display:block;margin-bottom:var(--s24);}
/* hero statement: manifesto grande (fs-display), colonna ampia, a bandiera */
.about-statement{grid-column:1/9;font-size:var(--fs-display);font-weight:var(--w-semibold);
  line-height:var(--lh-tight);letter-spacing:var(--ls-title);margin-bottom:var(--s40);
  text-wrap:pretty;hyphens:none;}
.ab-hero__intro{grid-column:4/10;line-height:var(--lh-normal);
  color:color-mix(in srgb, var(--ink) 86%, transparent);text-wrap:pretty;}
/* la media grid dell'about vive nel blocco PHANTOM PATTERNS (.ab-media) */

/* approach — lead sulle prime 6 delle 9 colonne, principi 4+4 con gutter di mezzo */
.ab-lead{grid-column:1/7;font-size:var(--t-lg);line-height:1.45;margin-bottom:var(--s40);text-wrap:pretty;}
.ab-principles{grid-column:1/-1;display:grid;grid-template-columns:repeat(9,minmax(0,1fr));
  gap:var(--s40) var(--grid-gutter);}
.ab-principle{display:flex;gap:var(--s16);grid-column:span 4;}
.ab-principle:nth-child(even){grid-column:6/span 4;}
.ab-principle__n{color:var(--accent);padding-top:3px;}
.ab-principle__t{font-size:var(--t-body);font-weight:var(--w-semibold);margin-bottom:var(--s8);}
.ab-principle__d{font-size:var(--t-sm);color:var(--muted);line-height:1.55;text-wrap:pretty;}

/* experience / teaching rows — periodo 2col · ruolo 4col · nota 3col (sulle 9) */
.ab-xp{grid-column:1/-1;display:flex;flex-direction:column;}
.ab-xp__row{display:grid;grid-template-columns:repeat(9,minmax(0,1fr));gap:var(--grid-gutter);
  padding:var(--s24) 0;border-top:1px solid var(--border);align-items:baseline;}
.ab-xp__row:first-child{border-top:0;padding-top:0;}
.ab-xp__period{grid-column:span 2;color:var(--muted);}
.ab-xp__main{grid-column:span 4;}
.ab-xp__note{grid-column:span 3;font-size:var(--t-sm);color:var(--muted);line-height:1.55;text-wrap:pretty;}
.ab-xp__role{font-size:var(--t-body);font-weight:var(--w-semibold);}
.ab-xp__org{font-size:var(--t-sm);color:var(--muted);}

/* capabilities — due colonne da 4 con il gutter di mezzo */
.ab-list{grid-column:1/-1;list-style:none;display:grid;grid-template-columns:repeat(9,minmax(0,1fr));
  column-gap:var(--grid-gutter);}
.ab-list__item{grid-column:span 4;font-size:var(--t-body);padding:var(--s16) 0;border-top:1px solid var(--border);}
.ab-list__item:nth-child(even){grid-column:6/span 4;}

/* clients wall — 3 colonne da 3 (allineata alle 9 del valore).
   Filetti sulle celle, non sul gap: se l'ultima riga è incompleta il muro resta
   aperto invece di lasciare un buco di colore diverso. */
.ab-clients{grid-column:1/-1;list-style:none;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  border-top:1px solid var(--border);border-left:1px solid var(--border);}
.ab-clients__item{border-right:1px solid var(--border);border-bottom:1px solid var(--border);
  min-height:80px;display:flex;align-items:center;justify-content:center;
  text-align:center;padding:var(--s16);font-family:var(--mono);font-size:var(--t-mono);
  text-transform:uppercase;letter-spacing:var(--ls-label);color:var(--ink);transition:color .2s var(--ease);}
.ab-clients__item:hover{color:var(--accent);}

/* stats — 3 blocchi da 3 colonne, filetto in testa invece del box chiuso */
.ab-stats{grid-column:1/-1;display:grid;grid-template-columns:repeat(9,minmax(0,1fr));gap:var(--grid-gutter);}
.ab-stats .stat{grid-column:span 3;}

/* blocco "in volo": prosa + CTA nella colonna di lettura */
.ab-flight{grid-column:1/7;}

/* CTA — a bandiera come il resto della pagina, non centrata */
.ab-cta{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--grid-gutter);
  padding:var(--s88) 0 var(--s40);border-top:1px solid var(--border);margin-top:var(--s48);text-align:left;}
.ab-cta__title{grid-column:1/9;font-size:var(--fs-display);font-weight:var(--w-semibold);line-height:var(--lh-tight);
  letter-spacing:var(--ls-title);margin-bottom:var(--s32);}
.ab-cta__link{grid-column:1/5;justify-self:start;font-family:var(--mono);font-size:var(--t-mono);
  text-transform:uppercase;letter-spacing:var(--ls-label);
  border:1px solid var(--border);border-radius:999px;padding:12px 22px;display:inline-block;}
.ab-cta__link:hover{border-color:var(--accent);color:var(--accent);}

/* tags — SAME pill style as .chip (one chip language site-wide) */
.tag-row{display:flex;flex-wrap:wrap;gap:var(--s8);margin-top:var(--s8);}
.tag{font-family:var(--mono);font-size:var(--t-mono);text-transform:uppercase;letter-spacing:var(--ls-label);
  color:var(--ink);border:1px solid var(--border);border-radius:999px;padding:7px 14px;}
.tag:hover{border-color:var(--accent);color:var(--accent);}

@media (max-width:1000px){
  .about-statement{grid-column:1/-1;}
  .ab-hero__intro,.ab-lead,.ab-flight{grid-column:1/-1;}
  .ab-cta__title{grid-column:1/-1;}
  .ab-cta__link{grid-column:1/-1;}
  .ab-principles,.ab-list,.ab-stats,.ab-xp__row{grid-template-columns:repeat(6,minmax(0,1fr));}
  .ab-principle,.ab-principle:nth-child(even),
  .ab-list__item,.ab-list__item:nth-child(even){grid-column:span 3;}
  .ab-stats .stat{grid-column:span 2;}
  .ab-xp__period{grid-column:span 6;}
  .ab-xp__main{grid-column:span 3;}
  .ab-xp__note{grid-column:span 3;}
}
@media (max-width:720px){
  .ab-principles,.ab-list,.ab-stats,.ab-clients{grid-template-columns:1fr;}
  .ab-principle,.ab-principle:nth-child(even),
  .ab-list__item,.ab-list__item:nth-child(even),
  .ab-stats .stat{grid-column:1/-1;}
  .ab-xp__row{grid-template-columns:1fr;gap:6px;}
  .ab-xp__period,.ab-xp__main,.ab-xp__note{grid-column:1/-1;}
  .ab-cta{padding-top:var(--s48);}
}

/* ---------- INDEX LIST (journal + work list) ---------- */
.index-list{border-top:1px solid var(--border);}
.index-row{
  display:grid;grid-template-columns:64px 120px 1fr 200px;gap:var(--s24);align-items:baseline;
  padding:var(--s24) 0;border-bottom:1px solid var(--border);
  cursor:pointer;transition:padding-left .25s var(--ease);
}
.index-row:hover{padding-left:var(--s16);}
.index-row__idx{font-family:var(--mono);font-size:var(--t-mono);color:var(--muted);}
.index-row__date{font-family:var(--mono);font-size:var(--t-mono);color:var(--muted);text-transform:uppercase;}
.index-row__title{font-size:var(--fs-sub);font-weight:400;letter-spacing:var(--ls-title);transition:color .2s var(--ease);}
.index-row:hover .index-row__title{color:var(--accent);}
.index-row__cat{font-family:var(--mono);font-size:var(--t-mono);color:var(--muted);text-transform:uppercase;text-align:right;}
.index-row__abstract{grid-column:3 / 4;font-size:var(--t-sm);line-height:1.4;color:var(--muted);margin-top:var(--s8);max-width:64ch;}
@media (max-width:720px){
  .index-row{grid-template-columns:48px 1fr;}
  .index-row__date,.index-row__cat{display:none;}
  .index-row__abstract{grid-column:2 / 3;}
}

/* ---------- JOURNAL: grid (toggle/hero styles live in the JOURNAL block below) ---------- */
.journal-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s48) var(--s32);}
.journal-grid[hidden]{display:none;}
@media (max-width:1000px){.journal-grid{grid-template-columns:repeat(2,1fr);}}
@media (max-width:640px){.journal-grid{grid-template-columns:1fr;}}

.jcard{display:flex;flex-direction:column;gap:var(--s16);cursor:pointer;}
.jcard__cover{aspect-ratio:16/10;border:1px solid var(--border);border-radius:var(--radius);
  overflow:hidden;background:rgba(128,128,128,.06);}
.jcard__cover img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .6s var(--ease);}
.jcard:hover .jcard__cover img{transform:scale(1.04);}
.jcard--noimg .jcard__cover{display:none;}
.jcard__meta{display:flex;justify-content:space-between;gap:var(--s16);color:var(--muted);}
.jcard__title{font-size:var(--fs-title);font-weight:var(--w-semibold);line-height:var(--lh-tight);letter-spacing:var(--ls-title);transition:color .2s var(--ease);}
.jcard:hover .jcard__title{color:var(--accent);}
.jcard__abstract{font-size:var(--t-sm);line-height:1.45;color:var(--muted);}

/* ---------- CONTACT (phantom agency-style: statement + spec rows) ---------- */
/* ---------- ARTICLE (journal reading view) ---------- */
/* titolo articolo — display H1, come la project page */
.article-title{font-size:var(--fs-display);font-weight:var(--w-semibold);line-height:var(--lh-tight);
  letter-spacing:var(--ls-title);margin-bottom:var(--s32);max-width:18ch;}

/* booking (Cal.com) */
.booking{margin-top:var(--s88);border-top:1px solid var(--border);padding-top:var(--s40);}
.booking__head{display:flex;flex-direction:column;gap:var(--s16);margin-bottom:var(--s32);}
.booking__note{font-size:var(--t-sm);line-height:1.45;color:var(--muted);max-width:54ch;}
.booking__btn{display:inline-flex;align-items:center;gap:var(--s8);cursor:pointer;
  font-size:var(--t-lg);font-weight:var(--w-semibold);letter-spacing:var(--ls-title);color:#000;background:var(--accent);
  border-radius:999px;padding:16px 24px;transition:transform .25s var(--ease),opacity .2s var(--ease);}
.booking__btn:hover{transform:translateY(-2px);opacity:.92;}

/* quick contact form — hairline fields, square corners, reCAPTCHA-gated */
/* il form vive dentro una riga .spec — il ritmo verticale lo danno i divider */
.cform{margin:0;}
.cform__note{font-size:var(--t-sm);line-height:1.45;color:var(--muted);max-width:54ch;}
.cform__grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s32) var(--s40);max-width:880px;}
.cform__field{display:flex;flex-direction:column;gap:10px;}
.cform__field--full{grid-column:1 / -1;}
.cform__label{color:var(--muted);}
.cform input,.cform textarea{
  -webkit-appearance:none;appearance:none;   /* kill native UA chrome on Safari/Chrome */
  font:inherit;color:var(--ink);background:transparent;border:0;border-bottom:1px solid var(--border);
  padding:10px 2px;border-radius:0;outline:none;transition:border-color .2s var(--ease);}
.cform textarea{border:1px solid var(--border);padding:12px;resize:vertical;min-height:120px;}
.cform input:focus,.cform textarea:focus{border-color:var(--accent);}
.cform__hp{position:absolute;left:-9999px;opacity:0;pointer-events:none;}   /* honeypot */
.cform__captcha{margin-top:var(--s32);min-height:78px;}
.cform__row{display:flex;align-items:center;gap:var(--s24);margin-top:var(--s24);flex-wrap:wrap;}
.cform__status{color:var(--muted);}
.cform__status.is-ok{color:var(--accent);}
.cform__status.is-err{color:#ff5050;}
@media (max-width:720px){.cform__grid{grid-template-columns:1fr;}}
/* autofill: keep our colours, no yellow/blue UA fill */
.cform input:-webkit-autofill,.cform textarea:-webkit-autofill{
  -webkit-text-fill-color:var(--ink);
  -webkit-box-shadow:0 0 0 1000px var(--bg) inset;transition:background-color 9999s;}
.cform ::placeholder{color:var(--muted);opacity:.7;}

.contact-foot{margin-top:var(--s24);font-family:var(--mono);font-size:var(--t-mono);text-transform:uppercase;color:var(--muted);letter-spacing:var(--ls-label);}

/* ---------- BACK (indietro: project / article / legal) ----------
   Non è più un bottone fisso sotto l'header: è il primo posto della riga
   dell'header. Entrando in un work la sua casella si APRE (width 0→48 +
   gap) e logo e orologi scivolano a destra; uscendo la casella si richiude
   e tutto torna al suo posto. Resta ancorato a --pad-x perché è il primo
   figlio di .topbar__lead, che parte dal padding della topbar.

   Le due transizioni sono sfasate apposta:
     entrata → prima si apre lo spazio, POI il tasto compare (delay .18s)
     uscita  → prima il tasto svanisce, poi lo spazio si richiude
   Senza lo sfasamento il tasto e il logo si attraversano a metà strada. */
.topbar__back{
  display:flex;align-items:center;
  width:0;margin-right:0;
  opacity:0;transform:translateX(-10px) scale(.9);
  pointer-events:none;
  transition:
    width .5s var(--ease),
    margin-right .5s var(--ease),
    opacity .22s var(--ease),
    transform .22s var(--ease);
}
body[data-view="project"] .topbar__back,
body[data-view="article"] .topbar__back,
body[data-view="legal"]   .topbar__back,
body[data-view="notice"]  .topbar__back{
  width:48px;margin-right:var(--s16);
  opacity:1;transform:none;
  pointer-events:auto;
  transition:
    width .5s var(--ease),
    margin-right .5s var(--ease),
    opacity .32s var(--ease) .18s,
    transform .42s var(--ease) .18s;
}
.project__close{
  border-radius:50%; /* cerchio pieno, override del 999px condiviso */
  color:var(--ink);
  flex:none;
}
.project__close svg{flex:none;}
/* tre tasti nello stesso posto: si mostra solo quello della vista corrente */
.project__close{display:none;}
body[data-view="project"] #projectClose,
body[data-view="article"] #articleClose,
body[data-view="legal"]   #legalClose,
body[data-view="notice"]  #noticeClose{display:inline-flex;}
@media (prefers-reduced-motion:reduce){
  .topbar__back{transition:opacity .2s linear;}
}

/* ---------- NOTICE (404 · presto in arrivo) ----------
   Due pagine di servizio con la stessa impaginazione: la cifra/parola grande
   fa da immagine, sotto una riga di spiegazione e le vie d'uscita. Verticale
   centrata sul viewport perché non c'è contenuto sotto: una pagina di errore
   che comincia in alto e finisce a metà schermo sembra rotta anche lei. */
.section--notice{
  display:flex;align-items:center;
  min-height:100vh;
}
.section--notice .section__inner{width:100%;}
/* la cifra: grossa ma non schiacciante — deve restare in rapporto col
   titolo (46px), non farlo sparire. Peso normale: il corpo basta. */
.notice__mark{
  margin:var(--s16) 0 var(--s24);
  font-size:clamp(72px,13vw,168px);
  font-weight:var(--w-semibold);
  line-height:.86;letter-spacing:-.045em;
  color:var(--ink);
}
.section--notice .page-hero{padding-bottom:var(--s16);}
.section--notice .page-hero__title{max-width:18ch;}
.section--notice .page-hero__sub{max-width:52ch;}
.notice__links{
  display:flex;flex-wrap:wrap;gap:var(--s32);
  margin-top:var(--s40);
}
@media (max-width:640px){
  .notice__links{flex-direction:column;gap:var(--s16);align-items:flex-start;}
}

/* ---------- LEGAL (privacy / cookie) ---------- */
.legal{margin:0;padding-bottom:var(--s88);}        /* a bandiera (sx); larghezza data dalla col-span */
.legal p, .legal__list{max-width:68ch;}            /* misura di lettura comoda dentro la colonna */
.legal__block{margin-top:var(--s40);}
.legal__h{font-family:var(--font);font-weight:var(--w-semibold);letter-spacing:var(--ls-title);
  font-size:var(--fs-sub);margin-bottom:var(--s12);}
.legal p{font-size:var(--fs-body);line-height:1.65;color:var(--ink);margin-bottom:var(--s12);}
.legal__list{margin:0 0 var(--s12) 1.1em;padding:0;}
.legal__list li{font-size:var(--fs-body);line-height:1.6;margin-bottom:6px;}
.legal a{color:var(--accent);text-decoration:underline;text-underline-offset:3px;}
.legal__updated{margin-top:var(--s40);color:var(--muted);}
.legal__switch{margin-top:var(--s24);}
/* legal links in the cookie banner + contact footer */
.cookie__text a, .contact-foot a{color:inherit;text-decoration:underline;text-underline-offset:2px;opacity:.8;}
.cookie__text a:hover, .contact-foot a:hover{opacity:1;color:var(--accent);}

/* article inherits the roll transition from .section; just tune the easing slightly */
.section--article{transition:opacity .55s var(--ease), transform .7s cubic-bezier(.16,1,.3,1);}
.section--article.is-active{transform:none;}

/* titolo progetto — display H1, full width, a bandiera */
.case-title{font-size:var(--fs-display);font-weight:var(--w-light);line-height:var(--lh-tight);
  letter-spacing:var(--ls-title);margin-bottom:var(--s32);max-width:18ch;}

/* fade-up util used by JS reveal */
.reveal{opacity:0;transform:translateY(18px);}
.reveal.is-in{opacity:1;transform:none;transition:opacity .9s var(--ease),transform .9s var(--ease);}

/* ============================================================
   CTA SYSTEM
   primary  — glass (nav-style): bg gradient + backdrop-filter + specular
   secondary — outline only: white border, no bg, no blur
   solid    — solid fill: bianco/nero invertito per tema (alt primary)
   link     — link testuale sottolineato (tertiary)
   ============================================================ */
.cta{
  display:inline-flex;align-items:center;gap:8px;
  font-size:var(--fs-small);font-weight:var(--w-semibold);letter-spacing:var(--ls-title);
  padding:13px 22px;border-radius:999px;cursor:pointer;
  /* glass — uguale al nav */
  background:linear-gradient(to bottom,rgba(255,255,255,.14) 0%,rgba(255,255,255,.06) 100%);
  -webkit-backdrop-filter:blur(20px) saturate(1.8) brightness(1.08);
          backdrop-filter:blur(20px) saturate(1.8) brightness(1.08);
  border:0.5px solid rgba(255,255,255,.08);
  color:var(--ink);
  transition:background .2s var(--ease),color .2s var(--ease),
             border-color .2s var(--ease),transform .2s var(--ease);
}
.cta:hover{
  background:linear-gradient(to bottom,rgba(255,255,255,.22) 0%,rgba(255,255,255,.10) 100%);
  transform:translateY(-1px);
}
/* light theme — inverti i canali RGBA per leggibilità su sfondo chiaro */
:root[data-theme="light"] .cta{
  background:linear-gradient(to bottom,rgba(0,0,0,.07) 0%,rgba(0,0,0,.03) 100%);
  border-color:rgba(0,0,0,.12);
}
:root[data-theme="light"] .cta:hover{
  background:linear-gradient(to bottom,rgba(0,0,0,.12) 0%,rgba(0,0,0,.06) 100%);
}

/* secondary — solo outline bianco, trasparente */
.cta--secondary,.cta--ghost{
  background:transparent;
  border:1px solid rgba(255,255,255,.35);
  -webkit-backdrop-filter:none;backdrop-filter:none;
  box-shadow:none;
  color:var(--ink);
}
.cta--secondary:hover,.cta--ghost:hover{
  border-color:rgba(255,255,255,.7);
  background:rgba(255,255,255,.06);
  box-shadow:none;
}
:root[data-theme="light"] .cta--secondary,
:root[data-theme="light"] .cta--ghost{border-color:rgba(0,0,0,.3);}
:root[data-theme="light"] .cta--secondary:hover,
:root[data-theme="light"] .cta--ghost:hover{border-color:rgba(0,0,0,.7);background:rgba(0,0,0,.04);}

/* solid — sfondo pieno; bianco su scuro, nero su chiaro */
.cta--solid{
  background:#fff;color:#000;
  border:0.5px solid rgba(255,255,255,.12);
  -webkit-backdrop-filter:none;backdrop-filter:none;
}
.cta--solid:hover{background:#e8e8e8;}
:root[data-theme="light"] .cta--solid{background:#000;color:#fff;border-color:rgba(0,0,0,.12);}
:root[data-theme="light"] .cta--solid:hover{background:#222;}

/* link — tertiary sottolineato */
.cta--link{
  padding:0;border:0;border-radius:0;
  background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none;
  box-shadow:none;color:var(--ink);position:relative;
}
.cta--link::after{
  content:"";position:absolute;left:0;bottom:-3px;width:100%;height:1px;
  background:currentColor;opacity:.4;transform:scaleX(1);transform-origin:left;
  transition:opacity .25s var(--ease);
}
.cta--link:hover{color:var(--accent);transform:none;}
.cta--link:hover::after{opacity:1;}

/* disabled */
.cta[disabled],.cta[aria-disabled="true"]{
  opacity:.4;cursor:not-allowed;color:var(--muted);
  border-color:var(--border);background:transparent;box-shadow:none;
}
.cta[disabled]:hover{transform:none;}

/* ============================================================
   PAGE HERO — phantom-style display statement (about / contact)
   ============================================================ */
.page-hero{padding:var(--s24) 0 var(--s48);}
/* compact variant (contact): everything closer, fits one viewport */
.page-hero--compact{padding-bottom:var(--s24);}
.page-hero--compact .page-hero__title{font-size:var(--fs-title);}
.page-hero--compact .page-hero__sub{margin-top:var(--s16);font-size:var(--t-body);}
.page-hero__title{font-size:var(--fs-display);font-weight:var(--w-light);line-height:.95;letter-spacing:var(--ls-title);
  max-width:14ch;}
.page-hero__sub{margin-top:var(--s24);font-size:var(--t-lg);color:var(--muted);max-width:46ch;line-height:1.45;}

/* stats row (about) — numeri grandi su filetto, allineati alle colonne (niente box chiuso) */
.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--border);
  border:1px solid var(--border);margin:var(--s48) 0 var(--s24);}
.stat{background:var(--bg);padding:var(--s32) var(--s24);}
.ab-stats .stat{padding:var(--s16) 0 0;border-top:1px solid var(--border);background:none;}
.stat__n{font-size:var(--fs-display);font-weight:var(--w-semibold);line-height:1;font-variant-numeric:tabular-nums;}
.stat__n em{color:var(--accent);font-style:normal;}
.stat__l{margin-top:var(--s8);}
@media (max-width:720px){.stats{grid-template-columns:1fr;}}

/* ============================================================
   PARALLAX — .plx wraps an <img data-plx="depth">; JS drives
   a translateY as the block crosses the viewport. Image is
   oversized 14% so the drift never reveals edges.
   ============================================================ */
.plx{overflow:hidden;position:relative;}
.plx img{display:block;width:100%;height:114%;object-fit:cover;will-change:transform;}

/* ============================================================
   CASE (work) — phantom project-page anatomy:
   H1 → divider → spec (label/valore) → hero full-bleed → lead →
   ABOUT/FEATURES spec → galleria (singola/coppia) → related work.
   I pattern condivisi (.spec/.rule/.lead-xl/.case-gal) sono nel
   blocco PHANTOM PATTERNS in alto.
   ============================================================ */
/* solo l'HERO è full-viewport; il resto dei media resta boxed */
.case-bleed{width:100vw;margin-left:calc(50% - 50vw);}
.case-heroBlock{height:68vh;min-height:380px;margin-bottom:var(--s48);}
.case-heroBlock img{height:118%;}

/* ── FULL-BLEED HERO (work + article) ────────────────────────────
   Risale sopra il padding della .section per toccare il bordo top.
   Il testo è sovrapposto in basso con gradiente scuro. */
.case-hero{
  position:relative;
  width:100vw;
  margin-left:calc(50% - 50vw);
  margin-top:calc(-1 * (var(--s88) + var(--grid-margin)));
  height:92vh;
  min-height:520px;
  margin-bottom:var(--s62);
  overflow:hidden;
  background:#111;
}
.case-hero__img{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
  transform-origin:center;
  transition:transform 8s ease-out;
}
/* subtle Ken Burns on load */
.case-hero:hover .case-hero__img,
.case-hero.is-ready .case-hero__img{transform:scale(1.04);}
/* gradient blur layers — dal basso verso l'alto, blur crescente */
.case-hero__gblur{position:absolute;inset:0;pointer-events:none;}
.case-hero__gblur > div{position:absolute;left:0;right:0;bottom:0;}
.case-hero__gblur > div:nth-child(1){
  height:75%;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  -webkit-mask:linear-gradient(to bottom,transparent 0%,black 65%);
          mask:linear-gradient(to bottom,transparent 0%,black 65%);
}
.case-hero__gblur > div:nth-child(2){
  height:58%;
  -webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);
  -webkit-mask:linear-gradient(to bottom,transparent 0%,black 60%);
          mask:linear-gradient(to bottom,transparent 0%,black 60%);
}
.case-hero__gblur > div:nth-child(3){
  height:40%;
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  -webkit-mask:linear-gradient(to bottom,transparent 0%,black 55%);
          mask:linear-gradient(to bottom,transparent 0%,black 55%);
}
.case-hero__gblur > div:nth-child(4){
  height:24%;
  -webkit-backdrop-filter:blur(22px) brightness(.85);backdrop-filter:blur(22px) brightness(.85);
  -webkit-mask:linear-gradient(to bottom,transparent 0%,black 50%);
          mask:linear-gradient(to bottom,transparent 0%,black 50%);
}
/* overlay leggero — solo per scurire leggermente, il blur fa il lavoro principale */
.case-hero__overlay{
  position:absolute;inset:0;
  display:flex;flex-direction:column;justify-content:flex-end;
  background:linear-gradient(to top,
    rgba(0,0,0,.55) 0%,
    rgba(0,0,0,.2)  28%,
    transparent     55%);
}
.case-hero__inner{
  max-width:var(--maxw);
  margin-inline:auto;
  width:100%;
  padding:var(--s88) 0;
}
.case-hero__overlay .case-eyebrow{color:rgba(255,255,255,.65);margin-bottom:var(--s8);}
.case-hero__overlay .case-title,
.case-hero__overlay .article-title{
  color:#fff;
  margin-bottom:var(--s16);
  text-shadow:0 2px 24px rgba(0,0,0,.35);
}
.case-hero__overlay .gtag-row{gap:var(--s8);}
@media (max-width:720px){.case-hero__inner{padding:var(--s88) var(--grid-margin-sm) var(--s40);}}
/* se manca l'immagine, collassa a un header compatto con bg della section */
.case-hero--noimg{height:auto;min-height:0;background:transparent;margin-bottom:var(--s40);}
.case-hero--noimg .case-hero__img{display:none;}
.case-hero--noimg .case-hero__overlay{
  position:relative;inset:auto;
  padding:var(--s88) 0 var(--s40);
  background:none;
}
@media (max-width:720px){
  .case-hero{
    height:72vh;
    margin-top:calc(-1 * (var(--s88) + var(--s24)));
  }
}
.chip-row{display:flex;flex-wrap:wrap;gap:var(--s8);}

/* related work — 3 cards + see-all, replaces the single next-link */
.related{border-top:1px solid var(--border);padding-top:var(--s40);margin-top:var(--s48);}
.related__head{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:var(--s32);}
.related__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s24);}
.rcard{cursor:pointer;}
.rcard__img{aspect-ratio:4/3;overflow:hidden;border:1px solid var(--border);background:#0d0d0d;}
.rcard__img img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .6s var(--ease);}
.rcard:hover .rcard__img img{transform:scale(1.05);}
.rcard__t{margin-top:12px;font-size:var(--t-body);font-weight:var(--w-semibold);transition:color .2s var(--ease);}
.rcard:hover .rcard__t{color:var(--accent);}
.rcard__c{margin-top:4px;}
@media (max-width:720px){.related__grid{grid-template-columns:1fr;}}

/* selectable chips (radio/checkbox) — pill, accent when active */
.chips{display:flex;flex-wrap:wrap;gap:var(--s8);}
.chips input{position:absolute;opacity:0;pointer-events:none;}
.chips label{font-family:var(--mono);font-size:var(--t-mono);text-transform:uppercase;letter-spacing:var(--ls-label);
  color:var(--muted);border:1px solid var(--border);border-radius:999px;padding:9px 16px;cursor:pointer;
  transition:color .2s var(--ease),border-color .2s var(--ease),background .2s var(--ease);}
.chips label:hover{color:var(--ink);border-color:var(--ink);}
.chips input:checked+label{background:var(--accent);border-color:var(--accent);color:#000;}
.chips input:focus-visible+label{outline:2px solid var(--accent);outline-offset:2px;}

/* confirmation state */
.cform-done{padding:var(--s88) 0;border-top:1px solid var(--border);margin-top:var(--s88);}
.cform-done__t{font-size:var(--fs-title);font-weight:var(--w-semibold);margin-bottom:var(--s16);}
.cform-done__p{color:var(--muted);max-width:48ch;line-height:1.5;}

/* ============================================================
   JOURNAL — aligned with the phantom-style system:
   page-hero → featured entry (full-width, parallax) →
   3-col editorial grid · pill view-toggle · square media
   ============================================================ */
.journal-tools{display:flex;align-items:center;justify-content:space-between;gap:var(--s24);
  border-top:1px solid var(--border);padding-top:var(--s24);margin-bottom:var(--s48);}
.journal-toolbar{display:flex;gap:var(--s8);}

/* featured (first) entry — editorial lead story */
.jfeat{cursor:pointer;margin-bottom:var(--s88);}
.jfeat .plx{aspect-ratio:21/9;border:1px solid var(--border);}
.jfeat__row{display:grid;grid-template-columns:1fr 1fr;gap:var(--s40);padding-top:var(--s24);align-items:start;}
.jfeat__t{font-size:var(--fs-display);font-weight:var(--w-semibold);line-height:1.08;letter-spacing:var(--ls-title);
  transition:color .2s var(--ease);max-width:22ch;}
.jfeat:hover .jfeat__t{color:var(--accent);}
.jfeat__a{font-size:var(--t-lg);line-height:1.5;color:var(--muted);max-width:52ch;}
.jfeat__meta{display:flex;gap:var(--s16);margin-bottom:var(--s16);}
@media (max-width:900px){.jfeat__row{grid-template-columns:1fr;gap:var(--s16);}.jfeat .plx{aspect-ratio:16/10;}}

/* article reading view — corpo di lettura più grande dentro la colonna spec */
.article-body p{font-size:var(--t-lg);line-height:1.65;margin-bottom:var(--s32);}
.article-body p:last-child{margin-bottom:0;}
.article-foot{margin-top:var(--s88);}

/* ============================================================
   HAND TRACKING — webcam gesture control (archive only)
   Toggle via HANDTRACK_ENABLED in js/handtrack.js
   ============================================================ */

/* handtrack: vive nel dock (#dockSlot), quindi niente position:fixed —
   la visibilità per vista la gestisce .dock. Stile base da .icon-btn condiviso. */
.handtrack-btn {
  transition: color .2s var(--ease), border-color .2s var(--ease),
              box-shadow .2s var(--ease), background .2s var(--ease);
}
.handtrack-btn svg { width: 20px; height: 20px; flex: none; }
.handtrack-btn.is-active { color: var(--accent); border-color: var(--accent); }
.handtrack-btn.is-loading { animation: htPulse .9s var(--ease) infinite; }
@keyframes htPulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }

/* cursor — visionOS glass ring */
.handtrack-cursor {
  position: fixed;
  top: 0; left: 0;
  width: 44px; height: 44px;
  pointer-events: none;
  z-index: 999;
  opacity: 0;
  border-radius: 50%;
  border: 1.5px solid rgba(255,255,255,0.38);
  box-shadow:
    0 0 0 0.5px rgba(255,255,255,0.10),
    inset 0 1px 0 rgba(255,255,255,0.18),
    0 2px 10px rgba(0,0,0,0.25);
  transition:
    opacity .3s var(--ease),
    border-color .18s var(--ease),
    box-shadow .18s var(--ease);
}
.handtrack-cursor.is-active { opacity: 1; }
/* inner shimmer: top highlight only */
.handtrack-cursor::before {
  content: '';
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, rgba(255,255,255,0.12) 0%, transparent 65%);
  transition: opacity .18s;
}
/* centre dot */
.handtrack-cursor::after {
  content: '';
  position: absolute;
  inset: 19px;
  border-radius: 50%;
  background: rgba(255,255,255,0.82);
  box-shadow: 0 0 5px rgba(255,255,255,0.6);
  transition: inset .16s cubic-bezier(.22,.61,.36,1), background .16s, box-shadow .16s;
}
/* pinching → ring turns accent, dot expands */
.handtrack-cursor.is-pinching {
  border-color: rgba(255,99,71,0.75);
  box-shadow:
    0 0 14px rgba(255,99,71,0.35),
    0 0 0 0.5px rgba(255,99,71,0.18),
    inset 0 1px 0 rgba(255,255,255,0.1);
}
.handtrack-cursor.is-pinching::before { opacity: 0; }
.handtrack-cursor.is-pinching::after {
  inset: 12px;
  background: var(--accent);
  box-shadow: 0 0 10px rgba(255,99,71,0.55);
}
@media (prefers-reduced-motion: reduce) {
  .handtrack-cursor,
  .handtrack-cursor::before,
  .handtrack-cursor::after { transition: opacity .15s; }
}

/* central floating panel — holographic hand skeleton */
.handtrack-preview {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0.92);
  width: 280px;
  border-radius: 20px;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,0.10);
  background: rgba(8,8,8,0.72);
  -webkit-backdrop-filter: blur(28px) saturate(1.4);
          backdrop-filter: blur(28px) saturate(1.4);
  box-shadow:
    0 0 0 0.5px rgba(255,255,255,0.06) inset,
    0 8px 48px rgba(0,0,0,0.55);
  z-index: 70;
  opacity: 0;
  pointer-events: none;
  transition:
    opacity .45s var(--ease),
    transform .5s cubic-bezier(.16,1,.3,1);
}
.handtrack-preview.is-active {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}
.handtrack-preview video  { display: none; }
.handtrack-preview canvas { display: block; width: 100%; height: auto; }
/* label */
.handtrack-label {
  position: absolute;
  top: 12px;
  left: 0; right: 0;
  text-align: center;
  font-family: var(--mono);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: rgba(255,255,255,0.18);
  pointer-events: none;
  z-index: 1;
  transition: color .35s var(--ease);
}
.handtrack-preview.has-hand .handtrack-label {
  color: rgba(255,99,71,0.75);
}

/* ============================================================
   TAGS — .gtag · .chip  stessa pill, etichetta maiuscola, testo arancione
   ============================================================ */
.gtag-row{display:flex;flex-wrap:wrap;gap:var(--s8);}

.gtag,
.chip{
  display:inline-flex;align-items:center;
  font-family:var(--mono);
  font-size:var(--fs-label);font-weight:400;letter-spacing:var(--ls-label);text-transform:uppercase;
  color:rgba(246,88,40,.70);
}

/* accent — "In evidenza", pieno */
.gtag--accent{
  background:rgba(246,88,40,.88);
  border-color:rgba(246,88,40,.95);
  color:#fff;
}
.gtag--accent:hover{background:rgba(246,88,40,.96);color:#fff;}

/* page header block — eyebrow + title + gtag-row (work + article) */
.case-header{padding:var(--s24) 0 var(--s40);}
.case-eyebrow{display:block;margin-bottom:var(--s16);color:var(--muted);}

/* journal card tags — spacing between cover and title */
.jcard__tags{margin-top:var(--s16);margin-bottom:var(--s8);}
.jfeat__tags{margin-bottom:var(--s16);}

/* ============================================================
   TITLES — one family (Helvetica Neue LT Pro), 500 = 55 Roman, tight tracking.
   Last block so it normalises title weight across components.
   ============================================================ */
.page-hero__title, .lead-h, .case-title, .article-title, .jfeat__t,
.about-statement, .ab-cta__title, .cform-done__t,
.stat__n, .jcard__title, .index-row__title,
.hud__title, .rcard__t{
  font-family:var(--font);
  font-weight:var(--w-semibold);
  letter-spacing:var(--ls-title);
  /* NIENTE font-size qui: essendo l'ultimo blocco, a parità di specificità
     vincerebbe su .page-hero__title, .case-title, .jcard__title… e li
     schiaccerebbe tutti a una misura sola. Qui si normalizza SOLO famiglia,
     peso e tracking; il corpo lo decide ogni componente. */
}
