/* ===========================================================================
   Gallery a schermo intero il cui contenuto sta su R2 — caricata SOLO dalle
   pagine `type: gallery` (oggi /dev/illustrazioni-ai/), quindi qui dentro
   nient'altro. Copiata da andrea-dilorenzo-website (static/css/gallery.css):
   stessa struttura, stesse animazioni, stesse manopole. Differenze:
     - le celle le renderizza Hugo (data/dev_illustrations.yml) invece del JS;
     - niente monogramma "ADL": qui non c'è, e con lui sono spariti i blocchi
       che gli davano prospettiva e blend.
   Il body ha `is-rgallery`; le classi sono prefissate `rg-` per non incrociare
   il resto del sito (che comunque su questa pagina non è caricato).

   Due viste, stesso DOM (le celle NON vengono ricostruite: cambia solo la classe
   sul contenitore, e il JS anima il passaggio con una FLIP):
     .is-grid   griglia larga, ordine per RIGHE
     .is-pair   due colonne, immagini grandi
   =========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
a { color: inherit; text-decoration: none; }

/* ---- Top bar condivisa (assets/shared/topbar.css, montata da topbar.html) -----------
   Le variabili stanno su `:root` e non su `.rg`: `.nav` è FISSA e sta fuori da `.rg` (è
   montata da single.html come overlay, fratella nel markup), quindi `.rg` non è un suo
   antenato — le custom property non risalgono l'albero. `:root` è l'antenato comune a
   entrambi (stessa regola della nota "--tb-*" in CLAUDE.md). Tema chiaro, sui toni della
   gallery (`--rg-bg`/`--rg-ink` più sotto): qui i valori sono ripetuti in chiaro perché
   `:root` non vede le custom property di `.rg`. */
:root {
  --tb-sans: "Helvetica Neue", Arial, sans-serif;
  --tb-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
  --tb-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --tb-pad: 3.2vw;
  --tb-pill: rgba(17, 17, 17, 0.08);
  --tb-pill-hover: rgba(17, 17, 17, 0.14);
  --tb-fg: #111;
  --tb-fg-dim: rgba(17, 17, 17, 0.45);
  --tb-cta-bg: #111;
  --tb-cta-fg: #e7e7e7;
  --tb-card: #fff;
  --tb-card-fg: #111;
  --tb-card-muted: rgba(17, 17, 17, 0.42);
  --tb-link-hover: #1e2bff;
}

/* ⚠️ Bug di compositing Blink (stessa famiglia di quello già in CLAUDE.md, "z-index più
   alto che appare dietro un fratello con z-index più basso"), qui in una forma nuova: il
   backdrop blu del menu (`.menu-backdrop`, opaco, dentro `.nav`, z-index 100) su
   Chrome/Brave mostrava le foto sotto, tinte, invece di coprirle. Qualcosa dentro `.rg`
   (verificato: non è `perspective` — toglierla non cambia nulla; il sospetto è
   `.rg-scroll` con `overflow-y: auto`, che Blink promuove a layer composito proprio per
   lo scroll) resta su un layer composito PERMANENTE, non solo durante le transizioni, e
   Blink lo dipinge sopra il backdrop nonostante il suo z-index più basso. Su Safari
   (WebKit) era già corretto.
   Fix (verificato in pagina): promuovere ANCHE backdrop e pannello del menu a layer
   composito permanente, così Blink torna a ordinare per z-index — stesso principio del
   fix già in CLAUDE.md (promuovere il fratello non composito), applicato ai due elementi
   giusti.
   ⚠️ NON promuovere `.nav` stesso: `transform`/`will-change:transform` su un ANTENATO di
   un `position: fixed` lo rende il suo containing block (è la stessa regola di
   `perspective`) — promuovendo `.nav` invece dei suoi figli, `inset:0` su
   `.menu-backdrop`/`.menu-panel` si sarebbe risolto contro il box di `.nav` (~90px, la
   sua altezza) invece che contro il viewport: il backdrop copriva solo la barra.
   `.menu-backdrop`/`.menu-panel` non hanno discendenti fissi, quindi promuovere LORO è
   sicuro. Qui e non in assets/shared/topbar.css perché è un rimedio a un'interazione con
   QUESTA pagina (la sola con uno scroller a schermo intero sotto la barra) — altrove
   (food/dev/corp) il menu sta già sopra tutto senza bisogno di questo. */
