:root {
  --bar-w: 1px;

  /* Palette: directing/editing/about condividono lo stesso blu notte quasi nero
     ("midnight cobalt", non nero assoluto); musing è l'unica eccezione, rosso
     scuro profondo — è la sezione che si "accende" rispetto alle altre. */
  --c-directing: #000103;
  --c-editing: #000103;
  /* **Musing è carta.** Era `#1f0303`, rosso notte, per tutta la costruzione del sito:
     dal 10 agosto la sezione ha un fondo chiaro, ed è l'unico — non c'è più un secondo
     stato né un interruttore. Resta l'eccezione fra le quattro sezioni, solo nell'altra
     direzione: le altre tre sono notte, questa è giorno.
     Il valore è quello della carta, e passa da `--c-paper` invece di essere riscritto:
     la superficie è la stessa del segnaposto di DUST GIRL e della card che chiede un
     pensiero, e devono restare la stessa cosa. */
  --c-musing: var(--c-paper);
  --c-about: #000103;

  /* **Il rosso notte che era il fondo di musing** fino al 10 agosto, quando quella
     pagina è passata alla carta. È sopravvissuto in about, dove era il colore che si
     intravedeva fra una foto del ritratto e l'altra — scelto lì *perché* era il rosso
     di musing, cioè un rimando fra due pagine. Quando musing è diventata carta il
     rimando è caduto, e il 17 agosto è caduto anche il colore: il riquadro del
     ritratto è passato al bianco, insieme al filo del suo hover.
     **Le due variabili rosse non le usa più nessuno**, e restano dichiarate qui e
     basta. Non sono un residuo da ripulire: sono l'unico punto del foglio in cui è
     scritto quanto costa quel rosso, ed è una misura che è servita due volte.
     `--c-ember` non si vede come tratto (1,07:1 su `--c-base`, cioè nulla: è nato
     come colore di SFONDO di una pagina); `--c-musing-line` è lo stesso rosso alzato
     di chiarezza fino a 1,95:1, che come linea da un pixel si vedeva ma appena — ed è
     il motivo per cui è uscito. Provati a confronto, ingranditi 3x su fondo di
     pagina: #5c1111 (1,53) è ancora un sussurro, #b52626 (3,25) è già acceso.
     Se serve di nuovo un rosso, la scala sta qui e non va rifatta. */
  --c-ember: #1f0303;
  --c-musing-line: #7a1717;

  /* Base scura del documento: evita il flash bianco tra una pagina e l'altra.
     Ogni pagina ripete il proprio colore in uno style inline su <html>, perché
     l'attributo viene applicato prima che styles.css sia scaricato. */
  --c-base: #000103;

  /* Fallback di sicurezza: testo NERO. Vale solo se <html> non porta nessuna
     classe theme-* (tutte le pagine ne hanno una statica, quindi in pratica non
     dovrebbe mai servire). Nero perché l'unico sfondo non noto in anticipo è il
     video della home, che è chiaro: nel dubbio si legge nero su chiaro, mai
     bianco su chiaro. Non invertirlo senza aver riletto CLAUDE.md § Contrasto. */
  --ink: #000000;
  --ink-dim: rgba(0, 0, 0, 0.65);

  /* Bordi interni dei due blocchi fissi ai lati: dove finisce la nav a sinistra e
     dove cominciano i testi ruotati a destra. Sono stime di ripiego —
     initFixedEdges() in script.js le sostituisce con le misure vere, perché la
     larghezza di quei blocchi dipende dal testo e dal font. Le usano la colonna del
     mosaico e il breadcrumb, che devono risultare centrati sulla stessa cosa. */
  /* --- Superficie "carta" ---
     Bianco sporco e il suo nero, definiti come COPPIA: dove va uno va l'altro, e
     su questa superficie il nero è scritto a mano perché --ink qui è bianco (le
     pagine sono theme-dark) e non c'entra niente.
     Non è bianco netto per una ragione già stabilita: accanto alle superfici
     morbide del sito il #fff sembra carta fotografica in mezzo a carta da lettera.
     **Ed è neutro, non più panna** (era `#f6f3ed`, cioè nove punti di blu in meno
     degli altri due canali). Il motivo non è di gusto ed è misurato: il bianco della
     **home** — che è l'unica altra superficie chiara del sito — è perfettamente
     neutro, R=G=B in ogni punto, campionato sui pixel resi del video di sfondo. Fra
     due pagine chiare una panna e una neutra il salto si vedeva passando dall'una
     all'altra, e la panna era musing. Portata qui la media della home, `#f6f6f6`.
     **Da sapere per il giorno in cui si tocca il video**: quel bianco non è un colore
     ma un fotogramma — va da 240 a 254 attraverso il frame, più chiaro a destra, e
     cambia con la clip. `#f6f6f6` ne è la media, non un valore che si possa rileggere
     da qualche parte. Se `bg.mp4` viene riesportato con un'altra gradazione, questa
     riga va ricampionata (§ HANDOFF, Come guardare le pagine).
     Lo usano il fondo di musing e la tile segnaposto di DUST GIRL. Sta qui, e non nei
     due posti, perché cambiarlo deve essere una riga sola e non una caccia: le due
     cose condividono il colore per scelta, non per caso. */
  --c-paper: #f6f6f6;
  --c-paper-ink: #14100e;

  /* --- La misura che centra i due blocchi fissi nella loro fascia nera ---

     Una sola distanza, usata DUE volte per lato: quanto il blocco fisso dista dal
     bordo del foglio, e quanto il mosaico dista dal blocco. Le due cose uguali sono
     esattamente la condizione perché il blocco risulti centrato nella fascia fra il
     bordo del foglio e l'inizio dei video — non c'è nessun calcolo da fare, e resta
     vero a qualunque larghezza di finestra, perché la fascia cresce di quanto
     cresce il mosaico.

     Perciò: se cambi questo numero cambiano insieme la posizione della nav, quella
     dei link laterali e la larghezza della colonna. Se ne cambiassi uno solo (per
     esempio riportando la nav a 6vw, dov'era) i blocchi tornerebbero fuori asse. */
  --gutter: 64px;

  /* La stanghetta e il suo spazio, presi insieme. Servono come misura perché la
     centratura si fa sul TESTO, non sul blocco: la barra è 1px, di inchiostro non
     ne ha, e contarla dentro sposta la parola di 4,5px fuori asse — si vede.
     I due blocchi fissi arretrano quindi di questa misura verso il bordo del
     foglio, e la barra resta fuori dal conto, appoggiata al bordo. */
  --bar-gap: 8px;
  --bar-lead: calc(var(--bar-w) + var(--bar-gap));

  --nav-edge: calc(6vw + 66px);
  --side-edge: 60px;
  --content-center: 50%; /* senza JS: centro finestra, come prima */
}

/* --- Tema testo adattivo: lo script.js imposta una di queste classi su <html>
     in base alla luminosità dello sfondo (video/immagine) o, sulle pagine con
     sfondo piatto noto, la classe è scritta staticamente nel markup. --- */

html.theme-dark {
  --ink: #ffffff;
  --ink-dim: rgba(255, 255, 255, 0.65);
}

html.theme-light {
  --ink: #000000;
  --ink-dim: rgba(0, 0, 0, 0.65);
}

* {
  box-sizing: border-box;
}

html, body {
  height: 100%;
  margin: 0;
}

/* Base scura su <html>: è la superficie che il browser dipinge mentre la vecchia
   pagina viene scaricata e la nuova non ha ancora reso il proprio sfondo. Senza
   questo si vede il bianco di default a ogni navigazione. color-scheme:dark
   allinea anche il canvas e gli elementi di sistema (scrollbar). */
html {
  background: var(--c-base);
  color-scheme: dark;
}

body {
  background: var(--c-base);
  color: var(--ink);
  /* Lo stack sans del sito, e si scrive **in un modo solo**: per un periodo è
     esistito anche come `'Helvetica Neue', Helvetica, Arial, sans-serif`, in sei
     punti su dodici. Rendevano identico — su macOS "Helvetica" è un alias di Arial,
     misurato — quindi non si vedeva, ma erano due scritture della stessa cosa e
     prima o poi sarebbero divergute. Unificate il 19 agosto. */
  font-family: 'Helvetica Neue', Arial, sans-serif;
  position: relative;
  overflow-y: auto;
  overflow-x: hidden;
}

/* Pagine a schermo pieno senza scroll (home, musing) */
body.no-scroll {
  overflow: hidden;
}

/* --- Sfondo --- */

/* **Il poster non è un attributo, è questo sfondo**, e la ragione è che i poster sono
   DUE — uno per formato, come i video (vedi i due <source> in index.html). L'attributo
   `poster` invece è uno solo e non si può condizionare a una media query, quindi con
   due fondi diversi mostrerebbe per forza quello sbagliato su uno dei due.
   Il risultato visivo è identico: il video è opaco e con `object-fit: cover` riempie la
   stessa scatola, quindi appena decodifica un fotogramma copre lo sfondo — esattamente
   quello che faceva il poster. Il browser scarica **solo** l'immagine la cui regola vale.
   La soglia è la stessa dei <source> (`1/1`, più alto che largo) e le due cose vanno
   cambiate INSIEME: un poster orizzontale sopra un video verticale si vedrebbe per il
   secondo che passa fra il primo pixel e il primo fotogramma. */
.bg-media {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* mai #fff: sarebbe un lampo bianco mentre il video carica */
  background-color: var(--c-base);
  background-image: url('bg.jpg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

@media (max-aspect-ratio: 1/1) {
  .bg-media {
    background-image: url('bg-vert.jpg');

    /* **Il ritaglio resta centrato.** Per un giorno è stato al 30%, per allontanare le
       clip dalla nav quando la firma era in cima: le clip del montaggio verticale sono
       tutte centrate su x 613,5 del fotogramma (misurato su dieci campioni), cioè 73,5px
       a destra del centro. Tornata la firma al bordo, quello spostamento non serve più.
       Se dovesse riservire, il verso è controintuitivo: `object-position` sposta la
       *finestra di ritaglio*, non la clip, quindi per allontanare dalla nav si **scende**
       sotto il 50%, non si sale. Il pavimento è 18%, dove il bianco a destra scende ai
       16px del gutter; a 0% la clip tocca il bordo destro dello schermo. */
  }
}

/* Il video di sfondo è cliccabile: click al centro schermo mette in pausa/riprende
   esattamente sul frame corrente (vedi script.js). */
video.bg-media {
  cursor: pointer;
}

/* Sfondo piatto (directing, editing, musing, about) */
.bg-flat {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Blocco colore pieno mostrato in hover sulla nav: sostituisce visivamente
   lo sfondo reale (video/foto/pagina) senza anticipare il contenuto vero. */
.hover-color-block {
  position: fixed;
  inset: 0;
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
  /* **2, non 1**: deve passare davanti anche al filtro, che sta a 1. Sopra ci
     restano solo le cose che devono restare leggibili mentre il blocco è acceso —
     nav, link laterali, social e l'anteprima — che sono a 2 come lui ma vengono
     dopo nel markup. */
  z-index: 2;
}

.hover-color-block.visible {
  opacity: 1;
}

.hover-color-block[data-color="directing"] { background: var(--c-directing); }
.hover-color-block[data-color="editing"] { background: var(--c-editing); }
.hover-color-block[data-color="musing"] { background: var(--c-musing); }

/* **Il blocco chiaro non si dissolve: appare.** È l'unico dei quattro che costringe il
   testo a invertirsi (nero su carta, mentre gli altri tre restano bianco su notte), e una
   dissolvenza incrociata fra due stati opposti passa per il punto in cui **coincidono**:
   a metà strada il fondo è grigio medio (123,122,120) e le voci di nav, che hanno la loro
   transizione di 0,2s sul colore, sono a metà fra bianco e nero (128,128,128).
   Contrasto misurato in quel punto: **1,09:1**, cioè la nav sparisce per un decimo di
   secondo — proprio la voce su cui il cursore sta sopra. Si vedeva su tutte le pagine, ma
   su about, che è una pagina di testo su un fondo piatto, l'intera superficie diventava
   grigia e sembrava un difetto (ed era un difetto).
   Togliendo la transizione **al solo blocco chiaro** il fondo salta diretto alla carta, e
   quello che resta è il testo che passa da bianco a nero sopra la carta: il suo punto
   peggiore è grigio medio su carta, **3,9:1**, che si legge. Uscendo, specularmente, grigio
   medio sul fondo notte, 5,3:1.
   Gli altri tre blocchi tengono la dissolvenza: fra scuro e scuro il testo resta bianco
   dall'inizio alla fine e non c'è nessun punto di mezzo da attraversare.
   **Se un domani un'altra sezione diventa chiara, questa regola vale anche per lei** — e la
   coppia da tenere insieme è sempre la stessa: `colorTheme` in `script.js` e questa riga. */
.hover-color-block[data-color="musing"] {
  transition: none;
}
.hover-color-block[data-color="about"] { background: var(--c-about); }

/* --- Anteprima all'hover sulla nav ---------------------------------------

   Una clip sola, uguale su tutte e quattro le voci: non è l'anteprima di *dove
   stai andando* (a quello pensa il colore, che è diverso per sezione), è la sola
   cosa che compare quando tocchi la nav. Per questo non c'è nessuna pesca casuale
   e nessun `data-` da tenere allineato — il file sta scritto in un punto solo,
   in `script.js`.

   **Il riquadro non ha fondo, ed è il punto.** La clip è nera per quasi tutta la
   sua superficie, quindi sui tre fondi notte i bordi non si vedono e quello che
   resta è il punto di luce, come se fosse ritagliato. Un `background` qui —
   fosse anche `--c-base` — glieli restituirebbe. Su musing, che è carta, il
   quadrato invece si vede: è l'unica sezione dove ha una forma, ed è accettato.

   200×200: la clip è 720×720, quindi il riquadro è quadrato e non ritaglia niente
   (`object-fit: cover` è lì per il giorno in cui la clip cambia rapporto, non per
   ritagliare questa).

   Sta su `--content-center` come tutto quello che appartiene alla colonna dei
   contenuti — 17px a destra del centro della finestra — e a `z-index: 2`, sopra
   il blocco colore che è 1. La nav è 2 anche lei, ma sta a sinistra e non si
   sovrappone: l'ordine nel markup basta.

   `.visible` non la mette l'hover: la mette l'evento `playing` del video (vedi
   `initNavPreview()`). Col preload a `none` il primo passaggio deve prima
   scaricare, e comparire subito vorrebbe dire un riquadro vuoto sul colore pieno
   — che qui si vedrebbe più che nel mosaico, dove sotto c'è sempre la copertina. */
.nav-preview {
  position: fixed;
  left: var(--content-center, 50%);
  top: 50%;
  width: 200px;
  height: 200px;
  transform: translate(-50%, -50%);
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.25s ease;
}

.nav-preview.visible {
  opacity: 1;
}

.nav-preview video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: transparent;
}

/* --- Navigazione --- */

.main-nav {
  position: fixed;
  /* Non 6vw: la distanza dal bordo del foglio è la stessa che il mosaico tiene
     dalla nav, ed è quello che la centra nella fascia nera (vedi --gutter). Il
     --bar-lead tira fuori la stanghetta dal conto: a essere centrate sono le
     parole. */
  left: calc(var(--gutter) - var(--bar-lead));
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 20px;
  z-index: 2;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--bar-gap);
  text-decoration: none;
  color: var(--ink-dim);
}

.nav-bar {
  width: var(--bar-w);
  height: 9px;
  background: var(--ink-dim);
  /* `margin` sta nella transizione insieme a `height`, e **non è decorativo**: la
     regola accesa più sotto alza la barra a 14 e le fa restituire 5px al flusso con un
     margine negativo. Se solo l'altezza fosse animata, il margine scatterebbe subito a
     -2,5 e per due decimi di secondo la riga si **rimpicciolirebbe** — il difetto che
     stiamo togliendo, al contrario. Animate tutte e due con la stessa durata e la
     stessa curva, l'altezza esterna resta 9 a ogni fotogramma:
         h = 9 → 14   m = 0 → −2,5   →   h + 2m = 9 sempre, perché entrambe lineari.
     **Se un giorno una delle due cambia durata o easing, l'invariante salta.** */
  transition: height 0.2s ease, margin 0.2s ease, background 0.2s ease;
}

.nav-label {
  font-size: 11px;
  letter-spacing: 0.4px;
  transition: color 0.2s ease;
  white-space: nowrap;
}

/* La barra accesa: all'hover, col fuoco da tastiera, e sulla voce della pagina in cui
   sei. Sale da 9 a 14 — è il segno che dice "questa" e "sei qui".

   **`margin-block: -2.5px` è quello che le impedisce di spostare la pagina.** La barra
   disegna 14px ma ne occupa 9, cioè quanti ne occupava da spenta: la riga non cresce,
   la nav non cresce, e le voci sotto non si muovono.
   Senza, il difetto era doppio e c'era da sempre:
   - **all'hover la nav tremava.** È centrata con `translateY(-50%)`, quindi i 3px in
     più si aprivano 1,5 sopra e 1,5 sotto e **tutte** le voci si spostavano ogni volta
     che il puntatore ne toccava una. Sul computer erano 3px su 110 e non si notava; in
     verticale sono 3 su 92 e si vede.
   - **la nav era più alta sulle quattro pagine con una voce corrente** (95 contro 92 in
     verticale, 110 contro 108 sul computer): passando dalla home ad about il blocco
     cambiava misura, ed è quello che si vedeva a occhio.
   Provate anche: la barra ferma a 11 (segnale dimezzato) e più spessa invece che più
   alta (sposta l'etichetta di 1px, perché allarga la riga). Questa non costa niente —
   misurato, **nessun numero cambia rispetto a una voce spenta tranne la barra resa**.
   La strada che sembra ovvia, `position: absolute`, **non va**: uscendo dal flusso la
   barra si porta via anche gli 8px di `--bar-gap` e l'etichetta le scivola addosso. */
.nav-item:hover .nav-bar,
.nav-item:focus-visible .nav-bar,
.nav-item[aria-current="page"] .nav-bar {
  height: 14px;
  margin-block: -2.5px;
  background: var(--ink);
}

/* La voce della sezione in cui sei resta accesa. Da quando i chooser non ci sono
   più la nav è l'unica navigazione del sito, ed è l'unica cosa in pagina che dice
   dove sei: il breadcrumb ha lasciato il posto al filtro, e il colore di sfondo è
   lo stesso su directing, editing e about. Il trattamento non è nuovo — è quello
   dell'hover, tenuto acceso. */
.nav-item[aria-current="page"] .nav-label {
  color: var(--ink);
}

.nav-item:hover .nav-label,
.nav-item:focus-visible .nav-label {
  color: var(--ink);
}

.nav-item:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 4px;
}

/* --- Link laterali: "directed by lorenzofiale" (-> homepage, sempre presente) e
     "previous" (-> un livello sopra, assente in home), stesso stile ruotato --- */

/* Colonne parallele, non una sotto l'altra: row-reverse tiene "directed by
   lorenzofiale" (primo nel markup) attaccato al bordo destro e mette "previous"
   alla sua sinistra. align-items:center li centra verticalmente tra loro. */
