/* ==========================================================================
   Font

   Due @font-face con lo stesso nome e pesi diversi: font-weight 400 e 700
   funzionano da soli, senza classi.
   ========================================================================== */

@font-face {
  font-family: 'Alte Haas Grotesk';
  src: url('../fonts/AlteHaasGroteskRegular.woff2') format('woff2'),
       url('../fonts/AlteHaasGroteskRegular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Alte Haas Grotesk';
  src: url('../fonts/AlteHaasGroteskBold.woff2') format('woff2'),
       url('../fonts/AlteHaasGroteskBold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   Reset
   ========================================================================== */

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* ==========================================================================
   Variabili
   ========================================================================== */

:root {
  --gap: 2px;

  /* Il tema. Due sole variabili: il sito ha due colori e basta.
     In scura si scambiano — non ci sono grigi intermedi da ritarare. */
  --fondo: #ffffff;
  --inchiostro: #000000;
}

/* ==========================================================================
   Modalità scura

   Automatica, dall'impostazione del dispositivo: nessun interruttore in
   pagina, nessun JavaScript, niente da ricordare fra una visita e l'altra.

   Qui si scambiano soltanto le due variabili. Tutto il resto del foglio le
   usa e si adegua da solo — comprese le fughe da 2px fra le foto, che sono
   lo sfondo della pagina e diventano nere senza che nessuno le nomini.

   Tre elementi NON compaiono qui e non devono: .header, .work-index e
   .crocetta sono color: #ffffff dentro mix-blend-mode: difference. Quel
   bianco non e' "il colore del testo", e' l'operando della differenza, ed e'
   cio' che li fa invertire da soli contro qualunque fondo. Sostituirlo con
   var(--inchiostro) darebbe difference(nero, nero) su fondo nero: header e
   nomi sparirebbero.

   L'unica regola di componente e' quella dell'ombra della figurina, che sta
   accanto al suo componente nella sezione About: su fondo nero un'ombra nera
   non esiste, e li' serve un alone chiaro.
   ========================================================================== */

@media (prefers-color-scheme: dark) {
  :root {
    --fondo: #000000;
    --inchiostro: #ffffff;
  }
}

/* ==========================================================================
   Base
   ========================================================================== */

html,
body {
  background: var(--fondo);
  color: var(--inchiostro);
}

body {
  font-family: 'Alte Haas Grotesk', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.01em;
}

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

/* ==========================================================================
   Header — livello di sfondo

   Due elementi fratelli, entrambi figli diretti di <body>:
   .header-bg  z-90   colore pieno, si dissolve fino a sparire
   .header     z-100  solo testo, in blend mode difference

   Un solo livello: nessun gradiente, nessuna sfocatura, nessuna maschera.
   Allo scroll dietro le scritte non resta niente.
   ========================================================================== */

.header-bg {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 48px;
  background: var(--fondo); /* colore pieno, nessun gradiente */
  z-index: 90;
  pointer-events: none;
  opacity: 1;
  transition: opacity 400ms ease;
}

body.scrolled .header-bg {
  opacity: 0;
}

/* ==========================================================================
   Header — testo
   ========================================================================== */

.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 48px;
  z-index: 100;
  padding: 0 10px; /* distanza delle scritte dal bordo finestra */
  background: transparent; /* obbligatorio: uno sfondo qui romperebbe il blend */
  color: #ffffff;          /* bianco + difference = inversione automatica */
  mix-blend-mode: difference;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.header a {
  color: inherit;
  text-decoration: none;
}

/* Il nome resta sempre Bold, nessun cambiamento all'hover. */
.header > a {
  font-weight: 700;
}

.header nav {
  display: flex;
  gap: 24px;
}

.header nav a {
  display: inline-block;
  font-weight: 700;
  transition: font-weight 200ms ease;
}

/* Riserva in modo permanente la larghezza del Bold, così il passaggio a
   Regular all'hover non sposta nulla di lato. */
.header nav a::before {
  content: attr(data-text);
  display: block;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  font-weight: 700;
  pointer-events: none;
}

.header nav a:hover {
  font-weight: 400;
}

/* Pagina corrente: stesso segnale visivo dell'hover, ma stabile. */
.header nav a.current {
  font-weight: 400;
}

/* ==========================================================================
   Griglia — condivisa da index.html e dalle pagine in work/

   Le regole responsive stanno solo dentro le media query qui sotto:
   su desktop restano sempre 3 colonne piene.
   ========================================================================== */

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gap);
  padding: calc(48px + var(--gap)) var(--gap) var(--gap) var(--gap);
}

.grid-item {
  aspect-ratio: 4 / 5;
}

.grid-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity 300ms ease;
}

.grid-item img:hover {
  opacity: 0.85;
}