.menu-backdrop, .menu-panel {
  transform: translateZ(0); will-change: transform; backface-visibility: hidden;
}

/* Testo per i soli lettori di schermo: il titolo vero (le lettere visibili sono
   finestrelle decorative, vedi .rg-tl). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* Profondità del warp: `perspective` è la distanza dell'osservatore dal piano, il
   translateZ degli elementi non deve mai avvicinarsi troppo a questo valore (a z =
   perspective la scala è infinita). Sta sul <body> perché è da lì che scende per
   eredità fino a .rg, dove il JS la rilegge (cssNum). */
body.is-rgallery { --rg-persp: 1100; background: var(--rg-bg, #e7e7e7); }
/* Il warp scaglia le celle ben oltre i bordi del viewport: senza questo comparirebbero
   le barre di scorrimento del documento mentre passano. */
body.is-rgallery { overflow: hidden; }

.rg {
  --rg-bg: #E7E7E7;
  --rg-ink: #111;
  --rg-pad: 3.2vw;          /* margine del contenuto */
  /* Il gap NON è un valore estetico qualsiasi: è calibrato sulla griglia a 6 colonne.
     Detta `w` la colonna, una verticale è alta w/ratio e una orizzontale su due
     colonne (2w + gap)/ratio: con gap = 0,25·w le due altezze si avvicinano abbastanza
     da tenere le righe regolari senza masonry. Con --rg-pad 3,2vw quel quarto vale
     ~3,2vw: è da lì che esce questo numero. Cambiando colonne o padding, rifare il conto. */
  --rg-gap: 3.2vw;
  --rg-cols: 6;             /* colonne della griglia (desktop) */
  /* Spazio riservato alla top bar condivisa (position: fixed, overlay — vedi sopra):
     senza, la prima riga di foto e il titolo finiscono sotto la barra. 64px copre la
     sua altezza reale su entrambi gli scaglioni (~64px mobile, fino a ~92px su desktop
     larghissimo si somma comunque a un --rg-top già proporzionale al viewport, quindi
     resta margine). Va sommato ovunque compaia --rg-top: qui e nella vista ravvicinata. */
  --rg-topbar: 64px;
  /* Tetti in ALTEZZA (le larghezze le dà la colonna): impediscono che una verticale molto
     stretta si mangi lo schermo. Non sono l'altezza delle celle, che segue le proporzioni. */
  --rg-top: calc(8vh + var(--rg-topbar));  /* da dove parte il contenuto: prima riga di foto E titolo */
  --rg-row-max: 42vh;       /* vista griglia */
  --rg-row-max-pair: 84vh;  /* vista ravvicinata */
  --rg-warp-z: 620;         /* quanto "esce dallo schermo" una cella che se ne va */
  --rg-warp-in: -900;       /* … e da quanto lontano arriva quando entra */
  --rg-warp-dur: 900;       /* ms */
  --rg-warp-step: 26;       /* stagger fra una cella e l'altra, ms */
  /* Passaggio griglia <-> coppia. Non è un movimento uniforme: l'immagine su cui si è
     cliccato è la più veloce e le altre la seguono tanto più lente quanto più sono
     lontane, come se le trascinasse.
       --rg-morph        ms dell'immagine cliccata (la più rapida)
       --rg-morph-drag   quanto si allunga la durata a distanza massima (0.85 = +85%)
       --rg-morph-lag    ritardo massimo di partenza, ms (il "ritardo della scia") */
  --rg-morph: 1050;
  --rg-morph-drag: 0.85;
  --rg-morph-lag: 240;
  --rg-hover: 1.045;        /* ingrandimento della cella sotto il puntatore, in griglia */

  position: fixed; inset: 0;
  background: var(--rg-bg); color: var(--rg-ink);
  font-family: "Helvetica Neue", Arial, sans-serif;
}

/* ---- Contenitore di scroll ----------------------------------------------------------
   `perspective` sta QUI, non sulla griglia: è il punto di vista dello spettatore, e deve
   restare fermo mentre il contenuto scorre. Il punto di fuga lo sposta il JS
   (--rg-ox/--rg-oy) sul punto in cui l'utente ha cliccato, così il warp parte da lì. */
.rg-scroll {
  position: absolute; inset: 0;
  overflow-y: auto; overflow-x: hidden;
  padding: var(--rg-top) var(--rg-pad) 12vh;
  perspective: calc(var(--rg-persp) * 1px);
  perspective-origin: var(--rg-ox, 50%) var(--rg-oy, 50%);
  scrollbar-width: none; -ms-overflow-style: none;
}
.rg-scroll::-webkit-scrollbar { width: 0; height: 0; display: none; }
/* Mentre l'immagine su cui si è cliccato è in volo lo scroll è bloccato: si sta muovendo in
   profondità e trascinarla nel frattempo mostrerebbe celle che rientrano da sole.
   Dura quanto l'ANCORA (--rg-morph), non quanto l'ultima cella della scia: quelle in coda
   si limitano a scivolare al loro posto e possono farlo anche se si scorre (il loro
   transform è una traslazione che va a zero, non c'è niente che possa saltare), e tenerlo
   chiuso fino all'ultima rendeva la pagina sorda per oltre due secondi. Chi lo toglie è morph(). */
.rg.is-warping .rg-scroll { overflow: hidden; }

.rg-status {
  margin: 0; padding: 2vh 0; max-width: 46em;
  font: 500 11px/1.8 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.1em; opacity: 0.55;
}
.rg-status[hidden] { display: none; }

/* ---- Griglia -------------------------------------------------------------------------
   Ordine per RIGHE (è l'ordine naturale di CSS Grid: si riempie una riga alla volta) e
   celle allineate in ALTO, così le immagini più basse lasciano aria sotto invece di
   essere stirate. Niente masonry a incastro: le righe restano leggibili come righe. */
.rg-grid {
  display: grid;
  grid-template-columns: repeat(var(--rg-cols), 1fr);
  gap: var(--rg-gap);
  align-items: start;
  /* `dense`: quando un'immagine larga due colonne non entra in coda a una riga, Grid la
     manda a capo lasciando scoperta l'ultima cella. Con `dense` quel posto viene preso da
     una foto successiva invece di restare vuoto. In cambio l'ordine può scavalcare di una
     posizione — solo lì, e la lettura resta per righe. */
  grid-auto-flow: row dense;
  /* Le celle si muovono in Z: senza questo la griglia appiattirebbe i figli sul proprio
     piano e la prospettiva di .rg-scroll non si vedrebbe. */
  transform-style: preserve-3d;
}

.rg-cell {
  margin: 0; padding: 0;
  display: flex; justify-content: center;
  cursor: zoom-in;
  /* Il tetto in ALTEZZA vive qui, sulla cella, e non come `max-height` sull'immagine come
     nella reference. Espresso come tetto di LARGHEZZA equivalente: altezza massima ×
     proporzioni (`--arf` = w/h, un numero puro che il template scrive dal data file).
     Perché non sull'immagine: `max-height` su un elemento rimpiazzato restringe anche la
     larghezza — mantenendo le proporzioni — SOLO se la larghezza è `auto`. Con `width:auto`
     però la larghezza dell'immagine è quella INTRINSECA, che con `srcset`+`sizes` non è più
     quella nativa del file ma il valore di `sizes` corretto per la densità: il layout
     finiva per dipendere da un suggerimento di download (foto piccole in vista
     ravvicinata). Con `width: 100%` la larghezza è definita e il browser clampa solo
     l'altezza: l'immagine si schiaccia. Spostando il tetto sulla cella non serve nessuna
     delle due: la cella si restringe, l'immagine la riempie, e le proporzioni le tiene il
     rapporto width/height dell'`<img>`. Nessuna dipendenza dalla dimensione intrinseca.
     La cella resta un item della griglia: rimpicciolita, va ricentrata nella sua colonna.
     ⚠️ `width: 100%` non è ridondante: `justify-self: center` toglie allo item lo stretch e
     lo manda in shrink-to-fit, cioè di nuovo alla dimensione INTRINSECA dell'immagine (il
     valore di `sizes`) — il problema che stiamo evitando. Con una larghezza definita la
     cella vale `min(colonna, tetto)` e basta.
     Effetto collaterale voluto: così la cella coincide con l'immagine, e la FLIP — che
     misura le celle — anima esattamente il rettangolo che si vede. Se la cella fosse più
     larga dell'immagine (verticali col tetto che morde), la scala calcolata sulla cella
     rimpicciolirebbe l'immagine di quella differenza nel primo fotogramma: uno scatto. */
  width: 100%;
  max-width: calc(var(--rg-row-max) * var(--arf, 0.75));
  justify-self: center;
  /* Il transform lo scrive il JS (warp e FLIP).
     Qui NON ci sono né `will-change` né `backface-visibility`, e non è una dimenticanza:
     promuovono la cella a layer composito, e ogni layer si tiene la propria texture — in
     vista ravvicinata una cella è più di mille pixel per lato. Al cambio di vista, che le
     fa crescere di parecchie volte in linea, verrebbero invalidate e ri-rasterizzate TUTTE
     insieme, comprese quelle fuori campo che non si muovono nemmeno. Non è tempo di main
     thread (il cambio classe costa 2-3 ms) e infatti non si vede in un profilo JS: è il
     compositor, ed era la causa dello scatto all'apertura della coppia.
     La promozione serve davvero solo alle celle che si stanno muovendo, e per il tempo in
     cui si muovono: gliela mette il JS inline (`fly()` in gallery.js), insieme a
     `backface-visibility` — che evita il flicker di WebKit sugli elementi che attraversano
     il piano dell'osservatore, ma promuove anch'esso, quindi vale la stessa regola. */
}
/* Quante colonne prende una cella: 1 per le verticali, 2 per le orizzontali, di più per
   formati molto larghi. Il numero lo calcola il template dalle proporzioni note nel data
   file (stessa formula di `spanFor` nel JS), perché dipende dal gap calibrato qui sopra.
   Solo in griglia — in vista ravvicinata le colonne sono due in tutto, e una foto che le
   prendesse entrambe spezzerebbe la coppia. */
.rg.is-grid .rg-cell { grid-column: span var(--span, 1); }
.rg-cell img {
  display: block;
  /* L'immagine è larga quanto la colonna e alta secondo le proporzioni native; quando è il
     tetto in altezza a mordere (verticali molto slanciate) è la LARGHEZZA a cedere, e
     l'immagine si restringe mantenendo le proporzioni — è l'algoritmo min/max degli
     elementi rimpiazzati: violato `max-height`, la larghezza usata diventa
     max-height × ratio. Niente bande vuote ai lati, quindi, nemmeno con `width: 100%`.
     Mai `height` fissa: ritaglierebbe o deformerebbe.

     ⚠️ `width: 100%` e NON `width: auto` (che è quello che usa la reference, dove le
     immagini non hanno srcset). Con `srcset` + `sizes` la larghezza INTRINSECA che il
     browser attribuisce all'immagine non è più quella nativa del file: è corretta per la
     densità in modo da valere esattamente quanto dice `sizes`. Con `width: auto` la
     larghezza dell'immagine diventa quindi il valore di `sizes` — che è tarato sulla
     GRIGLIA — e in vista ravvicinata le foto restavano larghe come in griglia invece di
     riempire la colonna, con `max-width: 100%` che non mordeva mai. Con `width: 100%` il
     layout dipende solo dalla colonna, e `sizes` torna a essere ciò che deve essere: un
     suggerimento su QUALE file scaricare, non una misura di layout (vedi `setSizes` in
     gallery.js, che lo rialza entrando nella vista ravvicinata).
     Le proporzioni le tiene il rapporto fra gli attributi `width`/`height` dell'`<img>`:
     larghezza definita + `height: auto` = altezza derivata, niente da violare. Il tetto in
     altezza è sulla CELLA (vedi sopra), non qui. */
  width: 100%; height: auto;
  max-width: 100%;
}
/* Cella ancora senza immagine: qui la larghezza serve, altrimenti il segnaposto (che non ha
   dimensioni intrinseche) collasserebbe a zero e il lazy loading tornerebbe a non mordere. */
.rg-cell.is-loading img { width: 100%; background: #dcdcdc; }

/* Hover in vista griglia: si ingrandisce TUTTO il rettangolo, non l'immagine dentro un
   riquadro fermo (che sarebbe un ritaglio, non un avvicinamento).
   Lo scale sta sull'IMMAGINE e non sulla cella di proposito: il transform della cella è di
   chi anima il passaggio griglia <-> coppia (la FLIP lo scrive inline), e i due si
   sovrascriverebbero a vicenda — l'hover farebbe saltare l'animazione a metà. Su elementi
   diversi convivono senza sapere l'uno dell'altro.
   Niente hover in vista ravvicinata: lì l'immagine è già grande e non è cliccabile. */
.rg-cell img { transition: transform 320ms cubic-bezier(0.22, 1, 0.28, 1); }
.rg.is-grid .rg-cell:hover img { transform: scale(var(--rg-hover)); }
/* Su touch `:hover` resta appiccicato all'ultimo elemento toccato: lì l'ingrandimento non
   ha senso e resterebbe acceso dopo il tap. */
@media (hover: none) {
  .rg.is-grid .rg-cell:hover img { transform: none; }
}
/* `aspect-ratio` qui NON è estetica, è ciò che fa funzionare il lazy loading: un'immagine
   non ancora caricata non ha dimensioni intrinseche, quindi senza questo le celle sarebbero
   alte quasi zero e l'intera griglia starebbe dentro la finestra di prefetch del browser —
   che le scaricherebbe TUTTE invece delle poche in vista. Con un'altezza riservata
   plausibile la griglia ha la sua lunghezza vera fin da subito e il lazy morde. Il valore
   arriva dal data file (proporzioni native); appena l'immagine è caricata la classe cade. */
.rg-cell.is-loading img { opacity: 0; aspect-ratio: var(--ar, 2 / 3); }

/* ---- Vista ravvicinata (due colonne) -------------------------------------------------
   Stesso DOM: cambia il numero di colonne e l'altezza di riga. Il passaggio NON è una
   transizione CSS su queste proprietà (grid-template-columns non anima in modo utile):
   lo anima il JS con una FLIP, misurando prima e dopo. */
/* Margini più stretti che in griglia: qui le foto sono il contenuto, l'aria attorno serve
   solo a separarle. Con `--rg-top` a 8vh come in griglia, un'immagine alta 84vh non ci
   stava nella finestra e andava scorsa di poco — fastidioso proprio dove si vuole guardare.
   `--rg-topbar` resta comunque: la barra è sempre sopra, anche qui (il titolo si toglie di
   mezzo — vedi `.rg.is-pair .rg-head` più sotto — ma le FOTO no, e senza quel margine la
   prima riga entrerebbe sotto la barra). */
.rg.is-pair { --rg-cols: 2; --rg-gap: 2vw; --rg-pad: 2vw; --rg-top: calc(4vh + var(--rg-topbar)); }
.rg.is-pair .rg-cell { max-width: calc(var(--rg-row-max-pair) * var(--arf, 0.75)); cursor: default; }

/* ---- Titolo + targhetta della sezione ---------------------------------------------------
   `.rg-head` è il contenitore che li tiene insieme: JS (placeTitle) sposta QUESTO, non il
   titolo da solo, così titolo e targhetta restano uniti nell'ordine giusto sia sotto la
   griglia (mobile: nel flusso, prima della griglia) sia nella corsia (desktop: fissi,
   il JS lo muove fra `root` e `scroller` a seconda dello scaglione — vedi gallery.js).
   Qui sotto lo stato MOBILE (in flusso); la corsia desktop è in fondo al file. */
.rg-title {
  margin: 0 0 var(--rg-gap);
  font-family: "Helvetica Neue", Arial, sans-serif; font-weight: 700; line-height: 1;
  /* Il corpo lo scrive `fitTitle()` in --fs; il clamp è il valore di partenza (e quello che
     resta se il JS non gira). È lo STESSO nei due stati: cambiarlo all'hover si vedeva come
     uno scatto. Lo sceglie il più largo fra titolo e alternativa — vedi buildTitle. */
  font-size: var(--fs, clamp(28px, 10vw, 46px));
  letter-spacing: 0.01em; text-transform: uppercase; color: var(--rg-ink);
}
.rg-title a { color: inherit; text-decoration: none; }

/* Targhetta da museo: la didascalia dell'opera, un `<p>` per paragrafo (il data file la
   scrive come lista — vedi single.html). Registro discreto — non deve competere col
   titolo né con le foto — quindi corpo piccolo, interlinea larga (si legge come un testo
   lungo, non come un'etichetta) e opacità ridotta.
   Margine PICCOLO fra un paragrafo e l'altro, GRANDE (--rg-gap, lo stesso spazio di
   sezione usato altrove) solo dopo l'ultimo, prima della griglia — quello lo mette lui
   sul proprio `margin-bottom`: con un margine uguale su tutti la lista di tre paragrafi
   apriva vuoti larghi quanto una sezione fra una riga di testo e l'altra. */
.rg-plaque {
  margin: 0 0 0.75em;
  max-width: 34em;
  font: 400 14.5px/1.65 "Helvetica Neue", Arial, sans-serif;
  letter-spacing: 0.005em; color: var(--rg-ink); opacity: 0.68;
}
.rg-title + .rg-plaque { margin-top: 0.6em; }
.rg-plaque:last-of-type { margin-bottom: var(--rg-gap); }

/* Lettere del titolo: ognuna è una finestrella alta una riga con dentro DUE glifi
   impilati — quello del titolo e quello di `data-alt` ("<DEV"). Sopra la griglia la
   colonnina scorre in su di 1em e ogni lettera è sostituita da quella che arriva dal
   basso; la finestrella intanto passa dalla larghezza di un glifo a quella dell'altro
   (--wa -> --wb, misurate dal JS in em), così le lettere non si accavallano né vengono
   tagliate — e le parole più corte crescono da zero, le più lunghe si richiudono.
   Lo stagger è `--i`, l'indice della lettera: la sostituzione corre da sinistra a destra. */
.rg-tw { white-space: nowrap; }   /* una parola non si spezza mai a metà */
/* Lo spazio fra una parola e l'altra. Serve perché le parole sono span affiancati SENZA
   spazi nel markup (buildTitle salta il carattere spazio e apre una nuova parola), quindi
   su una riga sola si leggerebbero attaccate — nella reference non si vedeva perché quel
   titolo è una parola sola. Sul margine DESTRO e non sinistro: quando le due parole
   finiscono su righe diverse, così resta in fondo alla riga (invisibile) invece di
   rientrare la seconda. */
.rg-tw:not(:last-child) { margin-right: 0.26em; }
.rg-tl {
  display: inline-block; vertical-align: top;
  height: 1em; overflow: hidden;
  width: var(--wa, auto);
}
.rg-tl-in { display: block; }
.rg-tl i { display: block; height: 1em; line-height: 1; font-style: normal; }
.rg-tl, .rg-tl-in {
  transition: width 460ms cubic-bezier(0.65, 0, 0.35, 1) calc(var(--i, 0) * 32ms),
              transform 460ms cubic-bezier(0.65, 0, 0.35, 1) calc(var(--i, 0) * 32ms);
}
.rg.is-back .rg-tl { width: var(--wb, 0); }
.rg.is-back .rg-tl-in { transform: translateY(-1em); }
/* Il simbolo di testa ("<") non sostituisce nessuna lettera: la sua finestrella parte
   chiusa e lui arriva da SINISTRA mentre si apre. Ha un glifo solo, quindi la regola
   verticale qui sopra non deve toccarlo. */
.rg-tl.is-lead .rg-tl-in { transform: translateX(-100%); }
.rg.is-back .rg-tl.is-lead .rg-tl-in { transform: translateX(0); }

/* ---- Pulsante di zoom-out ------------------------------------------------------------
   Circolare, in alto a destra: quattro angoli che rientrano verso il centro.
   `top` tiene conto della top bar (z-index 100, più alto di questo): senza la stessa
   clearance di `--rg-topbar` il pulsante nascerebbe sotto il pulsante Menu della barra,
   nello stesso angolo. */
.rg-out {
  position: fixed; top: calc(3vh + var(--rg-topbar)); right: 3vh; z-index: 5;
  width: 48px; height: 48px; padding: 0;
  border-radius: 999px; border: 1px solid rgba(0,0,0,.25);
  background: rgba(255,255,255,.72); color: var(--rg-ink);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  display: grid; place-items: center; cursor: pointer;
  opacity: 0; transform: scale(0.85);
  /* Invisibile in vista griglia, e anche INTOCCABILE: senza questo resterebbe un bersaglio
     trasparente che si mangia i click nell'angolo in alto a destra. */
  pointer-events: none;
  transition: opacity 300ms ease, transform 300ms cubic-bezier(0.16,1,0.3,1), background 200ms ease;
}
.rg-out[hidden] { display: none; }
.rg.is-pair .rg-out { opacity: 1; transform: none; pointer-events: auto; }
.rg-out:hover { background: #fff; }
.rg-out svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

/* ---- Mobile ---------------------------------------------------------------------------
   Sei colonne su uno schermo stretto sarebbero francobolli; e la vista ravvicinata passa a
   una colonna sola, che è già "il più vicino possibile". */
@media (max-width: 900px) {
  /* Due colonne e non tre: con tre, un'orizzontale larga due ne lascerebbe scoperta una
     (e il gap che allineerebbe le altezze varrebbe 6vw, troppo su uno schermo stretto).
     Con due colonne l'orizzontale prende semplicemente tutta la riga: nessun buco per
     costruzione, e a quella larghezza si legge come un'apertura. */
  .rg { --rg-cols: 2; --rg-row-max: 40vh; --rg-gap: 4vw; --rg-pad: 5vw; }
  .rg.is-pair { --rg-cols: 1; }
}

/* ---- Motion ridotto -------------------------------------------------------------------
   Niente warp né FLIP: il JS salta le animazioni e le celle compaiono al loro posto. */
@media (prefers-reduced-motion: reduce) {
  .rg-cell, .rg-cell img { transition: none !important; }
  /* La sostituzione delle lettere resta, ma secca: niente scorrimento. */
  .rg-tl, .rg-tl-in, .rg-title { transition: none !important; }
  .rg.is-grid .rg-cell:hover img { transform: none; }
}

/* ---- Corsia di sinistra (desktop) ------------------------------------------------------
   La griglia rinuncia alla PRIMA colonna. Le altre cinque restano larghe ESATTAMENTE come
   prima — il conto qui sotto è quello a sei colonne, e il padding a sinistra si mangia una
   colonna più il suo gap — quindi le foto non cambiano dimensione: cambia solo che una
   colonna resta vuota. È lì che si vedono titolo e targhetta, a filo della prima riga,
   senza che nessuna foto ci passi sotto.
   Solo in vista GRIGLIA: la ravvicinata è il "più vicino possibile" e resta a tutta
   larghezza — lì il blocco si toglie di mezzo. */
@media (min-width: 901px) {
  .rg {
    /* larghezza di UNA colonna nella griglia a sei: (contenuto - 5 gap) / 6.
       vw e non % perché .rg è fisso a tutto viewport e la barra di scorrimento è nascosta:
       i due valori coincidono, e così il conto si può fare senza conoscere il contenitore. */
    --rg-col: calc((100vw - 2 * var(--rg-pad) - 5 * var(--rg-gap)) / 6);
    --rg-lane: calc(var(--rg-col) + var(--rg-gap));   /* la colonna liberata, col suo gap */
  }
  .rg.is-grid { --rg-cols: 5; }
  .rg.is-grid .rg-scroll { padding-left: calc(var(--rg-pad) + var(--rg-lane)); }

  /* La posizione FISSA (corsia) sta sul CONTENITORE, non più sul titolo da solo: così
     titolo e targhetta si impilano nel flusso normale dentro un box che non si muove,
     invece di essere due elementi fissi indipendenti da tenere allineati a mano. */
  .rg-head {
    position: fixed; z-index: 3;
    left: var(--rg-pad);
    /* A filo della prima riga di foto. Con `line-height: 1` il top della "I" NON è il top
       della riga di testo: fra i due c'è il gap che il font si tiene sopra le maiuscole
       (Helvetica Neue ~0.17em). Senza toglierlo il titolo cadrebbe qualche px più in basso
       delle immagini. */
    top: calc(var(--rg-top) - 0.17em);
    width: var(--rg-col);
    transition: opacity 300ms ease;
  }
  .rg.is-pair .rg-head { opacity: 0; }

  .rg-head .rg-title {
    /* I titoli lunghi vanno a capo dentro la corsia invece di sbordare sulle foto. */
    margin: 0; overflow-wrap: break-word;
    /* Il corpo lo decide `fitTitle()` in gallery.js, che lo scala finché la parola più
       lunga è larga quanto la colonna: qui c'è solo il valore di partenza, che è anche il
       riferimento su cui il JS misura (e ciò che resta se il JS non gira). */
    font-size: var(--fs, clamp(17px, 1.6vw, 28px)); line-height: 1.02;
  }
  .rg-head .rg-plaque {
    /* Corpo più piccolo che in flusso mobile: qui la corsia è stretta (una colonna), un
       testo lungo al corpo mobile andrebbe a capo su troppe righe. */
    margin: 0.9em 0 0; max-width: none;
    font-size: 12.5px; line-height: 1.6; opacity: 0.6;
  }
}