.side-links {
  position: fixed;
  /* Stessa misura del lato opposto, e per la stessa ragione: a restare centrato fra
     la fine dei video e il bordo del foglio è il TESTO, con la stanghetta fuori dal
     conto (vedi --gutter e --bar-lead).
     Meno --sbw, cioè la larghezza della barra di scorrimento: `right` si misura dal
     bordo dell'AREA UTILE, che sulle pagine che scorrono finisce prima della barra,
     mentre l'occhio confronta col bordo dello schermo. Senza la sottrazione lo
     stesso blocco cadeva a 64px dal bordo in home e su musing (che non scorrono) e
     a 79 su directing, editing e about — e la nav, ancorata a sinistra, non se ne
     accorgeva: il difetto si vedeva su una colonna sola. La misura la scrive
     initFixedEdges(); dove la barra è a scomparsa (macOS di serie) vale 0 e non
     cambia niente. Il blocco resta comunque a 40px dalla barra, non ci va sotto. */
  /* **Niente --bar-lead qui**, e non è una dimenticanza: quella misura serviva a
     tirare fuori dal conto la stanghetta, che adesso non c'è più. Tolta la stanghetta
     e lasciata la sottrazione, il testo scivolerebbe di 9px verso il bordo del foglio.
     Così invece il TESTO resta esattamente dove stava, a --gutter dal bordo — che è
     l'invariante di questa pagina, e vale ancora identica per la nav dall'altro lato,
     che la stanghetta ce l'ha e continua a scontarla. */
  right: calc(var(--gutter) - var(--sbw, 0px));
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: row-reverse;
  align-items: center;
  gap: 14px;
  z-index: 2;
}

/* **Il link è solo testo ruotato: la stanghetta è uscita il 20 agosto**, e su tutto il
   sito, non solo in verticale.
   C'era per una ragione scritta — *un testo ruotato al bordo dello schermo, senza,
   sembra una firma e basta* — e la ragione era vera quando il segno serviva a dire
   "si preme". Vale la pena tenere cos'era, perché è una misura: 1px di larghezza, alta
   9px a riposo e 14 all'hover, cioè lo stesso rapporto 9/11 della nav, che il suo segno
   ce l'ha ancora.
   **Quello che resta a dire che si preme è l'inchiostro che si accende all'hover**, che
   è la stessa cosa che fanno i social e le voci del filtro. */
.side-link {
  display: flex;
  align-items: center;
  text-decoration: none;
  cursor: pointer;
}

.side-link-text {
  writing-mode: vertical-rl;
  font-size: 11px;
  letter-spacing: 0.5px;
  color: var(--ink-dim);
  transition: color 0.2s ease;
}

.side-link:hover .side-link-text,
.side-link:focus-visible .side-link-text {
  color: var(--ink);
}

.side-link:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 4px;
}

/* --- Link social, centrati in basso: "instagram | email" ---

   **La barra non è il `//` del sito, ed è una distinzione voluta.** Il `//` lega
   parti di una cosa sola — anno, testata e titolo di una voce di press; nome della
   sezione e opzioni del filtro — mentre qui ci sono due destinazioni diverse, che
   non compongono niente insieme. Un segno per unire, uno per separare.
   Vale su tutte e due le pagine che hanno questa riga, home e about: le classi sono
   le stesse, e il carattere sta nel markup di ognuna — se cambia, cambia in due
   posti. --- */

.social-links {
  position: fixed;
  /* **Sull'asse della finestra, ed è l'unico caso del sito.** Ovunque altrove il
     centro è --content-center (il punto di mezzo fra i due blocchi fissi), che a
     1440 cade a 737 invece che a 720: la nav è più larga dei testi ruotati, quindi
     lo scarto è costante e vale (--nav-edge − --side-edge)/2 = 17px.
     Qui vince la finestra perché **sotto c'è il video**, e il riquadro dipinto
     dentro bg.mp4 è centrato sul fotogramma: su --content-center questa riga si
     leggeva fuori asse rispetto all'unica cosa che si vede in pagina.
     **Ed è gratis, da quando about non ha più la sua riga in fondo**: i social di
     about stanno di fianco alla mail (vedi .contact-social), quindi non c'è più
     nessun altro oggetto in questo slot con cui questa riga possa disallinearsi.
     Prima invece la stessa riga saltava di 17px passando da una pagina all'altra,
     ed era un difetto vero. Le sigle di musing stanno sì in fondo al centro e sì su
     --content-center, ma sono un altro oggetto — non è la stessa riga che si sposta.
     **Se un domani about rimette una riga social in fondo, queste due tornano a
     dover stare sullo stesso asse** e la scelta va rifatta. */
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  /* **1 come il filtro, non 2 come la nav**: in hover sulla nav questa riga va
     coperta dal blocco colore (che sta a 2), o resterebbe l'unica cosa al centro
     insieme all'anteprima — e le due non sono nemmeno sullo stesso asse (17px,
     vedi sopra). Sotto il blocco, home si comporta come le altre quattro: restano
     la nav e "directed by lorenzofiale", e basta.
     Sopra l'1 non c'è niente da scavalcare: la home non scorre e il video di fondo
     è fisso e viene prima nel markup. */
  z-index: 1;
  display: flex;
  align-items: baseline;
  gap: 5px;
  white-space: nowrap;
  font-size: 11px;
  letter-spacing: 0.4px;
}

.social-sep {
  color: var(--ink-dim);
}

.social-link {
  text-decoration: none;
  color: var(--ink-dim);
  transition: color 0.2s ease;
  /* **Il bersaglio cresce in altezza, il testo e la riga no.** L'inchiostro e' alto
     13px e la scatola era esattamente quella: un tocco un filo sopra o sotto cadeva
     fuori. Con 12px per lato passa a **37px**.
     **Il padding e' annullato da un margine negativo uguale**, ed e' quello che lo rende
     gratis: la scatola cresce per il dito, il flusso non se ne accorge. Serviva perche'
     questa riga sta in due posti che reagirebbero in due modi diversi — in home e'
     ancorata con `bottom: 24px`, quindi il padding sotto spingerebbe l'inchiostro in su;
     su about sta in una colonna flex, quindi allungherebbe la colonna di sinistra e
     **sposterebbe la soglia di impilamento**, che va rimisurata a ogni cambio li' dentro
     (§ About). Annullandolo non succede ne' l'una ne' l'altra cosa, e la regola resta
     una sola per tutti e due i posti.
     E' la stessa costruzione del padding orizzontale delle voci del filtro. */
  padding-block: 12px;
  margin-block: -12px;
}

.social-link:hover,
.social-link:focus-visible {
  color: var(--ink);
}

.social-link:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 4px;
}

/* --- Breadcrumb (pagine di contenuto/leaf) --- */

/* Stessa tipografia delle intestazioni di about (.about-block h2): maiuscoletto
   12px, tracking largo, peso 500. Il markup resta minuscolo, il maiuscolo è
   solo di resa (text-transform). */

/* --- La velatura in cima, e vale su tutti e due i formati -------------------------

   **Nata per il verticale il 22 agosto, estesa al computer il 24**, e la ragione e' una
   misura: sul computer non c'era mai stata, e il filtro e' fisso mentre il mosaico gli
   scorre sotto. Su tutti gli scorrimenti raggiungibili, con l'inchiostro composto sul
   fondo:

       directing  nome sezione  1,00:1 nel peggiore, 25,1% sotto 4,5
       directing  opzioni       1,00:1 nel peggiore, 29,0% sotto 4,5
       editing    nome sezione  1,04:1 nel peggiore, 54,9% sotto 4,5
       editing    opzioni       1,03:1 nel peggiore, 76,5% sotto 4,5

   Cioe' su editing il filtro era illeggibile per tre quarti della pagina. Si vedeva a
   occhio solo sopra il foglio bianco di DUST GIRL, che e' il caso limite, ma il difetto
   era generale: bastano le copertine chiare di short docs.
   **Le misure del verticale reggono qui senza toccarle**, ed e' il motivo per cui la
   regola e' una sola invece di due: il filtro cade alla stessa y sui due formati (nome
   22-42, opzioni 46-66), quindi vede la stessa alfa — 0,736 e 0,718 — e su un fondo
   quasi bianco da' 10,2:1 e 5,07:1.

   **Il prezzo, dichiarato**: la fascia scurisce i primi 220px di qualunque cosa stia
   li' sotto, e su un segnaposto — che e' carta bianca — si vede come una sfumatura
   grigia in cima al foglio. Non e' un secondo difetto da chiudere: **e' il modo in cui
   il primo si chiude**. L'unica cosa che lo attenua e' che la velatura sia lunga e
   morbida invece che corta e scura, che e' gia' cosi'.

   Sta su `.content-page` perche' ce l'hanno solo directing ed editing, cioe' le sole
   pagine dove sotto quella fascia scorre un'immagine: su about il fondo e' piatto, su
   musing non si scorre, in home non c'e' filtro. Un pseudo `fixed` dentro un elemento
   non trasformato si ancora al viewport, quindi resta fermo mentre il mosaico scorre.

   **0,76 e' costato tre misure, e le prime due erano sbagliate.** Vale la pena tenerle,
   perche' l'errore e' ripetibile:
     1. **0,56** — contava l'inchiostro come bianco pieno. Ma `--ink-dim` e' bianco al
        65%, e un inchiostro semitrasparente si porta il fondo dentro di se': piu' il
        fondo e' chiaro, piu' l'inchiostro schiarisce con lui.
     2. **0,70** — l'inchiostro composto sul fondo, ma guardando la sola firma. **Nel
        filtro e' bianco pieno solo l'opzione attiva**: le altre e il separatore sono
        `--ink-dim`, e sono la banda piu' larga e piu' in basso, dove la velatura e' gia'
        scemata.
     3. **0,74** e' il pavimento vero, **0,76** quello con un margine — la misura dipende
        dalle copertine di oggi, e un progetto nuovo piu' chiaro la sposta.
   La regola generale, che vale oltre questa riga: **il contrasto si misura
   sull'inchiostro reso, e su questo sito quasi niente e' bianco pieno.**
   --------------------------------------------------------------------------------- */
/* Spenta quando non c'e' niente che possa arrivare sotto il filtro: il conto lo fa
   `aggiornaVelo()` in projects.js e lo scrive qui come classe. Vale su "videoclip", che
   e' un foglio bianco alto meno di una schermata — la velatura non lo protegge da
   niente e gli lascerebbe solo una macchia grigia in cima. */
html.senza-velo .content-page::after {
  display: none;
}

.content-page::after {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 220px;
  /* **0 e non 1**, ed è la trappola degli strati già presa due volte (§ Gli strati).
     `.breadcrumb` sta a 1 e viene PRIMA nel markup, quindi a pari numero la velatura
     gli passava sopra: il filtro veniva velato insieme al fondo, e restava illeggibile
     come prima — la misura sul fondo diceva 5:1 mentre a schermo non si leggeva.
     A 0 la velatura sta sopra il mosaico (che non ha z-index) e sotto tutto l'arredo:
     filtro a 1, nav e firma a 2. **Chi vela deve stare sotto chi è velato.** */
  z-index: 0;
  pointer-events: none;
  /* **Sei fermate e non tre, e la coda è lunga il doppio.** Con 130px e una sola
     spezzata il bordo inferiore si vedeva: una velatura che finisce netta è una riga
     orizzontale sull'immagine, e su una pagina che scorre quella riga sta ferma mentre
     tutto il resto si muove — è la cosa che la fa notare.
     **Allungata, non alzata**: il picco resta 0,76 e la fascia dove cade il testo
     (0→80) tiene lo stesso nero di prima; quello che cambia è la coda, che scende con
     una curva a esse invece che con una retta e si spegne a 220 invece che a 130.
     Le fermate approssimano uno smoothstep — il ginocchio a 120 e la parte quasi
     piatta in fondo sono quello che toglie il bordo. */
  background: linear-gradient(to bottom,
    rgba(0, 0, 0, 0.76) 0%,
    rgba(0, 0, 0, 0.70) 36%,
    rgba(0, 0, 0, 0.52) 55%,
    rgba(0, 0, 0, 0.28) 73%,
    rgba(0, 0, 0, 0.11) 86%,
    rgba(0, 0, 0, 0) 100%);
}

/* Centrato sulla colonna dei contenuti, non sulla finestra: a sinistra la nav
   occupa molto più spazio di quanto occupino i testi ruotati a destra, quindi il
   centro vero della finestra cadrebbe una sessantina di pixel fuori asse rispetto
   alle tile sotto. Vedi --content-center in :root. */
.breadcrumb {
  position: fixed;
  left: var(--content-center);
  top: 24px;
  transform: translateX(-50%);
  /* **1, in mezzo, e i due lati contano tutti e due.** Sopra il contenuto, perché
     il filtro è fisso e il mosaico gli scorre sotto: senza un numero più alto di
     `.content-page` le copertine gli passerebbero davanti scorrendo (non è
     l'hover, è lo scroll — ed è la ragione per cui questo z-index esiste).
     Sotto il blocco colore, che sta a 2: passando sulla nav il filtro se ne va
     insieme al mosaico, e le cinque pagine si comportano uguali. Sparisce anche
     sopra la voce della pagina in cui sei — voluto. */
  z-index: 1;
  font-size: 12px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--ink-dim);
  white-space: nowrap;
}

/* Il filtro sta dove stava il breadcrumb e ne eredita il trattamento, ma su DUE
   righe: sopra il nome della sezione, sotto le opzioni. In fila unica il nome
   sembrava la prima di quattro cose cliccabili; staccato dice quello che deve
   dire — dove sei, non dove puoi andare. */
.project-filter {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* **4 e non 10, e il vuoto che si vede resta 10.** Le opzioni hanno 6px di padding
     sopra (vedi .filter-item): il gap misura fra le scatole, l'occhio fra gli
     inchiostri, quindi `gap + padding-top` = 10. **Le due misure vanno insieme** —
     e' la stessa costruzione della nav in verticale, dove il vuoto visto e'
     `gap + 2 x padding`. */
  gap: 4px;
}

.project-filter .filter-section {
  /* Il nome è l'unica riga che non si preme: nessun hover, nessun cursore. */
  cursor: default;
}

.project-filter .filter-row {
  display: flex;
  align-items: baseline;
  /* **La barra fra le opzioni**, e con lei il `//` è uscito da tutto il sito: la
     distinzione fra un segno che lega e uno che separa non c'è più, il segno è uno
     — qui, nei link social, nelle voci di press e awards, nelle due righe scandite
     della bio. Vedi .list-sep, dov'è scritto cosa è stato lasciato indietro.
     **Il gap è 5px**, lo stesso di `.social-links`, che è la stessa costruzione
     (parola, barra, parola) e l'unico posto in cui questa misura era già stata
     scelta. Due valori per la stessa cosa divergono; questo è uno.
     Sono passati da 18 a 8 a 5 in un giro solo, e i tre numeri dicono la stessa
     regola: **18 è lo spazio senza segno, 5 è lo spazio attorno a un segno**. Se la
     barra un giorno esce, il gap torna a 18 — mai lasciare l'uno senza l'altro.
     Nota che qui il corpo è 12px e nei social 11: proporzionalmente sarebbero 5,5.
     Vince il numero tondo condiviso, perché mezzo pixel di aria non si vede e due
     misure diverse per lo stesso segno sì. Il caso limite resta `SHORT DOCS`, due
     parole con dentro uno spazio di ~4px: con la barra a distinguere le voci non è
     più l'aria, quindi quel confronto non vincola più il gap. */
  gap: 5px;
}

/* La barra non è cliccabile e va più spenta di quello che separa, come `.social-sep`
   e `.list-sep`: è la stessa regola scritta tre volte in tre punti del foglio, e se
   una cambia vanno cambiate tutte. `aria-hidden` nel markup, perché a chi ascolta la
   fila i tre bottoni arrivano già distinti. */
.filter-sep {
  color: var(--ink-dim);
  user-select: none;
}

/* Il nome della sezione in bianco pieno, non spento come i separatori: spento aveva
   esattamente il colore delle opzioni non attive, cioè di quattro parole che si
   premono, e si leggeva come la prima di quelle. Il bianco lo stacca — dice dove
   sei, e la riga sotto dice dove puoi andare. Che sia lo stesso bianco dell'opzione
   attiva non confonde: stanno su due righe diverse, e nessuna delle due è ambigua
   da sola. */
.project-filter .filter-section {
  color: var(--ink);
}

/* I bottoni non ereditano niente dal body: font, corpo e tracking vanno ridetti,
   o il filtro esce in Helvetica di sistema a 13px in mezzo alla riga. */
.filter-item {
  border: 0;
  /* **Il bersaglio scende sotto la scritta.** L'inchiostro e' alto 14px (12 su
     mobile) e la scatola era esattamente quella: un tocco un filo basso — che e'
     il modo naturale di premere una riga di testo col pollice — cadeva fuori e non
     succedeva niente. Con 6 sopra e 14 sotto la scatola passa a **34px**, e la
     corsa in piu' sta dalla parte da cui il dito sbaglia.
     **In larghezza il padding c'e' ma non si vede**, ed e' il punto: 6px per lato
     annullati da un margine negativo uguale. Serviva perche' 5px e' lo spazio
     attorno alla barra (vedi .filter-row) e un padding scoperto lo porterebbe a 11,
     cambiando un segno di punteggiatura in un vuoto — mentre il bersaglio di ALL,
     che e' tre lettere, era largo **23,6px**. Cosi' la riga resta identica al pixel
     e le scatole arrivano ad abbracciare la barra da tutte e due le parti: chi mira
     in mezzo prende una voce invece di non prendere niente, che e' la stessa
     ragione per cui in verticale i bersagli della nav si toccano.
     Il padding sopra e' compensato dal gap della colonna, che scende a 4. */
  padding: 6px 6px 14px;
  margin-inline: -6px;
  background: none;
  font: inherit;
  font-size: 12px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--ink-dim);
  cursor: pointer;
  transition: color 0.2s ease;
}

.filter-item:hover,
.filter-item.is-active {
  color: var(--ink);
}

.filter-item:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 4px;
}

/* --- Pagine di contenuto (leaf) --- */

.content-page {
  position: relative;
  /* **Niente z-index, ed è una correzione.** Con `z-index: 1` questo blocco finiva
     nello STESSO strato di `.hover-color-block`, e stando dopo nel markup ci
     passava sopra: il blocco colore non copriva più niente. Sulle pagine del
     mosaico restavano le tile, su about restava tutta la pagina, e l'anteprima
     della nav si piantava in mezzo a quello che stavi guardando. Il fondo di
     pagina (`.bg-flat`/`.bg-media`) sta comunque sotto senza bisogno di un numero,
     perché è fisso e viene prima nel markup. È lo stesso difetto già preso sulle
     frecce di musing (HANDOFF, 12 agosto): qualunque cosa arrivi a 1 o più si
     ritrova davanti al blocco. */
  min-height: 100%;
  /* padding-left generoso per non finire mai sotto la nav fissa mentre si scorre */
  padding: 96px 0 0 240px;
}

/* I link social stanno SOLO in home. Sulle pagine di sezione sono stati provati
   sopra il mosaico e tolti: una riga in cima a una pagina che scorre per otto
   schermate è fuori vista dopo il primo scatto di rotella, e in fondo si
   intravedeva sotto le tile. Se dovessero rientrare, la costruzione era
   `margin: 0 0 28px -240px` più i due padding di --nav-edge/--side-edge: il
   margine negativo annulla il padding di .content-page, o `margin: auto`
   centrerebbe a x 840 invece che sui 772 della colonna. */

/* --- Griglia progetti: thumbnail a contatto, dimensioni uniformi --- */

.project-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 0;
  align-items: start;
}

.project-cell {
  display: flex;
  flex-direction: column;
}

.project-tile {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  cursor: pointer;
  background-color: #15181c; /* fondo mentre la thumbnail reale carica (oEmbed) */
  background-size: cover;
  background-position: center;
}

/* Editing // social: contenuti Instagram Reels, nativamente verticali */
.project-tile.aspect-9-16 {
  aspect-ratio: 9 / 16;
}

/* Velatura e testo sono due strati distinti: nel mosaico si comportano in modo
   opposto (la velatura si apre all'hover, il testo compare) e servono separati. */
.project-tile-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
}

.tile-caption {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  text-align: center;
  padding: 16px;
  opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
}

.tile-caption-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.project-tile:hover .project-tile-overlay,
.project-tile:focus-visible .project-tile-overlay,
.project-tile:hover .tile-caption,
.project-tile:focus-visible .tile-caption {
  opacity: 1;
}