/* Sotto i 900px: 2 colonne */
@media (max-width: 900px) {
  .grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Sotto i 600px: 1 colonna */
@media (max-width: 600px) {
  .grid {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   work.html — indice tipografico

   Stessa logica dell'header: .work-preview e .work-index sono fratelli,
   figli diretti di <body>. L'elenco e' in difference su colore bianco, cosi'
   i nomi sono neri sul bianco della pagina e si invertono da soli sopra
   l'anteprima. Nessun antenato deve avere filter/transform/isolation o
   opacity < 1.

   L'anteprima insegue il cursore (js/work.js). La transform del contenitore
   la scrive il JS a ogni frame, quindi opacita' e scale di entrata/uscita
   stanno su .work-preview-inner: due elementi distinti, cosi' la transizione
   CSS non litiga con il requestAnimationFrame.
   ========================================================================== */

.work-preview {
  position: fixed;
  top: 0;
  left: 0;
  /* Altezza esplicita e non aspect-ratio: con tutti i figli in posizione
     assoluta il rapporto non genera altezza e il contenitore resterebbe a 0. */
  --pw: 20.8vw; /* 26vw meno il 20% */
  width: var(--pw);
  height: calc(var(--pw) * 5 / 4); /* 4:5 */
  z-index: 5;
  pointer-events: none;
  will-change: transform;
}

/* inset invece di width/height 100%: l'altezza del contenitore nasce da
   aspect-ratio e una percentuale non ci si risolve contro (verrebbe 0). */
.work-preview-inner {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: scale(0.96);
  transition: opacity 200ms ease, transform 200ms ease; /* uscita, piu' rapida */
}

.work-preview.is-on .work-preview-inner {
  opacity: 1;
  transform: scale(1);
  transition: opacity 300ms ease, transform 300ms ease; /* entrata */
}

/* Le cinque immagini stanno tutte nel DOM e si alternano in opacita':
   cambiare src al volo mostrerebbe il caricamento al primo passaggio. */
.work-preview img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 300ms ease;
}

.work-preview img.is-current {
  opacity: 1;
}

.work-index {
  position: relative;
  z-index: 10;
  /* 48px di header + circa 8vh di respiro. Padding e non margin per non
     incappare nel collasso dei margini.
     A sinistra 10px come le scritte dell'header, non var(--gap): i numeri si
     allineano a THOMAS PAVEL invece che al bordo delle foto. */
  padding: calc(48px + 8vh) var(--gap) var(--gap) 10px;

  color: #ffffff;
  mix-blend-mode: difference;

  --name-fs: clamp(40px, 8vw, 112px);
  font-size: var(--name-fs);
  line-height: 0.85; /* sotto 1: e' questo che rende il blocco un oggetto solido */
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

/* Numero e nome su due colonne: le cifre formano una colonna netta, le
   iniziali dei nomi un'altra. Zero margine e padding: la distanza tra le
   righe viene solo dall'interlinea. */
.work-item {
  display: grid;
  grid-template-columns: 3.5rem 1fr;
  align-items: start;
  margin: 0;
  padding: 0;
  color: inherit;
  text-decoration: none;
  font-weight: 700;
}

/* Etichetta di sistema: dimensione fissa, non scala con il nome. */
.work-num {
  font-size: 20px;
  line-height: 1;
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
  align-self: start;
  font-weight: 700; /* resta Bold anche all'hover: e' il contrasto che si legge */

  /* Ritocco ottico: align-self allinea al bordo del line box, non alla
     sommita' delle maiuscole; fra i due c'e' il half-leading, che dipende
     dalle metriche del font e dall'interlinea.
     La distanza bordo-riga -> inchiostro vale F * [(L - (asc+desc))/2 + asc - cap]:
     0.075 * F per il nome (interlinea 0.85), 0.150 * F per il numero
     (interlinea 1). Il recupero e' la differenza fra i due.
     NB: qui em non servirebbe — su margin-top si risolve sul font-size
     dell'elemento stesso (20px), non su quello del nome. Serve la calc()
     agganciata a --name-fs, che scala con la finestra. */
  margin-top: calc(var(--name-fs) * 0.075 - 20px * 0.150);
}

/* Hover: il nome passa a Regular, il numero resta Bold. Nessuna transizione:
   con due pesi statici non c'e' interpolazione, quindi lo scatto e' netto e
   voluto invece che incerto. Non serve il trucco del data-text usato
   nell'header: i nomi sono allineati a sinistra e ognuno ha la sua riga,
   quindi accorciandosi non spostano niente. */
.work-name {
  font-weight: 700;
}

.work-item:hover .work-name {
  font-weight: 400;
}

/* Da provare: anche il numero in Regular all'hover.
.work-item:hover .work-num {
  font-weight: 400;
}
*/

/* --- ingresso dell'indice ------------------------------------------------
   Le cinque voci entrano in cascata dall'alto, una dopo l'altra. La curva e'
   una decelerazione esponenziale: la voce copre quasi tutta la distanza nel
   primo terzo del tempo e poi si posa. E' la curva a dare il carattere
   cinematografico, piu' della durata.

   L'animazione sta su .work-item e non sui figli: numero e nome entrano come
   un'unica riga. Solo opacity e transform, cosi' resta sul compositore.

   both e' obbligatorio: senza fill-mode le voci lampeggiano al loro posto
   prima che il ritardo scada. L'opacity: 0 dichiarata a parte copre il caso
   in cui l'animazione non parta affatto.

   L'anteprima non entra in scena con l'elenco: a riposo non e' visibile e
   compare solo quando il cursore arriva sui nomi. E nessun pointer-events
   qui: l'inseguimento risponde da subito, anche mentre la cascata e' in
   corso. */

@keyframes workIn {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}

.work-item {
  opacity: 0;
  animation: workIn 1100ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

/* 110ms di scarto: abbastanza da leggere la cascata, non tanto da far
   aspettare — l'ultima voce e' a posto entro 1,7s. Aggiungendo categorie si
   riduce lo scarto, non la durata: la durata e' il carattere, lo scarto e'
   solo il ritmo. */
.work-item:nth-of-type(1) { animation-delay: 120ms; }
.work-item:nth-of-type(2) { animation-delay: 230ms; }
.work-item:nth-of-type(3) { animation-delay: 340ms; }
.work-item:nth-of-type(4) { animation-delay: 450ms; }
.work-item:nth-of-type(5) { animation-delay: 560ms; }

/* Sotto i 900px non c'e' hover: niente anteprima e nessuna copertina sotto i
   nomi — resta il solo elenco, e il tap apre direttamente la categoria.
   Senza anteprima sotto, il blend non ha piu' niente da invertire: si spegne
   e il nero torna nero pieno. */
@media (max-width: 900px) {
  .work-preview {
    display: none;
  }

  .work-index {
    mix-blend-mode: normal;
    color: var(--inchiostro);
    /* Si sovrascrive la variabile, non font-size: cosi' il ritocco ottico
       del numero resta agganciato al corpo reale del nome. */
    --name-fs: clamp(32px, 9vw, 56px);
  }
}

/* Movimento ridotto: nessun inseguimento e nessuna rotazione. L'immagine
   compare in dissolvenza in una posizione fissa a destra (il JS non scrive
   la transform in questo caso). E l'elenco e' gia' al suo posto al primo
   fotogramma: niente cascata. */
@media (prefers-reduced-motion: reduce) {
  .work-preview {
    top: 50%;
    left: auto;
    right: var(--gap);
    transform: translateY(-50%);
  }

  .work-item {
    animation: none;
    opacity: 1;
  }
}

/* ==========================================================================
   Link alla categoria successiva (pagine in work/)
   ========================================================================== */

.next {
  display: block;
  padding: 0.4em var(--gap) var(--gap) var(--gap);
  color: var(--inchiostro);
  text-decoration: none;
  font-weight: 700;
  font-size: clamp(32px, 6vw, 72px);
  line-height: 0.95;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

/* ==========================================================================
   Pagina About

   Impaginazione presa dalla composizione 1920x1080, tradotta in unita' relative.

   Ritratto 4:5 a sinistra e blocco di testo a destra, centrati sullo stesso asse
   orizzontale a meta' altezza della finestra — nella composizione i due centri
   coincidono, ed e' quello a tenere insieme la pagina. I contatti stanno in
   fondo, centrati, fuori dal flusso per non spostare quel centro.

   Il ritmo verticale del testo nasce da due soli stacchi, --about-gap-stretto e
   --about-gap-largo, entrambi legati al corpo del nome. E' il loro rapporto a
   far leggere due gruppi invece di un elenco di righe.

   Due deroghe volute alle regole del sito, entrambe circoscritte alla pastiglia
   di stato: border-radius sugli estremi, ed e' la forma a dire "stato"; e il
   verde, unico colore dell'interfaccia insieme all'iridescenza sulla foto.

   Tutte le misure sono dichiarate su .about, non in :root: restano locali a
   questa pagina e non ricadono su Home e Work.
   ========================================================================== */

.about {
  --about-edge: 10px; /* lo stesso inset orizzontale dell'header */

  /* --- corpi tipografici -------------------------------------------------- */

  /* Il nome scala con la larghezza della finestra; le etichette e i valori
     restano a corpo fisso. E' lo stesso criterio dei numeri nell'indice Work:
     misure che non scalano si leggono come dati di servizio invece che come
     testo. Il clamp sul nome ha un minimo che tiene THOMAS PAVEL su una riga
     anche su un telefono stretto. */
  --about-name-fs: clamp(26px, 4.9vw, 100px);
  --about-name-lh: 0.88;
  --about-role-fs: clamp(14px, 2vw, 42px);
  --about-role-lh: 1.05;
  --about-label-fs: 15px;
  --about-value-fs: 17px;
  /* Un solo corpo e un solo padding per la pastiglia e per i due riquadri dei
     contatti: sono la stessa famiglia di elementi, e devono leggersi come tale.
     Cambiando queste tre righe si muovono tutti e tre insieme. */
  --about-chip-fs: 13px;
  --about-chip-pad-y: 0.7em;
  --about-chip-pad-x: 0.95em;
  --about-box-gap: 0.69em; /* 9px sui 13px del corpo, come nelle composizioni */

  /* --- ritmo verticale ---------------------------------------------------- */

  /* I due stacchi del blocco di testo, entrambi legati al corpo del nome cosi'
     che il ritmo scali con la pagina. E' il loro RAPPORTO a fare la lettura: se
     si somigliano si legge un elenco di righe invece di due gruppi.
     I coefficienti vengono dalla composizione: 19px e 60px di spazio fra
     inchiostro e inchiostro, su un nome da 94px. Ma questi sono margini fra
     SCATOLE, e sotto la pastiglia ci si aggiunge il half-leading del line box
     del nome: il primo coefficiente e' gia' scontato di quel tratto. */
  /* Stacco stretto: fra lo stato e i riquadri dei contatti, che formano un
     gruppo solo. Tarato per dare lo stesso spazio d'inchiostro che c'e' fra il
     nome e il ruolo, cosi' i due gruppi respirano allo stesso modo. */
  --about-gap-stretto: calc(var(--about-name-fs) * 0.1);
  --about-gap-largo: calc(var(--about-name-fs) * 0.58);   /* ruolo -> scheda dati */

  /* Interlinea della scheda: e' lei a tenere strette fra loro FOUNDER e BASED,
     senza nessun margine sulle singole righe. */
  --about-lh-dati: 1.6;

  /* Stacco fra ritratto e testo. Stretto di proposito. */
  --about-col-gap: 2vw;

  /* --- ritratto ----------------------------------------------------------- */

  /* Altezza presa dalla composizione; la larghezza segue dal 4:5. */
  --about-portrait-h: 47vh;

  /* Cornice da figurina. In percentuale, non in px: le percentuali di padding si
     risolvono sempre sulla larghezza, quindi i quattro lati hanno lo stesso
     spessore in px e la foto resta centrata, e tutto scala con la carta. */
  --about-frame: 6%;

  /* Verde da spia di stato, campionato dalla composizione. E' l'unico colore
     dell'interfaccia in tutto il sito, insieme all'iridescenza sulla foto. */
  --about-green: #00ac4a;

  /* --- impianto ----------------------------------------------------------- */

  /* Il gruppo ritratto + testo e' centrato nella finestra, senza padding che ne
     sposti il centro: nella composizione i due centri cadono esattamente a meta'
     altezza. I contatti sono fuori da quel centro e ancorati al fondo, quindi
     stanno in posizione assoluta e non tirano il gruppo verso l'alto. */
  position: relative;
  height: 100vh;
  display: grid;
  place-items: center;
}

/* --- blocco centrale ----------------------------------------------------- */

/* Due colonne dimensionate dal contenuto, non dalla finestra: e' il blocco a
   essere centrato, non il testo a essere allineato al centro.
   align-items: center mette ritratto e testo sullo stesso asse orizzontale — e'
   quello che nella composizione tiene insieme la pagina. */
.about-body {
  display: grid;
  grid-template-columns: auto auto;
  column-gap: var(--about-col-gap);
  align-items: center;
}

/* --- ritratto ------------------------------------------------------------ */

/* Rettangolo 4:5 con gli spigoli vivi, come le celle della griglia.
   Qui sta la prospettiva; la rotazione sta sul figlio, perche' perspective e
   transform sullo stesso elemento non producono profondita'. 900px e' abbastanza
   vicina da far leggere lo spazio senza deformare i bordi.

   isolation: isolate non e' decorativa. I due livelli del riflesso usano
   mix-blend-mode: senza isolare, il loro contesto di fusione risalirebbe fino a
   incontrare il difference dell'header, e scorrendo la pagina il nome in alto
   farebbe cose strane. Cosi' la fusione si esaurisce dentro il ritratto. */
.about-portrait {
  position: relative;
  height: var(--about-portrait-h);
  aspect-ratio: 4 / 5;
  width: auto;
  perspective: 900px;
  isolation: isolate;
}

/* --- ombra dinamica ------------------------------------------------------- */

/* Fratello di .about-card e non figlio, e senza rotazione: un box-shadow su un
   elemento ruotato in 3D ruoterebbe con lui, e l'ombra si inclinerebbe invece
   di restare appoggiata al foglio.
   Il nero e' sfocato una volta sola: di qui in poi il JavaScript anima soltanto
   transform e opacity, le due proprieta' che il compositore gestisce senza
   ridipingere. Animare offset e blur di un box-shadow costringerebbe a
   ridisegnare la sfocatura a ogni fotogramma.
   A riposo l'opacita' e' 0: con la carta piatta la pagina e' esattamente come
   se l'ombra non ci fosse. */
.about-shadow {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: #000000;
  filter: blur(18px);
  opacity: var(--about-shadow-o, 0);
  transform:
    translate3d(var(--about-shadow-x, 0px), var(--about-shadow-y, 0px), 0)
    scale(var(--about-shadow-s, 0.95));
}

/* In modalita' scura un'ombra nera su fondo nero non esiste, e la carta perde
   il distacco dal foglio proprio dove si vede di piu' che e' sollevata.
   Diventa un alone chiaro. Geometria, sfocatura e le tre variabili scritte da
   js/about.js restano identiche: cambia il colore, e l'opacita' scende a poco
   piu' di un terzo. Un alone chiaro alla stessa intensita' di un'ombra scura
   non direbbe "sollevata" ma "luminosa", che e' un'altra affermazione.
   Si moltiplica la variabile invece di sostituirla, cosi' il JavaScript
   continua a pilotarla come prima e la costante OMBRA_OPACITA resta una. */
@media (prefers-color-scheme: dark) {
  .about-shadow {
    background: #ffffff;
    opacity: calc(var(--about-shadow-o, 0) * 0.35);
  }
}

/* --- la carta ------------------------------------------------------------- */

/* Il piano che si inclina. Le tre variabili sono scritte da js/about.js; i
   valori di ripiego lasciano la carta piatta, quindi senza JavaScript non si
   vede nessuna trasformazione. z-index la tiene sopra l'ombra. */
.about-card {
  position: absolute;
  inset: 0;
  z-index: 1;
  transform:
    rotateX(var(--about-tilt-x, 0deg))
    rotateY(var(--about-tilt-y, 0deg))
    scale(var(--about-lift, 1));
}

/* La cornice da figurina: bianca, spigoli vivi, foto centrata.
   Il padding e' uguale sui quattro lati — le percentuali di padding si risolvono
   sempre sulla larghezza del contenitore, quindi anche sopra e sotto valgono gli
   stessi px e la fotografia resta esattamente al centro.
   Il filo nero da 1px sul perimetro esterno da' alla carta un confine che su
   fondo bianco altrimenti non avrebbe: senza, sembra che la foto galleggi.
   La carta resta 4:5 nel complesso — e' la fotografia dentro a rimpicciolire. */
.about-frame {
  position: absolute;
  inset: 0;
  z-index: 1; /* sopra la lastra dello spessore */
  background: #ffffff;
  border: 1px solid #000000;
  padding: var(--about-frame);
}

/* Nessun bordo: la fotografia si appoggia direttamente al bianco della cornice. */
.about-photo {
  position: relative;
  width: 100%;
  height: 100%;
}

/* width/height in HTML danno il rapporto al browser prima che l'immagine
   arrivi: il blocco non salta al caricamento. */
.about-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- riflesso di lamina --------------------------------------------------- */

/* Livelli decorativi, creati da js/about.js e non presenti nell'HTML: su touch e
   con movimento ridotto non esistono affatto.

   Sono figli di .about-card e non di .about-frame: con inset 0 coprono tutta la
   carta, cornice compresa. Su una carta olografica la lamina sta sotto tutta la
   stampa, e un riflesso che si fermasse al bordo della fotografia romperebbe
   l'illusione di netto.

   pointer-events: none e' obbligatorio — coprono la carta per intero e senza di
   esso si mangerebbero gli eventi. A riposo l'opacita' e' 0: si vede una
   fotografia normale dentro la sua cornice. */
.about-grain,
.about-sheen,
.about-sheen-2,
.about-iris {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-repeat: repeat;
}

.about-sheen,
.about-sheen-2,
.about-iris {
  background-size: 260% 260%;
  background-repeat: no-repeat;
}

/* La grana della lamina: righe diagonali finissime, passo 3px. Sono i
   micro-solchi che sulla lamina vera spezzano la luce, ed e' il singolo
   ingrediente che piu' separa "riflesso" da "olografia". Scorre con
   l'inclinazione, in px e non in percentuale perche' il motivo si ripete. */
.about-grain {
  opacity: var(--about-grain-o, 0);
  background-position: var(--about-grain-x, 0px) var(--about-grain-y, 0px);
  background-image: repeating-linear-gradient(
    100deg,
    rgb(255 255 255 / 0) 0px,
    rgb(255 255 255 / 0.85) 0.75px,
    rgb(255 255 255 / 0) 1.6px,
    rgb(255 255 255 / 0) 3px
  );
  mix-blend-mode: overlay;
}

/* Prima banda: larga e morbida. Su una figurina vera la luce non e' mai un
   unico blocco, quindi si spezza in due bande con inclinazioni e scorrimenti
   leggermente diversi. La posizione la scrive il JavaScript e si muove in verso
   opposto all'inclinazione, con ampiezza maggiore: e' lo scorrimento relativo
   fra superficie e riflesso a far leggere la lamina. Solidale alla foto
   sembrerebbe una texture stampata sopra. */
.about-sheen {
  opacity: var(--about-sheen-o, 0);
  background-position: var(--about-sheen-x, 50%) var(--about-sheen-y, 50%);
  background-image: linear-gradient(
    103deg,
    rgb(255 255 255 / 0) 24%,
    rgb(255 255 255 / 0.3) 39%,
    rgb(255 255 255 / 0.62) 50%,
    rgb(255 255 255 / 0.3) 61%,
    rgb(255 255 255 / 0) 76%
  );
  mix-blend-mode: screen;
}

/* Seconda banda: stretta e netta, con un altro angolo e un altro scorrimento.
   E' quella che da' il lampo. */
.about-sheen-2 {
  opacity: var(--about-sheen2-o, 0);
  background-position: var(--about-sheen2-x, 50%) var(--about-sheen2-y, 50%);
  background-image: linear-gradient(
    96deg,
    rgb(255 255 255 / 0) 45%,
    rgb(255 255 255 / 0.8) 49.3%,
    rgb(255 255 255 / 1) 50%,
    rgb(255 255 255 / 0.8) 50.7%,
    rgb(255 255 255 / 0) 55%
  );
  mix-blend-mode: color-dodge;
}

/* L'iridescenza: lo stesso taglio obliquo, a spettro. Gli estremi trasparenti
   tengono il colore dentro la banda, quindi emerge solo dove il riflesso e' piu'
   forte — senza bisogno di una maschera.
   Qui il colore si deve vedere: e' un cambio voluto rispetto ai giri precedenti,
   dove era appena accennato. Resta l'unico colore di tutto il sito.
   Non si limita a spostarsi: hue-rotate fa virare la tinta con l'inclinazione, ed
   e' quello che si legge come iridescenza vera invece che come arcobaleno
   stampato. filter e mix-blend-mode convivono: prima si filtra l'elemento, poi
   il risultato si fonde con lo sfondo. */
.about-iris {
  opacity: var(--about-iris-o, 0);
  background-position: var(--about-iris-x, 50%) var(--about-iris-y, 50%);
  background-image: linear-gradient(
    103deg,
    rgb(255 255 255 / 0) 42%,
    rgb(255 64 160 / 0.75) 46.5%,
    rgb(255 214 64 / 0.75) 48.5%,
    rgb(64 255 190 / 0.75) 51.5%,
    rgb(96 150 255 / 0.75) 53.5%,
    rgb(255 255 255 / 0) 58%
  );
  filter: hue-rotate(var(--about-iris-hue, 0deg));
  mix-blend-mode: overlay;
}

/* --- pastiglia di stato --------------------------------------------------- */

/* Su desktop nessun riquadro: solo il pallino e la scritta, senza contorno ne'
   fondo. Sotto i 900px il riquadro torna, e non e' un ripensamento: li' la
   pastiglia scende a cavallo del bordo inferiore della foto, e per meta' finisce
   sul nero del soggetto — senza fondo bianco la scritta sparirebbe.
   Resta inline-flex perche' pallino e testo devono allinearsi al centro
   verticale, non sulla linea di base. */
.about-status {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: 0.62em;
  padding: 0;
  font-size: var(--about-chip-fs);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Il pallino. L'alone e' uno pseudo-elemento: si espande e svanisce senza
   toccare l'ingombro del pallino, che resta quello.
   Si animano solo opacity e transform — le due proprieta' che il compositore
   muove senza ridisegnare. Animare box-shadow o width qui costerebbe davvero,
   perche' e' un'animazione che gira per tutta la vita della pagina. */
.about-dot {
  position: relative;
  flex: none;
  width: 0.66em;
  height: 0.66em;
  border-radius: 50%;
  background: var(--about-green);
  animation: about-pulsa 2s ease-in-out infinite;
}

.about-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--about-green);
  animation: about-alone 2s ease-in-out infinite;
}

/* Pulsazione morbida, mai a zero: un on/off netto legge come errore o come
   notifica che chiede attenzione, una pulsazione respira e dice "attivo". */
@keyframes about-pulsa {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}

@keyframes about-alone {
  0%        { opacity: 0.45; transform: scale(1); }
  70%, 100% { opacity: 0; transform: scale(2.6); }
}

/* Movimento ridotto: il pallino resta verde e fermo. Un elemento che pulsa
   all'infinito e' esattamente cio' che quell'impostazione serve a togliere, e
   il significato "disponibile" si legge lo stesso senza animazione.
   L'alone sparisce del tutto: fermo a meta' scala sarebbe solo un anello. */
@media (prefers-reduced-motion: reduce) {
  .about-dot {
    animation: none;
  }

  .about-dot::after {
    display: none;
  }
}

/* --- scheda dati e testo ------------------------------------------------- */

/* Le distanze fra i blocchi vengono da due soli margini, non da margin diversi
   riga per riga: sotto la pastiglia lo stacco stretto, sopra la scheda quello
   largo. Nome e ruolo non hanno stacco: li tengono attaccati le loro interlinee,
   e si leggono come un blocco unico. */
.about-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Lo stato apre il terzo gruppo: sopra lo stacco largo che lo separa dalla
   scheda dati, sotto quello stretto verso i riquadri.
   Sta qui e non sopra il nome: senza riquadro, una riga da 13px sotto un nome da
   94px si legge come un avanzo, mentre accanto ai contatti sta con testi del
   suo stesso corpo — e "sono disponibile" e "ecco come raggiungermi" sono la
   stessa informazione. */
.about-status {
  margin-top: var(--about-gap-largo);
  margin-bottom: var(--about-gap-stretto);
}

.about-data {
  margin-top: var(--about-gap-largo);
}

/* Su una riga sola: nowrap perche' THOMAS PAVEL non deve mai spezzarsi. Se la
   finestra e' stretta e' il corpo a scendere, non il nome ad andare a capo. */
.about-name {
  font-size: var(--about-name-fs);
  line-height: var(--about-name-lh);
  font-weight: 700;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* In Regular e in minuscolo: il contrasto di peso col nome basta a separarli. */
.about-role {
  font-size: var(--about-role-fs);
  font-weight: 400;
  line-height: var(--about-role-lh);
  letter-spacing: 0.01em;
}

/* Griglia vera, non paragrafi: le etichette formano una colonna netta, i valori
   un'altra. Nessun bordo e nessun grigio — separa il peso.
   Le righe non hanno margin: la distanza fra FOUNDER e BASED e' l'interlinea. */
.about-data {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline; /* etichetta piccola e valore grande sulla stessa base */
  column-gap: 0.85em;
  font-size: var(--about-value-fs);
  line-height: var(--about-lh-dati);
}

.about-label {
  font-size: var(--about-label-fs);
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.about-value {
  font-weight: 700;
}

/* --- contatti ------------------------------------------------------------ */

/* Due riquadri affiancati, dentro la colonna di testo: su desktop si allineano
   a sinistra come tutto il resto del blocco.
   margin-top: auto non fa niente su desktop, dove la colonna e' alta quanto il
   suo contenuto; sotto i 900px, dove la colonna viene stirata, spinge i riquadri
   in fondo. Una riga sola per due impianti.
   flex-wrap e' la sicurezza chiesta: su uno schermo molto stretto i due riquadri
   vanno a capo restando centrati, invece di rimpicciolire il testo. */
.about-contacts {
  /* Nessuno stacco proprio: lo stato sopra apre il gruppo e se ne occupa lui. */
  display: flex;
  flex-wrap: wrap;
  gap: var(--about-box-gap);
}

/* Stessa famiglia della pastiglia: stesso corpo, stesso peso, stessa spaziatura
   e stesso padding. Cambia solo il contenuto — qui minuscolo e sottolineato,
   perche' sono indirizzi e non un'etichetta di stato. */
.about-box {
  display: inline-block;
  padding: var(--about-chip-pad-y) var(--about-chip-pad-x);
  border: 1px solid var(--inchiostro);
  background: var(--fondo);
  font-size: var(--about-chip-fs);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.06em;
}

/* --- link ---------------------------------------------------------------- */

/* Neri e sottolineati come nelle composizioni, mai blu. All'hover non cambia il
   colore ma lo spessore del tratto: e' l'unico segnale che non introduce una
   tinta nuova. */
.about-box,
.about-value a {
  color: var(--inchiostro);
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
}

/* --- effetti col puntatore ----------------------------------------------- */

/* Tutto dentro (hover: hover) and (pointer: fine), come nell'indice Work: su
   touch questa regola non esiste proprio, quindi il primo tap non lascia il
   link sottolineato per sempre.
   L'effetto olografico non ha regole qui: chi decide se esiste e' js/about.js,
   che interroga le stesse due media query e crea i livelli del riflesso solo se
   passano. Livelli che non vengono creati non c'e' bisogno di nasconderli, e
   senza JavaScript i valori di ripiego lasciano la foto piatta. */
@media (hover: hover) and (pointer: fine) {
  /* I link sono gia' sottolineati: all'hover si ispessisce il tratto. Nessun
     cambio di colore, che introdurrebbe una tinta nuova. */
  .about-box:hover,
  .about-value a:hover {
    text-decoration-thickness: 2px;
  }
}

/* --- sotto i 900px ------------------------------------------------------- */

/* Impianto verticale, non il desktop schiacciato: una colonna simmetrica, tutto
   centrato, con la pastiglia che scende a cavallo del bordo inferiore del
   ritratto e la scheda dati che si incolonna invece di stare su due colonne.
   Misure dalla composizione verticale 572x1080, tradotte in unita' relative. */
@media (max-width: 900px) {
  .about {
    --about-portrait-w: 53.3vw;

    /* Il nome e' molto piu' grande, in proporzione, che su desktop: occupa
       circa il 70% della larghezza della finestra. Il coefficiente e' ricavato
       dalla larghezza resa, non dall'altezza delle maiuscole nella
       composizione: la larghezza e' una base di misura piu' lunga e quindi
       piu' affidabile. */
    --about-name-fs: clamp(26px, 9.5vw, 86px);
    --about-role-fs: clamp(15px, 6.35vw, 56px);
    --about-label-fs: clamp(11px, 2.87vw, 18px);
    --about-value-fs: clamp(13px, 2.9vw, 19px);
    /* La pastiglia scende un po' di corpo, altrimenti su un telefono da 390px
       non entrerebbe nella larghezza che ha nella composizione. */
    --about-chip-fs: clamp(11px, 2.3vw, 13px);

    /* Stacco fra il ruolo e la scheda dati: 29px sui 572 della composizione. */
    --about-gap-mobile-dati: calc(var(--about-name-fs) * 0.43);

    /* Interlinea piu' stretta che su desktop: qui etichetta e valore sono
       incolonnati e devono leggersi come una coppia, non come due righe. */
    --about-lh-dati: 1.35;

    /* Colonna dall'alto, non centrata: la cima del ritratto e' ancorata al 17%
       dell'altezza, come nella composizione. */
    height: auto;
    min-height: 100vh;
    min-height: 100svh; /* barra del browser esclusa, dove supportato */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    padding: 17.4vh var(--about-edge) 10vh;
  }

  /* Una colonna. position: relative serve alla pastiglia, che qui esce dal
     flusso: e' l'unica pastiglia del documento, riposizionata e non duplicata.
     La seconda riga si allunga, cosi' l'auto-margine dei contatti ha spazio da
     assorbire e li spinge in fondo. */
  .about-body {
    position: relative;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    justify-items: center;
    /* stretch e non center, che qui si erediterebbe dal desktop: senza, la
       colonna di testo non riempie la riga e l'auto-margine dei contatti non
       ha spazio libero da assorbire, quindi non li spinge in fondo. */
    align-items: stretch;
    /* Stacco fra il bordo inferiore del ritratto e la cima del nome: 52px di
       inchiostro sui 572 della composizione. E' su questo tratto che la
       pastiglia scende a cavallo, ma essendo fuori dal flusso non lo occupa. */
    row-gap: calc(var(--about-name-fs) * 0.87);
    width: 100%;
    flex: 1;
  }

  /* Il ritratto non deve prendere tutta la larghezza: su un telefono
     occuperebbe una schermata e mezza. Qui comanda la larghezza e l'altezza
     segue dal 4:5, al contrario del desktop. */
  .about-portrait {
    height: auto;
    width: var(--about-portrait-w);
  }

  /* La pastiglia scende a cavallo del bordo inferiore del ritratto, centrata
     sulla sua larghezza. Il top e' l'altezza del ritratto — che qui e' nota,
     larghezza per 5/4 — e translate(-50%, -50%) la mette a meta' su quel bordo,
     come nella composizione. z-index la tiene sopra la foto; nessun contenitore
     ha overflow: hidden, quindi non viene ritagliata. */
  .about-status {
    position: absolute;
    top: calc(var(--about-portrait-w) * 5 / 4);
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 3;
    margin-top: 0;
    margin-bottom: 0;

    /* Qui il riquadro serve: meta' pastiglia sta sul nero della foto, e il
       fondo bianco e' l'unica cosa che tiene leggibile la scritta.
       Spigoli vivi, come la foto e come i riquadri dei contatti.

       Colori letterali e non var(--fondo)/var(--inchiostro): questa pastiglia
       non si inverte in modalita' scura. E' l'unico elemento del sito il cui
       fondo di riferimento non e' la pagina ma la fotografia, che resta scura
       in entrambe le modalita' — e sta a cavallo del bordo della carta, che
       per la stessa ragione resta bianca. Invertendola seguirebbe la pagina e
       si staccherebbe dai due piani su cui poggia davvero.
       Il colore del testo va dichiarato: senza, in scura erediterebbe il
       bianco da body e sparirebbe sul proprio fondo. */
    padding: var(--about-chip-pad-y) var(--about-chip-pad-x);
    border: 1px solid #000000;
    background: #ffffff;
    color: #000000;

    /* Un po' piu' piccola dei riquadri dei contatti, solo qui. Si tocca il
       solo corpo e non anche il padding: le due quote della pastiglia sono in
       em, quindi rimpiccioliscono con lui e la forma resta la stessa.
       Non si abbassa --about-chip-fs, che e' condiviso con .about-box: li'
       il corpo resta quello di prima. */
    font-size: calc(var(--about-chip-fs) * 0.85);
  }

  /* Tutto il testo centrato, e la colonna si stira per tutta la riga. */
  .about-text {
    align-items: center;
    text-align: center;
    width: 100%;
  }

  /* L'etichetta va SOPRA il valore, non accanto: una colonna sola. */
  .about-data {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    margin-top: var(--about-gap-mobile-dati);
    /* Assorbe lo spazio libero: e' questo a spingere i contatti in fondo alla
       colonna quando il contenuto e' piu' corto della finestra. */
    margin-bottom: auto;
  }

  /* Stacco netto fra il gruppo FOUNDER e il gruppo BASED. */
  .about-data .about-value + .about-label {
    margin-top: 0.75em;
  }

  /* Qui lo stato e' fuori dal flusso, quindi tocca ai riquadri aprire il
     gruppo. Lo spazio vero glielo da' comunque l'auto-margine della scheda. */
  .about-contacts {
    justify-content: center;
    margin-top: var(--about-gap-largo);
  }
}

/* --- ingresso in cascata --------------------------------------------------

   Gli elementi entrano dall'alto uno dopo l'altro, con lo stesso carattere
   dell'indice Work: 1100ms, decelerazione esponenziale, 110ms di scarto.

   I fotogrammi sono una copia, non un riuso: workIn e i ritardi di .work-item
   restano dove sono. Condividerli farebbe ricadere su Work — che e' chiusa e
   approvata — ogni futura modifica ad About.

   both e' obbligatorio: senza, gli elementi lampeggiano al loro posto prima
   che scada il ritardo. L'opacity: 0 dichiarata a parte copre il caso in cui
   l'animazione non parta affatto.

   Il ritratto si anima su .about-portrait, mai su .about-card: e' la carta
   che riceve l'inclinazione scritta da js/about.js a ogni frame, e le due
   transform si sovrascriverebbero a vicenda. .about-portrait porta la
   prospettiva e resta ferma, quindi e' il posto giusto — e l'ombra, che le e'
   figlia, entra insieme alla foto.

   La pastiglia si anima su .about-status e non sul pallino: .about-dot ha gia'
   la sua pulsazione infinita, e una seconda animation la sostituirebbe.

   Il footer entra solo qui — .about ~ .site-footer —, perche' About e' l'unica
   pagina in cui si vede senza scorrere e quindi fa parte della composizione.
   -------------------------------------------------------------------------- */

@keyframes aboutIn {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Sotto i 900px la pastiglia e' in posizione assoluta e si centra da sola con
   translate(-50%, -50%): quel translate fa sia il centramento orizzontale sia
   la risalita di meta' altezza che la mette a cavallo del bordo della foto.
   Un keyframe che scrive solo translateY lo cancellerebbe, e la pastiglia
   scivolerebbe a destra e in basso. Qui il ritardo d'ingresso si somma al
   centramento invece di sostituirlo. */
@keyframes aboutInPastiglia {
  from { opacity: 0; transform: translate(-50%, -50%) translateY(28px); }
  to   { opacity: 1; transform: translate(-50%, -50%) translateY(0); }
}

.about-portrait,
.about-name,
.about-role,
.about-data > dt,
.about-data > dd,
.about-status,
.about-contacts,
.about ~ .site-footer {
  opacity: 0;
  animation: aboutIn 1100ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

/* I ritardi sono scritti per classe, uno per uno, e non con un nth-of-type
   sull'ordine del DOM: nel markup .about-status sta dopo .about-data, e un
   ciclo sull'ordine del codice la farebbe entrare fuori posto.

   Le due righe della scheda entrano intere: dt e dd condividono il ritardo,
   quindi etichetta e valore si muovono insieme come il numero e il nome in
   Work. */

/* Sopra i 900px l'ordine sullo schermo e' quello del flusso: la pastiglia sta
   fra la scheda dati e i contatti. */
.about-portrait                 { animation-delay: 120ms; }
.about-name                     { animation-delay: 230ms; }
.about-role                     { animation-delay: 340ms; }
.about-data > dt:nth-of-type(1),
.about-data > dd:nth-of-type(1) { animation-delay: 450ms; }
.about-data > dt:nth-of-type(2),
.about-data > dd:nth-of-type(2) { animation-delay: 560ms; }
.about-status                   { animation-delay: 670ms; }
.about-contacts                 { animation-delay: 780ms; }
.about ~ .site-footer           { animation-delay: 890ms; }

/* Sotto i 900px l'impianto cambia e con lui l'ordine sullo schermo: il
   ritratto sta sopra a tutto e la pastiglia esce dal flusso, a cavallo del suo
   bordo inferiore, quindi si vede subito dopo la foto e prima del nome.
   Risale al secondo posto e le quattro voci in mezzo slittano di un passo.
   Contatti e footer non si spostano: sono ultimi in entrambi gli impianti. */
@media (max-width: 900px) {
  /* Qui cambia anche il keyframe, non solo il ritardo: vedi la nota su
     aboutInPastiglia. Durata, curva e fill-mode restano quelli comuni. */
  .about-status                   { animation-name: aboutInPastiglia;
                                    animation-delay: 230ms; }
  .about-name                     { animation-delay: 340ms; }
  .about-role                     { animation-delay: 450ms; }
  .about-data > dt:nth-of-type(1),
  .about-data > dd:nth-of-type(1) { animation-delay: 560ms; }
  .about-data > dt:nth-of-type(2),
  .about-data > dd:nth-of-type(2) { animation-delay: 670ms; }
}

/* Movimento ridotto: tutto gia' al suo posto al primo fotogramma, come per
   .work-item. */
@media (prefers-reduced-motion: reduce) {
  .about-portrait,
  .about-name,
  .about-role,
  .about-data > dt,
  .about-data > dd,
  .about-status,
  .about-contacts,
  .about ~ .site-footer {
    animation: none;
    opacity: 1;
  }
}

/* ==========================================================================
   Footer — su sette pagine: ovunque tranne work.html

   Una riga sola in fondo alla pagina. Scorre con il contenuto, non e' fissa:
   sta alla fine di quello che c'e', non incollata alla finestra.

   Centrata e in maiuscolo. Il padding orizzontale e' simmetrico apposta: con
   10px a sinistra e var(--gap) a destra il centro cadrebbe 4px fuori asse.

   Nero come tutto il resto: l'interfaccia resta sui due soli colori, #000 e
   #fff. A tenerlo defilato bastano il corpo piccolo e il peso 400 — non
   serve un grigio, e il sito non ne ha nessun altro.

   Fuori dall'indice Work per scelta: li' i cinque nomi sono in difference e
   riempiono la schermata, e una riga sotto sarebbe stata sia un problema di
   fusione sia un problema di altezza. La classe resta comunque priva di
   mix-blend-mode e di z-index, cosi' se un domani tornasse su quella pagina
   non erediterebbe l'inversione e resterebbe sotto l'anteprima fissa.
   ========================================================================== */

/* Le tre quote stanno su body e non in :root: le usa il footer, ma anche la
   pagina About, che sottrae esattamente questo ingombro alla propria altezza.
   Dichiarate in un posto solo, cosi' non possono divergere. */
body {
  --footer-aria: 6vh;   /* stacco dal contenuto sopra */
  --footer-riga: 12px;  /* corpo del testo */
  --footer-sotto: 10px; /* stacco dal bordo inferiore, come l'inset a sinistra */

  /* Ingombro verticale del blocco. Su desktop e' una riga sola con
     line-height 1, quindi coincide col corpo; su mobile le righe sono due e i
     due valori si separano. E' questo — non --footer-riga — che About sottrae
     alla propria altezza. */
  --footer-blocco: var(--footer-riga);
}

.site-footer {
  padding: var(--footer-aria) 10px var(--footer-sotto); /* orizzontale simmetrico: vedi nota */
  font-size: var(--footer-riga); /* fisso: non scala con la finestra */
  line-height: 1;
  font-weight: 400; /* tutto il sito e' in Bold: qui il Regular fa parte del farsi da parte */
  color: var(--inchiostro);
  text-align: center;
  text-transform: uppercase;
  /* Spaziatura presa dalla reference, dove il maiuscolo e' molto aperto: e'
     quella a far leggere la riga come una didascalia legale invece che come
     testo. Piu' larga della pastiglia di stato, che sta a 0.06em. */
  letter-spacing: 0.1em;
}

/* Il separatore fra le due parti. Nella reference e' molto piu' tenue del
   testo — misurato, sta al 22% della sua intensita' — e ha un respiro largo
   ai lati: e' quello a tenere separate le due frasi senza bisogno di un
   bordo. L'opacita' invece di un grigio dichiarato: cosi' il colore resta
   quello del footer e non si introduce una seconda tinta. */
.site-footer-sep {
  margin: 0 1.4em;
  opacity: 0.22;
}

/* Rete di sicurezza al meta format-detection: alcune versioni di iOS lo
   ignorano in certi contesti, e altri lettori (Mail, WhatsApp in-app)
   linkificano comunque. Se il link viene creato, almeno non e' azzurro.
   inherit e non un colore dichiarato: cosi' segue il tema chiaro/scuro. */
.site-footer a[href^="tel"] {
  color: inherit;
  text-decoration: none;
  pointer-events: none;
}

/* --- About ----------------------------------------------------------------
   E' l'unica pagina progettata per stare in una schermata sola. Aggiungendo il
   footer sotto, la somma supererebbe la finestra e comparirebbe una barra di
   scorrimento su una pagina che non deve scorrere.

   L'ingombro del footer si toglie allo spazio dei contatti, non alla pagina.
   Ma i due impianti sono diversi e vanno trattati separatamente, senza che
   l'uno ricada sull'altro: sopra i 900px .about ha height: 100vh e centra il
   blocco; sotto, ha height: auto con min-height e padding-bottom: 10vh, ed e'
   quel 10vh il margine inferiore dei contatti.

   L'ingombro e' sempre lo stesso: aria + riga + stacco dal fondo. */

/* Desktop: si accorcia il contenitore. Il blocco e' centrato, quindi risale di
   meta' dell'ingombro — e sopra come sotto c'e' spazio in abbondanza. */
@media (min-width: 901px) {
  .about {
    height: calc(100vh - var(--footer-aria) - var(--footer-blocco) - var(--footer-sotto));
  }
}

/* Mobile: si accorcia il min-height, e il padding inferiore cede al footer
   esattamente quello che il footer occupa. Cosi' i contatti non si muovono di
   un pixel e la pagina resta di una schermata.
   Il 10vh qui sotto e' lo stesso valore del padding dichiarato nella sezione
   About: se cambia la', va cambiato anche qui. */
@media (max-width: 900px) {
  .about {
    min-height: calc(100vh - var(--footer-aria) - var(--footer-blocco) - var(--footer-sotto));
    min-height: calc(100svh - var(--footer-aria) - var(--footer-blocco) - var(--footer-sotto));
    padding-bottom: calc(10vh - var(--footer-aria) - var(--footer-blocco) - var(--footer-sotto));
  }
}

/* --- mobile ---------------------------------------------------------------
   A 12px la riga non ci sta in larghezza su un telefono: circa 40 caratteri
   maiuscoli, piu' 0.1em di spaziatura e i due margini larghi del separatore,
   superano i 390px di un iPhone e la riga va a capo su due.

   Si ridimensiona la variabile, non font-size: --footer-riga e' la stessa
   misura che About sottrae alla propria altezza, quindi cambiandola qui la
   pagina si riadatta da sola e i conti restano giusti in un posto solo.

   Anche spaziatura e margini del separatore scendono: sono proporzionali al
   corpo, ma a corpi piccoli restano larghi in proporzione e continuerebbero a
   spingere la riga oltre il bordo. Cosi' sta dentro anche a 320px, la
   larghezza dei telefoni piu' stretti ancora in giro. */
@media (max-width: 900px) {
  body {
    --footer-aria: 4vh;
    --footer-sotto: 8px;

    /* Una riga sola, come su desktop, a qualunque larghezza.
       Il footer resta una riga sola su ogni schermo, come su desktop: sotto
       una certa larghezza e' il corpo a scendere, non il testo ad andare a
       capo.
       E' l'unico testo del sito legato alla larghezza della finestra: e'
       anche l'unico che non puo' andare a capo. */
    /* Una riga sola a qualunque larghezza. Con 66 caratteri effettivi, la
       spaziatura ridotta e i tre separatori, la riga misura circa 49 volte il
       corpo piu' il padding: perche' stia in W servono corpi sotto
       (W - 12) / 49. A 320px fa 6.3px, e 1.85vw ne da' 5.9 — un margine del
       6% sulla stima, che e' approssimata.
       Il tetto di 8px evita che su tablet e finestre strette il corpo
       ricresca oltre quello del desktop. */
    --footer-riga: min(8px, 1.85vw);
    --footer-blocco: var(--footer-riga);
    --footer-blocco: var(--footer-riga);
  }

  /* Spaziatura e margini dei separatori scendono insieme al corpo: sono
     proporzionali, ma a corpi piccoli pesano in proporzione di piu' e sono
     loro a spingere la riga oltre il bordo.
     nowrap e' la garanzia: se un domani il testo si allunga, invece di andare
     a capo di nascosto sborda e si vede subito che il conto non torna. */
  .site-footer {
    /* Padding e spaziatura scendono insieme al corpo: sono i tre termini che
       compongono la larghezza della riga, e a corpi piccoli i due fissi
       pesano in proporzione molto di piu'.
       nowrap e' la garanzia: se un domani il testo si allunga, invece di
       andare a capo di nascosto sborda e si vede subito che il conto non
       torna. */
    padding-left: 6px;
    padding-right: 6px;
    letter-spacing: 0.01em;
    line-height: 1;
    white-space: nowrap;
  }

  .site-footer-sep {
    margin: 0 0.3em;
  }

  .site-footer-sep {
    margin: 0 0.9em;
  }
}

/* ==========================================================================
   Puntatore a crocetta — tutte le pagine

   Due barre incrociate da 1px che inseguono il cursore con inerzia. Non c'e'
   markup negli otto HTML: l'elemento lo crea js/main.js, che gira ovunque.

   Bianca in difference, non nera. Sul bianco della pagina si inverte in nero;
   sopra le fotografie scure della griglia resta bianca. Una crocetta nera
   fissa sparirebbe su meta' del sito. E' la stessa soluzione dell'header e
   dell'indice Work.

   E' figlia diretta di <body>, mai annidata: cosi' non entra nel contesto di
   fusione dell'header ne' in quello isolato del ritratto olografico.

   Tutto sta dentro (hover: hover) and (pointer: fine). Su touch non esiste —
   ma la difesa vera e' nel JavaScript, che su touch non aggiunge nemmeno la
   classe .ha-crocetta.
   ========================================================================== */

@media (hover: hover) and (pointer: fine) {

  /* cursor: none dipende dalla classe che mette il JS, non e' scritto a secco:
     se lo script non parte o va in errore, il cursore di sistema resta al suo
     posto e la pagina resta usabile. La regola e' la stessa cosa che disegna
     la crocetta, quindi le due cose non possono esistere l'una senza l'altra.
     Vale anche sui figli — sui link il pointer di sistema rimetterebbe la
     manina accanto alla crocetta. */
  .ha-crocetta,
  .ha-crocetta * {
    cursor: none;
  }

  .crocetta {
    /* --- le costanti regolabili --------------------------------------- */
    --crocetta-ingombro: 18px;       /* da braccio a braccio */
    --crocetta-ingombro-larga: 28px; /* sopra gli elementi cliccabili */
    --crocetta-spessore: 1px;        /* 1px netto, anche da larga */
    --crocetta-dissolvenza: 160ms;

    position: fixed;
    top: 0;
    left: 0;
    z-index: 1000; /* sopra tutto, header compreso */
    pointer-events: none;

    width: var(--crocetta-ingombro);
    height: var(--crocetta-ingombro);

    color: #ffffff; /* bianco + difference = inversione automatica */
    mix-blend-mode: difference;

    /* Nascosta finche' il cursore non si muove la prima volta: senza, comparirebbe
       nell'angolo in alto a sinistra prima di sapere dov'e' il puntatore. */
    opacity: 0;

    /* L'ingombro e' l'unica misura che cambia, e cambia solo all'ingresso su un
       elemento cliccabile: non e' il movimento, che sta tutto su transform. */
    transition: opacity var(--crocetta-dissolvenza) ease,
                width 180ms ease,
                height 180ms ease;

    will-change: transform;
  }

  .crocetta.is-visibile {
    opacity: 1;
  }

  /* Sopra i cliccabili si allarga e basta: nessun colore, nessuna rotazione,
     nessun riempimento. Restituisce il segnale che si perde nascondendo la
     manina di sistema. Lo spessore non cambia: e' una misura fissa, non scala
     con l'ingombro. */
  .crocetta.is-larga {
    width: var(--crocetta-ingombro-larga);
    height: var(--crocetta-ingombro-larga);
  }

  /* Le due barre. currentColor cosi' il bianco e' dichiarato una volta sola. */
  .crocetta::before,
  .crocetta::after {
    content: '';
    position: absolute;
    background: currentColor;
  }

  /* Orizzontale: larga quanto l'ingombro, alta lo spessore, centrata. */
  .crocetta::before {
    left: 0;
    right: 0;
    top: 50%;
    height: var(--crocetta-spessore);
    margin-top: calc(var(--crocetta-spessore) / -2);
  }

  /* Verticale: la stessa cosa ruotata di novanta gradi. I quattro bracci
     risultano uguali perche' il contenitore e' quadrato. */
  .crocetta::after {
    top: 0;
    bottom: 0;
    left: 50%;
    width: var(--crocetta-spessore);
    margin-left: calc(var(--crocetta-spessore) / -2);
  }
}

/* Movimento ridotto: la crocetta resta, agganciata al cursore senza ritardo —
   il JS porta lo smorzamento a 1. Qui cadono anche le transizioni: togliere
   l'inerzia e lasciare l'ingombro che si gonfia sarebbe una contraddizione. */
@media (prefers-reduced-motion: reduce) {
  .crocetta {
    transition: none;
  }
}

/* ==========================================================================
   Pagina Privacy

   L'unica pagina di solo testo del sito. Riprende gli assi che ci sono gia':
   inset di 10px come l'header e come l'indice Work, titolo in maiuscolo
   Bold, etichette a corpo fisso e valori in Regular — la stessa distinzione
   fra dato di servizio e contenuto usata nella scheda di About.

   La misura di riga e' limitata: 68 caratteri circa. Righe piu' lunghe si
   leggono peggio, perche' l'occhio fatica a ritrovare l'inizio di quella
   dopo. E' l'unico punto del sito in cui la larghezza e' un vincolo di
   lettura e non di composizione.
   ========================================================================== */

.legal {
  padding: calc(48px + 10vh) 10px 0 10px;
  max-width: 34em;
}

.legal-title {
  font-size: clamp(40px, 6.4vw, 96px);
  line-height: 0.85;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  font-weight: 700;
}

/* Il paragrafo d'apertura e' piu' grande del corpo: dice la cosa che conta —
   che non si viene tracciati — e chi legge solo la prima riga ha gia' la
   risposta. */
.legal-lead {
  margin-top: 1.2em;
  font-size: 18px;
  font-weight: 700;
  line-height: 1.45;
}

.legal-body {
  margin-top: 3em;
  font-size: 14px;
  line-height: 1.55;
}

/* Etichetta di sezione: stesso ruolo dei numeri nell'indice Work e delle
   voci nella scheda di About — si legge come indice, non come titolo. */
.legal-body dt {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 12px;
}

.legal-body dd {
  font-weight: 400;
  margin: 0.5em 0 2.4em 0;
}

.legal-body a,
.legal-lead a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
}

/* Nota di servizio dentro un blocco di testo: stesso corpo, ma piu' defilata.
   Non un grigio dichiarato — l'opacita' segue il tema chiaro/scuro da sola. */
.legal-note {
  opacity: 0.55;
}

.legal-date {
  margin-top: 1em;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.5;
}

/* Il link nel footer eredita tutto dal footer e non si distingue in nulla:
   una sottolineatura, a questo corpo, spezzerebbe la riga in due pesi e
   toglierebbe leggerezza a tutta la fascia.

   Nessun tratto nemmeno all'hover, su nessuna delle due versioni. Il segnale
   che sia cliccabile resta comunque: su desktop la crocetta del puntatore si
   allarga sopra i cliccabili, e su touch la parola si tocca e basta. */
.site-footer a {
  color: inherit;
  text-decoration: none;
}

@media (max-width: 900px) {
  .legal {
    padding-top: calc(48px + 6vh);
  }

  .legal-lead {
    font-size: 16px;
  }
}