/* Progetto ancora senza link: niente cursore a mano, perché non c'è niente da aprire.
   **Questa e' l'unica cosa che `placeholder` dice ancora.** Il foglio bianco, la
   didascalia sempre accesa e l'inchiostro scuro sono passati a `senza-copertina`
   (qui sotto): erano nella stessa regola finché un progetto senza link era per forza
   anche senza immagine, e DUST GIRL ha separato i due stati portandosi una copertina
   vera prima del suo link. Un progetto puo' ora avere l'una senza l'altro. */
.project-tile.placeholder {
  cursor: default;
}

/* Nessuna copertina sotto: il riquadro resta vuoto in attesa del video, e la
   didascalia sta sempre in vista invece di comparire all'hover — sotto non c'è
   nessuna thumbnail, e un rettangolo scuro e muto si leggerebbe come una tile rotta,
   non come un segnaposto. Il fondo è quello che la tile ha già mentre aspetta
   l'oEmbed: qui non arriverà.
   **Con una copertina vera nessuna di queste regole si applica**, e la tile torna
   quella di tutte le altre: sfumatura nera in fondo e inchiostro bianco. */
.project-tile.senza-copertina .tile-caption {
  opacity: 1;
  /* Sopra la carta la didascalia va invertita anche lei, o non si vede: il titolo
     è #fff e la fascia sotto è una sfumatura nera al 75%, che su un foglio chiaro
     diventerebbe una banda scura in fondo — il contrario di quello che serve.
     Via la sfumatura, e inchiostro scuro. */
  background: none;
}

.project-tile.senza-copertina .tile-name {
  color: var(--c-paper-ink);
}

/* Le righe di servizio restano più spente del titolo, come sul fondo scuro. Il
   valore è lo stesso che la card bianca di musing usa sulla stessa carta: è nero
   a percentuale, quindi segue --c-paper-ink senza doverne dichiarare una versione
   smorzata. */
.project-tile.senza-copertina .tile-category,
.project-tile.senza-copertina .tile-year,
.project-tile.senza-copertina .tile-note {
  /* **0,62 e non 0,45** (24 agosto). Sul foglio bianco quel 45% dava **3,32:1**, cioe'
     sotto soglia — ed e' lo stesso difetto, rovesciato, dei secondari sulle copertine
     scure: un inchiostro a percentuale si porta dentro il fondo che ha sotto, e su una
     carta a 246 il nero al 45% resta un grigio chiaro. A 0,62 sono **5,9:1**, e restano
     comunque piu' spenti del titolo, che qui e' nero pieno. */
  color: rgba(0, 0, 0, 0.62);
}

.project-tile.senza-copertina .tile-note a {
  color: var(--c-paper-ink);
}

/* Scritta al centro del riquadro in attesa ("OUT SOON"). Non è più un buco scuro
   nella pagina ma un foglio: la stessa struttura di prima — un layer a tutta tile
   con la scritta al centro — con i colori rovesciati.
   Il corpo resta quello del sottotitolo dell'etichetta, così non introduce un
   trattamento tipografico nuovo. Le misure sono ripetute e non ereditate perché
   .tile-category le prende dentro .project-stack, e questa sta al centro della
   tile, fuori dalla caption.
   pointer-events: none — non deve rubare l'hover al riquadro. */
.tile-pending {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  text-align: center;
  font-size: 11px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  background: var(--c-paper);
  color: var(--c-paper-ink);
  pointer-events: none;
}

.tile-name {
  color: #fff;
  font-size: 13px;
  letter-spacing: 0.4px;
}

.tile-category,
.tile-year {
  color: rgba(255, 255, 255, 0.7);
  font-size: 10px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
}

/* --- Variante a mosaico edge-to-edge ---
   Si attiva aggiungendo `project-stack` accanto a `project-grid` nel markup della
   singola pagina: non è il default, le altre sezioni restano sulla griglia sopra.
   Regge lo stesso array di progetti e lo stesso markup generato da projects.js.
   Una riga per progetto; `half: true` nell'array mette due progetti sulla stessa
   riga, dentro un `.project-row` che projects.js crea da sé. */

.project-grid.project-stack {
  display: grid;
  grid-template-columns: 1fr;
  /* Nessuna distanza, in nessuna direzione: le tile si toccano. */
  gap: 0;

  /* La colonna è centrata fra i due elementi fissi — la nav a sinistra e i testi
     ruotati a destra — non fra i bordi della finestra: --column-gap è la stessa
     aria da entrambe le parti.
     Il margine negativo annulla il padding-left di .content-page: quel padding è
     una misura fissa pensata per stare larghi dalla nav, mentre la nav sta a 6vw e
     quindi si sposta con la finestra. Senza annullarlo, sotto una certa larghezza
     il padding richiesto sarebbe minore di 240px, e un padding non può essere
     negativo: il bordo resterebbe inchiodato lì. */
  margin-left: -240px;
  padding-left: calc(var(--nav-edge) + var(--column-gap));
  padding-right: calc(var(--side-edge) + var(--column-gap));
  padding-bottom: 96px;

  /* --nav-edge e --side-edge arrivano da :root, misurati da initFixedEdges() in
     script.js. NON vanno ridichiarati qui: una dichiarazione locale vincerebbe su
     quella scritta su <html>, e la colonna tornerebbe alle stime di ripiego mentre
     il breadcrumb userebbe le misure vere — cioè due centrature diverse. */
  --column-gap: var(--gutter);
}

/* --- Il cambio di gruppo: si spegne, si salta in cima, si riaccende ---

   Il filtro nasconde e rimostra, quindi cambiando gruppo la pagina si accorcia sotto
   i piedi e bisogna tornare in cima (vedi `initProjectFilter()`). Il salto però è
   secco, e su una pagina alta sette schermate si legge come uno scatto.

   La strada NON presa è `scroll-behavior: smooth`: da 1500px la scorsa dura più di un
   secondo e fa sfilare davanti agli occhi tutto il mosaico che stai lasciando — e
   quello che sfila è già il gruppo nuovo, perché il filtro si applica prima. Molto
   movimento per niente.

   Qui invece il mosaico si spegne, il salto avviene **mentre non si vede**, e il
   gruppo nuovo si riaccende dall'alto. Il viaggio sparisce: quello che resta è un
   cambio di stato, che è quello che è davvero. 0,22s per lato — la stessa lingua
   dello 0,25 del blocco colore e dell'anteprima.

   Si spegne solo la griglia: nav, filtro e link laterali restano accesi, o il cambio
   sembrerebbe un caricamento di pagina. */
.project-stack {
  transition: opacity 0.22s ease;
}

.project-stack.is-swapping {
  opacity: 0;
}

/* Rapporto reale del video, in forma numerica. Sta sulla CELLA e non sulla tile
   perché serve a due cose: la tile se lo eredita per il proprio aspect-ratio, e la
   cella lo usa come peso per dividersi la riga quando è affiancata a un'altra.
   projects.js lo sovrascrive col valore letto dall'oEmbed; questo è il ripiego
   finché la risposta non arriva — all'arrivo le altezze si assestano, ed è l'unico
   sussulto di layout al caricamento. */
.project-stack .project-cell {
  --tile-ratio: 1.7778;
}

/* Riga con più progetti affiancati, di formato anche diverso.
   `flex-grow: var(--tile-ratio)` con base 0 divide la larghezza in proporzione ai
   rapporti: ogni cella riceve W · r_i/Σr, che è esattamente r_i · H con H = W/Σr.
   Ne segue che le tile vengono alte uguali qualunque siano i formati — la più larga
   è quella col rapporto maggiore — senza nessun calcolo in JS e senza scalini.
   Vale per qualsiasi numero di tile, non solo per le coppie.
   min-width: 0 è obbligatorio: senza, la larghezza minima del contenuto vince sulla
   base 0 e la proporzione salta. */
.project-stack .project-row {
  display: flex;
  align-items: flex-start;

  /* Tetto all'altezza della riga. Serve per i verticali: due 9:16 affiancati a
     piena larghezza vengono alti W/(0,5625+0,5625) = 0,89·W, cioè quasi il doppio
     di una schermata — inguardabili anche se affiancati.
     La riga non si può schiacciare in altezza, o le proporzioni salterebbero: si
     restringe. A un'altezza massima H corrisponde una larghezza H·Σr, e dentro
     quella le proporzioni interne restano identiche. Sotto il tetto vale 100% e la
     riga resta edge-to-edge come nel resto del mosaico — è il caso di tutte le
     righe orizzontali già in pagina, che non cambiano di un pixel.
     Il tetto vale solo per le righe affiancate: una tile a piena larghezza non è
     vincolata, perché lì restringere vorrebbe dire rinunciare all'edge-to-edge su
     cui è costruito tutto il mosaico. Un 9:16 da solo a piena larghezza resta
     quindi inguardabile: va messo in riga, non a tutta pagina. */
  --row-max-h: 76vh;
  --row-ratio: 3.5556; /* ripiego: due 16:9. projects.js scrive la somma vera */
  width: min(100%, calc(var(--row-max-h) * var(--row-ratio)));
  margin-inline: auto;
}

/* `hidden` da solo non basta, e la specificità nemmeno: il `display: flex` qui
   sopra è (0,2,0) come lo sarebbe `.project-row[hidden]`, quindi a parità vince
   l'ultima scritta. Questa regola deve stare DOPO quella che accende il flex ed
   essere più specifica di lei — è la stessa trappola di .project-player-nav[hidden],
   presa una seconda volta.
   Vale sulle righe e sulle celle a piena larghezza: sono le due cose che il filtro
   nasconde. Mai una cella dentro una riga, o le superstiti si allargherebbero. */
.project-stack .project-row[hidden],
.project-stack > .project-cell[hidden] {
  display: none;
}

.project-stack .project-row > .project-cell {
  flex: var(--tile-ratio) 1 0;
  min-width: 0;
}

.project-stack .project-tile {
  /* Qui il vincolo è la LARGHEZZA: la tile riempie la sua colonna e l'altezza
     discende dal rapporto. Un 4:3 viene alto, un 2.39:1 basso, larghi uguale.
     È l'opposto della versione precedente, dove comandava l'altezza. */
  width: 100%;
  height: auto;
  aspect-ratio: var(--tile-ratio);
}

/* Nel mosaico la velatura resta spenta in entrambi gli stati: al suo posto ora
   parte l'anteprima, e scurirla la sprecherebbe. Il contrasto del testo lo dà la
   sfumatura della caption, non lei. Nelle altre sezioni continua a funzionare
   come prima — la regola qui sopra vale solo dentro .project-stack. */
.project-stack .project-tile-overlay,
.project-stack .project-tile:hover .project-tile-overlay,
.project-stack .project-tile:focus-visible .project-tile-overlay {
  opacity: 0;
}

/* L'anteprima copre la thumbnail: stesso riquadro, ritagliata a coprire perché la
   clip non ha per forza il rapporto della tile.
   Il fondo scuro non è decorativo: un elemento video senza fotogrammi mostra il
   canvas del browser, che è bianco (CLAUDE.md § Palette). */
.tile-preview {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--c-base);
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}

.tile-preview.visible {
  opacity: 1;
}

/* Il testo si stacca dal centro e va in fondo al riquadro: titolo a sinistra, nota
   a destra, allineati sulla stessa base. */
.project-stack .tile-caption {
  inset: auto 0 0 0;
  flex-direction: row;
  align-items: flex-end;
  justify-content: space-between;
  text-align: left;
  gap: 32px;
  padding: 22px 26px;
  /* **Sempre accesa, anche sul computer** (23 agosto). Era a comparsa sull'hover, e
     in verticale era gia' accesa perche' li' l'hover non esiste: due comportamenti
     per la stessa cosa, e quello del computer nascondeva il titolo del lavoro
     finche' non ci passavi sopra. Ora il mosaico si legge fermo.
     **La sfumatura viene con lei, e non e' un di piu'**: sopra una copertina chiara
     il titolo e' bianco su bianco: e' la sola cosa che regge il contrasto, visto che
     nel mosaico la velatura piena resta spenta in tutti e due gli stati (qui sopra).
     Accesa la didascalia, va accesa anche quella — **le due cose vanno insieme**.
     Niente transizione: non c'e' piu' niente che passi da uno stato all'altro. */
  opacity: 1;
}

/* **La sfumatura sotto il testo, e non e' piu' il fondo della didascalia.**

   Era `background` del contenitore, quindi alta quanto lui: 77px, cioe' il testo piu'
   i suoi 22 di padding. Bastava finche' compariva sull'hover e la si guardava un
   momento; sempre accesa non basta piu', ed e' stato **misurato sulla copertina piu'
   chiara del sito** (KETTLEBAG, che e' quasi bianca): il titolo stava a **4,48:1** e la
   categoria a **1,97:1**, cioe' illeggibile. Nel mosaico la velatura piena resta spenta
   in tutti e due gli stati, quindi qui non c'e' nient'altro a reggere il contrasto.

   **320px ancorati al fondo, nero 0,85**, che sono gli stessi 0,85 del verticale. La
   fascia sborda sopra il contenitore — un assoluto non e' ritagliato dal genitore — e
   questo e' il punto: il testo sta nei primi 50px, il resto e' la coda che serve a non
   far vedere dove la velatura finisce (§ la velatura in cima, stessa lezione).
   **In px e non in percentuale**, al contrario del verticale: li' la fascia e' una
   frazione di tile perche' le tile hanno rapporti diversi; qui la didascalia e' della
   stessa misura su tutte — una 2.39 alta 304 e una 16:9 alta 634 portano lo stesso
   testo — quindi vuole la stessa fascia.

   **Da 160 a 320, e non piu' una retta: allungata, non schiarita** (24 agosto). A 160px
   con una spezzata sola il bordo si vedeva — la stessa cosa gia' successa alla velatura
   in cima, e si chiude allo stesso modo. Una retta ha una pendenza sola: dove il nero
   e' quasi finito continua a calare alla stessa velocita' e arriva a zero di scatto,
   che e' il punto in cui l'occhio vede una riga. Le otto fermate qui sotto disegnano una
   S — scende in fretta dove sta il testo, poi si appiattisce in una coda lunga che
   arriva a zero senza toccarlo.
   **E il contrasto non e' sceso, e' salito di un filo**: alle due righe che contano
   l'alfa passa da 0,688 a 0,711 (titolo, 30px dal fondo) e da 0,588 a 0,610
   (categoria, 49px). E' la regola della velatura in cima, riscritta qui perche' vale
   ogni volta: **allungare non costa contrasto, alzare l'alfa costa immagine.**
   Se un domani si toccano queste fermate, quello che va tenuto sono i due valori a
   9,5% e 15,4% — il resto e' coda. */
.project-stack .tile-caption::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 320px;
  background: linear-gradient(to top,
    rgba(0, 0, 0, 0.85) 0%,
    rgba(0, 0, 0, 0.72) 9%,
    rgba(0, 0, 0, 0.60) 16%,
    rgba(0, 0, 0, 0.45) 25%,
    rgba(0, 0, 0, 0.29) 38%,
    rgba(0, 0, 0, 0.15) 54%,
    rgba(0, 0, 0, 0.06) 72%,
    rgba(0, 0, 0, 0.015) 88%,
    rgba(0, 0, 0, 0) 100%);
  pointer-events: none;
}

/* **LA TRAPPOLA DEGLI STRATI, quinta volta — e questa e' stata prevista invece che
   presa.** `::before` e' `position: absolute`, quindi dipinge nello strato dei
   posizionati, cioe' **sopra** il testo, che e' statico: il nero all'85% coprirebbe le
   lettere e i titoli, dichiarati `rgb(255,255,255)`, arriverebbero a schermo intorno a
   98. E' successo davvero sul verticale il 22 agosto. Basta rendere posizionati anche i
   due blocchi di testo: a pari z-index vince chi viene dopo nel DOM, e loro vengono
   dopo. Finche' la sfumatura era il `background` del contenitore il problema non
   esisteva — un fondo sta sotto i propri figli per costruzione. */
.project-stack .tile-caption-text,
.project-stack .tile-note {
  position: relative;
}

/* Il segnaposto e' carta bianca con inchiostro scuro: una fascia nera li' sopra sarebbe
   il contrario di quello che serve. Prima bastava il `background: none` della regola
   del segnaposto, perche' la sfumatura stava sul contenitore; ora sta sullo pseudo e va
   spenta a parte. */
.project-tile.senza-copertina .tile-caption::before {
  display: none;
}

/* Le due righe riprendono trattamenti già in uso nel sito invece di introdurne di
   nuovi: sopra la resa delle voci di nav, sotto quella delle intestazioni di about
   (le stesse del breadcrumb — se cambia una, vanno allineate tutte). */
.project-stack .tile-category,
.project-stack .tile-year {
  font-size: 11px;
  letter-spacing: 0.4px;
  text-transform: none;
  /* **0,85 e non il 65% di --ink-dim**, che e' la stessa correzione gia' fatta in
     verticale e per la stessa ragione, ora che vale anche qui: --ink-dim e' nato per
     un testo che compare quando lo chiedi, su un fondo che sai. Queste righe stanno
     sempre accese sopra un'immagine qualunque, e un inchiostro semitrasparente si
     porta il fondo dentro di se' — su una copertina chiara schiarisce con lei e
     sparisce (misurato: 1,97:1 sulla piu' chiara). Il titolo resta bianco pieno,
     quindi la gerarchia regge lo stesso: 1 contro 0,85 invece di 1 contro 0,65. */
  color: rgba(255, 255, 255, 0.85);
}

/* Dall'alto: anno, sottotitolo, titolo. Ottenuto con `order` invece che riordinando
   il markup, che resta com'è per le sezioni ancora a griglia. */
.project-stack .tile-year {
  order: -2;
}

.project-stack .tile-category {
  order: -1;
}

.project-stack .tile-name {
  font-size: 12px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--ink);
}

.project-stack .tile-caption-text {
  gap: 6px;
}

/* Su una riga da tre o quattro la tile si stringe e la didascalia su una riga sola
   non ci sta più: su quattro verticali la tile è larga 279px, e il titolo di LAZZA
   con la sua nota ne chiede 339. Da tre in su titolo e nota si impilano.
   La soglia è il numero di celle e non una media query, perché non dipende dalla
   finestra ma da quante ne ha la riga: renderProjectGrid scrive data-count. */
.project-row[data-count="3"] .tile-caption,
.project-row[data-count="4"] .tile-caption {
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.project-row[data-count="3"] .tile-note,
.project-row[data-count="4"] .tile-note {
  max-width: 100%;
  text-align: left;
}

/* La nota non è più un blocco fra una riga e l'altra — lì spezzava l'edge-to-edge —
   ma sta dentro la tile, in fondo a destra, e compare col titolo. Stessa resa del
   sottotitolo: è informazione di servizio, non deve competere col titolo. */
.project-stack .tile-note {
  max-width: 42%;
  text-align: right;
  font-size: 11px;
  line-height: 1.5;
  letter-spacing: 0.4px;
  /* Come la categoria qui sopra: sempre accesa sopra un'immagine, quindi 0,85. */
  color: rgba(255, 255, 255, 0.85);
}

/* --- I crediti: DOP e PROD, e sono la sola cosa che compare all'hover ---------

   Tutto il resto della didascalia sta sempre acceso (vedi .project-stack
   .tile-caption): questa e' l'unica riga che si mostra passandoci sopra, ed e' quello
   che rende di nuovo l'apparizione un'informazione invece di un effetto.

   **Stanno a destra, nello stesso posto della nota**, e possono farlo perche' nessun
   progetto ha una nota e dei crediti insieme — verificato su tutti e diciotto. Uno
   slot, due informazioni, mai contemporaneamente (il vincolo e' scritto anche in
   projects.js, dove si costruisce).

   **La resa e' quella del blocco di sinistra, rovesciata**: il ruolo ha il trattamento
   della categoria e il nome quello del titolo, con lo stesso vuoto di 6px in mezzo che
   .tile-caption-text usa fra le sue righe. Non e' una somiglianza, sono le stesse tre
   misure — se cambia una di quelle, cambia anche questa. */
.project-stack .tile-credits {
  /* LA TRAPPOLA DEGLI STRATI, che qui e' scattata in prova: la sfumatura e' un
     ::before assoluto e dipinge sopra i figli statici. Senza questa riga i crediti
     non comparivano affatto — non spenti, proprio coperti. */
  position: relative;
  display: flex;
  /* I due crediti si allineano in basso, cosi' i due nomi cadono sulla stessa base
     del titolo a sinistra: e' quello che tiene insieme le due meta' della riga. */
  align-items: flex-end;
  /* 18px, "lo spazio senza segno" della convenzione del sito (§ Filtro): fra i due
     crediti non c'e' nessun segno, e le due sigle separano gia' da se'. Serve anche a
     non introdurre una seconda barra sulla riga, visto che una ci sta gia' dentro un
     valore ("chimera studios | parallelia"). */
  gap: 18px;
  text-align: right;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.project-stack .project-tile:hover .tile-credits,
.project-stack .project-tile:focus-visible .tile-credits {
  opacity: 1;
}

.tile-credit {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}

/* Il ruolo: la resa della categoria (.project-stack .tile-category). Maiuscolo di
   resa e non nel dato, perche' qui il dato e' una sigla di tre lettere. */
.credit-role {
  font-size: 11px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
}

/* Il nome: la resa del titolo (.project-stack .tile-name). Bianco pieno, come lui —
   sono due nomi affiancati, non uno subordinato all'altro. */
.credit-name {
  font-size: 12px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
}

/* La caption ha pointer-events: none per non rubare l'hover alla tile, ma i link
   dentro la nota devono restare cliccabili. Il click non si propaga alla tile
   (vedi projects.js), altrimenti aprirebbe il player mentre si segue il link. */
.project-stack .tile-note a {
  color: var(--ink);
  pointer-events: auto;
}


/* --- Player fullscreen (click su una thumbnail nella griglia progetti) --- */

.project-player-overlay {
  position: fixed;
  inset: 0;
  z-index: 30;
  /* Opaco, non semitrasparente: sotto l'overlay c'è sempre una pagina scura,
     ma il fondo del player non deve dipendere da cosa c'è sotto. */
  background: var(--c-base);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 4vh 4vw;
}

.project-player-overlay.visible {
  display: flex;
}

.project-player-body {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--c-base);
}

/* L'iframe segue l'aspect ratio del video invece di riempire il riquadro: così
   non restano bande di fondo sopra e sotto. Essendo un elemento replaced, i
   vincoli max-* mantengono il rapporto invece di schiacciarlo.
   Il background scuro è la seconda rete di sicurezza: il documento del player
   Vimeo è trasparente, quindi senza di esso si vedrebbe il canvas bianco
   dell'iframe (color-scheme:dark non attraversa i confini di origine). */
.project-player-body iframe:not(.instagram-media) {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  max-width: 1400px;
  max-height: 100%;
  border: 0;
  background: var(--c-base);
}

/* Social verticale (9:16): Vimeo/YouTube in formato ritratto, non vanno allargati */
.project-player-body.portrait iframe:not(.instagram-media) {
  width: auto;
  height: 100%;
  aspect-ratio: 9 / 16;
  max-width: 500px;
  max-height: 100%;
}

/* Instagram si dimensiona da solo (embed.js aggiorna l'altezza via postMessage):
   niente aspect-ratio imposto, altrimenti la card viene schiacciata. La card
   resta bianca — è il loro design, non è modificabile da fuori l'iframe. */
.project-player-body .instagram-media {
  margin: 0 auto !important;
  max-height: 100%;
}

/* Il testo resta 11px — e' il corpo dell'arredo, non si tocca. Quello che cresce
   e' il bersaglio: senza padding la scatola era alta quanto l'inchiostro (13px), e
   13px col dito si mancano. Stessa correzione gia' fatta sulla nav (11 -> 23) e
   sulla firma (9 -> 33 x 114).
   **E va compensata**, come sulla firma: il padding spingerebbe l'inchiostro 15px
   verso l'interno, mentre l'invariante e' che a stare a 24px dai due bordi sia il
   TESTO e non la scatola. Quindi top e right scontano il padding — 24 - 15 = 9 —
   e l'inchiostro resta dov'era. **Le due righe vanno insieme.** */
.project-player-close {
  position: fixed;
  top: 9px;
  right: 9px;
  padding: 15px;
  z-index: 31;
  background: none;
  border: none;
  color: #fff;
  font-size: 11px;
  letter-spacing: 0.5px;
  cursor: pointer;
  font-family: 'Helvetica Neue', Arial, sans-serif;
}

/* Frecce di navigazione fra i progetti della sezione, ai due lati dello schermo.
   Le costruisce projects.js, non stanno nel markup delle pagine.
   Il bianco è scritto a mano e non è --ink: l'overlay è sempre scuro, qualunque
   sia il tema della pagina sotto (in home non c'è player, ma la regola vale).
   Il riquadro è più grande del glifo perché 44px è il bersaglio minimo di un dito:
   la freccia sta al centro, l'area cliccabile le sta intorno. */
.project-player-nav {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  z-index: 31;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: none;
  color: #fff;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  /* 30px e non i 22 della freccia che c'era prima: il guillemet è otticamente molto
     più piccolo del glifo che sostituisce, e alla stessa misura sparirebbe. È il
     corpo del segno, non del testo — il riquadro cliccabile resta 44px. */
  font-size: 30px;
  line-height: 1;
  cursor: pointer;
  /* Discrete a riposo: a fianco del video acceso non devono chiedere attenzione,
     ma restano visibili senza puntatore — su touch l'hover non esiste. */
  opacity: 0.35;
  transition: opacity 0.2s ease;
}

/* Va dichiarato: il display: flex qui sopra vince sul display: none che il
   browser dà all'attributo hidden, e la freccia di troppo resterebbe in vista
   sul primo e sull'ultimo progetto. */
.project-player-nav[hidden] {
  display: none;
}

.project-player-nav:hover {
  opacity: 1;
}

/* Da tastiera l'opacità piena non basta a dire dove si è — è lo stesso stato
   che si vede passandoci sopra col mouse. Serve un anello suo. */
.project-player-nav:focus-visible {
  opacity: 1;
  outline: 2px solid #fff;
  outline-offset: 2px;
}

.project-player-nav.prev {
  left: 24px;
}

.project-player-nav.next {
  right: 24px;
}

/* --- About --- */

/* La pagina è un blocco centrato fra i due elementi fissi — la nav a sinistra e i
   testi ruotati a destra — non fra i bordi della finestra: stessa costruzione della
   colonna del mosaico (vedi .project-grid.project-stack), stessa aria da entrambe
   le parti. Il centro della finestra cadrebbe una sessantina di pixel fuori asse,
   perché la nav occupa molto più spazio dei testi ruotati.
   A essere centrato è il BLOCCO, non le righe: dentro, il testo è allineato a
   sinistra. L'unica eccezione è la riga di stato in fondo.
   --nav-edge e --side-edge arrivano da :root, misurati da initFixedEdges() in
   script.js: NON vanno ridichiarati qui, o si otterrebbero due centrature diverse
   fra questa pagina e le altre. */
.about-content {
  position: relative;
  /* **Niente z-index, ed è una correzione.** Con `z-index: 1` questo blocco finiva
     nello STESSO strato di `.hover-color-block`, e stando dopo nel markup ci
     passava sopra: il blocco colore non copriva più niente. Sulle pagine del
     mosaico restavano le tile, su about restava tutta la pagina, e l'anteprima
     della nav si piantava in mezzo a quello che stavi guardando. Il fondo di
     pagina (`.bg-flat`/`.bg-media`) sta comunque sotto senza bisogno di un numero,
     perché è fisso e viene prima nel markup. È lo stesso difetto già preso sulle
     frecce di musing (HANDOFF, 12 agosto): qualunque cosa arrivi a 1 o più si
     ritrova davanti al blocco. */
  min-height: 100%;
  padding: 96px calc(var(--side-edge) + var(--column-gap)) 24px
           calc(var(--nav-edge) + var(--column-gap));
  --column-gap: 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 48px;
  text-align: left;
}

/* Quattro caselle in due righe:
     bio + contatto  | ritratto
     press           | awards
   Tracce `auto`: le larghezze le decide il contenuto, senza misure scritte a mano.
   A sinistra comanda la bio (394,6px a 13,5). A destra comandava la voce più lunga
   degli awards (237,5), e da quando il contatto è sceso nella colonna di sinistra non
   più: la riga in alto è cresciuta, il ritratto la pareggia in altezza e la sua
   larghezza discende da lì — 348,7px, cioè molto più delle voci degli elenchi. **È il ritratto a dettare la
   colonna di destra**, ed è anche il motivo per cui la soglia di impilamento si
   sposta ogni volta che quella colonna cambia altezza (vedi in fondo). Ne segue anche
   l'allineamento chiesto: le
   voci partono dallo stesso asse
   verticale dell'iniziale della loro etichetta, perché etichetta ed elenco sono
   figli dello stesso blocco e nessuno dei due porta rientro — l'<ul> ha
   `padding: 0` (vedi .about-list).
   `align-items: start` tiene le celle appese in alto: bio e ritratto partono dalla
   stessa riga anche se il ritratto è molto più alto.
   **`margin: auto 0` centra la griglia in verticale.** Erano due margini in due
   posti — `margin-top: auto` qui e `margin: auto 0 0` sulla riga di stato in fondo,
   che insieme si dividevano lo spazio che avanza. Quella riga non c'è più (i social
   sono passati di fianco alla mail), quindi il secondo margine è tornato qui: da
   solo, il `margin-top` avrebbe spinto la griglia **in fondo** allo schermo invece
   di centrarla. È il tipo di cosa che non dà errore — si vede e basta. */
.about-grid {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: center;
  max-width: 100%;
  align-items: start;
  column-gap: 44px;
  row-gap: 48px;
  margin: auto 0;
}

/* Il ritratto pareggia in altezza il blocco bio accanto: `height: 100%` prende
   l'altezza della riga — che è quella della bio, perché il riquadro non porta
   altezza propria — e da lì il rapporto nativo ricava la larghezza. Ritaglio zero,
   e sotto la bio non resta più il vuoto che c'era quando la foto riempiva la
   colonna. A 1440px viene 348,7x322,3; se la bio si allunga, la foto cresce con lei —
   ed è successo: con la gif sotto la mail la riga era più alta e il ritratto veniva
   459x424. Uscita la gif era tornato a 329, col testo nuovo a 13,5px è passato a 328,8,
   la mail come parola in una fila da 11px l'ha portato a 318,4, e l'interlinea nuova
   della bio — righe più strette ma paragrafi staccati di una riga intera — l'ha rimesso
   a **348,7**: ogni misura che tocca l'altezza di quella colonna si vede qui.
   `justify-self: start` è obbligatorio: senza, la casella verrebbe stirata alla
   larghezza della colonna (412px, quella del press) e si ritroverebbe le due
   misure imposte insieme — larghezza stirata e altezza al 100% — con l'aspect-ratio
   ignorato e il ritaglio di ritorno.
   L'immagine è assoluta dentro il riquadro perché così non porta larghezza propria:
   un <img> in flusso ci metterebbe dentro i suoi 819px nativi come larghezza
   minima, allargando la colonna.
   Il rapporto è ripetuto in about.html (width/height): se le foto cambiano formato
   vanno aggiornati insieme, altrimenti il ritaglio rientra.
   Il fondo è quello che si vede in trasparenza mentre una foto sfuma nell'altra, e
   ha avuto tre valori: il nero della pagina (cioè niente), poi il rosso `--c-ember`,
   e da oggi il bianco carta — **lo stesso `--c-paper` del filo che compare
   all'hover**, e le due cose vanno insieme: il riquadro ha un colore solo, che si
   vede sul bordo quando ci passi sopra e in tutta la superficie mentre le foto si
   scambiano. Cambiandone uno va cambiato l'altro.
   È un lampo chiaro su una pagina scura e dura quanto la dissolvenza, 0,18s: se un
   domani sembra troppo, la leva è quella durata (in .about-photo e in about.html,
   FADE) e non il colore. */
.about-photo-col {
  height: 100%;
  width: auto;
  justify-self: start;
  aspect-ratio: 819 / 757;
  position: relative;
  background: var(--c-paper);
}

/* `cover` è una rete di sicurezza, non serve: il riquadro ha lo stesso rapporto
   delle immagini, quindi non c'è niente da tagliare. Se una foto arrivasse con un
   rapporto diverso dalle altre, la ritaglia invece di deformarla. */
.about-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* La durata dell'opacità è ripetuta in about.html (FADE) e le due devono restare
     uguali: il cambio di `src` avviene a dissolvenza finita, altrimenti si vedrebbe
     la foto nuova entrare mentre la vecchia sta ancora uscendo. Quella del bordo non
     c'entra ed è indipendente: è la durata degli hover del sito (0,2s). */
  transition: opacity 0.18s ease, outline-color 0.2s ease;
}

/* Il ritratto cicla fra più foto al click, e il segnale che si può cliccare sono due:
   la mano sul cursore e un filo di bordo che compare all'hover lungo il perimetro
   della foto. La classe la mette il JS, e solo se le foto sono davvero più d'una: con
   una sola non deve sembrare interattivo, e non succede né l'una né l'altra cosa.
   È un `outline` e non un `border`: il bordo entrerebbe nel conto della scatola e
   sposterebbe l'immagine di un pixel proprio mentre il cursore ci passa sopra, mentre
   l'outline è disegnato fuori dal flusso e non muove niente. Sta appena FUORI dal
   perimetro (offset 0), quindi la linea si vede contro il fondo della pagina e non
   contro la foto — che è il motivo per cui il colore va misurato su --c-base.
   A riposo l'outline c'è già ma è trasparente: serve perché sia il COLORE a cambiare
   e la transizione abbia due estremi da percorrere. Passando da `none` a `solid` non
   ci sarebbe nessuna dissolvenza, comparirebbe e basta.
   La dissolvenza vale in entrata e in uscita, perché la `transition` sta sullo stato
   a riposo (in .about-photo) e non nell'hover. */
.about-photo.cyclable {
  cursor: pointer;
  outline: 1px solid transparent;
}

/* Il filo è **bianco carta**, lo stesso `--c-paper` di musing, e non più il rosso
   schiarito `--c-musing-line` (#7a1717). Il rosso lo si vedeva appena — 1,53 di
   contrasto su --c-base, cioè la scala su cui era stato tarato — e su una foto scura
   spariva del tutto: un segnale che si vede solo dove capita non è un segnale. Il
   bianco è la stessa lingua della stanghetta della nav e di quella dei link
   laterali, che sono gli altri due segni da 1px del sito.
   **E il fondo del riquadro è andato dietro al filo**: era `--c-ember`, ora è lo
   stesso `--c-paper`. Il riquadro ha un colore solo — sul bordo quando ci passi
   sopra, su tutta la superficie mentre le foto si scambiano — e le due righe vanno
   cambiate insieme. Sì, è un lampo chiaro su una pagina scura, e dura quanto la
   dissolvenza: 0,18s. */
.about-photo.cyclable:hover {
  outline-color: var(--c-paper);
}

/* Il focus da tastiera non può cavarsela con lo stesso filo rosso: è l'unico segno di
   dove si è, e un pixel di rosso cupo su nero non basta a dirlo. Dichiararlo qui è
   anche obbligatorio — l'`outline: transparent` di sopra è una regola d'autore e
   spegnerebbe l'anello di focus del browser, che è una regola di user agent. */
.about-photo.cyclable:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* La colonna di sinistra: bio sopra, contatto sotto. È una cella sola della griglia,
   e deve esserlo — con due celle separate il ritratto pareggerebbe la sola bio e non
   crescerebbe.
   I 32px non sono i 48 della griglia: dentro una colonna il contatto è la coda della
   bio, non un blocco pari agli altri, e alla distanza dei blocchi si staccava. */
.about-col {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

/* La riga dei contatti: **tre voci e due barre**, `email | instagram | vimeo`, e
   la mail è una parola come le altre invece di un indirizzo scritto per esteso.
   Sono le stesse classi della home (.social-link, .social-sep) e la stessa misura
   di lì — 11px, tracking 0,4, --ink-dim, `gap: 5px`: resa, hover e separatore non
   possono divergere fra le due pagine, e cambia solo la collocazione (la home la
   tiene fissa in fondo al centro, about la mette in coda alla bio).
   I 5px sono quelli di .social-links: senza, fra i link e la barra resterebbe lo
   spazio di parola, che è un'altra misura.
   `align-self: flex-start` perché in una colonna flex, senza, la riga si
   stirerebbe; `max-width: 100%` come sulla griglia, o una traccia `auto` si prende
   lo spazio libero e il blocco sborda a sinistra sotto la nav.
   **Qui c'era `.contact-mail`**, l'indirizzo in 13,5px su una riga sua, con i due
   profili di fianco a 24px. Era l'unica riga di about con due corpi affiancati, e
   diceva due volte la stessa cosa. Se un domani l'indirizzo deve tornare leggibile
   senza cliccare, quella regola sta in git. */
.about-contact {
  margin: 0;
  align-self: flex-start;
  max-width: 100%;
  display: flex;
  align-items: baseline;
  gap: 5px;
  white-space: nowrap;
  font-size: 11px;
  letter-spacing: 0.4px;
  color: var(--ink-dim);
}

/* **Qui c'era `.contact-mail`**: l'indirizzo per esteso, al corpo del testo di
   pagina e in bianco pieno, che è quello che lo staccava dalla bio sopra. È uscito
   quando la riga dei contatti è diventata `email | instagram | vimeo` — tre voci
   dello stesso peso, perché fanno lo stesso mestiere. */

/* **Qui c'erano le tre regole della gif** (`.contact-gif-box`, `.contact-gif`,
   `.contact-gif.togglable`): il riquadro largo quanto la mail, l'immagine assoluta
   dentro perché non portasse larghezza propria, la mano sul cursore. Sono uscite
   insieme alla gif, che è passata a musing come quarta voce del giro, e con loro
   `initGifToggle` in fondo a about.html. Stanno in git se dovessero rientrare. */

/* Intestazioni di sezione con la resa del SOTTOTITOLO delle tile (11px, tracking
   0.4), non del titolo: qui non deve esserci niente di grande, le sezioni sono
   etichette e non titoli.
   Erano 12px/0.6, le stesse del breadcrumb e del titolo delle tile — quella terna
   ora è una coppia. Il breadcrumb resta dov'era di proposito: dice dove sei, non
   intitola un blocco (vedi CLAUDE.md § Breadcrumb). */
.about-block h2 {
  font-size: 11px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin: 0 0 12px;
  font-weight: 400;
}

/* **Fra un paragrafo e l'altro passa esattamente una riga vuota**, e il margine non
   è un numero scelto: è l'interlinea, scritta una volta e usata due volte. Un
   paragrafo nuovo nel markup è una riga vuota sullo schermo — la stessa cosa che
   Lorenzo scrive quando manda il testo.
   Era `line-height: 1.6` con `margin-bottom: 8px`, e i due stacchi risultavano 22 e
   29px da fondo riga a fondo riga: un rapporto di 1,37, cioè **troppo vicini perché
   si leggessero come due cose diverse**. Il difetto si vedeva da tutte e due le
   parti insieme — le righe spezzate col <br> sembravano troppo distanti e i
   paragrafi troppo attaccati — perché era un problema solo: la distanza fra le due
   distanze. Ora sono 19,6 e 39,2, cioè esattamente il doppio.
   La bio ha righe spezzate a mano, non a capo naturali: è un testo che si legge come
   dei versi, e i versi vogliono l'interlinea più stretta della prosa. 1,45 è quella
   misura; sotto 1,4 le righe cominciano a impastarsi, sopra 1,55 tornano a sembrare
   paragrafi separati.
   **Toccare `--bio-interlinea` sposta tutti e due gli stacchi insieme**, ed è il
   punto: separatamente si torna al difetto di prima. E siccome cambia l'altezza
   della colonna di sinistra, va poi rimisurata la soglia di impilamento (in fondo). */
.about-bio {
  --bio-interlinea: 1.45;
}

.about-block p {
  font-size: 13.5px;
  line-height: var(--bio-interlinea, 1.45);
  margin: 0 0 calc(var(--bio-interlinea, 1.45) * 1em);
}

.about-block a {
  color: var(--ink);
}

.about-bio p:last-child {
  margin-bottom: 0;
}

/* **Qui c'erano il grassetto corsivo della bio (`.about-bio strong`) e il corsivo
   della riga-ritornello (`.bio-flow`)**, cioè le due sole cose che nella pagina
   chiedevano di essere lette prima delle altre. Sono uscite insieme al testo nuovo:
   la bio è dritta per dritta, e a dare il ritmo restano gli a capo e le due righe
   scandite dalla barra — `flowing | seeking | feeling | feeding` e `still moving |
   still looking`, che si distinguono da sole per come sono scritte e non per come
   sono rese. Con loro **about non ha più né grassetti né corsivi**, ed è l'unica
   pagina che ne aveva: erano l'unico `corsivo + grassetto insieme` del sito.
   Le classi sono uscite anche dal markup. Se un domani il ritornello deve staccarsi
   di nuovo, la leva è il colore (`--ink-dim`) e non l'inclinazione: il corsivo qui
   pesava su una riga sola e la faceva sembrare una citazione. */

/* **Tutto in maiuscolo, e il minuscolo è stato provato e bocciato** (18 agosto):
   la resa minuscola è stata messa in pagina, guardata, e rimessa com'era. Vale la
   pena tenerlo scritto perché è il tipo di cosa che verrà riproposta: about è la
   pagina con la scala più bassa del sito, e questi due elenchi sono l'unica cosa
   che ci tiene un po' di peso — in minuscolo la pagina diventa tutta dello stesso
   grigio. Il maiuscolo qui non è enfasi, è **l'unica gerarchia rimasta** dopo che
   sono usciti i corsivi, i grassetti e il corpo da 15.
   Il maiuscolo è solo di resa: nel markup le voci restano scritte normali, come per
   le intestazioni e per il filtro.
   La parte cliccabile la distinguono il link e il tracking di .press-outlet — il
   maiuscolo ce l'ha tutta la voce, quindi non è lui a segnalarla.
   Attenzione a quanto costa in larghezza: il maiuscolo allarga di circa un quarto,
   e a 13,5px la voce più lunga del press arriva a ~370 e quella degli awards a
   ~290. Non muove niente — da quando il contatto è sceso nella colonna della bio, a
   comandare le due colonne sono la bio (394,6) e il ritratto (348,7), più larghi di
   qualunque voce di queste liste (vedi .about-grid). Prima invece la soglia di
   impilamento la decidevano loro.
   `padding: 0` non è ereditato dal reset: senza, il rientro di lista del browser
   sposterebbe le voci rispetto all'iniziale dell'etichetta.
   `fit-content` e non `max-content`: la colonna resta larga quanto la voce più
   lunga ma può cedere dove non c'è spazio nemmeno per quella — con `max-content`
   la riga uscirebbe dallo schermo invece di andare a capo. */
.about-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: fit-content;
  font-size: 13.5px;
  line-height: 1.5;
  text-transform: uppercase;
}

/* Il nome della testata è l'unica parte cliccabile. Il maiuscolo non è più suo — ce
   l'ha tutta la voce — quindi qui resta solo il tracking, che insieme al link è
   l'ultima cosa che lo stacca dal testo accanto. Nel markup il nome resta scritto
   normale, come per breadcrumb e intestazioni. */
.press-outlet {
  letter-spacing: 0.4px;
}

/* La barra fra anno, testata e titolo del pezzo. **Era il `//`**, e il cambio ha
   chiuso una distinzione che il sito teneva scritta: il `//` legava parti di una
   cosa sola (questa voce di press è *una* voce), la barra separava destinazioni
   diverse (i due link social). Ora il segno è uno solo dappertutto — decisione
   presa sapendo cosa costa, ed è questo: anno, testata e titolo si leggono come
   tre cose pari fra loro invece che come i tre pezzi di una riga sola.
   **Se un domani quella distinzione serve di nuovo**, il posto dove rimetterla è
   qui e nella nota di DUST GIRL (editing.html), che erano gli ultimi due `//` del
   sito. Come lì, il segno è più spento di quello che separa. */
.list-sep {
  color: var(--ink-dim);
}

/* **Qui c'era `.about-status`**, la riga `instagram | vimeo` fissata in fondo al
   centro della pagina. È uscita: quei due link stanno ora di fianco alla mail
   (vedi .contact-social), che è il posto che gli tocca — bio, mail e profili sono
   tre parti dello stesso discorso e stanno insieme, invece di averne una appesa al
   fondo dello schermo.
   Due cose se ne sono andate con lei, e vale la pena saperlo: era **l'unico testo
   centrato di una pagina allineata a sinistra**, e teneva il secondo dei due
   margini automatici che centrano la griglia in verticale (ora sono tutti e due su
   .about-grid). Ne è discesa anche la scelta di rimettere la riga social della home
   sul centro della finestra: senza più una riga in fondo su about, non c'è più
   niente con cui possa disallinearsi (vedi .social-links). */

/* Sotto questa larghezza la griglia si impila in una colonna sola, nell'ordine del
   markup: bio e contatto, ritratto, press, awards.
   La soglia è **misurata**, non calcolata, e da questo giro non si può più calcolare:
   la colonna di destra non ha più una larghezza propria da sommare, perché il
   ritratto prende l'altezza della riga e la larghezza discende da quella. Le due cose
   si inseguono — se la bio va a capo la riga si alza, se la riga si alza il ritratto
   si allarga, e allargandosi stringe la traccia della bio. Quel giro è **stabile solo
   finché la bio non va a capo**, e oggi va a capo a **1053px**: a 1054 la riga lunga
   sta ancora intera e il ritratto è 348,7, a 1053 va a capo e il ritratto salta a 369,9.
   Il taglio sta quindi a **1100** — una cinquantina di pixel sopra il punto di rottura.
   **Si rifà guardando la larghezza del ritratto mentre si stringe la finestra: il primo
   valore diverso da quello a riposo (oggi 348,7) è il punto di rottura**, e va rifatto
   ogni volta che si tocca il corpo del testo, gli a capo scritti a mano della bio, o
   quello che sta nella colonna di sinistra sotto la bio.
   È già cambiato quattro volte, e le quattro dicono perché: 1120 quando il contatto
   stava in mezzo (a destra comandava la voce più lunga degli awards, 316, e la coppia
   era 831); 1280 con la gif sotto la mail, che alzava la riga e portava il ritratto a
   459, cioè la coppia a 974; 1160 uscita la gif, col ritratto tornato a 329; poi, in un
   pomeriggio solo, 1080 (corpo da 15 a 13,5), 1070 (l'indirizzo per esteso diventato la
   parola `email` in una fila da 11: la colonna si accorcia di 10px e il ritratto si
   stringe di altrettanti) e **1100 adesso**, che è il salto più grosso di tutti e va nel
   verso opposto — l'interlinea della bio è scesa a 1,45 ma il margine fra i paragrafi è
   salito a una riga intera, quindi la colonna è **cresciuta** di 30px e il ritratto con
   lei (318,4 → 348,7).
   **Sono cinque numeri in un giorno, e dicono tutti la stessa cosa**: qui non si tocca
   niente nella colonna di sinistra senza rimisurare. Non è pignoleria — una soglia
   lasciata indietro non rompe niente di visibile, semplicemente la griglia si impila
   quando avrebbe ancora spazio, o resta su due colonne quando la bio è già andata a capo.
   **La soglia segue l'altezza della colonna di sinistra**, che è la cosa da ricordare:
   qui è scesa perché la bio ha guadagnato una riga (il quarto paragrafo è su tre righe
   e non due) ma le righe sono più corte — la più lunga è passata da 471 a 394,6. */
@media (max-width: 1099px) {
  .about-grid {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 40px;
  }

  /* Impilato, il ritratto non ha più accanto una bio da pareggiare: l'altezza torna
     a discendere dalla larghezza, e senza questo `height: auto` resterebbe al 100%
     di una riga che ora è alta quanto lui — cioè zero.
     Il tetto serve perché a colonna piena una foto quasi quadrata diventa alta
     quanto larga — 700px e passa, cioè una schermata intera di solo ritratto. I 412
     erano la larghezza della colonna del press, quando il press stava a destra; oggi
     restano come misura di comodo, non discendono più da niente. */
  .about-photo-col {
    height: auto;
    width: 100%;
    max-width: 412px;
  }
}

/* --- musing: una voce per volta ---

   Qui c'era una bacheca di card trascinabili: otto oggetti su una carta, una
   disposizione messa a mano, ombre, inclinazioni, anteprime che sfumavano, una barra
   di scorrimento da ridisegnare due volte. Erano 829 righe, e sono queste.
   Il perché sta in HANDOFF.md § Il giro dell'11 agosto; in breve: erano oggetti
   appoggiati sopra la pagina, e il testo è tornato dentro la pagina.

   Ne discendono tre cose che non si vedono da qui: non c'è più niente da trascinare,
   quindi niente posizioni salvate; non c'è più un `reset`, perché non c'è più uno
   stato da rimettere a posto; e non c'è più il ghost, che era l'ultima decorazione
   rimasta. */

/* La misura di lettura, ed è **una sola per tutte le voci**. Serve a due cose: tiene
   la riga sotto i 70 caratteri, e — soprattutto — è l'ancora delle due frecce, che
   così stanno ferme passando da una voce all'altra. Se cambia questo numero si
   spostano anche loro, ed è voluto: sono i due bordi della stessa colonna. */
/* **La cornice che scorre, e la voce dentro.** Sono `.dialogo-overlay` e
   `.dialogo-corpo` con altri nomi, ed e' voluto: il problema e' lo stesso e la
   soluzione era gia' scritta una pagina piu' in la'.

   **Prima `.reading` era centrata con `top: 50%` e una trasformazione**, e quando un
   testo superava lo schermo usciva **da tutte e due le parti senza modo di
   raggiungerlo**: e' fissa, quindi non si scorre. La voce "posso?" e' alta 712px su un
   iPhone SE e ne perdeva 23 per lato — la prima riga e la firma, cioe' proprio i due
   capi. **E' esattamente la trappola che questo foglio aveva gia' scritto per il
   dialogo** (`align-items: center`, § .dialogo-corpo): la voce non l'aveva mai avuta
   corretta.

   Ora la cornice scorre e la voce si centra con `margin: auto`: **si centra quando c'e'
   spazio e riparte dall'alto quando non ce n'e'**. Misurato, l'inchiostro non si e'
   mosso di un pixel dove il testo ci stava gia' — la scatola cresce dei 24px di
   respiro, l'inchiostro no.

   **La cornice e' alta tutto lo schermo, e non copre niente**: in verticale sta a
   x 101→329 (la nav e' sotto 101, le frecce a 0-44 e 346-390), sul computer a
   x 477→997 (frecce a 399-443 e 1031-1075). Verificato, perche' una colonna fissa alta
   quanto la finestra e' l'unico rischio di questa costruzione.
   **Le frecce non si sono mosse**, e la ragione e' che non erano ancorate a `.reading`:
   leggono `--content-center` piu' due numeri scritti a mano. */
.reading-frame {
  --measure: 520px;
  position: fixed;
  top: 0;
  bottom: 0;
  left: var(--content-center, 50%);
  transform: translateX(-50%);
  width: var(--measure);
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  /* **Niente barra**, a differenza del dialogo: la barra di scorrimento visibile resta
     una cosa sola del sito, ed e' li'. Qui a dire che il testo continua ci sono le due
     sfumature, che e' il motivo per cui esistono. */
  scrollbar-width: none;
}

.reading-frame::-webkit-scrollbar { width: 0; height: 0; }

.reading {
  width: 100%;
  /* **`margin: auto` e non `justify-content: center`**, per la ragione scritta sopra.
     I 24px sono l'unica manopola: sono il respiro che impedisce al testo di toccare il
     bordo dello schermo quando scorre, e costano 48px di margine prima che lo
     scorrimento cominci. */
  margin: auto 0;
  padding: 24px 0;
  text-align: center;
  color: var(--c-paper-ink);
}

/* Le due sfumature, accese solo quando servono — le mette `sfumaVoce()` in board.js.
   `fixed` dentro un antenato trasformato si ancora all'antenato, quindi restano ferme
   mentre il testo scorre sotto. */
.reading-frame::before,
.reading-frame::after {
  content: '';
  position: fixed;
  left: 0;
  right: 0;
  height: 56px;
  opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
  z-index: 1;
}

.reading-frame::before {
  top: 0;
  background: linear-gradient(to bottom, var(--c-paper), rgba(246, 246, 246, 0));
}

.reading-frame::after {
  bottom: 0;
  background: linear-gradient(to top, var(--c-paper), rgba(246, 246, 246, 0));
}

.reading-frame.sfuma-sopra::before,
.reading-frame.sfuma-sotto::after {
  opacity: 1;
}

/* La sola voce serif del sito: qui sono parole, non etichette di progetto.
   `pre-line` perché le andate a capo sono di chi ha scritto — sono versi, non
   paragrafi — e nel markup le righe stanno a filo di margine.
   12px: musing è una pagina di caratteri piccoli, ed è una scelta. Sotto questa
   misura la scala non scala più, perché i secondari sono già al pavimento dei 10
   della meccanica (CLAUDE.md § Musing). */
.voce-testo {
  margin: 0;
  font-family: 'Iowan Old Style', Palatino, 'Palatino Linotype', Georgia, serif;
  font-size: 12px;
  line-height: 1.9;
  white-space: pre-line;
}

/* **Le quote non sono più corsive** (17 agosto): avevano una regola apposta, ed era
   l'unica cosa che le distingueva dagli altri testi. Una citazione si riconosce dalla
   firma che ha sotto, non dalla forma delle lettere — e su una pagina di 12px il corsivo
   costava leggibilità per dire una cosa che era già detta. Con la regola è uscita anche
   la classe: non la scriveva più nessuno.

   **La voce dei film è uscita nello stesso giro**, e con lei `.voce-films`,
   `.voce-films li + li`, `.film-title` e `.film-dir`. Erano l'unico punto della pagina
   con una gerarchia tipografica interna (11 maiuscolo contro 10 corsivo). Sta in git. */

/* Firma e attribuzione: la stessa voce bassa. Chiude il testo invece di introdurlo,
   quindi sta sotto e non sopra. */
.voce-firma {
  margin: 22px 0 0;
  font-family: 'Iowan Old Style', Palatino, 'Palatino Linotype', Georgia, serif;
  font-size: 10px;
  font-style: italic;
  color: rgba(0, 0, 0, 0.45);
}

/* L'unica voce che si guarda invece di leggersi, e l'unica senza kicker. Piccola: sulla
   bacheca era l'ancora della composizione e doveva pesare, qui è una delle voci e non
   deve pesare più delle altre. */
.voce-foto {
  display: block;
  width: 190px;
  height: auto;
  margin: 0 auto;
}

/* Una voce che porta a un video è tutta un link. Il cursore resta quello di default e
   a dire che c'è qualcosa da aprire è il testo che si accende: è la stessa scelta che
   valeva sulla bacheca. */
.voce-link {
  display: block;
  color: inherit;
  text-decoration: none;
  transition: color 0.2s ease;
}

.voce-link:hover {
  color: #000;
}

.voce-link:focus-visible {
  outline: 1px solid rgba(0, 0, 0, 0.45);
  outline-offset: 6px;
}

/* --- I due segni ---

   Sono quelli del player (`projects.js`): guillemet singoli a 30px, riquadro cliccabile
   da 44 — la misura del dito, non del glifo — e opacità 0,35 a riposo. Due differenze,
   e discendono tutte e due dal fatto che qui non c'è un overlay sopra la pagina:

   1. **sono neri**, non bianchi: sotto c'è la carta;
   2. **non stanno ai bordi della finestra.** Là l'overlay copre nav e testi laterali e
      i bordi sono liberi; qui a 24px ci finiscono addosso. Stanno quindi agganciati ai
      due lati della colonna di lettura (`--measure`), che è la stessa per ogni voce:
      così **non si spostano** passando da una voce all'altra, che sarebbe la cosa più
      fastidiosa in una pagina dove l'unica cosa che si muove è il testo.

   Tutti e due posizionati con `left`, anche quello a destra: `right` si misura dal bordo
   dell'area utile e va corretto con la barra di scorrimento (§ Link laterali). Da
   `--content-center`, che quel conto lo ha già fatto, il problema non esiste. */
.reader-nav {
  position: fixed;
  top: 50%;
  /* **Niente z-index, ed è una correzione.** Con `z-index: 2` restavano sopra il blocco
     che dipinge il colore della sezione all'hover sulla nav (`.hover-color-block`, z 1):
     passando su "directing" da qui, il fondo diventava notte e le due frecce — che sono
     inchiostro su carta scritto a mano, non `--ink` — restavano nere sul nero. Invisibili.
     Tutto il resto di musing sta sotto quel blocco e sparisce insieme alla pagina, che è
     il comportamento giusto: il blocco è un'anteprima di dove stai andando, e mentre la
     mostra la pagina di partenza non deve lasciare pezzi in giro. */
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: none;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  font-size: 30px;
  line-height: 1;
  color: var(--c-paper-ink);
  opacity: 0.35;
  cursor: pointer;
  transition: opacity 0.2s ease;
}

.reader-nav.prev {
  left: calc(var(--content-center, 50%) - 260px - 56px);
  transform: translate(-50%, -50%);
}

.reader-nav.next {
  left: calc(var(--content-center, 50%) + 260px + 56px);
  transform: translate(-50%, -50%);
}

.reader-nav:hover {
  opacity: 1;
}

.reader-nav:focus-visible {
  opacity: 1;
  outline: 1px solid rgba(0, 0, 0, 0.45);
  outline-offset: 2px;
}

/* --- Il pensiero di chi guarda ---

   **È una voce del giro, la terza, e sta al centro come le altre.** È stata provata in
   fondo alla pagina, ferma e sempre trovabile, ed è finita qui: in fondo era un comando
   fra i comandi, e questa non è una funzione della pagina — è una delle cose che la
   pagina ha da dire, la sola che invece di raccontare chiede.
   Stessa posizione di `.reading` perché sono alternative: quando c'è una, l'altra è
   `hidden`. La larghezza è minore — 300 contro 520 — perché due campi larghi mezza
   schermata invitano a scrivere un tema, e qui si chiede un pensiero. */
.ask {
  position: fixed;
  top: 50%;
  left: var(--content-center, 50%);
  /* **I 7px sono una centratura ottica, e la scatola non li può dare.** Centrata a
     scatole — che è quello che fa `-50%` — la colonna risulta comunque alta: in cima
     `YOU` è maiuscolo e l'inchiostro comincia subito, in fondo `SEND` e `NEVER MIND`
     sono maiuscoli anche loro, e sotto la loro linea di base resta vuoto lo spazio dei
     discendenti, che nessuna lettera occupa. Misurato sui pixel resi: l'inchiostro
     andava da 391 a 495 su una finestra da 900, cioè 7px sopra il centro. Spostato di
     quei 7, il blocco è centrato **come si vede**. */
  transform: translate(-50%, calc(-50% + 7px));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  width: 300px;
}

.ask[hidden] {
  display: none;
}

.ask-form {
  width: 100%;
}

/* L'esca per i bot. `display: none` e non `visually-hidden`: qui non serve che sia
   raggiungibile da nessuno, serve il contrario. */
.ask-botcheck {
  display: none;
}

/* Campi senza cornice: una riga sotto, come su un foglio. Il fondo è trasparente perché
   la carta della pagina è già il fondo. Centrati come tutto il resto. */
.ask-field {
  display: block;
  width: 100%;
  margin-bottom: 12px;
  padding: 3px 0;
  background: none;
  border: none;
  border-bottom: 1px solid rgba(0, 0, 0, 0.18);
  border-radius: 0;
  text-align: center;
  font-family: 'Iowan Old Style', Palatino, 'Palatino Linotype', Georgia, serif;
  font-size: 12px;
  line-height: 1.7;
  color: var(--c-paper-ink);
  caret-color: var(--c-paper-ink);
  transition: border-color 0.2s ease;
}

textarea.ask-field {
  resize: none;
  overflow: hidden; /* cresce con il testo, non scorre: lo fa board.js */
}

.ask-field::placeholder {
  color: rgba(0, 0, 0, 0.3);
}

.ask-field:focus {
  outline: none; /* è la riga sotto a rispondere: l'anello qui sarebbe una cornice */
  border-bottom-color: rgba(0, 0, 0, 0.55);
}

.ask-field:focus-visible {
  outline: 1px solid rgba(0, 0, 0, 0.45);
  outline-offset: 3px;
}

/* **I due comandi non sono più due colori.** Erano un verde bosco e un rosso mattone,
   scelti quando questa era una card bianca su una bacheca scura e servivano a leggersi
   sulla carta. Su una pagina che non ha più un solo punto di colore, due inchiostri
   diversi erano l'unica cosa colorata rimasta e si leggevano come due bottoni — cioè
   come un'interfaccia dentro una pagina che non ne ha nessun'altra.
   Ora sono **lo stesso nero spento di ogni altro comando** e si scuriscono al passaggio,
   come `you` e come le voci di nav. A distinguerli è quello che c'è scritto, che per due
   parole opposte basta e avanza. */
.ask-actions {
  display: flex;
  justify-content: center;
  gap: 20px;
  margin-top: 2px;
}

.ask-send,
.ask-cancel {
  padding: 0;
  background: none;
  border: none;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.45);
  cursor: pointer;
  transition: color 0.2s ease;
}

.ask-send:hover,
.ask-cancel:hover {
  color: var(--c-paper-ink);
}

.ask-send:focus-visible,
.ask-cancel:focus-visible {
  outline: 1px solid rgba(0, 0, 0, 0.45);
  outline-offset: 3px;
}

/* Mentre la richiesta è in volo "send" diventa "sending…" e smette di rispondere: su una
   connessione lenta, senza, si preme due volte e arrivano due mail. */
.ask-send[disabled] {
  color: rgba(0, 0, 0, 0.28);
  cursor: default;
}

/* Le tre righe di stato. Serif corsivo come i testi: sono le battute della stessa
   conversazione, non messaggi di sistema. */
.ask-done,
.ask-error,
.ask-wait,
.ask-full {
  display: none;
  margin: 0;
  font-family: 'Iowan Old Style', Palatino, 'Palatino Linotype', Georgia, serif;
  font-size: 12px;
  font-style: italic;
  color: rgba(0, 0, 0, 0.55);
}

.ask.sent .ask-done {
  display: block;
}

/* Inviato, o casella piena: il modulo sparisce e resta la riga che lo spiega. Non si
   lascia bussare a una porta che non si può aprire, e non si chiede due volte. */
.ask.sent .ask-form,
.ask.full .ask-form {
  display: none;
}

.ask.failed .ask-error {
  display: block;
}

/* Il cronometro: non e' un invio fallito, e' un invio non partito. Vedi musing.html. */
.ask.troppo-presto .ask-wait {
  display: block;
}

.ask.full .ask-full {
  display: block;
}

/* Il numero. Meccanica, quindi Helvetica e spento: dice quanto spazio resta, non è la
   ragione per cui si guarda la pagina. Vuoto finché la funzione non risponde — in
   locale non compare, ed è giusto: uno zero inventato direbbe "casella vuota". */
/* La parola `you` sta **sopra** il modulo, mentre sulle altre voci la stessa riga sta in
   fondo: là firma un testo, qui introduce uno spazio da riempire. Il margine glielo dà il
   `gap` di `.ask`, quindi va tolto quello che `.voce-firma` si porta dietro. */
/* **`you` ha la resa di `send`, non quella delle firme.** Sulle altre voci quella riga è
   una firma e sta in fondo; qui sta in cima a un modulo, insieme a `send` e
   `never mind`, ed è di quella famiglia — Helvetica, 10px, peso 700, maiuscolo di resa,
   stesso spento. Il maiuscolo è una scelta: `SEND` lo è, e due righe della stessa misura
   che si guardano da sopra e da sotto chiudono il blocco.
   **Ne discende la centratura.** Con la stessa famiglia e lo stesso corpo di `send`, i
   14px di aria che il blocco ha sopra e sotto — `gap` da una parte, margine del campo
   più quello dei comandi dall'altra — cadono sulla stessa mezza-interlinea, quindi
   diventano lo stesso spazio anche a vederli. Da serif corsivo 10px non lo erano: stessa
   scatola, inchiostro più in alto, ed è quello che si vedeva. */
.ask-firma {
  /* **Gli 8px in meno sono una misura, non un gusto.** Il `gap: 14px` della colonna vale
     da tutte e due le parti, ma quello che si vede non è la scatola: sopra il vicino è
     l'inchiostro del segnaposto, che dentro il campo comincia 8px più in basso del bordo
     (3 di padding più la mezza-interlinea di un 12px su 1,7); sotto il vicino è la
     sottolineatura, che sul bordo ci sta esatta. Misurato sui pixel resi: 23px sopra
     contro 15 sotto — ed è per quello che `you` sembrava più in alto.
     Tolti 8 dal `gap`, i due spazi diventano **15 e 15**, e il blocco si ricentra da sé
     perché è alto 8px di meno. Se cambia il corpo dei campi o la loro interlinea, questo
     numero va rimisurato: dipende da loro, non da `you`. */
  margin: 0 0 -8px;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  font-size: 10px;
  font-weight: 700;
  font-style: normal;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.45);
}

.ask-count {
  font-family: 'Helvetica Neue', Arial, sans-serif;
  font-size: 10px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.3);
  font-variant-numeric: tabular-nums;
}

/* Quasi piena: non è un allarme, è un "sbrigati". L'unico punto di colore rimasto in
   pagina, e ci sta perché è l'unico che avverte di qualcosa. */
.ask-count.low {
  color: #8f3123;
}

/* --- Il comando che apre il dialogo ---

   Resa dei comandi e non del testo: Helvetica, spento, si scurisce al passaggio. È
   meccanica, non voce, e su questa pagina la distinzione è dappertutto.
   **22px, come una firma**, e non i 30 di prima. L'idea era che staccato di più dicesse
   "non chiudo il testo, ne apro un altro" — ma a 30 si leggeva come una riga rimasta
   indietro, non come una riga che apre. Che c'è dell'altro lo dice già quello che ci
   sta scritto, e il sito ha una misura sola per "riga che sta sotto un testo": quella
   della firma. */
.voce-apri {
  display: block;
  margin: 22px auto 0;
  padding: 0;
  background: none;
  border: none;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.45);
  cursor: pointer;
  transition: color 0.2s ease;
}

.voce-apri:hover {
  color: var(--c-paper-ink);
}

.voce-apri:focus-visible {
  outline: 1px solid rgba(0, 0, 0, 0.45);
  outline-offset: 4px;
}

/* --- L'overlay del dialogo ---

   Stessa costruzione del player dei progetti (`.project-player-overlay`): prende tutto lo
   schermo, sta sopra ogni altra cosa, si chiude con `close ×` o con Esc. Il sito ha già
   questo gesto per "questa cosa vuole tutto lo schermo", e riusarlo non aggiunge
   un'eccezione — ne applica una che c'è.
   **Due differenze, e discendono dal contenuto.** Il player è nero perché contiene un
   video; questo è **carta** perché contiene del testo, ed è la stessa carta della pagina:
   non è un'altra stanza, è la stessa pagina che si allarga. E il player ha le frecce per
   passare da un progetto all'altro; qui non ci sono, perché il dialogo è una cosa sola e
   due segni ai lati direbbero il falso.
   `z-index: 30` è quello del player: sopra tutto, comprese le frecce e la nav. */
.dialogo-overlay {
  position: fixed;
  inset: 0;
  z-index: 30;
  background: var(--c-paper);
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  /* **`flex-start` in orizzontale**: la colonna non si centra sulla finestra ma si
     appoggia a `--content-center`, che è l'asse di tutto il resto di musing — nav,
     sigle, modulo, frecce. Fra i due centri ci sono 5px, e si vedono nel momento in cui
     l'overlay si apre sopra qualcosa che stava già lì. */
  justify-content: flex-start;
  /* **`flex-start`, e non lo `stretch` di serie.** Da stirato il corpo prendeva
     l'altezza del contenitore — 597px, cioè 813 meno i due padding — e il testo, che è
     lungo il triplo, gli usciva fuori. Quello che scorreva era quindi il
     **traboccamento**, e il traboccamento non si porta dietro il `padding-bottom` di
     chi lo contiene: restavano 96px sopra e **zero** sotto, con l'ultima riga incollata
     al bordo. Misurato prima della correzione: `scrollHeight` 1783 = 96 di padding più
     1687 di testo, e nient'altro. */
  align-items: flex-start;
  /* **Niente padding, in nessuna direzione.** Quello verticale sta sul corpo (§ sotto,
     è la correzione della sfumatura che si perdeva); quello orizzontale è uscito perché
     si sommava al margine sinistro del corpo e portava la colonna 24px fuori asse — la
     conta e le frecce cadevano su `--content-center` e il testo no. Lo spazio ai lati
     sulle finestre strette lo dà ora il `max(24px, …)` del margine. */
  padding: 0;
  /* La barra di scorrimento è di questo elemento, che è quello che scorre — non del
     corpo, dove stava prima: `scrollbar-width` su un elemento che non scorre non fa
     niente, quindi la barra sottile in Firefox non si è mai vista. Va ridisegnata due
     volte, per Firefox qui e per WebKit sotto, e le due vanno tenute allineate a mano. */
  scrollbar-width: thin;
  scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
}

.dialogo-overlay[hidden] {
  display: none;
}

/* **Le due sfumature: il testo finisce nella carta invece di tagliarsi sul bordo.**
   Il taglio netto è un segnale meccanico e per giunta ambiguo — non si distingue da un
   testo che è finito davvero. La dissolvenza dice la stessa cosa e dice anche "continua",
   che è l'informazione che serve. È la soluzione che avevano le card lunghe della
   bacheca, ed è l'unica cosa di quella pagina rimasta in piedi.
   **Accese solo quando servono** (le classi le mette `board.js` sullo scorrimento):
   accese sempre, la prima riga nascerebbe già sbiadita e l'ultima non finirebbe mai.
   `position: fixed` e non `absolute`: a scorrere è l'overlay, e da assolute
   scorrerebbero via col testo — sono due bordi della finestra, non due bordi del testo.
   Il colore è `--c-paper` due volte, una opaca e una no: **se la carta viene
   ricampionata vanno cambiati tutti e due**, o la sfumatura vira su un bianco che non è
   quello della pagina. `transparent` non si può usare al posto della seconda — è nero
   trasparente, e in mezzo alla rampa si vedrebbe sporcare di grigio. */
.dialogo-overlay::before,
.dialogo-overlay::after {
  content: '';
  position: fixed;
  left: 0;
  right: 0;
  height: 64px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.dialogo-overlay::before {
  top: 0;
  background: linear-gradient(to bottom, var(--c-paper), rgba(246, 246, 246, 0));
}

.dialogo-overlay::after {
  bottom: 0;
  background: linear-gradient(to top, var(--c-paper), rgba(246, 246, 246, 0));
}

.dialogo-overlay.sfuma-sopra::before,
.dialogo-overlay.sfuma-sotto::after {
  opacity: 1;
}

/* Il dialogo è l'unica cosa di musing che si scorre, e la barra c'è solo qui. */
.dialogo-corpo {
  width: 100%;
  /* **520, cioè `--measure`: la stessa colonna di ogni altra voce.** Le due colonne
     affiancate ci sono state per un giro: facevano stare le 48 righe in una schermata
     (1094px non ci stanno in 813, e non ci starebbero nemmeno togliendo tutta l'aria —
     mancherebbero 281px), ma il dialogo finiva per leggersi su una doppia pagina da
     1004px, cioè diverso da tutto il resto di musing. Con due pagine il problema
     dell'altezza si risolve senza toccare la larghezza: 21 righe e 26, cioè 479 e 593px,
     e ci stanno tutte e due. */
  max-width: 520px;
  /* **Lo spazio verticale sta qui e non sul contenitore, ed è la correzione.** Sul
     contenitore, quello sotto non entra nell'area che scorre e si perde; sul corpo è
     contenuto vero, quindi si scorre fino in fondo e i due spazi restano identici.
     **Un valore solo per tutti e due**: sopra e sotto devono essere lo stesso, e
     scritti come due numeri diventano due cose da tenere allineate. */
  padding: 72px 0;
  /* Verticale automatico (§ sotto), orizzontale sull'asse della pagina. `max()` è una
     rete per le finestre strette, dove `--content-center` scende sotto i 260 e il blocco
     uscirebbe a sinistra. */
  /* **`margin: auto` e non un padding tarato a mano.** Da due colonne il testo è alto
     570 e ci sta in una schermata: con `flex-start` l'avanzo cadeva tutto in fondo e il
     blocco restava in alto, e per centrarlo servivano 120px di padding — cioè un numero
     che è esatto **su una finestra sola**, 813. Bastava un browser un filo più basso e
     tornava a scorrere per tre pixel.
     Col margine automatico il blocco si centra da sé quando c'è spazio, e quando non ce
     n'è i due `auto` valgono zero: riparte dall'alto e scorre. **È la ragione per cui
     non si usa `align-items: center`**, che invece in negativo taglia il principio del
     testo e lo rende irraggiungibile. */
  margin: auto auto auto max(24px, calc(var(--content-center, 50%) - 260px));
}

.dialogo-overlay::-webkit-scrollbar {
  width: 6px;
}

.dialogo-overlay::-webkit-scrollbar-track {
  background: transparent;
}

.dialogo-overlay::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 3px;
}

.dialogo-overlay::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 0, 0, 0.38);
}

/* **Allineato a sinistra, e qui sta l'unica eccezione vera di questa pagina.** Tutte le
   voci sono centrate; un dialogo no. Chi parla si riconosce da dove comincia la riga, e
   settantaquattro righe centrate sono un muro in cui `X:` e `Y:` si perdono. Il centrato
   è una scelta per un testo che si guarda tutto insieme — questo si legge dall'alto in
   basso, ed è un'altra cosa. */
.dialogo-testo {
  margin: 0;
  font-family: 'Iowan Old Style', Palatino, 'Palatino Linotype', Georgia, serif;
  font-size: 12px;
  line-height: 1.9;
  text-align: left;
  /* **`pre-wrap` e non `pre-line`**, che è la differenza fra rispettare il testo e
     riscriverlo: `pre-line` collassa gli spazi consecutivi, e i `[    ]` con cui Lorenzo
     scrive i silenzi diventavano `[ ]`. Qui la spaziatura *è* la battuta — quanto dura il
     silenzio si legge da quanto è largo. `pre-wrap` tiene gli spazi e manda a capo le
     righe lunghe, che è quello che serve.
     Sulle altre voci resta `pre-line`: sono centrate, e `pre-wrap` conserverebbe anche
     gli spazi in coda, che su un testo centrato si vedono come un fuori asse. */
  white-space: pre-wrap;
  color: var(--c-paper-ink);
  /* **Centrato, come ogni altra voce di musing.** È stato a bandiera per due giri, con
     una ragione vera — chi parla si riconosce da dove comincia la riga — e la ragione è
     stata pagata in un altro modo: chi parla ora è in grassetto (§ sotto), quindi il
     segnale non dipende più da dove cade la riga.
     Quello che ha deciso è che **il dialogo era l'unica cosa allineata a sinistra del
     sito**: aprendo e chiudendo l'overlay si saltava fra due sistemi diversi, e chiudendo
     si tornava a un testo centrato che stava da un'altra parte. Centrare la sola scatola
     non bastava: con le righe a bandiera solo la più lunga arriva al bordo, quindi
     l'inchiostro pende a sinistra anche dentro una scatola centrata al pixel.
     **Si può centrare perché non c'è una sola riga con spazi in coda**, verificato in
     tutte e due le lingue: il dialogo tiene `pre-wrap` per via dei `[    ]`, e `pre-wrap`
     conserva anche gli spazi finali — su un testo centrato si vedrebbero come righe fuori
     asse. Se un domani il testo si tocca, quella verifica va rifatta. */
  text-align: center;
}

/* Chi parla: grassetto e dritto, in mezzo al corsivo di quello che dice. È quello che
   sostituisce il bordo sinistro come segnale, ora che le righe sono centrate. */
.dialogo-testo b {
  font-weight: 700;
  font-style: normal;
}

.dialogo-testo i {
  font-style: italic;
}

/* --- Le due pagine del dialogo ---

   Frecce e contatore stanno **dentro** l'overlay e sono suoi: la pagina sotto è coperta,
   e le sue frecce e le sue sigle non si vedono (nessuna delle due ha uno z-index, quindi
   l'overlay a 30 le copre tutte).
   Stessa resa dei due segni della pagina — guillemet a 30px, riquadro da 44, che è la
   misura del dito e non del glifo, e opacità 0,35 a riposo. E **stesso asse**: tutto qui
   dentro sta su `--content-center`, come il resto di musing, non sul centro della
   finestra. Erano centrate sulla finestra per un giro, con la scusa che l'overlay copre
   nav e testi laterali e quindi la colonna dei contenuti non si vede più — ma i due
   centri distano 5px, e quei 5px si vedono: `1/2` compare disallineato rispetto a `it en`
   che sta nello stesso identico posto un istante prima. **L'overlay non è un'altra
   stanza, è la stessa pagina che si allarga**, e allora ne tiene anche l'asse.
   I 260 sono metà colonna, i 56 lo stacco: le stesse due misure delle frecce di fuori. */
.dialogo-nav {
  position: fixed;
  top: 50%;
  z-index: 31;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: none;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  font-size: 30px;
  line-height: 1;
  color: var(--c-paper-ink);
  opacity: 0.35;
  cursor: pointer;
  transition: opacity 0.2s ease;
}

.dialogo-nav:hover {
  opacity: 1;
}

.dialogo-nav:focus-visible {
  outline: 1px solid rgba(0, 0, 0, 0.45);
  outline-offset: 2px;
}

/* Come per il player: senza questa riga il `display: flex` di sopra batte il `display:
   none` che il browser dà all'attributo, e la freccia di troppo resta in vista sul primo
   e sull'ultimo. È la terza volta che serve in questo progetto. */
.dialogo-nav[hidden] {
  display: none;
}

.dialogo-nav.prev {
  left: calc(var(--content-center, 50%) - 260px - 56px);
  transform: translate(-50%, -50%);
}

.dialogo-nav.next {
  left: calc(var(--content-center, 50%) + 260px + 56px);
  transform: translate(-50%, -50%);
}

/* Nel posto delle sigle e alla loro altezza: entrando nell'overlay quel punto non si
   sposta, cambia solo cosa ci sta scritto. Tipografia dei comandi, spenta come loro. */
.dialogo-conta {
  position: fixed;
  bottom: 40px;
  left: var(--content-center, 50%);
  transform: translateX(-50%);
  z-index: 31;
  margin: 0;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.6px;
  color: rgba(0, 0, 0, 0.45);
}

/* Stessa posizione e stessa misura del `close ×` del player, nero invece che bianco. */
.dialogo-close {
  position: fixed;
  top: 24px;
  right: 24px;
  z-index: 31;
  padding: 0;
  background: none;
  border: none;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  font-size: 11px;
  letter-spacing: 0.5px;
  color: rgba(0, 0, 0, 0.45);
  cursor: pointer;
  transition: color 0.2s ease;
}

.dialogo-close:hover {
  color: var(--c-paper-ink);
}

.dialogo-close:focus-visible {
  outline: 1px solid rgba(0, 0, 0, 0.45);
  outline-offset: 4px;
}

/* La pagina sotto non deve scorrere mentre si legge il dialogo: musing è `no-scroll` di
   suo, ma la regola va scritta lo stesso — è quella che regge se un domani la pagina
   dovesse scorrere. */
body.dialogo-aperto {
  overflow: hidden;
}

/* --- Le due lingue ---

   In fondo al centro, nel posto che il sito riserva alle "cose della pagina, non del
   contenuto" — dov'era `reset`, dove in home stanno i social — e che si è liberato
   proprio quando `you` è entrata nel giro.
   Tipografia del filtro (12px, tracking 0,6, maiuscolo di resa): dice dove sei, non
   intitola niente. La sigla attiva passa a piena forza come l'opzione attiva del filtro,
   ed è l'unico modo in cui si vede quale delle due è accesa.
   **Senza separatore.** Il `//` c'è stato per un giro: nel sito quel segno lega due parti
   di una cosa sola, e due sigle di due lettere sono già una cosa sola — non serve niente
   in mezzo che lo dichiari. */
.lang {
  position: fixed;
  bottom: 40px;
  left: var(--content-center, 50%);
  transform: translateX(-50%);
  display: flex;
  align-items: baseline;
  /* 5px e non 8: gli 8 erano la distanza che le due sigle avevano *attorno* al `//`,
     e tenuta uguale senza più niente in mezzo si legge come un buco. Stessa correzione
     già fatta sul filtro quando gli è stato tolto il suo separatore. */
  gap: 5px;
}

.lang-opt {
  padding: 0;
  background: none;
  border: none;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.45);
  cursor: pointer;
  transition: color 0.2s ease;
}

.lang-opt:hover,
.lang-opt.attiva {
  color: var(--c-paper-ink);
}

.lang-opt:focus-visible {
  outline: 1px solid rgba(0, 0, 0, 0.45);
  outline-offset: 4px;
}

/* Fuori dallo schermo ma dentro l'albero di accessibilità: le due label dei campi.
   Non `display: none`, che li toglierebbe anche a chi legge con uno screen reader. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* --- Mobile --- */

@media (max-width: 640px) {
  /* ============================================================================
     LA SCALA DEL VERTICALE

     Il sito ha **due famiglie tipografiche, e su mobile scende solo una**.

     - **L'arredo fisso** (nav, "directed by lorenzofiale", social) e **la meccanica
       di pagina** (filtro, sigle della lingua, etichette di about) scendono: sono
       quello che ti dice dove sei e dove puoi andare, e su uno schermo piccolo devono
       arretrare per lasciare il posto al lavoro.
     - **Il contenuto NON scende** — la bio e gli elenchi di about, le voci di musing,
       i titoli e le note delle tile restano ai corpi del computer. È la ragione per
       cui uno apre la pagina, e c'è anche un conto fisico dietro: un telefono da
       390 CSS px è largo ~64mm contro i ~300 di un portatile da 1440, quindi **lo
       stesso corpo in CSS è già ~22% più piccolo sul telefono**. Abbassarlo lo
       rimpicciolirebbe due volte.

     I corpi dell'arredo sono stati tarati in tre giri sulla home, guardandola su un
     telefono vero, e da lì valgono per tutte e cinque le pagine:

                     partenza   1° giro   2° giro   3° giro
         nav            12        11       10,5      9,5
         social         11        10        10        9
         identità       10         9        8,5      7,5

     Restano tre gradini di un pixel fra le tre righe, come all'inizio: **è cambiata
     la voce, non la gerarchia.** I mezzi pixel sono voluti — il sito ne ha già uno,
     il 13,5 della bio di about, arrivato per la stessa strada.
     I 7,5 dell'identità sono **il corpo più piccolo del sito**, su un testo ruotato e
     senza più la stanghetta accanto: è la prima misura da riguardare se qualcosa non
     si legge.
     ============================================================================ */

  /* **Il filtro, la firma e il mosaico si centrano tutti sulla finestra.**

     Sul computer il filtro sta su `--content-center`, il punto di mezzo fra i due blocchi
     fissi, che lì coincide col centro della colonna dei contenuti. In verticale ha smesso
     di coincidere due volte, e ogni volta per un motivo diverso:

     - finché il mosaico era inserito a sinistra e a filo a destra, il suo centro era
       `(inizio + 100%) / 2` = 239,5 mentre `--content-center` valeva 227;
     - **ora il mosaico va a filo da tutte e due le parti**, quindi il suo centro *è* il
       centro della finestra, e non serve più nessun conto: `left: 50%`.

     Ne discende che i tre oggetti in cima — firma, nome sezione, opzioni — e le tile
     sotto stanno tutti sullo stesso asse, che è anche quello dello schermo. È l'unica
     configurazione in cui non c'è un asse da tenere allineato a un altro. */
  .breadcrumb {
    left: 50%;
  }

  /* Le sigle si centrano sulla pagina e non su `--content-center`, che con la firma
     al bordo torna a valere 227: i 32px di scarto si vedevano, perché sono l'unica cosa
     in fondo alla pagina e l'occhio le confronta col bordo dello schermo. */
  /* **Le due sigle si separano: `it` sotto la freccia di sinistra, `en` sotto quella
     di destra.**

     In fondo al centro erano l'unica cosa su quell'asse e sembravano il piede della
     pagina. Divise, ognuna sta sotto il comando che le è più vicino, e la riga in fondo
     smette di esistere come oggetto: restano due coppie ai due angoli.
     **I 14px non sono un margine, sono dove comincia il glifo della freccia**: il
     riquadro cliccabile è 44 ma il segno `‹` ci sta dentro centrato, e allineare la
     sigla al bordo del riquadro — che è invisibile — la lascerebbe fuori squadra.
     Da qui `width: calc(100% - 28px)`: 14 di qua, 14 di là, e `space-between` fa il
     resto. Il `gap` va a zero, o si sommerebbe allo spazio fra i due estremi.
     `transform` annullato: centrava il blocco sul suo `left`. */
  .lang {
    /* **19 e 20, non 14 e 14** (24 agosto). Il 14 veniva da "i 14px sono dove comincia
       il glifo della freccia", che era vero sulla scatola del carattere e falso
       sull'inchiostro: il `‹` e' un chevron stretto dentro un riquadro da 44, e il suo
       tratto va da x19 a x24 — non da 14. Misurato sui pixel resi, non sulle scatole.
       Ora l'inchiostro di `it` comincia dove comincia quello di `‹` e quello di `en`
       finisce dove finisce `›`: le due coppie cadono sugli stessi due assi.
       I due numeri (19 e 18) sono diversi perche' i due glifi non sono simmetrici dentro il
       il loro riquadro. **Se cambia il corpo delle frecce, questi due vanno rimisurati.** */
    left: 19px;
    width: calc(100% - 37px);
    justify-content: space-between;
    gap: 0;
    bottom: auto;
    /* 22px sotto la scatola della nav danno 32px di inchiostro visto, cioe' lo stesso
       vuoto che c'e' sopra fra le frecce e la nav. Le due misure vanno insieme. */
    top: calc(var(--nav-bottom, 468px) + 22px);
    transform: none;
  }

  /* ============================================================================
     MUSING IN COLONNA CENTRATA

     Musing era l'ultima pagina rotta in verticale: la colonna di lettura è 520 su uno
     schermo da 390 — sbordava di 28 a sinistra e 102 a destra — e le due frecce
     finivano **fuori schermo**, a x −106 e 526.

     Prende la misura di about: **212 su asse 195**, cioè la colonna centrata sulla
     finestra. Vale per tutto — la voce, il modulo `you` (era 300 su asse 232) e
     l'overlay del dialogo (era 366, fuori asse).
     ============================================================================ */
  .reading-frame {
    --measure: var(--misura-verticale);
  }

  .ask {
    left: var(--content-center, 50%);
    width: var(--misura-verticale);
  }

  /* **I comandi si dispongono attorno alla nav: le frecce sopra, le sigle sotto**
     (24 agosto). Prima stavano tutti e due in basso — le frecce a y540 e le sigle a
     y578 — dove erano finiti per non farsi prendere sotto dalla nav.

     **Restano una per lato**, ai due bordi dello schermo: e' quello che dice cosa
     fanno. Affiancate sopra la nav sono state provate e scartate — due riquadri da 44
     sono larghi 88 e la nav ne e' larga 49, quindi la coppia sporgeva fino a x112
     dentro la colonna di lettura che comincia a 101, e soprattutto un `‹ ›` sopra un
     elenco di quattro pagine si legge come "pagina precedente/successiva".
     Ai bordi restano **57px liberi a sinistra e 17 a destra** dalla colonna.

     **Le due coppie cadono sugli stessi due assi**, e non e' una taratura nuova: i 14px
     delle sigle sono gia' *dove comincia il glifo della freccia* (vedi .lang), quindi
     allineando le y si allineano anche le x da se'.

     **I due stacchi visti sono 32px sopra e sotto**, misurati sull'inchiostro reso e non
     sulle scatole. Il -53 non e' 22+31: e' 44 (la scatola) piu' 9, e quel 9 viene dal
     fatto che il glifo `‹` e' alto 8px dentro un riquadro da 44 e ci sta 20px sotto il
     bordo alto. Sulla scatola sarebbero 34 e 32; sull'inchiostro sono 32 e 32.
     **--nav-top e --nav-bottom li pubblica initFixedEdges()**: la nav e' centrata
     verticalmente e la sua altezza dipende da quante voci ha, quindi scriverli a mano
     vorrebbe dire tenere allineata quell'altezza in due posti. */
  .reader-nav {
    top: calc(var(--nav-top, 376px) - 53px);
    transform: none;
    bottom: auto;
  }

  .reader-nav.prev { transform: none; left: 0; }
  /* **`right: 0` e non `left: 368px`.** Il valore scritto a mano era tarato su uno
     schermo da 390: su un iPhone SE (375) il riquadro finiva a x415, cioe' 40px fuori
     dallo schermo, e circa 3px del glifo erano tagliati. Difetto che c'era gia'. */
  .reader-nav.next { transform: none; left: auto; right: 0; }

  /* L'overlay del dialogo sta a z30 e copre la nav: lì le frecce non hanno niente da
     schivare e restano al centro verticale, come nel player.
     Tutte e due con `left`, anche quella a destra: `right` si misura dal bordo
     dell'area utile e andrebbe corretto con la barra (§ Link laterali). */
  /* **L'overlay si centra sulla pagina, non sull'asse nav-firma.**
     Fuori, quell'asse esiste perché la colonna deve stare fra due cose: la nav a
     sinistra e la firma a destra. Qui dentro non c'è né l'una né l'altra — l'overlay sta
     a z30 e le copre, il fondo è carta piena da bordo a bordo — quindi l'unico
     riferimento rimasto è lo schermo. È la stessa ragione per cui le frecce, qui dentro,
     tornano ai bordi e al centro verticale come nel player. */
  .dialogo-overlay { justify-content: center; }

  .dialogo-corpo {
    max-width: var(--misura-verticale);
    margin-inline: auto;
  }

  .dialogo-conta { left: 50%; }
  .dialogo-nav.prev { left: 22px; }
  .dialogo-nav.next { left: 368px; right: auto; }



  /* **La firma resta ruotata sul bordo destro anche in verticale.**

     Per un giro è stata portata in cima al centro, su tutte e cinque le pagine, con il
     ritmo dei tre blocchi (firma · 10 · nome sezione · 10 · opzioni) e il ritaglio della
     home spostato al 30% per allontanare la clip dalla nav. **È stato annullato tutto il
     23 agosto**: si torna alla firma al bordo, e la home al suo ritaglio centrato.
     Di quel giro resta una cosa sola, ed è indipendente dalla posizione: **il bersaglio
     allargato** (`.side-link` qui sotto).

     **Su directing ed editing la firma finisce sopra le tile**, che ora vanno a piena
     larghezza: è noto, è accettato per adesso, e non va chiuso con una velatura né
     stringendo il mosaico. Si guarda prima com'è l'insieme. */

  /* **Il bersaglio da toccare, che è un'altra cosa dall'inchiostro.**

     Il testo è 7,5px e resta così — è il corpo più piccolo del sito, ed è voluto.
     Quello che era troppo piccolo è la scatola cliccabile: senza padding valeva
     **9 × 90**, cioè esattamente l'inchiostro di un testo ruotato, e 9px di larghezza
     si mancano col dito. Col padding passa a **33 × 108**. È la stessa manovra della
     nav (§ La nav non si muove mai): si allarga la scatola, non la lettera.

     **E come lì, va compensata**: il padding orizzontale spingerebbe l'inchiostro 12px
     verso l'interno, mentre l'invariante è che a stare a `--gutter` dal bordo sia il
     TESTO e non la scatola (§ Link laterali). Quindi `right` sconta i 12 del padding.
     `--gutter` qui vale **16** e non i 64 del computer, ma la formula non cambia:
     verificato, l'inchiostro resta a x 365→374 come prima del padding.
     **Le due righe vanno insieme**: cambiando il padding senza il `right`, la firma si
     stacca dal bordo e non si vede che è un errore. */
  .side-link {
    padding: 12px;
  }

  /* **`--firma-bordo` è la distanza dell'INCHIOSTRO dal bordo dello schermo**, ed è il
     numero da cui discendono altre tre cose: il `right` qui sotto (che ne sconta i 12 del
     padding), la distanza a cui si fermano le didascalie delle tile, e — passando per
     `initFixedEdges()` — l'asse su cui si centrano musing e about.
     Scritta una volta sola apposta: **spostando la firma, si spostano con lei.** */
  :root {
    --firma-bordo: 24px;

    /* **La misura della colonna di lettura non si sceglie, si ricava.**

       L'asse è `--content-center`, il punto di mezzo fra il bordo destro della nav e
       l'inchiostro della firma (lo misura `initFixedEdges()`). Una colonna centrata lì
       che lasci lo stesso respiro da tutt'e due le parti è larga esattamente il doppio
       della distanza fra l'asse e il primo ostacolo:

           (asse − bordo nav − 16) × 2

       Su 390 fa **252**, con 16px netti dalla nav e 16 dalla firma — e i due numeri sono
       uguali per costruzione, perché l'asse è il punto di mezzo. **Spostando la firma si
       spostano insieme l'asse, la colonna e la sua larghezza**, senza ritoccare niente.
       I 16 sono `--column-gap`, scritti per esteso perché quello è dichiarato dentro i
       singoli blocchi e da `:root` non si vede. */
    --misura-verticale: calc((var(--content-center) - var(--nav-edge) - var(--respiro)) * 2);

    /* **`--respiro` è il vuoto che la colonna lascia da tutt'e due i lati**, ed è la sola
       leva da toccare: la larghezza discende da lui e dall'asse. Erano 16 (`--column-gap`)
       e la colonna 252; a 28 scende a **228**, e i due margini restano uguali per
       costruzione. Alzarlo stringe la colonna, abbassarlo la allarga — non c'è un secondo
       numero da tenere allineato. */
    --respiro: 28px;
  }

  .side-links {
    right: calc(var(--firma-bordo) - 12px - var(--sbw, 0px));
  }

  /* Torna a 24: la firma non è più sopra di lui (vedi qui sopra), quindi non c'è più
     un blocco da far scendere. */
  .breadcrumb {
    top: 24px;
  }

  .nav-label {
    font-size: 9.5px;
  }

  .side-link-text {
    font-size: 7.5px;
  }

  /* La riga social, che sta in fondo alla home e in coda alla bio di about: stesse
     classi, stessa misura, come sul computer. */
  .social-links,
  .about-contact {
    font-size: 9px;
  }

  /* **La meccanica di pagina sta un pixel sopra la nav**, ed è il rapporto che ha già
     sul computer (12 contro 11). Tenuta a 12 con la nav scesa a 9,5 sarebbe diventata
     l'oggetto più grande della pagina — più della nav, che è la cosa che porta
     altrove: la gerarchia si sarebbe ribaltata.
     Le sigle della lingua seguono il filtro perché ne hanno la tipografia per
     convenzione (vedi § Le due lingue in CLAUDE.md), e le etichette di about vanno
     alla pari della nav come ci stanno già sul computer. */
  .filter-section,
  .filter-item,
  .filter-sep {
    font-size: 10.5px;
  }

  /* **Le sigle si staccano dal filtro** (24 agosto). Avevano la sua tipografia per
     convenzione, e ce l'hanno ancora sul computer; ma il filtro sta su directing ed
     editing e le sigle su musing, e musing e' scesa di un pixel su tutto. Tenendole
     nella stessa riga sarebbero rimaste l'unica cosa di musing alla misura di prima. */
  .lang-opt {
    font-size: 9.5px;
  }

  .about-block h2 {
    font-size: 8.5px;
  }

  /* **La spaziatura della nav, e il vuoto sta DENTRO le voci invece che fra le voci.**

     Il vuoto che si vede scende da 16 a 12px, ma non togliendo spazio: spostandolo nel
     padding delle voci. La differenza non è di stile, è che **la scatola cliccabile era
     alta quanto l'inchiostro** — 11px, contro i 24 del minimo WCAG, i 44 di Apple e i 48
     di Material — e i 16px di vuoto non erano di nessuno: chi toccava lì non prendeva
     niente e doveva riprovare.
     Col padding il bersaglio passa a **23px** e il vuoto visto a 12. Stringere il solo
     `gap`, che era la mossa ovvia, avrebbe fatto il contrario: stessa scatola da 11px,
     più vicina alla successiva, quindi più facile sbagliare voce.

         inchiostro 11 + padding 6×2 = bersaglio 23   ·   vuoto visto = gap 0 + 6×2 = 12
         passo 23   ·   la nav resta alta 92px, cioè **non si sposta niente in pagina**

     `gap: 0` è voluto: **i bersagli si toccano**, non c'è spazio morto fra loro. Chi mira
     in mezzo prende una delle due voci invece di non prendere niente — su quattro
     destinazioni tutte legittime, aprire quella accanto si corregge con un tocco, mentre
     "non è successo niente" fa ripetere il gesto senza capire perché.
     **Le due misure vanno insieme**: il vuoto che si vede è `gap + 2 × padding`, quindi
     toccarne una sola lo cambia. E sotto i 10px di vuoto non si scende — a 9,5px di corpo
     la nav comincia a leggersi come un blocco solo invece che come quattro voci, che è la
     stessa soglia già misurata sul filtro. */
  .main-nav {
    gap: 0;
  }

  .nav-item {
    padding: 6px 0;
  }



  /* Su mobile la fascia nera non c'è: la nav sta sopra il contenuto e il mosaico
     è a una colonna sola. Qui il numero torna a essere un margine e basta, e non
     c'è nessuna centratura da correggere.
     c'è nessuna centratura da correggere. */
  :root {
    --gutter: 16px;
    --bar-lead: 0px;
  }

  .main-nav {
    left: 24px;
  }

  .content-page {
    /* la nav mobile è più stretta ma resta comunque fissa: manteniamo un
       margine di sicurezza a sinistra, solo un po' più stretto */
    padding-left: 170px;
  }

  /* About non ha un padding fisso da stringere: i suoi due margini sono
     `bordo del blocco fisso + --column-gap`, e la parte fissa la misura il JS. Qui
     basta togliere aria al gap, che a 640px di finestra è la metà di quello che
     serve altrove. */
  /* **Il contenuto scende di un pixel, ed è un'eccezione alla regola.** § La scala del
     verticale dice che bio, elenchi e voci di musing restano ai corpi del computer,
     perché il telefono li rimpicciolisce già di suo. Vale ancora come principio, ma la
     colonna qui è 228 contro i 737 del computer: lo stesso corpo in una colonna larga un
     terzo dà righe da ~30 caratteri, e il testo si stringe invece di respirare. Un pixel
     in meno compra due o tre caratteri per riga. **Se la colonna tornasse larga, questi
     due corpi tornano su.** */
  .about-block p,
  .about-list {
    font-size: 11.5px;
  }

  /* **11 e non 11,5** (24 agosto): mezzo pixel in meno sulla colonna piu' stretta del
     sito. Non e' il rimedio al taglio — quello e' la cornice che scorre — ma decide
     **quanto spesso lo scorrimento entra in funzione**: su un iPhone SE la voce piu'
     lunga passa da 93px di corsa a 43. */
  .voce-testo {
    font-size: 10px;
  }

  /* **Tutto musing scende di un pixel, non solo la voce** (24 agosto). Quando scende un
     corpo scende con lui quello che gli sta sotto, o la scala non si sposta: si
     schiaccia. Queste righe non avevano un valore verticale — ereditavano quello del
     computer — quindi qui il -1 va scritto per intero e non come differenza. */
  .voce-firma,
  .ask-firma,
  .ask-send,
  .ask-cancel,
  .ask-count {
    font-size: 9px;
  }

  .ask-field,
  .ask-done,
  .ask-error,
  .ask-full,
  .dialogo-testo {
    font-size: 11px;
  }

  /* **Le due immagini di musing scendono del 20%**, da 190 a 152. Erano tarate su un
     testo da 12px: con la voce a 10 pesavano piu' di quello che le sta intorno.
     Una regola sola perche' la gif e la foto sono tutt'e due `.voce-foto`.
     **Il file resta quello**: rimpicciolire la resa non rimpicciolisce i 143 KB della
     gif (HANDOFF.md § Ottimizzazione, punto 7). */
  .voce-foto {
    width: 152px;
  }

  .about-content {
    --column-gap: 16px;
    /* **La colonna di about è la stessa di musing**, e non è una somiglianza: legge le
       stesse due variabili. Comincia a `--nav-edge + --respiro` e finisce dove finisce
       `--misura-verticale`, quindi cade sull'asse nav-firma con lo stesso vuoto ai due
       lati — 228px su 390, con 28 di respiro.
       **Il padding sinistro va dichiarato anche qui**: sul computer è nella scrittura
       breve (`padding: 96px … 24px …`) e vale `--nav-edge + --column-gap`, cioè 16 di
       respiro invece di 28. Senza questa riga about restava larga 240 e musing 228, e le
       due colonne non si corrispondevano più — preso in prova. */
    padding-left: calc(var(--nav-edge) + var(--respiro));
    padding-right: calc(100% - var(--nav-edge) - var(--respiro) - var(--misura-verticale));
    /* **Lo stesso respiro sopra e sotto.** Il padding di questa pagina è `96px … 24px`:
       sul computer i 24 non si vedono, perché il contenuto ci sta in una schermata e
       sotto avanza spazio comunque. In verticale la pagina scorre, quindi quei 24 sono
       davvero l'ultima cosa dopo l'ultima riga degli awards, e il testo finisce a
       ridosso del bordo. 96 e 96: il vuoto in fondo è quello che si vede sopra "BIO". */
    padding-bottom: 96px;
  }

  /* **About si legge in colonna centrata, come musing**: bio, press, awards, e il
     ritratto per ultimo.

     **La foto va in fondo con `order`, non spostandola nel markup**: sul computer sta
     al secondo posto, accanto alla bio, e quello non si tocca. È la stessa manovra
     dell'anno nelle tile.
     Il ritratto per ultimo perché in mezzo spezzava la lettura in due: bio, poi una
     foto alta un terzo di schermata, poi di nuovo testo. In fondo chiude la pagina
     invece di interromperla. */
  .about-grid {
    justify-items: center;
    row-gap: 44px;
  }

  .about-photo-col {
    order: 1;
  }

  /* **Tutto a sinistra, non piu' centrato** (24 agosto). About in verticale e' una
     colonna da 228px che scorre, e centrare un testo che va a capo quasi a ogni riga
     lascia due bordi frastagliati invece di uno: l'occhio non trova da dove ricominciare
     la riga dopo. A sinistra il bordo di attacco e' uno solo e fermo, ed e' anche come
     la pagina si legge sul computer.
     **Bio, press e awards allineati uguale**: press a destra era stata provata — le tre
     sezioni si alternavano a zig-zag — e scartata, perche' su una colonna stretta il
     frastagliato passa da un lato all'altro e diventa la cosa che si nota.
     **`text-align` da solo non basta**, ed e' la trappola gia' scritta qui sotto: le due
     liste sono `width: fit-content`, quindi la scatola e' larga quanto la voce piu'
     lunga e allineare il testo dentro non sposta niente. Va prima ridata la larghezza
     della colonna. Stessa cosa per la riga dei contatti, dove `justify-content` da solo
     non fa niente perche' allinea dentro una scatola gia' stretta quanto il contenuto. */
  .about-col,
  .about-block {
    width: 100%;
    text-align: left;
  }

  .about-list {
    width: 100%;
    align-items: flex-start;
    text-align: left;
  }

  .about-contact {
    width: 100%;
    justify-content: flex-start;
  }

  /* Mosaico su mobile: una colonna sola. Con la nav fissa che si mangia già 170px,
     due tile affiancate diventerebbero due francobolli — le coppie si sciolgono e
     ogni progetto torna a piena larghezza. */
  .project-grid.project-stack {
    grid-template-columns: 1fr;
    /* qui .content-page ha 170px di padding-left, non 240 */
    margin-left: -170px;
    --column-gap: 16px;

    /* **Il mosaico va da bordo a bordo.**

       Sul computer è una colonna centrata fra i due blocchi fissi, e i due margini sono
       la stessa cosa: `blocco + --column-gap`. In verticale quei blocchi non delimitano
       più niente — **la firma se n'è andata in cima** (§ La firma in alto) e la nav sta
       sopra il contenuto — quindi non c'è più una fascia da rispettare da nessuna delle
       due parti, e la tile passa da 275 a **390**: +41,8%.

       **Il prezzo è dichiarato e accettato, e la decisione è chiusa** (24 agosto, dopo
       averlo guardato da un telefono vero). La nav resta sopra le tile: nel punto peggiore
       raggiungibile sta a **1,66:1**, con il 7,3% degli scorrimenti sotto 4,5:1.
       Una velatura a sinistra lo chiuderebbe — è misurata, serve circa 0,8 — e **non si
       fa**: rimetterebbe una tinta sulle immagini, che è quello da cui si è usciti
       passando la firma in cima e poi riportandola al bordo. Fra una nav che si legge
       sempre e delle copertine pulite, in verticale vince la copertina.
       **Non è una cosa da riaprire perché "manca il contrasto": è stata scelta.** */
    padding-left: 0;
    padding-right: 0;
  }

  /* Le righe affiancate si sciolgono e ogni progetto torna a piena larghezza.
     Va fatto sul contenitore flex: la regola `grid-column: span 1` che stava qui
     prima non faceva niente, perché le celle affiancate non sono figlie della
     griglia ma di .project-row. */
  .project-stack .project-row {
    flex-direction: column;
    align-items: stretch;
    width: 100%;
  }

  /* Il peso proporzionale va tolto, non solo ignorato: girata la direzione, quel
     `flex: r 1 0` diventa una base di ALTEZZA — base 0 in una colonna senza altezza
     definita significa tile alte zero, cioè pagina vuota. Il rapporto continua a
     valere sulla tile via aspect-ratio, che è quello che serve qui. */
  .project-stack .project-row > .project-cell {
    flex: 0 0 auto;
  }

  /* **La didascalia è sempre accesa, e sta tutta in basso a destra.**

     Sul computer compare all'hover: è l'informazione che chiedi avvicinandoti a una
     tile. **Su un telefono l'hover non esiste**, quindi da lì una didascalia a comparsa
     non è discreta, è irraggiungibile — il mosaico diventa una fila di immagini mute,
     senza titolo né categoria. Accesa sempre.
     La sfumatura sotto viene con lei ed è quello che la tiene leggibile: senza, il testo
     finirebbe bianco su bianco sulle copertine chiare (CLAUDE.md § Contrasto del testo).

     **Incolonnata a destra**, con l'ibrido. È stata a sinistra per un giro, quando il
     mosaico era inserito da tutte e due le parti e a destra c'erano 26px di nero: lì
     il lato giusto era quello della copertina. Ora il mosaico va a filo a destra, e a
     destra sta anche la firma con la sua velatura — cioè la parte di tile già più
     scura. La didascalia ci si appoggia invece di attraversare l'immagine pulita.
     Titolo e nota restano impilati e non uno per lato: su una riga da 390 si
     accavallerebbero, ed è la stessa correzione che il sito applica da tre celle in su
     (`.project-row[data-count="3"|"4"]`).

     **Il padding destro è 26 e non 18**, e non è simmetria mancata: la firma occupa
     x 380→389, e con 18 il titolo le finiva a 8px. Con 26 ne restano **16**.

     La soglia è la larghezza e non `(hover: none)` per stare con tutto il resto del
     blocco. Se un domani conta il puntatore e non lo schermo — un tablet largo senza
     mouse — è questa la regola da spostare. */
  .project-stack .tile-caption {
    /* La didascalia prende **tutta** la tile e non più la sola fascia in fondo: la
       nota sta in alto e il blocco anno/categoria/titolo in fondo, e per tenerli ai
       due capi serve che la scatola arrivi a tutti e due. `justify-content: flex-end`
       rimette il blocco dove stava.
       La sfumatura non può più stare qui — coprirebbe la tile intera — e passa ai
       due pseudo-elementi qui sotto. */
    inset: 0;
    justify-content: flex-end;
    /* **Il padding destro non è un numero, è dove finisce la firma.**
       L'inchiostro della firma occupa la fascia `--firma-bordo + 9` dal bordo (i 9 sono
       la sua larghezza da testo ruotato); le didascalie si fermano 16px prima, che è
       `--column-gap`. Con le tile a piena larghezza le due cose sono sullo stesso
       pixel e senza questo conto si accavallano — a 26px la didascalia finiva a 364 e
       l'inchiostro della firma cominciava a 357. */
    padding: 16px calc(var(--firma-bordo) + 9px + 16px) 16px 18px;
    opacity: 1;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
    background: none;
    gap: 6px;
  }

  /* **La riga da tre e da quattro va riscavalcata a mano, ed è una trappola di
     specificità.**

     Sul computer `.project-row[data-count="3"|"4"] .tile-caption` impila la didascalia
     a `flex-start`, perché su una tile stretta titolo e nota non ci stanno affiancati.
     Quella regola vale **0-3-0**, la mia qui sopra `.project-stack .tile-caption` vale
     0-2-0: vince lei, media query o no — le media query non contano nella specificità.
     Risultato, la riga da quattro di editing (LAZZA e i tre NAMELESS) teneva la
     didascalia a sinistra mentre tutte le altre erano a destra.
     **Non si era mai visto prima perché fino a ieri il verticale voleva `flex-start`
     anche lui**: la regola sbagliata dava per caso il risultato giusto, ed è saltata
     fuori solo girando il lato. È lo stesso inciampo del `[hidden]` sulle righe
     filtrate (§ Filtro), e si chiude allo stesso modo: più specifici, non più in basso. */
  .project-stack .project-row[data-count] .tile-caption {
    align-items: flex-end;
    gap: 6px;
  }

  .project-stack .project-row[data-count] .tile-note {
    text-align: right;
  }

  /* **La sfumatura, che è una sola perché il testo sta tutto in fondo.**
     Ce n'erano due, quando la nota stava in alto: quella sopra è uscita con lei, o
     sarebbe rimasta una banda scura in cima a ogni tile senza niente da rendere
     leggibile. L'altezza è in percentuale della tile e non in px, perché le tile hanno
     rapporti diversi — una 2.39 e una 16:9 non vogliono la stessa fascia — e il 58%
     tiene anche la didascalia più alta, quella con la nota su due righe. */
  /* **Il testo va messo sopra la sfumatura, e non lo era.**

     `::before` è `position: absolute`, quindi dipinge nello strato dei discendenti
     posizionati — cioè **sopra** il testo, che è statico. Il nero all'85% copriva le
     lettere: i titoli sono `rgb(255,255,255)` in CSS ma a schermo arrivavano a **98 su
     255**, e sembravano grigi perché lo erano davvero.
     Basta rendere posizionati anche i due blocchi di testo: a pari z-index vince chi
     viene dopo nel DOM, e loro vengono dopo. Misurato: il picco passa da 98 a 255. */
  .project-stack .tile-caption-text,
  .project-stack .tile-note {
    position: relative;
  }

  .project-stack .tile-caption::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 58%;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0));
    pointer-events: none;
  }

  /* Il segnaposto è **carta bianca con inchiostro scuro** (§ .project-tile.senza-copertina):
     una sfumatura nera lì sopra sarebbe una banda scura su un foglio, cioè il contrario
     di quello che serve. È la stessa ragione per cui la regola desktop gli toglie il
     `background` della didascalia — qui va ripetuta perché la sfumatura non sta più sul
     contenitore ma sullo pseudo. */
  .project-tile.senza-copertina .tile-caption::before {
    display: none;
  }

  /* **Anno, categoria e titolo si stringono a 3px** (dai 6 del computer). Non è il
     gap del computer scalato: è che qui le tre righe sono più piccole e più corte, e
     con 6px di vuoto smettevano di leggersi come una didascalia sola — l'anno
     galleggiava per conto suo e il titolo sembrava staccato dalla categoria che lo
     qualifica. Lo spazio va tarato sul corpo che separa, non sulla finestra: sceso il
     corpo, va sceso il vuoto. **Sono le tre righe di un blocco**, e i 6px del
     contenitore (`.tile-caption`) restano dove sono — quello separa il blocco dalla
     nota, che è un'altra cosa, e i due vuoti diversi sono ora quello che le distingue. */
  .project-stack .tile-caption-text {
    align-items: flex-end;
    gap: 2px;
    line-height: 1.2;
  }

  /* L'interlinea va stretta insieme al vuoto, o si stringe solo metà del problema:
     fra due righe quello che si vede è `gap + (interlinea − 1) × corpo`, e a 1,5 la
     seconda metà pesava più della prima. */
  .project-stack .tile-name,
  .project-stack .tile-category,
  .project-stack .tile-year {
    line-height: 1.2;
  }

  /* **La nota sta in fondo a destra, sotto il blocco anno/categoria/titolo.**

     Cioè in coda alla didascalia, ultima riga della colonna. Sul computer è in fondo a
     destra ma sulla *stessa riga* del titolo, perché lì la tile è larga e ci stanno
     affiancati; qui la riga è stretta e si impilano, e la nota va sotto — è
     informazione di servizio, e va dopo la cosa che qualifica.

     **È stata in alto a destra per un giro, e ne è uscita per una misura.** In alto
     stava fuori dal blocco, con `position: absolute` e `nowrap`, e a piena larghezza
     (390) ci stava su una riga sola. Ma con l'ibrido la tile è 301, quindi lo spazio
     utile è sceso da 354 a **257px**, e la nota più lunga — DUST GIRL, 72 caratteri —
     ne misura **274**. Con `nowrap` non andava a capo: **sforava di 18px e finiva sotto
     la firma**, a x381 contro i 380 dove "directed by lorenzofiale" comincia. Un
     `nowrap` su una misura che non ci sta non tiene il testo su una riga, lo manda
     fuori dalla scatola in silenzio.
     Rientrata nel flusso, va a capo da sé quando serve: DUST GIRL prende due righe,
     tutte le altre una. **È il comportamento giusto** — una nota lunga costa due righe
     di didascalia, non una collisione.

     I 6px del contenitore la staccano dal blocco sopra, contro i 2 fra anno, categoria
     e titolo: **due vuoti diversi apposta**, ed è quello che dice che le tre righe sono
     una cosa sola e la nota è un'altra. */
  .project-stack .tile-note {
    max-width: 100%;
    text-align: right;
    line-height: 1.2;
  }

  /* **I corpi della didascalia scendono con tutto il resto.** A 12px il titolo era
     l'oggetto più grande della pagina — più del filtro (10,5) e della nav (9,5) — e su
     una tile stretta si accavallava con la nota.

     **Il titolo si è poi staccato dal filtro** (era 10,5 come lui, perché sul computer
     stanno tutti e due a 12) ed è sceso in due passi a **9**. Le due cose non hanno lo
     stesso lavoro qui: il filtro è uno solo in cima alla pagina e si regge da sé, il
     titolo è ripetuto su ogni tile sopra un'immagine, e pesava più di quanto dicesse.
     **I secondari sono scesi con lui, a 8**, ed è la parte che conta: al primo giro il
     titolo era andato a 10 lasciandoli a 9,5, cioè mezzo pixel di distanza, e mezzo
     pixel non è una gerarchia — era una didascalia di tre righe quasi uguali, tenute
     insieme solo da maiuscolo e contrasto. A 9 e 8 la distanza torna **un pixel pieno**,
     che è il rapporto che le due righe hanno già sul computer (12 e 11).
     **9 è anche il pavimento del titolo**: sotto passerebbe la nav (9,5), e il nome di
     un lavoro diventerebbe più piccolo dell'arredo che gli sta accanto. Se un domani
     servisse stringere ancora, la leva è il vuoto, non il corpo. */
  /* **In verticale i crediti non ci sono.** Non e' che non ci starebbero — misurato,
     il piu' lungo prende 235px sui 323 della colonna e ci sta su una riga sola. E'
     che sul telefono tutta la didascalia sta sempre accesa, quindi il credito non
     sarebbe piu' la cosa che compare: sarebbe la quarta e la quinta riga su una tile
     che ne ha gia' tre, sopra un'immagine. Troppa informazione in poco spazio.
     Da qui il modo giusto di leggere questa riga: i crediti sono un dettaglio che si
     chiede, e sul telefono non c'e' modo di chiederlo. */
  .project-stack .tile-credits {
    display: none;
  }

  .project-stack .tile-name {
    font-size: 9px;
  }

  /* **I secondari sono più bianchi che sul computer**: 0,85 invece del 65% di
     `--ink-dim`. Là la didascalia compare all'hover, cioè quando la chiedi, e sta su una
     tile larga; qui è sempre accesa, su 8px, sopra un'immagine che le scorre sotto — e a
     65% si leggeva spenta invece che discreta. Il titolo resta bianco pieno, quindi la
     gerarchia regge lo stesso: 1 contro 0,85, invece di 1 contro 0,65. */
  .project-stack .tile-category,
  .project-stack .tile-year,
  .project-stack .tile-note {
    font-size: 8px;
    color: rgba(255, 255, 255, 0.85);
  }

  /* Su una finestra stretta il video occupa quasi tutta la larghezza e le frecce
     gli finiscono comunque sopra: si stringono ai bordi per stare il più possibile
     fuori dall'immagine. Il riquadro resta 44px — è la misura del dito, non del
     glifo, e stringere quella vorrebbe dire mancarle. */
  .project-player-nav.prev {
    left: 4px;
  }

  .project-player-nav.next {
    right: 4px;
  }
}

/* --- Riduzione animazioni --- */

@media (prefers-reduced-motion: reduce) {
  .nav-bar,
  .nav-label,
  .side-link-text,
  .hover-color-block,
  .project-tile-overlay,
  .tile-caption,
  .tile-preview,
  .about-photo,
  .project-player-nav,
  .voce-link,
  .lang-opt,
  .reader-nav,
  .ask-send,
  .ask-cancel {
    transition: none;
  }
}
