/* eccelsa - outdoor innovation
   Colori dal manuale di marca: #134074 primario, #0F3B60, #072535, bianco.
   Tipografia Poppins self-hostata. Nessun accento estraneo al manuale. */

/* I woff2 stanno dentro il CSS come data: URI, non come file accanto.
   Un font si richiede SEMPRE in modalita' CORS, anche self-hostato, e su una
   pagina aperta col doppio click l'origine e' 'null':
     Access to font at 'file:///.../poppins-300.woff2' from origin 'null' has
     been blocked by CORS policy: Cross origin requests are only supported for
     protocol schemes: chrome, chrome-untrusted, data, http, https.
   Non c'e' attributo o header che lo aggiri: `data:` e' l'unico schema di quella
   lista che un file su disco possa usare. Il sito deve restare leggibile in
   Poppins anche senza un server davanti, quindi i tre pesi viaggiano qui.
   Il prezzo, in produzione, e' 31 KB di base64 su un CSS che blocca il primo
   disegno. Si ripaga: sono 3 richieste in meno, e il testo nasce gia' in Poppins
   invece di comparire in font di sistema e riscriversi allo swap.
   Chi tocca i woff2 in web/fonts deve rigenerare queste tre righe, o restano
   quelli di prima: e' l'unico modo in cui questo blocco puo' mentire.

   Il peso 200 e' stato tolto: dichiarato e mai usato, l'extralight a display
   size sopra fotografia si sfilacciava e i titoli sono passati a 300. */
@font-face { font-family: Poppins; font-style: normal; font-weight: 300; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); }
@font-face { font-family: Poppins; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); }
@font-face { font-family: Poppins; font-style: normal; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format('woff2'); }

:root {
  --brand:     #134074;
  --brand-mid: #0F3B60;
  --field:     #072535;
  --field-up:  #0A3247;
  --ink:       #FFFFFF;
  --ink-dim:   rgb(255 255 255 / .82);

  --head-h:    68px;
  /* L'altezza della barra di progresso, che e' anche l'offset da cui parte
     l'header: la barra sta in cima e l'header le sta sotto, non sopra.
     E' una variabile e non piu' un 3px scritto tre volte. Il 21/08/2026 i tre
     posti erano due - `.progress` e l'`inset` di `.head` - e il terzo mancava:
     la cappa dell'header partiva dal bordo dell'header, cioe' 3px sotto il
     bordo dello schermo, e quei 3px non li copriva nessuno. Su mobile, dove la
     cappa e' campitura piena e non velatura, restava una fessura larga tutto lo
     schermo attraverso cui si vedevano scorrere i fotogrammi. */
  --progress-h: 3px;
  --pad-x:     clamp(1.25rem, 5vw, 5.5rem);
  --pad-y:     clamp(2rem, 7vh, 5rem);
  --ease:      cubic-bezier(.16, 1, .3, 1);

  /* Dispositivo grafico derivato dal pittogramma: i parallelogrammi del marchio
     hanno un'inclinazione di ~36 gradi (dx 74.71 / dy 54.61), cioe' un rapporto
     di 1,368 fra corsa orizzontale e verticale.
     Il taglio SCALA con l'elemento invece di essere fisso a 38x28px: su un
     bottone alto 53px una smussatura fissa mangiava mezzo bordo sinistro e
     sembrava un difetto, mentre su una fascia immagine da 300px spariva.
     Si ripete su pannelli, bottone, fascia immagine e footer: un dispositivo
     proprietario e' una regola che torna a scale diverse, non un angolo tagliato
     una volta sola. */
  --shear-ratio: 1.368;
  --shear-y:     20px;
}

/* `--shear-x` e `--shear-cut` vanno dichiarati SUGLI ELEMENTI che li usano, non
   su :root. Una proprieta' personalizzata si calcola dove viene dichiarata: su
   :root si sarebbe fissata sul --shear-y della radice e sarebbe scesa gia'
   risolta, dando lo stesso taglio da 27px al bottone da 54px e al pannello da
   153px, cioe' esattamente il difetto da correggere. */
.cta, .spec, .act__canvas, .open__canvas, .act__video, .open__frame {
  --shear-x:   calc(var(--shear-y) * var(--shear-ratio));
  --shear-cut: polygon(var(--shear-x) 0, 100% 0, 100% 100%, 0 100%, 0 var(--shear-y));
}

/* Ogni componente dichiara la propria corsa verticale, circa il 12-14% della
   propria altezza. L'angolo resta lo stesso ovunque, la smussatura resta in
   proporzione: e' questo che rende il taglio un dispositivo e non un vezzo. */
.cta  { --shear-y:  8px; }   /* bottone alto ~54px, 15% */
.spec { --shear-y: 22px; }   /* pannello alto ~181px, 12%. Era ~153px e 14%:
                                dal 20/08/2026 tre pannelli su sei hanno una riga
                                secondaria, e `align-items: stretch` sulla pista
                                alza tutti e sei alla stessa quota. Il taglio resta
                                in pixel fissi, quindi la sua proporzione scende. */

/* Le sette proprieta' che main.js riscrive a ogni giro di rAF, dichiarate come
   numeri invece che come testo. Senza @property una custom property e' una
   sequenza di token grezzi: il motore la ripassa dal parser a ogni scrittura,
   e queste si riscrivono fino a sette volte per fotogramma su tutta la corsa.
   Registrate, il valore e' gia' un numero al momento della scrittura.

   `initial-value` NON e' libero: registrare una proprieta' la rende sempre
   valida, quindi il ripiego scritto negli `var(--x, N)` piu' sotto non scatta
   mai piu'. Ogni valore qui deve essere lo STESSO che sta in quei ripieghi, o
   il giorno in cui l'atto non e' ancora stato toccato dal JS la pagina parte
   da un altro numero:
     --lead e --veil-k valgono 1 a riposo (testo e velo pieni),
     --run, --out, --j, --seam-t, --seam-b valgono 0 (corsa non cominciata).

   `inherits: true` per tutte, perche' e' il comportamento che avevano prima:
   --out e --j si scrivono sull'atto e si leggono su un discendente, --seam-t
   e --seam-b si leggono su ::before e ::after. Metterle a false le staccherebbe
   in silenzio. */
@property --run    { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --out    { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --j      { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --lead   { syntax: '<number>'; inherits: true; initial-value: 1; }
@property --veil-k { syntax: '<number>'; inherits: true; initial-value: 1; }
@property --seam-t { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --seam-b { syntax: '<number>'; inherits: true; initial-value: 0; }

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

/* Lo smooth-scroll globale, con l'ancora dell'header, farebbe attraversare 15
   schermate di scrubbing martellando rAF e decode. Salto istantaneo. */
html { scroll-behavior: auto; }

body {
  margin: 0;
  background: var(--field);
  color: var(--ink);
  font-family: Poppins, ui-sans-serif, system-ui, sans-serif;
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
}

/* ---------------------------------------------------------------- prologo */

/* Tre secondi prima del sito: il marchio si monta una lama alla volta su
   campitura piena, le lame escono insieme, il campo resta vuoto un istante e
   poi il velo si dissolve sulla schermata di apertura.

   Il marchio finisce di uscire a 1,958s e la dissolvenza comincia a 2,25s: in
   mezzo ci sono 292ms di campitura sola. Erano il margine di sicurezza quando il
   prologo era un filmato, che parte in ritardo e va a un orologio diverso;
   adesso e' un'animazione CSS come il velo, quindi lo stesso clock e nessun
   margine da tenere. Restano perche' sono diventati una battuta: il marchio se
   ne va, il campo resta vuoto un istante, poi si scopre il sito.

   Si SCOPRE, non arriva. Il velo era la prima meta' di uno stacco in due tempi:
   si toglieva di colpo, e sotto la schermata di apertura si montava da sola in
   750ms (diaframma, marchio, titolo, invito, su una variabile --boot). Erano due
   ingressi di fila per la stessa schermata, e il secondo ripeteva quello che il
   prologo aveva appena finito di dire. Adesso sotto il velo c'e' la schermata
   finita e ferma: il prologo consegna il sito invece di annunciarlo due volte.

   DISSOLVENZA e non piu' stacco netto, ed e' un cambio di regola, non un
   ripensamento. Lo stacco secco era giusto finche' sopra e sotto c'era lo stesso
   --field: quando il velo spariva, campitura piatta su campitura piatta identica
   non aveva niente da mostrare, e una dissolvenza avrebbe solo fatto attraversare
   due blu uguali. Adesso sotto non c'e' piu' campitura: c'e' una fotografia
   all'ora blu illuminata, con sopra marchio, logotipo e payoff. Fra quella e il
   campo pieno c'e' tutto da mostrare, e toglierlo di colpo sbatte. Lo stesso
   ragionamento di prima, applicato a quello che c'e' sotto adesso.

   750ms, cioe' esattamente la durata che aveva il montaggio --boot: il tempo
   totale prima del sito resta quello di sempre (2,25 + 0,75 = 3s), cambia solo
   che quei 750ms sono un gesto unico invece di cinque parti che arrivano una
   alla volta.
   La curva e' la smoothstep del resto del file: entra e si posa morbida invece
   di scattare, che su una dissolvenza a pieno schermo si vede.

   `visibility: hidden` sull'ultimo fotogramma resta: a opacita' zero il velo e'
   invisibile ma ancora dipinto e ancora nell'albero. `pointer-events: none` sta
   sulla regola e non sull'animazione perche' vale sempre: il velo non riceve
   click in nessun momento della sua vita, ed e' quello che permette la
   dissolvenza senza che 750ms di strato semitrasparente rubino il primo tocco.
   Zero JavaScript: l'animazione arriva in fondo da sola, quindi il velo non puo'
   restare incastrato se main.js non arriva o muore prima. */
@keyframes prologo {
  0%, 75% { opacity: 1; }
  100%    { opacity: 0; visibility: hidden; }
}

.prologo {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  background: var(--field);
  color: var(--ink);
  pointer-events: none;
  animation: prologo 3s cubic-bezier(.5, 0, .5, 1) both;
}

/* Il marchio e' l'unica cosa in campo, quindi sta piu' largo di come sta
   nell'impaginato (nella firma di marca, dove e' piu' grande, arriva a 7,1rem),
   ma un terzo di finestra e non tutta: a piena altezza tre poligoni bianchi su
   campitura piena diventano una superficie, non un marchio.
   In vh e non in vw perche' il marchio e' stretto (rapporto 0,38): l'altezza e'
   sempre il vincolo, e un termine in vw entrerebbe in gioco solo in verticale,
   dove rimpicciolirebbe senza motivo. Pavimento e tetto in rem tengono i due
   estremi, telefono in orizzontale e schermo grande.

   overflow visible, e non e' cosmetica: le lame traslano di 56,55 unita' su un
   viewBox larga 110,13, cioe' escono dal proprio box. Col ritaglio predefinito
   dell'SVG mezzo marchio veniva tagliato lungo il bordo del box per tutta la
   corsa, che si legge come un rettangolo trasparente sovrapposto al marchio. La
   corsa deve avvenire in aria libera: qui attorno non c'e' altro che campitura. */
.prologo__mark {
  display: block;
  height: clamp(7rem, 34vh, 20rem);
  width: auto;
  overflow: visible;
}

/* La corsa di entrata, in unita' del viewBox invece che in pixel: 41,34 e' il
   12% dell'altezza del fotogramma riportato nel sistema del marchio, e 56,55 e'
   quel valore per --shear-ratio.
   La direzione non e' scelta a occhio: e' l'asse di estrusione del pittogramma,
   i suoi ~36 gradi, cioe' la stessa inclinazione con cui il marchio e'
   costruito e con cui il sito taglia pannelli, bottone e fasce immagine.
   L'uscita e' la stessa corsa proseguita dall'altra parte: la lama attraversa
   invece di tornare indietro, come un pannello che scorre su un binario. */
@keyframes lama-entra {
  from { opacity: 0; transform: translate(56.55px, -41.34px); }
}

@keyframes marchio-esce {
  to { opacity: 0; transform: translate(-56.55px, 41.34px); }
}

/* La curva e' smoothstep, t*t*(3-2t), la stessa con cui il sito addolcisce
   l'uscita della firma (vedere --eo piu' sotto): qui vive nel tempo invece che
   nella posizione, ma e' la stessa funzione, e entrate e uscite si posano invece
   di scattare ai due estremi.
   `both`: durante il ritardo la lama tiene lo stato iniziale, cioe' e'
   trasparente e fuori posizione invece di lampeggiare in posizione e poi
   ripartire. */
.prologo__lame > path {
  animation: lama-entra .625s cubic-bezier(.5, 0, .5, 1) both;
}

/* Sfalsate di 125ms su una corsa di 625, cioe' il 20%: lo stesso rapporto
   sfalsamento/corsa delle quattro parti della firma. Entrano sfalsate perche' lo
   sfalsamento e' quello che fa leggere un arrivo. */
.prologo__lame > path:nth-child(1) { animation-delay: .125s; }
.prologo__lame > path:nth-child(2) { animation-delay: .25s; }
.prologo__lame > path:nth-child(3) { animation-delay: .375s; }

/* Escono invece tutte insieme, quindi l'uscita sta sul gruppo e non sulle lame:
   sfalsare anche l'uscita non farebbe leggere una partenza, farebbe leggere tre
   pezzi che si staccano. Sul gruppo vuol dire anche che le due animazioni non si
   contendono `transform` e `opacity`: si compongono, e la lama centrale conserva
   il proprio fill-opacity .72 attraverso entrambe. Vuol dire anche che il marchio
   si dissolve come un oggetto solo: con l'opacita' sulle singole lame, quelle che
   si sovrappongono si vedrebbero l'una attraverso l'altra mentre svaniscono.

   625ms come la corsa d'entrata, non i 500 di prima. L'entrata ha 625ms piu' 375
   di sfalsamento per farsi leggere; un'uscita in 500 arrivava piu' svelta di
   quanto il marchio fosse arrivato, e su un gesto che e' la stessa corsa
   proseguita dall'altra parte la differenza si sentiva come una fretta. */
.prologo__lame {
  animation: marchio-esce .625s cubic-bezier(.5, 0, .5, 1) 1.333s both;
}

/* Qui c'era --boot, la seconda meta' dello stacco: un numero da 0 a 1 su 750ms
   che apriva il diaframma della soglia e faceva entrare marchio, titolo e invito
   in quattro tempi sfalsati, tutto dopo che il velo se n'era andato.
   Non c'e' piu', e con lui non c'e' piu' niente che si monti al caricamento.
   Sotto il velo la schermata e' gia' quella finita: fotografia a pieno campo e
   firma di marca in posizione. La barra di progresso non ha piu' bisogno della
   sua dissolvenza (era legata a --boot): sta sotto il velo per z-index, quindi
   si scopre insieme a tutto il resto invece di accendersi da sola.
   L'unica cosa che si muove da sola resta il prologo qui sopra. Tutto quello che
   succede dopo lo muove lo scroll, che e' la regola del resto della pagina. */

/* ---------------------------------------------------------------- progresso */

.progress {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 30;
  height: var(--progress-h);
  background: rgb(255 255 255 / .12);
}

/* Bianco, non blu di marca: navy su quasi-nero era invisibile, e questo e'
   l'unico strumento di orientamento su una pagina lunga. */
.progress i {
  display: block;
  height: 100%;
  width: 100%;
  background: rgb(255 255 255 / .92);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

/* ---------------------------------------------------------------- header */

.head {
  position: fixed;
  inset: var(--progress-h) 0 auto 0;
  z-index: 20;
  height: var(--head-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-inline: var(--pad-x);
  pointer-events: none;
  opacity: 0;
  /* `visibility: hidden` e non solo opacita' zero, e non e' ridondanza.
     A opacita' zero la barra e' invisibile e non riceve click, ma i suoi due
     link restano nell'ordine di tabulazione: chi naviga da tastiera in cima alla
     pagina metteva il fuoco su "eccelsa" e su "Parliamone" senza vedere ne' l'uno
     ne' l'altro ne' il proprio anello di fuoco. Due tabulazioni nel vuoto prima
     di arrivare al contenuto, e nessun modo di capire dove si e'.
     `visibility` li toglie dall'ordine di tabulazione e dall'albero
     dell'accessibilita' finche' la barra non serve. E' animabile - commuta a
     scatto ma alla fine della transizione - quindi va dichiarata anche qui, o la
     comparsa avverrebbe senza dissolvenza. */
  visibility: hidden;
  transition: opacity .5s var(--ease), visibility .5s var(--ease);
}

/* Il fondo sta su uno pseudo-elemento e non sulla barra perche' deve essere
   PIU' ALTO di lei: la sfumatura ha bisogno di finire sotto il testo
   dell'header, non addosso. Assoluto, quindi resta fuori dalla disposizione
   flex dei tre blocchi; `z-index: -1` lo tiene dietro a marchio, indicatore e
   bottone senza uscire dal contesto di impilamento della barra, cioe' senza
   finire dietro la pagina.
   A desktop resta una velatura, non un fondo: qui sotto ci scorre la
   fotografia a pieno campo per tredici schermate, e il testo che potrebbe
   attraversarla e' gia' portato a zero dal raccordo fra atti molto prima di
   arrivare quassu'. */
.head::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  z-index: -1;
  height: calc(var(--head-h) + 1.25rem);
  background: linear-gradient(to bottom, rgb(7 37 53 / .58), rgb(7 37 53 / .20) 62%, rgb(7 37 53 / 0));
}

.head.is-visible { opacity: 1; visibility: visible; }
.head.is-visible a { pointer-events: auto; }

/* Contatto raggiungibile da qualunque punto: prima era sepolto in fondo. */
/* Target minimo 44px su tutti gli elementi interattivi, anche a desktop. */
.head__cta {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--ink);
  text-decoration: none;
  font-size: .8125rem;
  font-weight: 400;
  letter-spacing: .16em;
  text-transform: uppercase;
  white-space: nowrap;
  padding: 0 1.15rem;
  border: 1px solid rgb(255 255 255 / .55);
  transition: background .35s var(--ease), color .35s var(--ease), border-color .35s var(--ease);
}

.head__cta:hover,
.head__cta:focus-visible { background: var(--ink); color: var(--field); border-color: var(--ink); }

.head__pos {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: .7em;
  font-size: .75rem;
  font-weight: 400;
  letter-spacing: .2em;
  /* Con .2em fra le lettere lo spazio fra parole non si vede piu': va rialzato
     insieme, altrimenti il titolo dell'atto legge come una parola sola. */
  word-spacing: .3em;
  text-transform: uppercase;
  color: var(--ink-dim);
  white-space: nowrap;
  overflow: hidden;
}

.head__pos [data-pos-n] { font-variant-numeric: tabular-nums; color: var(--ink); }

@media (max-width: 900px) { .head__pos [data-pos-label] { display: none; } }
@media (max-width: 480px) { .head__pos { display: none; } }

/* ---------------------------------------------------------------- lockup */

.lockup { display: inline-flex; align-items: center; gap: .7em; color: var(--ink); text-decoration: none; }
a.lockup { min-height: 44px; }
.mark { height: 1em; width: auto; display: block; }
.lockup__word { font-weight: 300; letter-spacing: -.01em; line-height: 1; }

.lockup__tag {
  display: block;
  font-size: max(11px, .32em);
  font-weight: 300;
  letter-spacing: .07em;
  color: var(--ink-dim);
  margin-top: .55em;
}

.lockup--sm { font-size: 1.3rem; }
.lockup--sm .mark { height: 1.7em; }

.lockup--lg {
  font-size: clamp(2.1rem, 4.6vw, 3.4rem);
  margin-bottom: clamp(1.5rem, 3.5vh, 2.5rem);
}
.lockup--lg .mark { height: 2.1em; }
.lockup--lg .lockup__stack { text-align: left; }

/* ---------------------------------------------------------------- act */

.act { position: relative; height: var(--len, 220vh); }

/* Le altezze stanno qui e non in attributi `style=` inline, cosi' la CSP di
   produzione puo' restare `style-src 'self'` senza 'unsafe-inline'.
   Per gli atti orizzontali questi valori sono solo il ripiego senza JS: a
   runtime l'altezza la ricalcola main.js dalla corsa del binario. */
/* Accorciati da 210-250vh a 180. Sedici schermate per sei messaggi erano
   lunghezza gratuita, e accorciare migliora anche lo scrubbing: gli stessi 30
   fotogrammi si distribuiscono su meno scroll, quindi meno pixel fra un
   fotogramma e il successivo. */
/* L'atto 03 non compare qui: e' fuso con la soglia e la sua altezza la dichiara
   `.act--open` piu' sotto. Un `.act[data-act="03"]` avrebbe anche vinto per
   specificita' (classe + attributo contro una classe sola). */
.act[data-act="02"] { --len: 180vh; }   /* il tetto */
/* Le vetrate non traslano piu' (act--still): il JS non ne ricalcola l'altezza e
   questo valore e' quello vero. Allineato agli altri atti a soli fotogrammi:
   a 250vh la sezione teneva lo sticky per due schermate e mezzo con il testo
   fermo, cioe' una pausa, non un passaggio. */
.act[data-act="01"] { --len: 180vh; }   /* vetrate */
.act[data-act="05"] { --len: 180vh; }   /* dentro */
.act[data-act="04"] { --len: 240vh; }   /* specifiche, orizzontale: la ricalcola il JS */
.act[data-act="06"] { --len: 180vh; }   /* chiusura */

.act__stage {
  position: sticky;
  top: 0;
  /* `100svh`, ed e' l'unica delle tre che non paga niente. Il commento che
     stava qui sceglieva `vh` per non far muovere il palcoscenico durante lo
     scrub, e chiudeva cosi': "va guardato su un telefono vero prima di
     pubblicare. Se desse fastidio, la riga da rimettere e' questa sola." E'
     stato guardato, su un iPhone 14 Pro, e la riga e' questa.
     Misurato li': `100vh` vale 735px, il visibile va da 674 a 735. Quindi
     `vh` non si muove ma taglia - 40px all'arrivo, fino a 61 scorrendo - e
     `dvh` non taglia ma muove. `svh` non fa ne' l'uno ne' l'altro.
     Il costo dichiarato di `svh` sono 61px di riga testo non usati a barra
     nascosta, e non si vedono: sotto il palcoscenico c'e' la sezione con
     sfondo trasparente, quindi il body a `rgb(7 37 53)`, cioe' --field, lo
     stesso colore del campo su cui sta il testo.
     La premessa del vecchio commento - che `dvh` farebbe rimisurare il canvas -
     e' vera solo per la soglia: gli altri atti hanno la fascia legata alla
     LARGHEZZA, e il loro canvas resta identico a 735 come a 674.
     Vale per i palcoscenici incollati. Quelli degli atti orizzontali sotto i
     767px sono statici e restano alti quanto il contenuto (vedi
     `.act--h .act__stage`): forzarli a una schermata li fa sbordare sui vicini,
     misurato l'atto 01 di 263px e l'atto 04 di 841. */
  height: 100svh;
  overflow: hidden;
  display: grid;
  /* Senza il vincolo, il binario orizzontale (piu' largo del viewport) allarga
     la colonna della griglia: su mobile il canvas veniva disegnato a 1903px
     invece che a 375, fuori misura e fuori posizione. */
  grid-template-columns: minmax(0, 1fr);
}

.act__canvas,
.open__canvas,
.act__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* L'atto 05 non scorre fotogrammi, riproduce una clip in loop. Il canvas fa il
   cover a mano in drawImage ancorandolo al punto di messa a fuoco dell'atto;
   qui lo stesso lavoro lo fa `object-fit` e la percentuale la scrive main.js
   dallo stesso `data-focus`, cosi' i due meccanismi restano tarati sullo stesso
   numero invece di divergere.
   Il fondo di marca sotto e' quello che si vede finche' la clip non e' pronta,
   ed e' lo stesso che il canvas si campisce da solo in paintField. */
.act__video {
  object-fit: cover;
  background: var(--field);
}

/* CUCITURE FRA ATTI
   Due palcoscenici sticky si succedono con un taglio netto a 1px: il precedente
   scorre in alto mentre il successivo entra dal basso, e per una schermata
   intera si vedono due fotografie diverse separate da una riga.
   Qui il bordo inferiore dell'atto uscente e quello superiore dell'entrante
   sfumano nel colore di fondo. I due bordi si incontrano gia' sfumati: al posto
   della riga c'e' una dissolvenza attraverso il blu di marca.
   Si accendono SOLO agli estremi della corsa (--seam-t e --seam-b le scrive
   main.js): a meta' atto valgono 0 e la fotografia e' a pieno campo.
   Il gradiente finisce su rgb(7 37 53 / 0) e non su `transparent`, che
   interpolerebbe passando per il nero e lascerebbe una banda grigia.
   Le due fasce sono gli pseudo-elementi di `.act__seams`, un elemento vuoto che
   crea main.js, e non quelli di `.act__stage` come erano prima. La differenza
   non e' di stile ma di costo: `--seam-t` e `--seam-b` si riscrivono a ogni
   frame, e una custom property invalida lo stile di tutto cio' che sta sotto
   l'elemento su cui e' scritta: su `.act__stage` sono i pannelli, i titoli e
   tutto il testo dell'atto. Su un elemento senza figli il ricalcolo si ferma. */
.act__seams {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}

.act__seams::before,
.act__seams::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 16vh;
}

.act__seams::before {
  top: 0;
  background: linear-gradient(to bottom, var(--field), rgb(7 37 53 / 0));
  opacity: var(--seam-t, 0);
}

.act__seams::after {
  bottom: 0;
  background: linear-gradient(to top, var(--field), rgb(7 37 53 / 0));
  opacity: var(--seam-b, 0);
}

/* Unica eccezione: il primo atto e' anche il primo elemento della pagina. Sopra
   non ha nessun palcoscenico da cui arrivare, quindi non c'e' nessun taglio da
   cucire: la cucitura sarebbe solo una fascia scura sul bordo alto del
   fotogramma di apertura. Quella in basso resta e cuce verso l'atto 02. */
.act--open .act__seams::before { display: none; }

/* ------------------------------------------------------- passaggio fra atti */

/* Le cuciture qui sopra risolvono la RIGA, non la schermata. Fra la fine di un
   atto e l'inizio del successivo restava comunque una schermata intera in cui
   il palcoscenico uscente scorre in su e quello entrante sale da sotto: cento
   vh di scroll in cui l'unica cosa che si legge e' che due fotografie stanno
   scivolando. Sfumare il taglio nasconde il difetto, non riempie la schermata.
   Qui non scivola piu' niente. Per tutta la corsa del passaggio i due
   palcoscenici stanno fermi e sovrapposti a pieno campo, e l'uscente si
   dissolve su quello entrante con un respiro di scala: l'ultimo fotogramma di
   una scena diventa il primo dell'altra. E' il raccordo del cinema, ed e'
   l'unica transizione che non aggiunge niente sopra la fotografia: non c'e'
   nessun elemento nuovo in pagina, ci sono solo le due scene.
   La pagina non si allunga di un pixel: il passaggio vive dentro la schermata
   di scroll che c'era gia'.
   main.js scrive UN numero, --j, sui due atti coinvolti: 0 quando il bordo
   basso dell'uscente tocca il fondo della finestra, 1 quando l'entrante e' in
   posizione. Tempi, ampiezza del respiro e curva stanno qui.
   Sotto i 768px niente di tutto questo: gli atti sono fasce impilate, il testo
   sta sul fondo pieno e non c'e' nessun palcoscenico che scorre sull'altro. */
/* ---------------------------------------------------------- il confine

   "Desktop" vuol dire largo E ALTO. Il confine di questo sito ha sempre chiesto
   solo la larghezza, e il guasto era l'altezza: un telefono girato e' largo 734
   punti - 852 con `viewport-fit=cover` - e alto 283. Con una domanda sulla sola
   larghezza quel telefono cadeva nel ramo desktop non appena si adottava
   `cover`, e riceveva palcoscenici incollati alti quanto una schermata dentro
   una schermata che non c'e'.
   500 punti separa: un portatile a 1440x900 e' fuori, un telefono girato a 283
   o a 430 e' dentro. Chi tiene una finestra desktop piu' bassa di 500 riceve il
   ramo corto, ed e' giusto: e' esattamente il caso che il ramo corto risolve.
   `web/main.js` legge la STESSA condizione: vedere il commento a IMPILATO. */
@media (min-width: 768px) and (min-height: 501px) {
  .act.is-leaving,
  .act.is-entering {
    /* Il nucleo della dissolvenza si prende l'80% centrale della corsa: un
       decimo per parte resta scena piena, cioe' il tempo di riconoscerla prima
       che cominci a cedere e dopo che e' arrivata. Senza quelle due battute il
       raccordo comincia mentre l'occhio sta ancora leggendo il titolo.
       Smoothstep, la stessa curva del diaframma e della firma: la dissolvenza
       parte e arriva morbida invece di scattare ai due estremi. */
    --d: clamp(0, calc((var(--j, 0) - .10) / .80), 1);
    --e: calc(var(--d) * var(--d) * (3 - 2 * var(--d)));
  }

  /* Fermi e sovrapposti. Senza `fixed` i due palcoscenici continuerebbero a
     scorrere sotto la dissolvenza, cioe' si vedrebbero due fotografie che
     scivolano E si dissolvono: il movimento che si voleva togliere, piu' uno.
     L'altezza resta quella dichiarata su .act__stage, quindi il canvas non
     viene ne' rimisurato ne' ridisegnato, e la sezione tiene il proprio posto
     perche' la sua altezza e' scritta a parte (--len, o il calcolo del JS per
     gli atti orizzontali).
     A passaggio finito lo `sticky` rimette ogni palcoscenico esattamente dove
     lo teneva il `fixed`: l'entrante in cima alla finestra, l'uscente gia'
     fuori campo e per giunta trasparente. Nessun salto, in nessuno dei due
     versi di scroll. */
  .act.is-leaving .act__stage,
  .act.is-entering .act__stage { position: fixed; top: 0; left: 0; right: 0; }

  /* L'uscente sta SOPRA e si spegne: e' lei che se ne va. Senza z-index
     vincerebbe l'entrante, che viene dopo nel documento, e il raccordo
     andrebbe al contrario. */
  .act.is-leaving .act__stage { z-index: 2; opacity: calc(1 - var(--e)); }

  /* Il respiro. La scena che esce si allontana appena, quella che arriva si
     posa: sono i due mezzi gesti che fanno leggere un raccordo invece di due
     immagini sovrapposte. Il 6% e' quanto basta perche' si senta senza che si
     veda: sopra il 10% diventa uno zoom, e uno zoom su una fotografia di
     architettura si legge come un errore di inquadratura.
     Sul media e non sul palcoscenico: cosi' i titoli si dissolvono senza
     ingrandirsi, che a corpo display sarebbe la prima cosa a saltare
     all'occhio. */
  .act.is-leaving .act__canvas,
  .act.is-leaving .open__canvas,
  .act.is-leaving .act__video { transform: scale(calc(1 + var(--e) * .06)); }

  .act.is-entering .act__canvas,
  .act.is-entering .open__canvas,
  .act.is-entering .act__video { transform: scale(calc(1.06 - var(--e) * .06)); }

  /* I due testi non si attraversano. Due fotografie sovrapposte a mezza
     opacita' si leggono come un raccordo; due blocchi di testo sovrapposti si
     leggono come un errore di stampa, e negli atti orizzontali erano
     addirittura tre (titolo fisso piu' pannelli).
     Quindi il testo dell'uscente se ne va nella prima meta' della dissolvenza e
     quello dell'entrante arriva nella seconda, con un buco di sedici punti in
     mezzo: li' in campo ci sono solo le due fotografie che si attraversano, che
     e' esattamente la cosa che si vuole far vedere.
     La soglia dell'atto e la firma di marca non sono in elenco perche' a questo
     punto della corsa sono gia' spente dalle loro rampe (--open e --eo).

     Le due rampe sono CORTE e stanno attaccate al buco, non lunghe quanto tutta
     la corsa. Scritte lunghe, il testo entrante arrivava pieno solo alla fine
     del raccordo, cioe' molto dopo che la sua fotografia aveva preso il campo:
     misurato a meta' corsa, scena entrante al 100%, uscente al 32%, e il testo
     entrante ancora al 25%. Si legge come una scena senza scritte, ed e'
     esattamente cosi' che e' stato segnalato.
     Ora ciascuna rampa dura .12: l'uscente e' via poco prima del buco,
     l'entrante e' pieno poco dopo. Il buco resta quello di prima, i sedici
     punti fra .42 e .58, e i due testi continuano a non incontrarsi mai. */
  .act.is-leaving .act__copy,
  .act.is-leaving .act__track { opacity: clamp(0, calc((.42 - var(--e)) / .12), 1); }

  .act.is-entering .act__copy,
  .act.is-entering .act__track { opacity: clamp(0, calc((var(--e) - .58) / .12), 1); }

  /* Il titolo fisso ha gia' una sua opacita', quella con cui cede il campo ai
     pannelli (--lead). Scritta come le altre, la rampa del passaggio gliela
     SOSTITUIVA: il titolo era spento da un pezzo, il passaggio lo riportava a 1
     e "Come e' fatta" ricompariva a piena opacita' sopra i pannelli gia' scorsi
     a meta' campo, che e' il difetto segnalato. Le due opacita' non sono in
     concorrenza, sono in serie: si moltiplicano. Chi non ha un --lead scritto
     legge il ripiego 1 e si comporta esattamente come prima. */
  .act.is-leaving .panel-lead {
    opacity: calc(var(--lead, 1) * clamp(0, calc((.42 - var(--e)) / .12), 1));
  }

  .act.is-entering .panel-lead {
    opacity: calc(var(--lead, 1) * clamp(0, calc((var(--e) - .58) / .12), 1));
  }

  /* Cuciture spente durante il passaggio. Esistono per nascondere la riga di
     taglio fra due palcoscenici che scorrono, e qui non ne scorre nessuno;
     lasciate accese sarebbero due bande scure in mezzo alla dissolvenza, una
     sul fondo dell'uscente e una in cima all'entrante, cioe' proprio nei due
     punti in cui le due scene si stanno sovrapponendo.
     Restano per l'ultimo passaggio, quello verso la richiesta di sopralluogo,
     che e' una sezione a scorrimento normale e non si puo' inchiodare.

     Il selettore e' `.act__seams`, non `.act__stage`. Nato
     `.act__stage::before/::after`, cioe' due pseudo-elementi che non esistono:
     le cuciture erano state spostate su un elemento proprio dieci minuti prima
     che questa regola venisse scritta (commit 1947599, poi c8ec6ee), e nelle
     nove revisioni successive del foglio nessuno se n'e' accorto, perche' una
     regola che non colpisce niente non da' nessun errore.
     Misurato mentre succedeva: a `--j` 0,5 le due cuciture erano a opacita'
     PIENA su tutti e cinque i confini, e il bordo basso della scena usciva
     23 livelli su 255 piu' scuro di quanto dovesse. Cioe' esattamente il
     difetto che il commento qui sopra dice di aver tolto. */
  .act.is-leaving .act__seams::before,
  .act.is-leaving .act__seams::after,
  .act.is-entering .act__seams::before,
  .act.is-entering .act__seams::after { opacity: 0; }

  /* L'ULTIMO atto non ha un raccordo che lo dissolva: dopo di lui non c'e' un
     altro palcoscenico da inchiodare ma la richiesta di sopralluogo, che e' una
     sezione a scorrimento normale (vedi qui sopra e in main.js). Il suo testo
     esce quindi scorrendo, e su 1440x900 "Progettiamo il tuo spazio" passava
     dentro il marchio della barra per 210px di corsa: l'unico attraversamento
     rimasto a desktop durante uno scroll normale.
     main.js scrive --out, quanto palcoscenico e' gia' uscito dal bordo alto.
     La rampa e' tarata sulla geometria di QUESTO testo, che e' centrato: il
     titolo tocca la barra quando il palcoscenico e' uscito di circa un terzo,
     quindi la dissolvenza finisce prima, a .30, e comincia a .14 per non essere
     uno scatto. Nessun altro atto la legge, e va bene cosi': tutti gli altri
     hanno gia' il raccordo, che porta il testo a zero molto prima. */
  .act--close .act__copy {
    opacity: clamp(0, calc((.30 - var(--out, 0)) / .16), 1);
  }
}

/* Il velo copre l'INTERO palcoscenico, non un riquadro attorno al testo.
   La versione precedente era un radial-gradient dentro un box con inset
   negativi: la sfumatura finiva prima del bordo sull'asse lungo e veniva
   tagliata su quello corto, quindi si vedeva un rettangolo. Un gradiente
   grande quanto il viewport non ha bordi da mostrare. */
.veil { position: absolute; inset: 0; pointer-events: none; }

/* Tenuta piu' lunga prima della discesa: la riga sotto il titolo cade oltre il
   44% del raggio, dove la versione precedente era gia' scesa e il contrasto
   misurato dal detector crollava a 1.9:1. */
/* INTENSITA' DEI VELI
   Le opacita' qui sotto non sono a occhio: vengono da una misura sulla pagina
   davvero renderizzata. Metodo (scratchpad/misura_veli2.py): si rendono i glifi
   trasparenti lasciando in piedi veli, pannelli e filetti, si fotografa l'atto a
   sette posizioni di scroll, si prende il percentile 99 della luminanza dentro
   la scatola di ogni blocco di testo e si calcola il rapporto WCAG con il colore
   EFFETTIVO di quel testo (--ink-dim e' bianco all'82%, quindi si compone sul
   pixel piu' chiaro, cioe' proprio dove il contrasto e' peggiore).

   Il taglio di questa passata sta sulle CODE, non sul nucleo. Un velo che parte
   da .10 e finisce a .10 tinge di blu tutta la fotografia per proteggere una
   fascia centrale: la coda non porta testo e si vedeva come un alone. Le code
   vanno a zero, il nucleo scende di pochi punti, e il contrasto misurato resta
   sopra AA ovunque.

   Peggior caso dopo il taglio, campionando un fotogramma su due per atto:
     corpo   4,71:1  (le note dell'atto vetrate)   soglia 4,5
     titoli  4,50:1  ("Come e' fatta")             soglia 3,0
   Il margine piu' sottile e' quello delle note: se abbassi ancora `--full`,
   rimisura quello per primo.
   Resta una sola eccezione: i valori `data-todo` dei pannelli, bianchi al 58%
   per dichiararsi provvisori, che non devono comunque arrivare alla
   pubblicazione. L'altra - il paragrafo dell'atto del tetto, storicamente a
   4,42:1 - non e' piu' tale: quel velo ora segue la corsa e tiene 4,70:1 nel
   suo punto peggiore (vedi .veil--left qui sotto). */
.veil--center {
  background: radial-gradient(ellipse 82% 74% at 50% 48%,
    rgb(7 37 53 / .62) 0%, rgb(7 37 53 / .56) 42%, rgb(7 37 53 / .40) 64%,
    rgb(7 37 53 / .14) 80%, rgb(7 37 53 / .03) 92%, rgb(7 37 53 / 0) 100%);
}

/* L'unico velo che si muove, e l'unico che doveva. Sotto di lui la fotografia
   non ha piu' un'esposizione sola: la sequenza del tetto parte dall'ora blu e
   arriva al giorno pieno, quindi il fondo sotto il testo passa da 83 a 143 su
   255 nel corso della corsa. Col velo fermo ai valori di prima il corpo del
   paragrafo scendeva a 3,47:1, sotto AA da meta' sequenza in poi.

   Un velo statico abbastanza forte per il giorno pieno chiedeva di moltiplicare
   gli stop per 1,24, e l'apertura all'ora blu ne aveva bisogno di 0,53: sarebbe
   arrivata 2,3 volte piu' velata del necessario, cioe' il "valore storico,
   troppo alto" che questo file ha gia' scartato una volta.

   Percio' gli stop qui sotto sono scritti al MASSIMO della corsa (i valori di
   prima moltiplicati per 1,35) e `--veil-k` li riporta giu' all'inizio, dove il
   cielo e' scuro e non serve nulla. Si usa `opacity` e non un gradiente
   ricalcolato: su un elemento a colore unico moltiplicare l'opacita' e'
   esattamente moltiplicare gli stop, ma lo fa il compositore e non il pittore,
   su un palcoscenico che sta gia' ridipingendo un canvas a ogni fotogramma.

   Il valore di ripiego e' 1, cioe' il velo piu' pesante: senza JS si vede la
   versione troppo velata, mai quella illeggibile. Le due estremita' della corsa
   stanno in main.js (VEIL_K), misurate fotogramma per fotogramma. */
.veil--left {
  background: linear-gradient(100deg,
    rgb(7 37 53 / .972) 0%, rgb(7 37 53 / .81) 30%,
    rgb(7 37 53 / .297) 58%, rgb(7 37 53 / 0) 78%);
  opacity: var(--veil-k, 1);
}

/* L'unico velo dell'atto 05, e l'unico rimisurato sui suoi fotogrammi invece
   che sul caso peggiore di tutto il sito. I valori sopra vengono dal pixel piu'
   chiaro che cade sotto il testo su TUTTI gli atti, 180 su 255. Qui sotto il
   testo non ci passa mai niente di cosi' chiaro: misurato sui 158 fotogrammi
   del loop, il percentile 99 e' R161 G131 B128 sotto il titolo e R158 G113 B85
   sotto il corpo. Sono il pavimento in pietra e il bracciolo in teak, non un
   cielo.
   Con quel fondo il velo che serviva era quasi il doppio del necessario, e si
   vedeva: il blu saliva fino al 76% dell'altezza e copriva i divani e mezzo
   tetto. Qui scende a .50 sul bordo e si spegne al 58%, cioe' smette dove
   comincia il prodotto.
   Contrasto che resta, sul pixel del percentile 99: corpo fra 5,9 e 6,0:1
   (AA ne chiede 4,5), titolo fra 5,8 e 7,0:1 (AA ne chiede 3, e' testo grande).
   Piu' margine di quanto ne avessero i veli degli altri atti, che stanno fra
   5,2 e 5,6:1. Se abbassi ancora, rimisura: la casella del corpo e' la prima a
   cedere, ed e' quella stretta in fondo a sinistra. */
/* Questi valori stanno SOTTO quelli che la passata generale sulle code aveva
   lasciato qui (.56 / .46 / .12 / 0 a 72%), e non e' una svista: vanno nella
   stessa direzione, solo piu' in la'. Quella passata ha misurato l'atto 05
   quando era ancora una sequenza di fotogrammi; il loop che c'e' adesso e' una
   scena diversa e piu' scura sotto il testo. Rimisurato su quella, il velo che
   serve e' meno. Chi legge dopo non li riporti su per uniformita': se la clip
   cambia, si rimisura la clip. */
.veil--bottom {
  background: linear-gradient(to top,
    rgb(7 37 53 / .50) 0%, rgb(7 37 53 / .44) 18%,
    rgb(7 37 53 / .20) 40%, rgb(7 37 53 / 0) 58%);
}

/* Fascia, non campitura piatta: la fotografia resta viva sopra e sotto, il velo
   lavora solo dove cade il testo (41-59% dell'altezza, misurato). Ai due
   estremi ora vale zero: prima non scendeva mai sotto .10 e quel fondo
   costante era l'alone che si vedeva sull'intera immagine. */
.veil--full {
  background: linear-gradient(to bottom,
    rgb(7 37 53 / 0) 0%,    rgb(7 37 53 / .06) 16%,
    rgb(7 37 53 / .56) 36%, rgb(7 37 53 / .56) 68%,
    rgb(7 37 53 / .06) 86%, rgb(7 37 53 / 0) 100%);
}

/* Dove il testo sta sui PANNELLI e non sulla fotografia il velo non protegge
   nessuno: i pannelli si portano dietro la propria campitura al 74% e misurano
   5,6:1 sulle etichette da soli. Qui resta solo quel tanto che stacca il
   fotogramma dal fondo pagina, e l'unico testo che ci appoggia sopra e' il
   titolo fisso, che a 4,50:1 e' ben oltre la soglia dei titoli grandi.
   Va dopo .veil--full: stessa specificita', vince l'ordine. */
.veil--panels {
  background: linear-gradient(to bottom,
    rgb(7 37 53 / 0) 0%,    rgb(7 37 53 / .04) 16%,
    rgb(7 37 53 / .30) 36%, rgb(7 37 53 / .30) 68%,
    rgb(7 37 53 / .04) 86%, rgb(7 37 53 / 0) 100%);
}

/* ---------------------------------------------------------------- soglia */

/* Atto di soglia: la fotografia a pieno campo con sopra la firma di marca, e la
   firma che se ne va allo scroll per lasciare il campo allo scrubbing.
   Qui c'era un diaframma: una finestra 16:9 al centro che si allargava fino a
   pieno campo mentre quattro matte piene in --field uscivano di campo, e dentro
   la finestra "Fuori come dentro." si spezzava in due meta' che si separavano.
   L'apertura era la seconda meta' dello stacco del prologo, e la firma entrava
   dopo in quattro tempi sfalsati. Tre battute, e le prime due dicevano di nuovo
   quello che il prologo aveva appena detto: un marchio che si monta, un campo
   che si apre. Restava la terza, che e' l'unica che porta il sito avanti.
   Adesso la schermata e' gia' montata a scroll zero e l'atto porta una battuta
   sola: la firma tiene il campo, poi si dissolve.
   main.js scrive un solo numero, --run (0-1, la posizione lungo la soglia).
   Tutte le tempistiche sono qui: il JS non sa quando la firma se ne va. */
.act--open {
  /* 490vh: la soglia (60) piu' lo scrub (330), piu' la schermata di viewport che
     non e' corsa. Erano 420 quando la soglia doveva anche aprire il diaframma e
     far entrare la firma, poi 340 con 180vh di scrub, poi 260 con 100, poi 820
     con 660.
     Lo scrub e' meta' dei 660 pubblicati, e i fotogrammi sono meta' dei 240: i
     due numeri dimezzati INSIEME, come vuole la regola scritta sotto
     `--fotogrammi`. Il punto non e' la fluidita' e non e' il peso: e' che l'atto
     ARRIVA a meta' dell'arco e li' si ferma. La carrellata dell'apertura tirava
     indietro fino a mostrare la villa intera; adesso chiude sul fotogramma 120,
     la pergola inquadrata per intero con il mare a sinistra, che e' il punto in
     cui la scena e' gia' detta. La seconda meta' era in piu'.
     Il passo sullo scroll NON cambia, ed e' il motivo per cui i due numeri sono
     andati giu' insieme: 330vh su 119 intervalli fanno 2,77vh per fotogramma,
     cioe' i 2,76 che il sito pubblicato ha sempre avuto e la densita' degli
     altri cinque atti verticali. Stessa andatura, meta' corsa, meta' arco.
     Il guadagno e' l'altezza: questo atto passa da 8,2 schermate a 4,9, e la
     pagina da 20 a 16,7. La corsa utile e' 490 - 100 = 390vh. */
  --len:   490vh;

  /* Dove finisce la soglia e comincia lo scrub, in frazione della corsa.
     60/390 = .1538. La soglia resta 60vh come e' sempre stata: quello che si
     accorcia e' lo scrub, non la firma, che ha le sue rampe tarate su quella
     durata. Per questo il numero cambia quando cambia --len anche se
     la soglia sta ferma: e' una frazione della corsa, e la corsa e' cambiata.
     E' l'UNICO posto dove questo numero e' scritto: main.js lo legge da qui con
     getComputedStyle per la dissolvenza della firma, js/apertura.js per l'indice
     del fotogramma. Cosi' non ci sono due verita' da tenere allineate. */
  --split: .1538;

  /* Quanti fotogrammi ha la consegna di QUESTO ramo, e quindi quale delle due
     consegne dell'apertura serve js/apertura.js: 120 in WebP a due livelli qui,
     30 in AVIF a cinque livelli nel ramo mobile piu' sotto.
     Sta qui e non su `data-frames` nel markup per la stessa ragione di --split:
     il numero deve cambiare INSIEME a --len, perche' i due si moltiplicano - un
     numero senza l'altro e' la densita' sbagliata, ed e' esattamente il difetto
     che si sta correggendo. Il 21/08/2026 i fotogrammi sono passati da 240 a 30
     mentre --len restava 820vh, e l'apertura ha scorso a 22,76vh per fotogramma
     invece di 2,76: otto volte piu' rada di ogni altro atto della pagina. Un
     attributo nel markup non ha un ramo mobile e non poteva accorgersene; una
     variabile CSS vive nella stessa @media che decide la corsa.
     La regola vale in entrambi i versi. Poche ore dopo lo scrub e' passato da
     660vh a 330 e i fotogrammi NON sono cambiati: la si e' letta, si e' visto
     che il passo scendeva a 1,38vh - piu' fitto, quindi dalla parte giusta - e
     si e' lasciato 240. Muovere un numero solo non e' vietato: e' vietato farlo
     senza guardare il prodotto.
     Il 21/08/2026 i due numeri si sono mossi insieme e nello stesso verso,
     partendo da quelli PUBBLICATI: scrub da 660 a 330vh e fotogrammi da 240 a
     120. Dimezzati entrambi, il passo resta quello di sempre - 2,77vh - e a
     cambiare e' dove l'atto FINISCE: a meta' della carrellata invece che in
     fondo. La consegna scende da 27 a 14 MB al livello 1600, ma e' una
     conseguenza, non lo scopo.
     Il riferimento da dimezzare e' quello pubblicato, non quello in repo, ed e'
     una distinzione che e' costata un giro: in repo lo scrub era gia' 330vh per
     un commit non ancora arrivato sul server, dove valeva ancora 660. Chi
     confronta il locale con il sito vivo confronta con 660vh e 240 fotogrammi.
     I 120 file sul disco sono i PRIMI 120 dei 240 pubblicati, contigui e con i
     nomi che avevano: la seconda meta' e' stata tolta, non ricampionata. Nessuna
     ricodifica, quindi nessuna perdita in piu', e nessun passo diverso dentro
     l'arco che resta. Da qui si torna indietro con `git checkout` sui due
     livelli; i master, che permetterebbero di rifarli, non stanno in versione e
     la ricetta e' in tools/build-apertura.py.
     `data-frames` resta sull'atto ma e' solo il selettore con cui main.js
     raccoglie gli stage: il numero vero e' questo. */
  --fotogrammi: 120;

  /* Posizione lungo la SOGLIA (0-1 sui primi --split della corsa), scritta da
     main.js. Essendo locale alla soglia, la rampa qui sotto resta scritta in
     frazioni della soglia e non della sezione: il numero .5 vuol dire "a meta'
     della soglia" a prescindere da quanto dura lo scrub. */
  --run:   0;

  /* La firma tiene il campo per la prima meta' della soglia (30vh) e se ne va
     nella seconda. La tenuta non e' scroll sprecato: e' il tempo in cui si legge
     "Oltre la pergola." prima che cominci a muoversi qualcosa.
     Tutta insieme, non scaglionata: lo sfalsamento serve a far leggere un
     arrivo, in uscita produrrebbe solo quattro pezzi che si staccano. Finisce a
     --run 1, cioe' esattamente dove comincia lo scrub: il logo svanisce e i
     fotogrammi partono, senza niente in mezzo.
     --so e' lineare, --eo la stessa passata per smoothstep: si posa morbida
     invece di scattare ai due estremi. Si dichiarano qui e non su :root perche'
     dipendono da --run, che vive su questo elemento. */
  --so: clamp(0, calc((var(--run) - .5) / .5), 1);
  --eo: calc(var(--so) * var(--so) * (3 - 2 * var(--so)));

  /* Quanto resta del velo quando la firma se n'e' andata. Il velo esiste per
     dare fondo al testo (le opacita' dentro .veil--center sono misurate sul
     contrasto, non a occhio): finito il testo tiene solo del blu steso sopra la
     fotografia, e lo fa proprio quando comincia lo scrub, cioe' nell'unico
     momento in cui la fotografia deve farsi guardare da sola.
     Non zero: un residuo tiene il fotogramma dentro la gamma di marca e fa si'
     che il calo si legga come la scena che si apre, non come uno stacco di
     esposizione. Alza o abbassa questo numero e cambia solo questo. */
  --veil-rest: .28;
}

.act--open .act__stage { background: var(--field); }

/* Il velo cala sulla STESSA rampa della firma (--eo): quando il logo ha finito
   di svanire il velo e' gia' sceso, e lo scrub parte sulla fotografia piena.
   Sulla rampa e non a scatto: --eo e' gia' smoothstep, quindi il calo e' morbido
   e legato al gesto invece che a una soglia. */
.act--open .veil { opacity: calc(1 - var(--eo) * (1 - var(--veil-rest))); }

/* La cornice tiene insieme media e velo, cosi' su mobile e in reduced motion
   basta spostare lei per far diventare il palcoscenico una fascia. */
.open__frame { position: absolute; inset: 0; z-index: 0; overflow: hidden; }

.open__media { position: absolute; inset: 0; display: block; }

/* Il poster stava a scala 1.06 e si posava a 1 mentre la finestra finiva di
   aprirsi: senza finestra che si apre non c'e' niente da accompagnare, e una
   fotografia che si assesta da sola sarebbe movimento senza causa. Resta il solo
   ancoraggio, lo stesso del cover del canvas (data-focus 0.52 0.58): il centro
   geometrico di un 16:9 qui e' cielo. */
.open__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 52% 58%;
}

/* Il canvas nasce spento e copre il poster solo quando ha davvero un fotogramma
   disegnato: la classe la mette main.js al primo draw riuscito. Senza, il canvas
   e' opaco (alpha:false) e coprirebbe il poster con la campitura blu piatta,
   annullando il motivo per cui il poster esiste.
   Scambio netto, NIENTE transizione. Non serve, perche' i due mostrano lo stesso
   identico fotogramma 001 con lo stesso ancoraggio e la stessa scala: lo stacco
   non si vede. E soprattutto una transizione qui legherebbe la comparsa del
   canvas al clock di rendering: se quello si ferma, la transizione resta a meta'
   e sotto si vede solo un poster fermo per tutto lo scrub. */
.act--open .open__canvas { opacity: 0; }

.act--open.is-drawn .open__canvas { opacity: 1; }

/* ------------------------------------------------------------- firma di marca */

/* will-change solo mentre l'atto e' in campo, come per i binari orizzontali: una
   superficie promossa a livello per tutta la pagina e' memoria video sprecata.
   La classe la mette e la toglie l'IntersectionObserver.
   Solo il blocco, non le sue quattro parti: promuovere anche quelle sarebbe
   memoria video per una traslazione da un rem e tre quarti. Composte dentro
   questo livello costano lo stesso. */
.act--open.is-live .open__sign { will-change: transform, opacity; }

/* Il blocco si muove solo in uscita, tutto insieme: sale di poco e si spegne.
   Non ha entrata perche' e' gia' in campo quando la pagina si scopre. */
.open__sign {
  z-index: 3;
  grid-area: 1 / 1;
  place-self: center;
  width: 100%;
  padding-inline: var(--pad-x);
  text-align: center;
  opacity: calc(1 - var(--eo));
  transform: translate3d(0, calc(var(--eo) * -1.75rem), 0);
}

.open__sign .lockup--lg { justify-content: center; }
.open__sign .display,
.open__sign .lead { margin-inline: auto; }

/* ---------------------------------------------------------------- attesa */

/* Un filo in fondo al palcoscenico, acceso solo finche' non c'e' nemmeno un
   fotogramma disegnabile. Non un velo ne' uno scheletro: la campitura di marca
   che copre il canvas e' gia' un'attesa credibile, qui serve solo dire che
   qualcosa sta arrivando. */
.act__wait {
  position: absolute;
  inset: auto 0 0 0;
  height: 2px;
  z-index: 4;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s var(--ease);
}

.act.is-waiting .act__wait { opacity: 1; }

.act__wait::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 32%;
  background: linear-gradient(90deg, rgb(7 37 53 / 0), var(--ink), rgb(7 37 53 / 0));
}

/* L'animazione parte solo mentre l'attesa e' davvero in corso. Sul selettore
   nudo girava sempre, anche a opacita' zero: sei cicli infiniti tenuti vivi sul
   compositor per tutta la pagina, e un ciclo infinito senza motivo e' proprio
   quello che il controllo anti-pattern segnala. */
@media (prefers-reduced-motion: no-preference) {
  .act.is-waiting .act__wait::after { animation: attesa 1.5s linear infinite; }
}

/* Senza movimento resta un filo fermo e attenuato: comunica la stessa cosa. */
@media (prefers-reduced-motion: reduce) {
  .act__wait::after { width: 100%; opacity: .3; }
}

@keyframes attesa {
  from { transform: translateX(-100%); }
  to   { transform: translateX(413%); }
}

/* ---------------------------------------------------------------- copy */

.act__copy {
  position: relative;
  z-index: 2;
  padding: calc(var(--head-h) + var(--pad-y)) var(--pad-x) var(--pad-y);
  max-width: min(92vw, 44rem);
}

.copy--bottom-left { place-self: end start; }
.copy--mid-left    { place-self: center start; }
.copy--center      { place-self: center; text-align: center; max-width: min(92vw, 40rem); }

/* Il vincolo va sul TITOLO e in em, cosi' si misura sul font del titolo.
   Con max-width in ch sul blocco, "ch" valeva il font del blocco (16px) e i
   titoli display uscivano dal contenitore di 61px e 215px. */
.display {
  margin: 0;
  max-width: 13em;
  font-size: clamp(2.7rem, 5.6vw, 4.8rem);
  font-weight: 300;
  line-height: 1.06;
  letter-spacing: -.03em;
  text-wrap: balance;
}

/* Il coefficiente sale da 3.9vw a 5vw e il pavimento da 1.8 a 2.4rem, il tetto
   resta 3.2rem: sopra i 1024px non cambia niente, sotto si chiude un buco.
   Il difetto stava a 768, e si e' visto solo dopo aver alzato il corpo: il
   titolo d'atto era 29,95px sopra un corpo da 19,1, cioe' rapporto 1,57 - lo
   stesso valore che si era appena corretto su mobile, ricomparso sul tablet.
   Alzare il corpo senza rialzare il titolo sposta il problema invece di
   risolverlo, e la fascia intermedia e' quella che si guarda per ultima.
   Ora: 38,4px a 768 (rapporto 2,01), 51,2 da 1024 in su (2,56). */
.display--sm { max-width: 14em; font-size: clamp(2.4rem, 5vw, 3.2rem); }

.copy--center .display { margin-inline: auto; }

/* Il corpo e' l'unica cosa che si legge davvero, e per due volte non era
   trattato come tale.
   Il `clamp` precedente, `clamp(1.06rem, 1.15vw, 1.2rem)`, era fluido solo sulla
   carta: il termine centrale supera il pavimento di 16,96px solo sopra i 1475px
   di viewport, quindi da 375 a 1440 - cioe' su tutta la gamma reale - il corpo
   restava FERMO a 16,96px mentre il titolo saliva da 25,6 a 51,2. Misurato.
   Ora il termine centrale parte da una base in rem e ci somma una quota di
   viewport, cosi' cresce da subito: 17px a 375, 19,1 a 768, 20 dal 930 in su.
   Il peso passa da 300 a 400. Il DESIGN.md vieta gia' l'extralight sui titoli
   sopra fotografia perche' "si sfilaccia", e a 17px lo stesso fenomeno costa di
   piu', non di meno: sotto c'e' la stessa immagine. La 400 e' gia' su disco e
   serviva solo alle etichette maiuscole, cioe' si pagava un peso di font senza
   usarlo dove conta. Il contrasto non cambia - dipende dal colore, non dal peso -
   ed e' stato rimisurato lo stesso. */
.lead {
  margin: 1.25rem 0 0;
  max-width: 40ch;
  font-size: clamp(1.0625rem, .55vw + .93rem, 1.25rem);
  font-weight: 400;
  line-height: 1.62;
  color: var(--ink-dim);
}

.copy--center .lead { margin-inline: auto; }

/* ---------------------------------------------------------------- fase orizzontale */

.act__track {
  position: relative;
  z-index: 2;
  place-self: center start;
  display: flex;
  align-items: center;
  gap: clamp(2.5rem, 6vw, 6rem);
  /* Il bordo iniziale lascia posto al titolo fisso; quello finale fa chiudere
     l'ultimo pannello vicino al margine invece che a mezzo campo. */
  padding-inline: min(42vw, 36rem) max(var(--pad-x), 8vw);
}

/* Titolo di sezione fisso sul palcoscenico: resta leggibile per tutta la corsa
   mentre i pannelli gli scorrono accanto. Sta nella fascia centrale, dove il
   velo protegge; il binario parte dopo di lui. */
/* Titolo e binario nella STESSA cella di griglia, non uno sotto l'altro.
   Come figli separati la griglia creava due righe implicite (486 + 413px):
   il titolo finiva al 18-36% dell'altezza e i pannelli al 72-82%, cioe' fuori
   entrambi dalla fascia in cui il velo protegge. Qui condividono la cella e si
   affiancano grazie al padding iniziale del binario. */
.act--h .panel-lead,
.act--h .act__track { grid-area: 1 / 1; }

.panel-lead {
  position: relative;
  z-index: 3;
  place-self: center start;
  margin: 0;
  padding-left: var(--pad-x);
  max-width: 9em;
  pointer-events: none;
  /* Il titolo cede il campo ai pannelli PRIMA che lo raggiungano. Condividendo
     la cella, dopo un terzo di corsa il primo pannello gli arriva sotto: nelle
     specifiche la campitura blu passava dietro "Come e' fatta" e i due testi si
     leggevano uno sopra l'altro. Tenerlo fisso fino in fondo costava una
     sovrapposizione; toglierlo dalla cella lo faceva uscire di campo al 35%
     lasciando pannelli senza contesto. Sparisce, e il suo lavoro lo continua
     l'indicatore di posizione in alto, che porta lo stesso titolo.
     main.js scrive --lead da 1 a 0 misurando quanta corsa manca al contatto:
     qui c'e' solo il modo in cui il titolo se ne va. La scrive su QUESTO
     elemento e non sull'atto: e' l'unico che la legge, e piu' in alto un valore
     riscritto a ogni frame trascinava nel ricalcolo tutto il resto dell'atto. */
  opacity: var(--lead, 1);
  /* Non solo opacita': arretra di poco nella direzione della corsa, cosi' si
     legge come una cosa che esce di campo e non come una luce che si spegne.
     La corsa e' minima perche' il titolo non deve entrare in competizione con
     i pannelli che gli passano accanto proprio mentre se ne va. */
  transform: translate3d(calc((1 - var(--lead, 1)) * -1.4rem), 0, 0);
}

.note {
  flex: 0 0 auto;
  width: min(80vw, 23rem);
  padding-left: 1.25rem;
  /* Filo verticale al posto della scatola: il pannello non deve competere con
     la fotografia che gli sta dietro. */
  border-left: 1px solid rgb(255 255 255 / .34);
}

.note h3 {
  margin: 0;
  font-size: clamp(1.12rem, 1.5vw, 1.35rem);
  font-weight: 400;
  letter-spacing: -.01em;
  line-height: 1.25;
}

.note p {
  margin: .7rem 0 0;
  font-size: clamp(1rem, 1.05vw, 1.08rem);
  line-height: 1.6;
  color: var(--ink-dim);
}

/* ATTO FERMO
   Con la traslazione spenta il binario non e' piu' un binario: deve stare
   dentro il viewport a qualunque larghezza, altrimenti il terzo pannello
   resta fuori campo per sempre invece che fino a meta' corsa.
   Quindi griglia, non fila: le colonne si stringono con lo spazio disponibile
   e sotto la misura minima il terzo pannello va a capo invece di uscire.
   Le regole valgono solo dove i pannelli sarebbero in fila: sotto i 768px e in
   reduced motion gli atti orizzontali sono gia' impilati in colonna. */
@media (min-width: 768px) and (min-height: 501px) and (prefers-reduced-motion: no-preference) {
  /* La misura minima sale da 14 a 19rem, e non e' una preferenza: con 14rem
     l'auto-fit teneva tre colonne anche a 1440, dove restano 824px fra il titolo
     fisso e il margine. Tre colonne li' dentro fanno 244px l'una, cioe' una
     misura di **23 caratteri** contro i 45-75 che rendono un testo leggibile.
     Un paragrafo largo 23 caratteri si legge a scatti, e questi tre pannelli
     sono il punto in cui il sito spiega il prodotto.
     A 19rem l'auto-fit scende a due colonne da 389px, cioe' 38 caratteri: sotto
     la soglia ma quasi il doppio di prima. Arrivare a 45 vorrebbe dire stringere
     il padding sinistro, che e' lo spazio del titolo fisso: e' un'altra
     decisione e va presa guardando l'atto intero, non questa riga. */
  .act--still .act__track {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
    align-items: start;
    gap: clamp(1.75rem, 2.6vw, 3rem) clamp(2rem, 3.2vw, 4rem);
    width: 100%;
    /* Il bordo iniziale lascia posto al titolo fisso, come nel binario: qui pero'
       non c'e' corsa che recuperi lo spazio, quindi si tiene piu' stretto. */
    padding-inline: min(38vw, 34rem) max(var(--pad-x), 4vw);
    transform: none;
  }

  /* In griglia la larghezza la decide la colonna: lasciare min(80vw, 23rem)
     sfondava di nuovo il viewport a tre pannelli affiancati. */
  .act--still .note { width: auto; }
}

/* ---------------------------------------------------------------- specifiche */

/* stretch, non center: con altezze diverse i fondi dei pannelli restavano
   sfalsati di 8px, che su un sistema dichiaratamente geometrico si legge. */
.act__track--specs { gap: clamp(1.5rem, 3vw, 3rem); align-items: stretch; }

.spec {
  flex: 0 0 auto;
  width: min(76vw, 19rem);
  margin: 0;
  /* Il taglio d'angolo mangia 38x28px: senza spazio in piu' in alto a sinistra
     il testo finisce contro la smussatura. */
  padding: calc(var(--shear-y) + .9rem) clamp(1.4rem, 2.2vw, 1.9rem)
           clamp(1.4rem, 2.2vw, 1.9rem) calc(var(--shear-x) * .55 + .9rem);
  /* Pannello pieno, niente backdrop-filter: tre superfici sfocate che traslano
     sopra un canvas ridipinto a ogni frame e' la composizione piu' costosa
     possibile, e a .72 di opacita' il contrasto misurato scendeva a 1.6:1. */
  /* Campitura nel blu principale del manuale, non nel fondo pagina: e' l'unico
     punto del sito dove #134074 puo' esistere ed essere visibile, perche' e' una
     superficie e non un tratto. Contrasto misurato sopra il fotogramma piu'
     chiaro: 7,7:1 sul bianco pieno, 6,2:1 sul testo attenuato. */
  /* .88, salito da .74 dopo aver GUARDATO la schermata invece di leggere solo il
     numero. A .74 il contrasto era gia' sopra soglia (6,7:1 sui valori) e il
     testo si staccava, ma attraverso il pannello passavano l'ulivo, il montante
     e le luci della costa: la superficie di marca leggeva come un velo, e il
     taglio d'angolo - che e' il dispositivo proprietario del progetto - si
     perdeva nel rumore della fotografia. Un contrasto sopra soglia dice che il
     testo si legge, non che la superficie funziona: sono due domande diverse e
     la seconda non ha un numero.
     Misurato a .88 sul pixel vero, testo nascosto e fotogramma sotto:
     **7,73:1 sui valori** (bianco pieno) e ~6,4:1 sulle etichette (bianco
     all'82% composto sul fondo). Entrambi migliori di prima.
     Non .93, che il DESIGN.md dichiarava: li' il pannello diventa una scheda
     appoggiata sopra e perde ogni legame con la fotografia. */
  background: rgb(19 64 116 / .88);
  /* Niente border: il clip-path lo taglia via sulla diagonale e tronca i due
     tratti adiacenti, quindi la smussatura si leggeva come un artefatto invece
     che come una scelta. La campitura piena basta a staccare dal fotogramma. */
  clip-path: var(--shear-cut);
}

.spec dt {
  font-size: .8rem;
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.spec dd {
  margin: .6rem 0 0;
  font-size: clamp(1.1rem, 1.5vw, 1.35rem);
  font-weight: 300;
  line-height: 1.35;
}

/* Riga secondaria: il secondo <dd> sotto lo stesso <dt>. Dal 20/08/2026 tre
   pannelli su sei ne hanno una - la velocita' del vento, il Qualicoat, le norme
   del vetro - e deve leggersi come una precisazione del valore sopra, non come
   un secondo valore di pari rango: stessa colonna, un gradino di corpo sotto e
   il bianco attenuato delle etichette.
   Lo stacco e' .35rem contro i .6rem che separano dt e dd: se i due <dd>
   distassero quanto dista il termine dal suo valore, il pannello si leggerebbe
   come tre righe indipendenti invece che come uno a due livelli. */
.spec dd + dd {
  margin-top: .35rem;
  font-size: clamp(.9rem, 1vw, 1rem);
  color: var(--ink-dim);
  line-height: 1.4;
}

/* Valori ancora da confermare dal cliente: devono essere visibilmente
   provvisori, mai scambiabili per un dato reale. */
[data-todo] {
  color: rgb(255 255 255 / .58);
  font-style: italic;
}

/* Eccezione, e va dichiarata perche' toglie una rete.
   Nei pannelli specifica i sei valori devono leggersi come UNA scheda: cinque
   in corsivo attenuato accanto a uno in bianco pieno non si leggevano come
   "cinque da confermare", si leggevano come due qualita' di stampa diverse
   nella stessa riga di pannelli.
   Il segnaposto non sparisce, cambia solo dove vive: resta nell'attributo
   `data-todo`, che e' quello che prima-del-deploy.mjs conta e su cui blocca la
   pubblicazione. Quindi il sito continua a non poter andare online con questi
   numeri; quello che si perde e' il riconoscerli a occhio guardando la
   schermata. Chi apre l'atto 5 per controllarli deve guardare il markup. */
.spec dd[data-todo] {
  color: inherit;
  font-style: normal;
}

/* ---------------------------------------------------------------- form */

.form { margin-top: 2rem; text-align: left; }
.copy--center .form { max-width: 22rem; margin-inline: auto; }

/* `minmax(0, 1fr)` e non la colonna implicita `auto`, ed e' una correzione non
   un ritocco. La dimensione minima automatica di un `input` e' la sua larghezza
   intrinseca, circa venti caratteri, e una traccia `auto` non scende sotto il
   minimo dei suoi contenuti: si allargava fino a li' trascinandosi dietro la
   riga. Misurato a 320 di viewport: riga larga 280px, colonna calcolata 346,78,
   i tre campi da x=20 a 367 - che era esattamente lo `scrollWidth` del
   documento, cioe' 47px di scorrimento laterale su tutta la pagina.
   `minmax(0, 1fr)` toglie quel pavimento e la colonna torna a valere quanto la
   riga. Safari non traboccava (assorbiva senza dare scroll) e Chrome e Firefox
   si': un difetto invisibile su iPhone e visibile su Android. */
.form__row { display: grid; grid-template-columns: minmax(0, 1fr); gap: .4rem; margin-bottom: 1rem; }

.form__row label {
  font-size: .78rem;
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* Il campo delle misure e' un textarea e non un input, ma e' lo stesso campo:
   stesso fondo, stesso bordo, stesso fuoco. Elencarli insieme e' l'unico modo
   perche' restino uguali anche fra sei mesi. */
.form__row input,
.form__row select,
.form__row textarea {
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: rgb(7 37 53 / .72);
  border: 1px solid rgb(255 255 255 / .42);
  border-radius: 0;
  padding: .8rem .9rem;
  min-height: 46px;
}

/* La tendina della fascia oraria. `appearance: none` perche' la freccia di
   sistema si disegna col colore di sistema: su questo fondo scuro sparisce su
   Windows e diventa un rettangolo chiaro su Android. Quella qui sotto e' un SVG
   in `data:`, che la CSP della pagina ammette (`img-src 'self' data:`, la stessa
   riga che serve alla sonda AVIF di main.js).
   Il riempimento a destra tiene il testo lontano dalla freccia: senza, la voce
   piu' lunga - "Dalle 11:00 alle 13:00" - ci finisce sotto.
   `option` ha fondo e colore scritti a mano perche' il menu a tendina lo disegna
   il sistema operativo, non questa pagina: senza queste due righe su Windows
   esce testo chiaro su fondo chiaro, cioe' un elenco che non si legge. */
.form__row select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 2.6rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23ffffff' stroke-width='1.4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .9rem center;
  background-size: 12px 8px;
  cursor: pointer;
}

.form__row select option {
  color: #FFFFFF;
  background: #072535;
}

/* CAP e Regione sulla stessa riga. Il guscio `.form__coppia` tiene le due
   `.form__row` di js e' `index.html` una accanto all'altra da 420px in su: il
   CAP e' un campo di cinque cifre, e da solo su una riga intera era largo
   quanto il nome. 8rem bastano a cinque cifre con il riempimento del campo;
   il resto va alla tendina, dove "Friuli-Venezia Giulia" e' la voce piu'
   lunga. `minmax(0, 1fr)` e non `1fr` per la stessa ragione scritta su
   `.form__row`: una tendina ha una larghezza minima intrinseca e senza il
   pavimento a zero trascinerebbe la riga fuori dalla colonna.
   Sotto i 420px una colonna sola: a 320 di viewport la riga e' larga 280px,
   e 8rem di CAP piu' la freccia e il riempimento della tendina lasciano alla
   voce piu' lunga meno spazio di quanto le serva.
   Il margine di sotto resta quello delle righe dentro, cosi' la coppia
   stacca dal comune quanto ogni altro campo dal successivo. */
.form__coppia { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: .9rem; }

@media (min-width: 420px) {
  .form__coppia { grid-template-columns: 8rem minmax(0, 1fr); }
}

.form__row textarea {
  /* Verticale e basta: in orizzontale il campo esce dalla colonna del modulo e
     scavalca il bordo della sezione. */
  resize: vertical;
  min-height: 5.5rem;
  line-height: 1.5;
}

/* Il segnaposto e' un esempio, non un'etichetta: deve leggersi come suggerimento
   e sparire appena si scrive. Piu' spento del testo digitato, non quanto il
   grigio di sistema, che su questo fondo scende sotto il contrasto minimo. */
.form__row textarea::placeholder { color: rgb(255 255 255 / .45); }

/* "facoltativo" dentro l'etichetta, non accanto: chi usa uno screen reader lo
   sente leggendo il campo, e non come una parola sciolta. In minuscolo e
   attenuato perche' e' una nota, non un secondo nome del campo. */
.form__opt {
  text-transform: none;
  letter-spacing: .02em;
  font-size: .92em;
  color: rgb(255 255 255 / .55);
}

.form__row input:focus-visible,
.form__row select:focus-visible,
.form__row textarea:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 1px;
  /* `background-color` e non la scorciatoia `background`: quella azzera anche
     `background-image`, e sulla tendina qui sopra la freccia sparirebbe proprio
     mentre il campo e' a fuoco, cioe' nell'unico momento in cui la si guarda. */
  background-color: rgb(7 37 53 / .92);
}

/* Il campo Comune con la sua lista. Tutto questo blocco vale solo a elenco
   caricato: la classe qui sotto, la lista e la regione viva le mette js/form.js
   quando il file dei comuni e' arrivato, quindi senza JavaScript non c'e'
   niente da disegnare e il campo resta l'input di sopra. Il perche' sta nella
   testata di quel blocco.

   `.form__combo` cade sulla `.form__row` del campo, non su un guscio nuovo:
   spostare l'input dentro un elemento appena creato gli toglierebbe il fuoco
   proprio nell'istante in cui qualcuno lo sta usando. La riga funziona da
   ancora perche' e' etichetta piu' campo in una colonna sola, quindi il suo
   bordo di sotto e' quello del campo. */
.form__combo { position: relative; }

/* Fondo PIENO e non quello del campo, che e' `--field` al 72%: la lista sta
   sopra il campo delle misure e sopra la riga del consenso, e con un fondo
   trasparente si leggerebbero due testi sovrapposti.
   `z-index` per la stessa ragione: le righe che vengono dopo nel documento si
   disegnano sopra, e senza questa riga la lista finisce sotto il textarea.
   Bordo e raggio identici al campo: e' lo stesso oggetto che si allunga, non un
   pannello che compare. */
.form__combo-lista {
  position: absolute;
  z-index: 2;
  top: calc(100% - 1px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--field);
  border: 1px solid rgb(255 255 255 / .42);
  border-radius: 0;
  /* Quindici righe e poi si scorre. Piu' in alto la lista uscirebbe dalla
     finestra su un telefono in orizzontale, dove sopra la tastiera restano poco
     piu' di duecento pixel. */
  max-height: 15rem;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* 44px di altezza battuta: e' il bersaglio comodo al dito, e sotto quella
   soglia scegliere il comune giusto in una lista fitta diventa una lotteria.
   WCAG 2.5.8 ne chiede 24, questi sono i 44 delle linee guida di Apple, perche'
   qui le voci sono attaccate una all'altra e non hanno spazio intorno. */
.form__combo-voce {
  padding: .7rem .9rem;
  min-height: 44px;
  font-size: 1rem;
  line-height: 1.4;
  color: var(--ink);
  cursor: pointer;
}

/* Stesso segno per il dito e per la tastiera: `.e-attiva` la mette js/form.js
   sulla voce puntata dalle frecce, ed e' quella che `aria-activedescendant`
   annuncia. Se le due si vedessero diverse, chi passa dal mouse alle frecce
   dovrebbe imparare due linguaggi per la stessa lista. */
.form__combo-voce:hover,
.form__combo-voce.e-attiva {
  background: rgb(255 255 255 / .14);
}

/* La voce attiva deve restare leggibile anche a colori spenti o forzati, dove
   il fondo qui sopra puo' sparire del tutto. */
@media (forced-colors: active) {
  .form__combo-voce.e-attiva { forced-color-adjust: none; background: Highlight; color: HighlightText; }
}

/* "37 comuni trovati": esiste solo per chi la lista non la vede. Nascosta come
   la trappola anti-spam e per la stessa ragione tecnica - `display: none` non
   viene letto da nessuno - ma con l'intento opposto: quella si nasconde ai bot,
   questa parla a chi ascolta la pagina. */
.form__combo-stato {
  position: absolute;
  width: 1px; height: 1px;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Fuori dal flusso ma non display:none: i bot ignorano gli elementi nascosti. */
.form__trap {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.form__consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .7rem;
  align-items: start;
  margin: 1.25rem 0 .25rem;
}

/* 24px e' il minimo di WCAG 2.5.8 (Target Size Minimum, AA). L'etichetta e'
   associata con `for`, quindi l'area cliccabile reale e' l'intera riga. */
.form__consent input {
  width: 24px;
  height: 24px;
  margin: 1px 0 0;
  accent-color: var(--ink);
}

.form__consent label {
  font-size: .875rem;
  line-height: 1.5;
  color: var(--ink-dim);
}

.form__consent a { color: var(--ink); text-underline-offset: 3px; }

/* Esito dell'invio. Vive fuori dal <form>: a invio riuscito il form viene
   nascosto, e un messaggio dentro un elemento nascosto non lo vede nessuno.
   Vuoto non occupa spazio, cosi' il bottone non si sposta quando il messaggio
   compare. Il colore non e' l'unico segnale, il testo dice gia' cosa e'
   successo: un errore letto da chi non distingue i rossi resta leggibile. */
.form__esito {
  margin: 0;
  font-size: .9rem;
  line-height: 1.5;
  color: var(--ink-dim);
  max-width: 24rem;
  margin-inline: auto;
  text-align: left;
}
.form__esito:empty { display: none; }
.form__esito[data-stato] { margin-top: .9rem; }
/* Riceve il fuoco a invio riuscito, perche' il bottone che ce l'aveva e' finito
   dentro un form nascosto. Il contorno serve: e' un salto di fuoco, e senza
   segnale chi naviga da tastiera non sa dove e' arrivato. */
.form__esito:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }

/* Il rosso di sistema sul fondo #072535 non arriva a 4,5:1. Questo si', ed e'
   l'unico punto del sito con un colore fuori dal manuale di marca: un errore
   di invio deve staccare dal testo normale o non si vede. */
.form__esito[data-stato="errore"] { color: #ff9a8c; }

/* Fine corsa: il modulo non c'e' piu' e questo e' l'unico testo rimasto al suo
   posto. Prende il corpo di un paragrafo vero, non di una nota a margine. */
.form__esito[data-stato="fatto"] {
  margin-top: 2rem;
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--ink);
  border-left: 2px solid var(--brand);
  padding-left: 1rem;
}

/* ---------------------------------------------------------------- cta */

.cta {
  display: inline-block;
  width: 100%;
  margin-top: .75rem;
  padding: 1rem 2.25rem;
  font: inherit;
  font-size: .8125rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  text-decoration: none;
  /* Niente nowrap: a 320px "RICHIEDI UN SOPRALLUOGO" con questo tracking usciva
     dalla colonna. Meglio due righe che un bottone che sborda. */
  text-wrap: balance;
  cursor: pointer;
  color: var(--field);
  background: var(--ink);
  border: 1px solid var(--ink);
  clip-path: var(--shear-cut);
  transition: background .35s var(--ease), color .35s var(--ease), transform .18s var(--ease);
}

.cta:hover,
.cta:focus-visible { background: var(--brand); border-color: var(--brand); color: var(--ink); }
.cta:active { transform: translateY(1px); }

:where(a, button):focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* ---------------------------------------------------------------- contatto */

/* Sezione a scorrimento normale, non un palcoscenico sticky. Il form cresce
   quanto serve: dentro uno stage con overflow:hidden a 1366x700 il bottone di
   invio finiva 81px sotto il taglio e non era raggiungibile a nessuno scroll. */
.contact {
  position: relative;
  z-index: 2;
  background: var(--field);
  border-top: 1px solid rgb(255 255 255 / .10);
  padding: clamp(3.5rem, 9vh, 7rem) var(--pad-x) clamp(3rem, 7vh, 5.5rem);
  /* Adesso qualcosa ci punta: il bottone in alto e' diventato un'ancora a
     #contatto. Senza questo margine il salto porta il bordo della sezione a
     filo di finestra e "Parliamone." finisce sotto la barra, cioe' proprio il
     difetto che si e' appena tolto, rifatto da un link invece che dallo
     scroll. */
  scroll-margin-top: calc(var(--head-h) + 1.5rem);
}

.contact__inner { max-width: 34rem; margin-inline: auto; text-align: center; }
.contact__inner .display { margin-inline: auto; }
.contact__inner .lead { margin-inline: auto; }
.contact .form { max-width: 24rem; margin-inline: auto; text-align: left; }

/* `.contact__alt` e `.contact__tel` non ci sono piu': erano la riga "Oppure
   chiama" e il numero, cioe' il secondo percorso di conversione. Il sito ha un
   canale solo, e le due regole sono sparite con il markup che vestivano invece
   di restare qui a coprire una classe che nessuno scrive piu'. */

/* Due colonne da 1024 in su: il testo a sinistra, il modulo a destra. Il modulo
   tiene la sua misura (non si allarga: un campo lungo il doppio non si compila
   meglio), ma smette di galleggiare in mezzo al vuoto, perche' adesso la colonna
   accanto ha qualcosa dentro.
   `align-items: start` e non `center`: le due colonne hanno altezze molto
   diverse e centrarle farebbe partire il titolo a meta' del modulo. */
/* 960 e non 768, ed e' un numero misurato non un breakpoint di comodo: il modulo
   tiene 24rem (384px) e non si stringe, quindi a 768 alla colonna del testo
   restavano 267px e il lead cadeva a **24 caratteri**, meta' della soglia di
   leggibilita'. Correggere la misura del corpo e nello stesso giro dimezzarla in
   fondo alla pagina e' esattamente il modo in cui un fix si mangia se stesso.
   Misurato dopo il primo tentativo a 960: li' la colonna sinistra vale 432px e
   il lead sta ancora sotto la soglia. A 1024 vale 486px ed entra. Il numero
   giusto e' quello che regge la misura del testo, non quello che sembra un
   breakpoint: sotto, la colonna unica e' la composizione corretta, perche' due
   colonne entrano solo dove c'e' spazio per due colonne. */
@media (min-width: 1024px) {
  .contact__inner {
    max-width: 62rem;
    display: grid;
    grid-template-columns: 1fr minmax(20rem, 24rem);
    /* Una riga sola. Erano due, `auto 1fr`, perche' sotto il testo ci andava il
       telefono e le due caselle della colonna sinistra dovevano ancorarsi in
       cima invece di dividersi lo spazio in parti uguali. Tolto il telefono la
       seconda riga non ha piu' nessun contenuto: lasciarla vorrebbe dire tenere
       in griglia una riga vuota alta quanto il modulo, e nessuno la vedrebbe
       finche' un giorno qualcuno non ci mettesse qualcosa dentro chiedendosi
       perche' finisce a mezza altezza. */
    column-gap: clamp(2.5rem, 5vw, 5rem);
    align-items: start;
    text-align: left;
  }

  .contact__testo  { grid-column: 1; }
  .contact__modulo { grid-column: 2; }

  .contact__inner .display,
  .contact__inner .lead { margin-inline: 0; }
  .contact .form { max-width: none; margin-inline: 0; }
}

/* ---------------------------------------------------------------- footer */

/* La riga di chiusura, fra il modulo e il piede. Stesso fondo del piede e
   nessun bordo: e' l'ultima cosa che si legge, e una linea sopra ne farebbe una
   sezione a se' invece della coda della pagina.
   Le virgolette sono generate qui e non scritte nel testo, cosi' non finiscono
   nel contenuto: una sintesi vocale che incontra una virgoletta la nomina, e la
   frase si sente aprire e chiudere invece di essere solo detta. */
/* ---------------------------------------------------------------- guida */

/* La pagina di approfondimento: come funziona una pergola bioclimatica, il
   capitolato, il prezzo, le domande frequenti.
   Nata il 24/08/2026 staccando dalla home la sezione che ci era appena stata
   aggiunta. Qui restano solo la colonna di lettura e i ruoli di testo: telaio,
   fondo, spaziature e header li porta gia' `.catalogo, .scheda, .guida` piu' sotto,
   che e' il trattamento comune delle pagine ferme.
   Per un giorno questo blocco ha avuto anche un fondo `--field-up`, un
   `scroll-margin-top` e un allineamento a `.contact__inner` sopra i 1024: servivano
   a farlo convivere con lo scrollytelling della home. Su una pagina propria non
   serve piu' niente di tutto quello, ed e' il modo piu' pulito in cui quei tre
   problemi potessero chiudersi. */

/* 40rem: su Poppins valgono 67 caratteri per riga a 1440 e 41 a 375, dentro la
   finestra 45-75 dove il dispositivo lo consente. Non si scrive in `ch` perche'
   quell'unita' misura lo zero del font ereditato dal contenitore, che non e' il
   font in cui poi si legge il paragrafo. La ricetta per contarli davvero sta in
   WEB BRAIN/patterns/misura-della-riga.md. */
.guida__inner { max-width: 40rem; }

/* Il salto sul corpo e' 1,46-1,48, sotto l'1,6 che DESIGN.md fissa per i titoli
   d'atto, ed e' una deroga dichiarata li': oltre i 30px questi titoli
   comincerebbero a competere con `.display--sm`, che sulla stessa pagina vale
   33,75-51,2. La distanza che manca sul corpo la porta il peso, 300 contro 400.
   Prima della correzione del 24/08/2026 il rapporto era 1,25 a peso identico, e i
   titoli si leggevano come prime righe enfatizzate. */
.guida__titolo,
.scheda__titolo,
.catalogo__titolo {
  margin: clamp(2.5rem, 5vh, 3.5rem) 0 0;
  font-size: clamp(1.55rem, .85vw + 1.34rem, 1.85rem);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: -.015em;
}
.scheda__corpo > .scheda__titolo:first-child,
.catalogo__guida > .catalogo__titolo:first-child { margin-top: 0; }

/* Un ruolo, un nome. Prima erano tre classi con dichiarazioni identiche e tre
   margini diversi: il ruolo esisteva e il nome no. */
.guida__par,
.scheda__par,
.catalogo__par {
  margin: 1rem 0 0;
  font-size: clamp(1.0625rem, .55vw + .93rem, 1.25rem);
  font-weight: 400;
  line-height: 1.62;
  color: var(--ink-dim);
}

/* Il primo paragrafo dopo il titolo porta la definizione, che e' la riga che un
   motore di risposta estrae. Sta in bianco pieno per un gradino solo, senza
   cambiare corpo: e' l'unico punto di enfasi della pagina. */
.guida__attacco { color: var(--ink); }

/* Le due liste di definizione hanno lo stesso markup e due lavori diversi.
   ⚠️ Rifatte il 24/08/2026: nella prima scrittura i `dt` non dichiaravano
   `font-size` e i `dd` non dichiaravano `font-weight`, quindi ereditavano 16px e
   il 300 di `body`. Risultato: **la domanda piu' piccola della sua risposta** a
   ogni viewport sopra 375, e il corpo a 300 dove DESIGN.md §Typography prescrive
   400 "per la stessa ragione dei titoli". Nessuno dei due si vedeva, perche' il
   colore pieno del termine bastava a farlo leggere come termine.
   In un blocco tipografico nuovo si dichiarano corpo e peso su OGNI ruolo, anche
   dove sembrano ovvi: una proprieta' non dichiarata non e' un default neutro, e'
   il valore del padre. */
.capitolato,
.faq { margin: 1.5rem 0 0; }

/* Il termine: la convenzione etichette del sito, la stessa di `.spec dt`
   nell'atto 05. Sono gli stessi sei dati, e prima le due liste li vestivano al
   contrario - qui termine pieno e valore attenuato, li' il rovescio. */
.capitolato dt {
  margin-top: clamp(1.75rem, 4vh, 2.25rem);
  font-size: .8rem;
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.capitolato dt:first-of-type { margin-top: 0; }

/* Il dato. Bianco pieno, corpo sopra il testo: e' il numero, ed e' la ragione per
   cui questa pagina esiste. Prima stava dentro la prosa a 19px in `--ink-dim`,
   cioe' i sei numeri migliori del sito erano corpo di testo. */
.capitolato dd {
  margin: .55rem 0 0;
  font-size: clamp(1.1rem, 1.5vw, 1.35rem);
  font-weight: 300;
  line-height: 1.35;
  color: var(--ink);
}

/* La spiegazione: secondo <dd> sotto lo stesso <dt>, un gradino sotto il dato e
   nel bianco attenuato. Identico a `.spec dd + dd`, che il 20/08/2026 era gia'
   stato scritto per questo caso esatto. Lo stacco e' piu' stretto di quello fra
   termine e dato, o le tre righe si leggerebbero come tre voci indipendenti. */
.capitolato dd + dd {
  margin-top: .3rem;
  font-size: clamp(1rem, .4vw + .9rem, 1.0625rem);
  font-weight: 400;
  line-height: 1.55;
  color: var(--ink-dim);
}

/* Le domande frequenti restano impilate a ogni larghezza: una domanda su una
   colonna e la risposta sull'altra costringerebbe l'occhio a saltare avanti e
   indietro per ogni coppia, e qui le risposte vanno da 30 a 90 parole.
   Il termine sta un gradino SOPRA il corpo, non sotto: e' una domanda, si legge
   come frase e non come etichetta, quindi non prende la convenzione maiuscola del
   capitolato. */
.faq dt {
  margin-top: clamp(1.75rem, 4vh, 2.25rem);
  font-size: clamp(1.125rem, .45vw + 1.02rem, 1.3rem);
  font-weight: 500;
  line-height: 1.35;
  color: var(--ink);
}
.faq dt:first-of-type { margin-top: 0; }

.faq dd {
  margin: .5rem 0 0;
  font-size: clamp(1.0625rem, .55vw + .93rem, 1.25rem);
  font-weight: 400;
  line-height: 1.62;
  color: var(--ink-dim);
}

/* Il titolo deve possedere il suo gruppo: prima distava dalla sua prima voce
   esattamente quanto due voci distano fra loro, e galleggiava. */
.guida__titolo + .capitolato,
.guida__titolo + .faq { margin-top: 1.75rem; }

.scheda__par a,
.guida__par a,
.faq dd a,
.capitolato dd + dd a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: .22em;
  text-decoration-thickness: 1px;
  text-decoration-color: rgb(255 255 255 / .45);
  transition: text-decoration-color .35s var(--ease);
}
.scheda__par a:hover, .scheda__par a:focus-visible,
.guida__par a:hover, .guida__par a:focus-visible,
.faq dd a:hover, .faq dd a:focus-visible { text-decoration-color: var(--ink); }

/* `.cta` nasce con `width: 100%` perche' nel modulo vive in colonna stretta. Qui
   il tetto lo mette gia' `.catalogo .cta, .scheda .cta, .guida .cta` piu' sotto,
   che porta `width: auto`: una regola sola per tutte le pagine ferme invece di una
   eccezione per pagina. */
.guida__chiudi { margin: clamp(2.5rem, 5vh, 3.5rem) 0 0; }

.chiusa {
  /* Come .contact e .foot, e per la stessa ragione: tutto cio' che sta dopo
     </main> deve dichiararsi sopra i palcoscenici sticky, o l'ultimo atto lo
     copre. Scritta senza queste due righe, questa citazione era in pagina, alta
     121px, con il suo fondo giusto - e invisibile. */
  position: relative;
  z-index: 3;
  margin: 0;
  padding: 3.5rem var(--pad-x) 2.5rem;
  background: var(--field);
  color: var(--ink-dim);
  font-size: clamp(.95rem, .3vw + .88rem, 1.0625rem);
  font-style: italic;
  font-weight: 300;
  letter-spacing: .02em;
  text-align: center;
}
.chiusa::before { content: '\201C'; }
.chiusa::after  { content: '\201D'; }

/* Barra piena: prima il footer stava dove il velo e' gia' trasparente, sopra
   ulivi illuminati e muro bianco. Era il testo meno leggibile del sito, ed e'
   l'unico recapito della pagina. */
.foot {
  position: relative;
  z-index: 3;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .25rem 1.75rem;
  padding: 1.25rem var(--pad-x) 1.75rem;
  background: var(--field);
  border-top: 1px solid rgb(255 255 255 / .12);
  font-size: .875rem;
  letter-spacing: .04em;
  color: var(--ink-dim);
}

.foot a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.foot a:hover { color: var(--ink); }

/* La firma dello studio che ha fatto il sito. Sta nel piede di tutte e
   venticinque le pagine come le righe di legge, ma non e' una di quelle:
   quelle rispondono a un obbligo, questa e' un credito, e per questo va in
   coda alla barra e non in mezzo ai dati camerali.

   Il logo e' la copia ribaltata di quello del sito Progetto Pergole: li' il
   piede e' chiaro e la scritta INFOCUS e' quasi nera, qui il piede e' #072535 e
   la stessa scritta sparirebbe. Nel file di web/media/ la fiamma tiene i rossi
   di marchio e solo le sei lettere passano a bianco all'82%, cioe' esattamente
   --ink-dim: la firma pesa quanto il testo che le sta accanto, non di piu'.

   La sottolineatura sta sul testo e non sull'ancora: `.foot a` la mette su
   tutto il contenuto, e con l'immagine dentro un inline-flex correrebbe anche
   sotto il logo. */
.foot a.foot__firma {
  gap: .5rem;
  text-decoration: none;
}
.foot__firma span {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.foot__firma img {
  display: block;
  height: 22px;
  width: auto;
}

/* ---------------------------------------------------------------- noscript */

/* Anche qui il testo rientra nell'area sicura: queste tre pagine portano lo
   stesso meta viewport della principale, e con `cover` il loro contenuto
   arriverebbe sotto il ritaglio del notch in orizzontale. */
.fallback {
  max-width: 60rem; margin: 0 auto;
  padding: 4rem max(var(--pad-x), env(safe-area-inset-right))
           4rem max(var(--pad-x), env(safe-area-inset-left));
}
/* h1 e h2 con lo stesso disegno: nelle pagine di esito e nell'informativa il
   titolo e' un h1 (e' il titolo del documento), dentro <noscript> in index.html
   e' un h2, perche' li' l'h1 e' gia' "Oltre la pergola." nell'atto di apertura. */
.fallback h1,
.fallback h2 { font-weight: 300; font-size: 2rem; margin: 0 0 1rem; }
.fallback p { color: var(--ink-dim); line-height: 1.6; max-width: 40ch; }
.fallback img { width: 100%; height: auto; display: block; margin: 2rem 0; }

/* I link di queste pagine non erano stilati e cadevano sul blu di default del
   browser: misurato, #0000EE su #072535 fa 1,69:1. Non e' un dettaglio di
   rifinitura - su errore.html quel blu e' il numero di telefono, cioe' l'unica
   via d'uscita di chi ha appena visto fallire il modulo, e su privacy.html e'
   l'indirizzo a cui si scrive per esercitare i propri diritti.
   Il lockup in cima non era coinvolto: ha la sua classe e il suo colore. */
/* `:not(.lockup)`: il marchio in cima e' un'ancora anche lui, e con la sola
   `.fallback a` si prendeva la sottolineatura, che su un lockup e' un errore
   (`.lockup` dichiara `text-decoration: none`, ma perde per specificita').
   Non si vede in nessuna misura di contrasto: si vede guardando la pagina. */
.fallback a:not(.lockup) {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Il link che sta da solo e' un bersaglio, non una parola dentro una frase:
   li' l'eccezione per i link in linea di WCAG 2.5.8 non vale e l'area va data.
   Serve una classe e non `p > a:only-child`, che sembra dire la stessa cosa e
   non la dice: `:only-child` guarda gli ELEMENTI e ignora i nodi di testo,
   quindi in "scrivi a <a>un indirizzo</a>." l'ancora risulta figlia unica e si
   prendeva anche lei il box da 44px, in mezzo alla frase. Misurato quando quel
   caso c'era davvero, sul numero di telefono di errore.html: passava da 23 a
   44px di altezza e sfondava la riga. Il numero non c'e' piu', ma i link in
   linea si': nell'informativa privacy ce ne sono cinque dentro frasi.
   I link dentro il testo restano alti quanto la riga, ed e' corretto cosi'. */
.fallback__azione {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* ---------------------------------------------------------------- scorri */

/* Il richiamo allo scroll esiste solo nel layout impilato: lo accende il blocco
   a max-width 767px. Dichiararlo spento qui e non lasciarlo fuori dal CSS serve
   a una cosa sola: che a desktop non compaia mai, nemmeno per un frame, se un
   giorno qualcuno tocca l'ordine dei fogli. */
.scorri { display: none; }

/* ---------------------------------------------------------------- legale */

/* L'informativa privacy sta sullo stesso impianto delle pagine di esito
   (`.fallback`), ma non e' una pagina di esito: e' un documento che si legge
   tutto, con una gerarchia sua e una lunghezza vera. Queste righe cambiano solo
   cio' che quella lunghezza rende sbagliato.
   Vive accanto a `.fallback` e non dentro un foglio suo per la stessa ragione
   per cui i font stanno in questo file: una seconda richiesta CSS su una pagina
   che il sito linka dal modulo e dal piede non si ripaga. */
.legale { max-width: 48rem; padding-bottom: 5rem; }

/* 40ch e' la misura giusta per tre righe di ringraziamento, non per un
   documento: qui la colonna corta spezzerebbe ogni frase in cinque tronconi. */
.legale p,
.legale li { max-width: 72ch; }

.legale h1 { margin-bottom: .5rem; }

/* Data di revisione. Un'informativa senza data non si puo' confrontare con
   quella che si e' accettata, ed e' la prima cosa che chiede chi contesta. */
.legale__data {
  font-size: .78rem;
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .55);
  margin-bottom: 2.5rem;
}

/* Il numero della sezione sta nel testo dell'h2 e non in un contatore CSS:
   l'informativa si cita per numero di paragrafo ("al punto 7"), quindi quel
   numero deve esistere anche per chi copia il testo, chi lo stampa e chi lo
   ascolta con uno screen reader. */
.legale h2 {
  font-weight: 400;
  font-size: 1.15rem;
  letter-spacing: .01em;
  line-height: 1.35;
  margin: 3rem 0 .9rem;
  padding-top: 1.25rem;
  border-top: 1px solid rgb(255 255 255 / .12);
  color: var(--ink);
}

.legale h3 {
  font-weight: 500;
  font-size: .78rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .62);
  margin: 1.75rem 0 .6rem;
}

.legale ul {
  color: var(--ink-dim);
  line-height: 1.6;
  margin: 0 0 1rem;
  padding-left: 1.1rem;
}
.legale li { margin-bottom: .55rem; }
.legale li::marker { color: rgb(255 255 255 / .42); }

/* Elenco dei dati raccolti: termine e definizione su due colonne da 600px in
   su, impilati sotto. Non una tabella, perche' non ci sono due assi da
   incrociare: c'e' un campo e cosa se ne fa. */
.legale dl {
  margin: 0 0 1.5rem;
  color: var(--ink-dim);
  line-height: 1.6;
}

.legale dt {
  font-weight: 500;
  color: var(--ink);
  margin-top: 1rem;
}

.legale dd { margin: .2rem 0 0; max-width: 72ch; }

@media (min-width: 600px) {
  .legale dl {
    display: grid;
    grid-template-columns: minmax(9rem, 14rem) 1fr;
    gap: .2rem 2rem;
  }
  .legale dt { margin-top: .9rem; }
  .legale dd { margin-top: .9rem; }
}

/* Il piede della pagina legale: il ritorno al sito e il recapito, sullo stesso
   bordo che separa le sezioni qui sopra. */
.legale__piede {
  margin-top: 3.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgb(255 255 255 / .12);
}

/* ---------------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
  .act { height: auto; }
  /* Qui `dvh` resta: sotto reduced-motion il palcoscenico non e' incollato e non
     scorre fotogrammi, quindi la barra del browser che si nasconde non fa
     nessun danno - e `min-height` con il viewport piccolo e' la misura giusta,
     perche' garantisce la schermata piena senza mai spingere il testo sotto la
     barra. */
  .act__stage { position: static; height: auto; min-height: 100dvh; }
  /* Nessuno sticky, nessun passaggio da cucire. Sotto reduced-motion main.js
     non crea nemmeno l'elemento: la riga resta come rete, non come rimedio. */
  .act__seams { display: none; }
  .progress { display: none; }
  /* `visibility` insieme all'opacita': qui main.js non gira il ramo che mette
     `is-visible`, quindi questa e' l'unica riga che riaccende la barra. Con la
     sola opacita' resterebbe invisibile per sempre. */
  .head { opacity: 1; visibility: visible; }
  .head a { pointer-events: auto; }

  /* Le fasi orizzontali si impilano. La versione precedente faceva
     display:none sul track delle schede, cancellando titolo e specifiche:
     perdita di contenuto, non solo di movimento. */
  .act__track,
  .act__track--specs {
    flex-direction: column;
    align-items: flex-start;
    gap: 1.5rem;
    place-self: center start;
    padding: calc(var(--head-h) + var(--pad-y)) var(--pad-x) var(--pad-y);
    transform: none !important;
    will-change: auto;
  }
  .spec, .note { width: min(92vw, 34rem); }

  /* Senza scorrimento il titolo non ha nulla accanto a cui restare fisso:
     torna un normale blocco sopra i pannelli. */
  /* Senza scorrimento non c'e' nulla accanto a cui restare fissi: titolo e
     binario tornano due blocchi in colonna, quindi via la cella condivisa. */
  .act--h .panel-lead,
  .act--h .act__track { grid-area: auto; }

  .panel-lead {
    position: static;
    place-self: start start;
    max-width: none;
    padding: calc(var(--head-h) + var(--pad-y)) var(--pad-x) 0;
    /* Senza corsa non c'e' nessun pannello in arrivo da cui togliersi: il
       titolo resta. La riga vale anche come rete se --lead fosse rimasto
       scritto sull'atto da un layout precedente. */
    opacity: 1;
    transform: none;
  }

  /* Il palcoscenico della soglia qui diventa statico, quindi la cornice non puo'
     restare assoluta o collassa a zero: diventa una fascia e la firma le sta
     sotto, come il testo di ogni altro atto. Via anche la cella condivisa, che
     serviva a due battute che si scambiavano il posto: ne e' rimasta una. */
  .act--open .act__stage { grid-template-rows: min(56vh, 34rem) 1fr; align-content: start; }
  .act--open .open__frame { position: relative; grid-row: 1; }
  .act--open .open__sign {
    grid-area: auto;
    grid-row: 2;
    padding: var(--pad-y) var(--pad-x);
  }

  /* Nessuna riga per rimettere la firma opaca e ferma: main.js non gira in
     questo ramo, quindi --run resta 0, e a --run 0 l'uscita non e' ancora
     cominciata. La formula la lascia gia' dove deve stare. */

  /* Il prologo e' movimento e nient'altro: non porta contenuto, quindi qui si
     toglie del tutto. Il sito parte direttamente dalla sua schermata di
     apertura, che e' poi quello che fa anche altrove: qui si salta solo il velo.
     Con il contenitore non renderizzato non resta niente da scaricare: il
     marchio e' vettore in pagina, non un file a parte. */
  .prologo { display: none; }
}

/* ---------------------------------------------------------------- mobile */

/* Sotto i 768px il fotogramma NON viene piu' ritagliato: sorgenti 16:9 dentro
   un viewport 9:19.5 in cover mostravano il 30% centrale, e la pergola usciva
   dall'inquadratura proprio dove arriva la maggior parte del traffico.
   Qui l'immagine occupa una fascia 16:9 intera e il testo sta sotto, sul fondo
   di marca: composizione integra e contrasto garantito senza velo. */
@media (max-width: 767px), (max-height: 500px) {
  /* Fascia 5:4 invece di 16:9: a tutta larghezza il fotogramma sarebbe alto
     211px su 812, cioe' il 26% dello schermo per quello che e' il prodotto.
     Il taglio laterale e' del 12% e il punto di messa a fuoco per atto tiene
     dentro la struttura. */
  /* Fascia 1:1 e non 5:4. A 80vw l'immagine era alta 300px su 812, il 37% dello
     schermo, e lo scrubbing dentro quella striscia non si percepiva: si pagavano
     30 fotogrammi per un movimento invisibile. A 100vw l'area cresce del 25% e
     il gesto si legge. Il ritaglio dal 16:9 trattiene il 56% della larghezza,
     centrato sul punto di messa a fuoco tarato per atto. */
  /* La fascia ha un TETTO in altezza, e non e' un ritocco: `100vw` nudo era il
     difetto piu' grave del sito. Col telefono girato il viewport vero e'
     734x283 - non 844x390, che e' una misura di scocca - e li' `100vw` vuol
     dire una fascia alta 734 dentro una finestra alta 283. La riga di testo
     cominciava 451px sotto il bordo, dentro un palcoscenico incollato con
     `overflow: hidden`, e sugli atti 02, 05 e 06 il testo non si vedeva
     affatto: nascosto al 731%, 1047% e 1064% della propria altezza.
     `56svh` e' il tetto: in verticale non morde (a 393x735 vale 412 contro i
     393 della larghezza, quindi vince `100vw` e la fascia resta quadrata come
     prima), e in orizzontale scende e lascia respirare il testo. */
  :root { --fascia: min(100vw, 56svh); }

  /* Quanto della schermata si prende la barra: la sua altezza, i pixel di barra
     di progresso che le stanno sopra e la coda della cappa, cioe' il tratto in
     cui la sfumatura finisce di scaricarsi. Un numero solo, letto da due punti -
     la cappa che lo disegna e la fascia che gli sta sotto - perche' scriverlo due
     volte vuol dire che il giorno che se ne cambia uno la fascia e la cappa
     smettono di combaciare. */
  :root { --cappa-h: calc(var(--head-h) + var(--progress-h) + 1.5rem); }

  /* La fascia si prende TUTTO lo spazio che il testo non usa, e il testo sta
     sotto, alto quanto e' lui.
     Prima erano `var(--fascia) 1fr`: la fascia aveva un'altezza fissa e la riga
     sotto teneva tutto il resto, con il testo centrato dentro. Su un 375x812
     voleva dire 375px di fotografia, 270 di testo e 167 di fondo blu vuoto -
     una schermata che per un quinto non diceva niente, e che il fondo di marca
     rendeva tutta della stessa tinta. Il difetto e' lo stesso gia' corretto
     sulla soglia dell'apertura il giorno che la firma galleggiava fra due
     buchi: la' si era spostato il vuoto in fondo, qui lo si toglie.
     `minmax(0, 1fr)` e non `minmax(var(--fascia), 1fr)`: il minimo a zero e'
     cio' che tiene il ramo orizzontale. Col telefono girato il viewport e'
     734x283 e il testo se ne prende 150: con un minimo a 56svh la fascia
     pretenderebbe 158px che non ci sono, e il testo tornerebbe sotto il bordo -
     esattamente il difetto che il tetto `56svh` era stato messo a curare. Con
     lo zero la fascia cede quello che serve e il testo si vede sempre.
     `--fascia` resta e non e' morta: e' la misura su cui e' tarato il taglio
     d'angolo qui sotto, ed e' l'altezza che la fascia ha su uno schermo corto,
     dove il testo si prende quasi tutto il resto. */
  /* E la fascia comincia SOTTO la barra, non dietro.
     Il palcoscenico e' incollato a `top: 0` e la barra e' `fixed` in cima: per
     tutta la corsa dell'atto i 95px alti del fotogramma stavano dietro alla
     barra e alla sua cappa, cioe' il 18% dell'immagine coperto in modo fisso,
     non di passaggio. Sull'apertura non si vedeva perche' li' la barra e'
     ancora spenta - e' l'atto in cui compare - quindi il difetto cominciava
     esattamente dal secondo atto in poi e restava fino alla fine.
     Il rimedio non e' spostare la barra ne' schiarirla: e' dichiarare che quei
     pixel sono suoi. Il palcoscenico si incolla SOTTO la cappa e si accorcia di
     altrettanto, quindi la riga di griglia parte dove la sfumatura ha finito di
     scaricarsi: sopra la fotografia non passa nemmeno la coda e il primo pixel
     del fotogramma e' gia' pieno.
     Costo misurato su un 375x812: la fascia passa da 542 a 447 punti. Si perde
     il 17% di altezza per vedere il 100% di quello che resta, invece del 100%
     di un'immagine a cui manca la cima.
     `top` e `height` e non un `padding-top`, che e' come era scritta la prima
     volta. Col padding quei 95px erano DENTRO il palcoscenico, quindi mentre
     l'atto entrava dal basso si vedeva una striscia di campitura vuota fra
     l'ultimo pannello dell'atto precedente e il primo pixel di questo: la
     riserva per la barra si sommava al margine di chiusura di quello prima e i
     due facevano un buco di 203px. Spostata su `top`, la riserva non e' piu'
     una striscia di questo atto ma lo spazio che la barra occupa comunque, e al
     passaggio fra due atti non c'e' piu' niente da sommare.
     La misura e' costante e non legata a `.is-visible`: legarla rifarebbe il
     layout - e quindi la misura del canvas e i suoi fotogrammi - ogni volta che
     la barra va e viene. */
  .act__stage {
    grid-template-rows: minmax(0, 1fr) auto;
    align-content: start;
    top: var(--cappa-h);
    height: calc(100svh - var(--cappa-h));
  }

  /* Terza applicazione del taglio, a una scala del tutto diversa dal bottone e
     dai pannelli: la fascia immagine. Stesso angolo, corsa proporzionata
     all'altezza della fascia. */
  .act__canvas,
  .open__canvas,
  .act__video {
    position: static;
    grid-row: 1;
    width: 100%;
    /* L'altezza la decide la riga di griglia, non questa regola. Era
       `var(--fascia)`, cioe' lo stesso numero scritto due volte: il giorno che
       la riga ha smesso di essere alta `--fascia` la fotografia sarebbe
       rimasta della sua altezza vecchia dentro una cella piu' grande, con una
       striscia di fondo blu sotto - cioe' il vuoto che si stava togliendo,
       spostato di mezza schermata. */
    height: 100%;
    /* Il taglio segue l'ALTEZZA della fascia e non la larghezza. Legato a `vw`,
       col telefono girato diventava una diagonale da 81px su una fascia alta
       147: se la mangiava. Alla stessa frazione dell'altezza l'angolo resta
       quello di DESIGN.md - misurato 36,17 gradi sul canvas e sul bottone. */
    /* Il taglio resta tarato su `--fascia` e non sull'altezza vera della cella,
       che in CSS non si puo' leggere: `%` dentro `polygon()` si misura sulla
       larghezza per la x e sull'altezza per la y, quindi una coppia in
       percentuale terrebbe la proporzione ma NON l'angolo, che e' la sola cosa
       che conta (36,17 gradi, DESIGN.md). Il risultato: la smussatura resta
       quella di sempre in pixel - 41px su un 375 - e su uno schermo alto, dove
       la fascia adesso arriva a 542, si legge come il 7,6% invece dell'11.
       Piu' fine, non diversa: l'angolo e' identico. */
    --shear-y: calc(var(--fascia) * .11);
    clip-path: var(--shear-cut);
  }

  .veil { grid-row: 1; height: 100%; inset: auto; }
  /* Su mobile il testo sta sotto l'immagine, sul fondo pieno: il velo qui non
     protegge nulla, serve solo a chiudere il bordo inferiore della fascia.
     Quindi puo' essere molto piu' leggero che a desktop. */
  .veil--left, .veil--bottom, .veil--center {
    background: linear-gradient(to top, rgb(7 37 53 / .34) 0%, rgb(7 37 53 / 0) 40%);
  }
  /* Questo gradiente e' gia' il valore giusto, non il massimo di una corsa:
     lasciarlo scalare da `--veil-k` lo sbiadirebbe senza motivo, e qui sotto il
     testo non ci passa comunque nessuna fotografia. */
  .veil--left { opacity: 1; }

  /* Il testo rientra nell'area sicura, la fascia immagine no. E' la regola, e
     vale la pena scriverla per intero perche' la meta' facile e' quella
     sbagliata: rientrare TUTTO darebbe gli stessi pixel utili di prima piu' il
     cambio di ramo, cioe' il costo senza il guadagno.
     Misurato su un iPhone 14 Pro: in verticale gli inset sono zero con e senza
     `cover` - la cornice di Safari sta gia' fuori dalla pagina - quindi qui non
     cambia niente. In orizzontale sono 59 per lato: la pagina passa da 734 a
     852 punti, l'immagine se li prende tutti e il testo resta largo 734, cioe'
     esattamente quanto era prima.
     `max()` e non solo `env()`: dove il notch non c'e', `env()` vale 0 e il
     padding di marca deve restare. */
  .act__copy,
  .act__track,
  .act__track--specs {
    grid-row: 2;
    place-self: center start !important;
    text-align: left !important;
    max-width: none;
    padding: var(--pad-y) max(var(--pad-x), env(safe-area-inset-right))
             calc(var(--pad-y) + 3rem) max(var(--pad-x), env(safe-area-inset-left));
  }

  .act__copy { padding-block: 1.75rem 2.5rem; }
  .copy--center .display, .copy--center .lead, .copy--center .form { margin-inline: 0; }
  /* La gerarchia si dimezzava proprio dove arriva la maggior parte del traffico.
     Misurato a 375: titolo d'atto 25,6px sopra un corpo da 16,32, rapporto
     1,57:1, stesso peso e stesso bianco. A 1440 lo stesso rapporto e' 3,02:1.
     Un messaggio per schermata senza gerarchia e' un messaggio che non si legge:
     il titolo diventa "testo un po' piu' grande" e l'occhio non sa da dove
     partire.
     Ora il titolo d'atto sta a 33,75px su 375 e il corpo a 17: rapporto 1,98.
     Non arriva ai 3:1 di desktop, ed e' giusto cosi' - su una colonna da 375
     un display da 51px mangerebbe la schermata - ma smette di essere ambiguo.
     L'override del corpo a 1.02rem sparisce: il `clamp` di `.lead` ora cresce da
     solo e a 375 vale 17px, cioe' piu' di prima. Tenerlo qui significava
     ricomprimere a mano proprio dove serviva il contrario. */
  .display { font-size: clamp(2.05rem, 8.4vw, 2.7rem); }
  .display--sm { font-size: clamp(2rem, 9vw, 2.4rem); }

  /* Sotto i 767px le fasi orizzontali NON traslano. Il binario delle specifiche
     era largo 1903px su un viewport da 375: a qualunque posizione almeno un
     pannello restava bisecato da un bordo e il titolo di sezione era fuori campo.
     Qui l'atto diventa una sezione normale e i pannelli si impilano. */
  /* Impilato non c'e' nessun passaggio fra sticky da cucire: il testo sta su
     fondo pieno e una sfumatura sui bordi coprirebbe solo l'immagine. */
  .act__seams { display: none; }

  /* L'atto a video non ha nessuna corsa da far scorrere, e tenergliela era un
     blocco vero.
     Gli altri atti verticali sono alti 180vh su un palcoscenico incollato da
     100: i 675px di differenza a 390x844 non sono fermi, sono lo scrub, e il
     dito ci vede scorrere i fotogrammi. Qui no. La clip gira sul proprio
     orologio e non guarda lo scroll, il testo e' fermo, il palcoscenico e'
     incollato: per 675px lo schermo non risponde al gesto. Non e' una pausa di
     regia, e' l'unico punto del sito dove si scorre e non succede niente, e si
     legge esattamente per quello che e'.
     A 100vh il palcoscenico non ha piu' margine su cui restare incollato:
     l'atto e' alto quanto la schermata che mostra e si esce quando si e'
     finito di leggerlo.
     Solo qui e solo sotto i 768px. A desktop la corsa serve ancora, perche' e'
     su di lei che le cuciture fra sticky sfumano i due bordi (--seam-t e
     --seam-b, scritte da main.js sugli estremi della corsa): azzerarla farebbe
     ricomparire la riga di taglio fra questo atto e i suoi vicini. Sotto i
     768px le cuciture sono spente e non c'e' niente da preservare.
     main.js regge: `span = rect.height - vh` va a zero, `to` diventa 0, e il
     ramo che disegna i fotogrammi questo atto non lo attraversa comunque
     (`if (!s.video)`). L'altezza non gliela ricalcola nessuno: governHorizontal
     tocca solo gli atti con un binario. */
  /* `svh` come il palcoscenico. Con `vh` l'atto sarebbe 61px piu' alto della
     sua scena, cioe' esattamente la corsa morta che il commento qui sopra ha
     tolto: si scorre e non succede niente. */
  .act[data-act="05"] { --len: 100svh; }

  .act--h { height: auto; }
  /* Il palcoscenico non e' incollato: e' piu' alto di una schermata e deve
     scorrere tutto. A restare ferma e' la sola fascia, qui sotto. */
  .act--h .act__stage {
    position: static;
    height: auto;
    overflow: visible;
    grid-template-rows: var(--fascia) auto auto;
  }
  /* Impilati, il titolo torna un normale blocco sopra i pannelli: fissarlo
     accanto al binario ha senso solo quando il binario scorre. */
  .act--h .panel-lead {
    position: static;
    place-self: start start;
    grid-row: 2;
    max-width: none;
    padding: var(--pad-y) max(var(--pad-x), env(safe-area-inset-right)) 0
             max(var(--pad-x), env(safe-area-inset-left));
    /* Impilato il titolo sta sopra i pannelli e non incontra nulla: niente
       dissolvenza, qualunque cosa sia rimasta scritta su --lead. */
    opacity: 1;
    transform: none;
  }
  .act--h .act__track,
  .act--h .act__track--specs { grid-row: 3; }
  .act--h .act__track,
  .act--h .act__track--specs {
    flex-direction: column;
    align-items: flex-start;
    gap: 1.5rem;
    padding-inline: max(var(--pad-x), env(safe-area-inset-left))
                    max(var(--pad-x), env(safe-area-inset-right));
    /* `--pad-y` secco e non `calc(--pad-y + 3rem)`, che e' il valore ereditato
       dalla regola generale del testo d'atto. Quei 3rem in piu' servono dentro
       un palcoscenico incollato, dove il testo e' l'ultima riga e senza margine
       toccherebbe il bordo basso della schermata. Qui il binario e' l'ultimo
       blocco di una sezione che finisce, quindi i 48px non staccano il testo da
       niente: sono il fondo del vuoto che si legge fra un atto e il successivo.
       Misurati 107,64px, su un buco che ne faceva 203. */
    padding-bottom: var(--pad-y);
    /* Senza `!important`, che c'era. In colonna la traslazione non serve e va
       azzerata - se si arriva qui restringendo una finestra desktop, sul
       binario e' rimasta scritta quella del layout di prima - ma `!important`
       la azzerava anche nel ramo a binario qui sotto, dove e' il JS a
       scriverla. Senza, lo stile in linea vince comunque su questa riga, che
       resta a fare il suo lavoro dove il binario non trasla. */
    transform: none;
    will-change: auto;
  }
  /* `100%` e non `88vw`, ed e' una correzione non un ritocco: il binario che li
     contiene ha `padding-inline: var(--pad-x)`, che sotto i 768px vale 5vw per
     lato. 88 + 5 + 5 fa 98vw, ma il `vw` e' il viewport CON la barra di
     scorrimento mentre lo spazio disponibile e' il contenuto SENZA. Misurato a
     390 di finestra e barra classica da 15px: pannelli larghi 343 dentro 375 di
     contenuto, scrollWidth 383, cioe' 8px di scorrimento orizzontale su una
     pagina che non ne ha nessuno. Su un telefono non si vede (le barre stanno in
     sovrimpressione e non tolgono larghezza), si vede stringendo una finestra
     desktop sotto i 768.
     Con `100%` la misura e' quella del contenitore, gia' al netto del padding e
     della barra, e non puo' sforare per costruzione. Il tetto a 30rem resta. */
  .spec, .note { width: min(100%, 30rem); }

  /* Il richiamo allo scroll occupa la terza riga della soglia, quella che
     restava vuota. Centrato nella riga e non appoggiato al fondo: appoggiato
     al fondo diventerebbe un piede di pagina, al centro resta il seguito della
     firma che ha sopra. */
  /* A bandiera sinistra e non centrato, che sarebbe la scelta convenzionale per
     un richiamo allo scroll. Sotto i 768px questo sito non centra niente: la
     fascia, il marchio, il titolo, il sottotitolo e il testo di ogni atto sono
     tutti allineati allo stesso bordo a `var(--pad-x)`. Una parola centrata in
     mezzo a quella colonna non si legge come un'indicazione di servizio, si
     legge come un elemento fuori registro. */
  .scorri {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .8rem;
    grid-row: 3;
    place-self: center start;
    margin: 0;
    padding-inline: var(--pad-x);
    font-size: .68rem;
    font-weight: 400;
    letter-spacing: .28em;
    text-transform: uppercase;
    /* Attenuato: e' un'istruzione di servizio, non deve competere con il payoff
       che sta due righe sopra. Su --field misura 5,4:1, ben oltre la soglia. */
    color: rgb(255 255 255 / .5);
  }

  /* Il filo sotto la parola. Un gradiente che si spegne in basso e non una riga
     piena: cosi' la fine non e' un punto ma una direzione.
     La prima meta' resta piena e solo la seconda sfuma. Con la sfumatura su
     tutta l'altezza il filo era leggibile per una quindicina di pixel e poi
     spariva: alla scala a cui lo si guarda davvero restava un trattino, non una
     direzione. Stesso peso del filo dei pannelli vetrate (1px, bianco al 34%),
     che e' l'unico altro tratto sottile del sito e si vede. */
  .scorri::after {
    content: "";
    width: 1px;
    height: 3.2rem;
    background: linear-gradient(to bottom,
      rgb(255 255 255 / .5) 0%,
      rgb(255 255 255 / .5) 45%,
      rgb(255 255 255 / 0) 100%);
  }

  .lockup--lg { font-size: 1.55rem; margin-bottom: 1.1rem; }
  /* Target tattile minimo 44px: la versione stretta scendeva a 34. */
  .head__cta {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 .95rem;
    letter-spacing: .1em;
  }

  /* Qui la velatura diventa una cappa piena, ed e' l'unica differenza di
     disegno fra i due layout.
     Sotto i 768px il raccordo fra atti non esiste (vedere il blocco a
     min-width: 768px): i palcoscenici non si sovrappongono, sono fasce
     adiacenti che scorrono, e le fasi orizzontali non sono nemmeno incollate,
     sono sezioni normali. Non c'e' quindi nessuna dissolvenza che porti il
     testo a zero prima che arrivi quassu': misurati 21 attraversamenti su un
     390x844, uno per ogni titolo e per ognuno dei sei pannelli specifica, piu'
     il peggiore di tutti - "Parliamone." dentro il marchio, a fondo pagina,
     che e' uno stato fermo e non di passaggio.
     Con il testo su fondo pieno per quasi tutta la pagina la cappa e' anche
     invisibile: coincide con il colore che ha sotto. Si vede solo dove
     attraversa la fascia fotografica, ed e' li' che serve pure al bottone, che
     stava in bianco sopra i LED accesi. */
  /* La cappa parte dal bordo dello SCHERMO e non dal bordo dell'header, cioe'
     risale i --progress-h che separano i due. Quella fessura era l'unico punto
     della schermata in cui si vedevano scorrere i fotogrammi mentre il resto
     stava fermo: la traccia della barra di progresso e' bianca al 12%, quindi
     trasparente all'88%, e sotto ci passa il canvas dell'apertura.
     A desktop la fessura c'e' ancora ed e' giusto che ci sia: li' sotto
     l'header scorre la fotografia a pieno campo per tutta la pagina, la cappa
     e' una velatura e non una campitura, e tre pixel di fotografia in cima sono
     la continuazione di quello che si vede sotto. Qui no: qui sotto c'e'
     campitura piena, e quei tre pixel erano una crepa.
     La barra di progresso resta visibile e sopra la cappa (z-index 30 contro
     -1): cambia che ora il suo 12% di bianco sta su navy fermo invece che su
     una fotografia in movimento, cioe' si legge come una barra. */
  .head::before {
    top: calc(var(--progress-h) * -1);
    height: var(--cappa-h);
    background: linear-gradient(to bottom,
      var(--field) 0,
      var(--field) calc(var(--head-h) + var(--progress-h)),
      rgb(7 37 53 / 0) 100%);
  }
  .foot { font-size: .8125rem; }

  /* Il contatto si allinea a sinistra come tutto il resto del layout impilato.
     Era l'unico blocco rimasto centrato, e non per scelta: sotto i 768px ogni
     atto forza gia' `text-align: left !important` sul proprio copy, mentre
     questa sezione non e' un atto e quella regola non la tocca. Il risultato era
     titolo e sottotitolo centrati sopra etichette e campi a bandiera sinistra,
     cioe' due margini di lettura diversi nella schermata dove si decide se
     lasciare il proprio numero. Una colonna sola vuole un bordo solo. */
  .contact__inner { text-align: left; }
  .contact__inner .display,
  .contact__inner .lead,
  .contact .form,
  .form__esito { margin-inline: 0; }

  /* La soglia segue la stessa regola degli altri atti: sotto i 768px il
     fotogramma non si ritaglia, occupa la fascia e il testo sta sotto sul fondo
     pieno. */
  /* Fascia a 80vw e non 100 come gli altri atti: qui sotto la fascia non ci va
     una riga di testo ma la firma intera (lockup, titolo display e tre righe di
     sottotitolo, ~241px misurati). Su un 360x640 la fascia da 100vw ne lasciava
     280 e la firma veniva tagliata dal basso; a 80vw ne restano 352 e ci sta con
     56px di margine. Il fotogramma non ci perde: 100vw x 80vw ritaglia il 28%
     dei lati contro il 44% del quadrato, quindi si vede piu' pergola, non meno. */
  /* Niente soglia da scorrere, quindi niente split: qui la firma sta sotto la
     fascia su fondo pieno e non se ne va (vedere piu' sotto), mentre a desktop
     i primi 60vh servono a dissolverla. Tenerli anche qui sarebbe mezza
     schermata di scroll per non far succedere niente prima che i fotogrammi
     comincino. Lo scrub e' 100vh, cioe' tutta la corsa (200 - 100 di viewport).
     E qui la consegna e' l'altra: 30 fotogrammi in AVIF a cinque livelli, non i
     240 in WebP del ramo desktop. Le ragioni sono tre, misurate, e stanno per
     esteso in tools/build-apertura.py; la piu' corta e' che 240 fotogrammi su
     735px di corsa fanno un fotogramma ogni 3,1 pixel, e nessun dito e' cosi'
     preciso. Il peso ne e' la conseguenza: 0,57 MB su un iPhone contro 10,89.
     Il passo non e' identico ai due rami e non deve sembrarlo: 100vh su 29
     intervalli fanno 3,45vh per fotogramma, contro l'1,38 di desktop. Due volte
     e mezzo piu' rado, su una corsa che il pollice fa in un gesto solo - dove
     l'unita' di misura non e' la tacca della rotellina ma la sfiorata, e la
     scorsa e' comunque piu' lenta di quella che un dito puo' dare a una pagina
     alta venti schermate.
     I due numeri di questa riga vanno insieme: cambiare --len senza
     --fotogrammi (o viceversa) e' il difetto del 21/08/2026, spiegato dove
     --fotogrammi e' dichiarato la prima volta. */
  .act--open { --len: 200vh; --split: 0; --fotogrammi: 30; }

  /* Tre righe e non due, ed e' il rimedio a una schermata che non teneva.
     Con `80vw 1fr` la fascia era alta 312px su un 390x844 e la firma, dentro
     l'unica riga elastica, stava al suo CENTRO: 178px di campitura vuota fra
     immagine e testo e 184 sotto il testo. Il prodotto entrava per il 37%
     dello schermo, il resto era due buchi quasi uguali e una firma che
     galleggiava in mezzo senza appartenere a niente. E' la prima schermata sul
     dispositivo da cui arriva piu' gente.
     Adesso la fascia cresce fino a mezza schermata scarsa, la firma le sta
     attaccata sotto, e lo spazio che avanza sta tutto in fondo, in una riga
     sua: un vuoto solo, dopo il testo, dove si legge come respiro invece che
     come errore di montaggio.
     `min(100vw, 46vh)` e non `100vw` secco: il quadrato pieno su uno schermo
     corto - 360x640 e' ancora in giro - lascerebbe 280px per una firma che ne
     misura 241 piu' i suoi margini, e il sottotitolo verrebbe tagliato dal
     basso. A 46vh restano 294px di fascia e la firma chiude a 595 su 640.
     `svh` e non `vh` ne' `dvh`: `dvh` rifarebbe il layout mentre la barra del
     browser si nasconde, e `vh` e' il viewport grande, cioe' piu' alto del
     palcoscenico che ora e' `100svh`. Stessa scelta del resto degli atti.
     La soglia aveva gia' il tetto in altezza quando gli altri atti non ce
     l'avevano: quello che segue e' il caso generale che la raggiunge, non il
     contrario. Qui il numero e' 46 e non 56 perche' sotto la fascia non ci va
     una riga di testo ma la firma intera. */
  .act--open { --fascia: min(100vw, 46svh); }
  /* Due righe e non tre, dal 21/08/2026, e ribalta la scelta che il commento
     qui sopra racconta. Allora il vuoto c'era e lo si era spostato tutto in
     fondo, in una riga sua, perche' un buco solo dopo il testo si legge come
     respiro mentre due buchi attorno alla firma si leggono come errore di
     montaggio. Vero, ma restava un buco: su un 390x844 sono 180px di fondo blu
     sotto la firma, e su un telefono il fondo di marca e' gia' quasi tutto lo
     schermo. La richiesta e' stata di ridurre il blu, quindi il vuoto non si
     sposta piu': la fascia se lo prende.
     `minmax(0, 1fr) auto` come gli altri atti, e per le stesse ragioni scritte
     dove quella riga e' dichiarata. Qui sotto la fascia non c'e' una riga di
     testo ma la firma intera (~241px misurati), quindi la fascia resta la
     meta' scarsa dello schermo su un telefono corto: il tetto `46svh` di
     `--fascia` ora conta solo per il taglio d'angolo. */
  /* E niente spazio riservato alla barra, che negli altri atti la fascia cede.
     Qui la barra e' spenta: compare a --run 1, cioe' quando la soglia ha finito
     la sua corsa e questo atto sta gia' uscendo di campo. Tenerle i pixel
     comunque vorrebbe dire una striscia di campitura vuota in cima alla prima
     schermata del sito, per una barra che li' non c'e'. */
  .act--open .act__stage {
    grid-template-rows: minmax(0, 1fr) auto;
    align-content: start;
    top: 0;
    height: 100svh;
  }

  /* Qui il taglio d'angolo va sulla CORNICE e non sul canvas come negli altri
     atti: nella soglia il canvas non e' la fascia, e' uno dei livelli dentro la
     fascia. Tagliando solo lui, poster e velo resterebbero fuori dalla smussatura
     e il bordo si leggerebbe come un errore di sovrapposizione. */
  .act--open .open__frame {
    position: relative;
    grid-row: 1;
    /* L'altezza la decide la riga di griglia, non questa regola: erano due
       numeri per la stessa misura e il giorno che se ne cambia uno solo la
       fascia e la sua cella smettono di coincidere. */
    height: 100%;
    /* Un numero solo per la stessa misura, che e' quello che dice il commento
       qui sopra: il taglio legge la fascia invece di ripeterne il valore. */
    --shear-y: calc(var(--fascia) * .11);
    clip-path: var(--shear-cut);
  }

  /* Sottratto alla regola a fascia qui sotto: dentro la cornice il canvas resta
     assoluto e a pieno riquadro, come a desktop. */
  .act--open .open__canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    clip-path: none;
  }

  /* La regola .veil qui sopra vale per tutti i veli e li stacca dal loro
     riquadro: dentro la cornice va rimesso a inset 0, o perde ancoraggio.
     E niente calo: il velo scende quando la firma se ne va, ma qui la firma non
     se ne va (sta sotto la fascia, su fondo pieno). Legarlo comunque a --eo lo
     farebbe scendere mentre il testo e' ancora tutto in campo, cioe' un cambio
     senza causa visibile. Su mobile poi non protegge testo: chiude il bordo
     basso della fascia, e quel lavoro serve per tutto lo scrub. */
  .act--open .veil { position: absolute; inset: 0; height: auto; opacity: 1; }

  /* La firma torna un blocco di testo sotto la fascia, come il copy di ogni
     altro atto: niente cella condivisa, che serviva a due battute che si
     scambiavano il posto. */
  /* `start` e non `center`: la firma appartiene alla fotografia che ha sopra e
     le sta attaccata. Centrata dentro la riga elastica galleggiava a meta' di
     un'area alta il doppio di lei. Lo spazio che avanza ora e' la terza riga,
     sotto. */
  .act--open .open__sign {
    grid-row: 2;
    place-self: start start;
    text-align: left;
    padding: 1.5rem var(--pad-x) 2rem;
  }

  .act--open .open__sign .lockup--lg { justify-content: flex-start; }
  .act--open .open__sign .display,
  .act--open .open__sign .lead { margin-inline: 0; }

  /* La firma non se ne va. A desktop lo fa perche' sta sopra la fotografia e
     deve liberare il campo allo scrub; qui sta sotto la fascia, su fondo pieno,
     e non copre niente. Dissolvendola resterebbe una fascia da 80vw in alto e
     ~350px di campitura vuota sotto per tutti i 180vh di scrub: mezzo schermo di
     niente. Il testo resta e lo scrub gli scorre sopra. */
  .act--open .open__sign { opacity: 1; transform: none; }
}

/* ------------------------------------------------- specifiche a due colonne */

/* Solo da 600 a 767, e il confine basso non e' arbitrario. Sotto i 600 le due
   colonne misurerebbero 167px l'una: "lega EN AW-6060, verniciato a polveri" ci
   sta in quattro righe, e sei pannelli sfrangiati sono peggio dei 971px in
   colonna che si volevano accorciare. A 600 le colonne stanno a 270px e i valori
   entrano in una riga o due, quindi l'atto si dimezza senza che il testo ne
   paghi niente.
   `grid` scavalca il `flex-direction: column` del blocco impilato qui sopra, che
   resta la regola giusta sotto i 600. */
/* Due colonne solo quando si impila. Affiancati i pannelli stanno gia' dentro
   la colonna del testo, e spezzarli ancora darebbe due colonne da ~190 punti. */
@media (min-width: 600px) and (max-width: 767px) and (max-aspect-ratio: 1/1) {
  .act--h .act__track--specs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.25rem;
    align-items: stretch;
  }
}

/* ------------------------------------------------- la barra su schermo basso

   68 punti su 283 sono il 24% dello schermo, e dentro ci stanno due bersagli
   alti 44 - il pavimento sotto cui non si scende - piu' 24 di respiro. Si
   tolgono i 24: restano 48, cioe' il 17%, e i bersagli non perdono un pixel.
   Solo dove lo schermo e' basso: a 393x735 gli stessi 68 punti sono il 9% e non
   c'e' niente da correggere. Un numero solo, letto da quattro punti del foglio.
   L'altra meta' - la barra che si toglie di mezzo mentre si legge - non e' CSS:
   sta in aggiornaHead(), web/main.js. */
@media (max-height: 500px) {
  :root { --head-h: 48px; }
}

/* ------------------------------- sotto i 767px e piu' largo che alto: affiancati

   Il confine di questo sito ha sempre chiesto "e' stretto?". Il guasto era che
   e' BASSO. Col telefono girato il viewport vero e' 734x283 - non 844x390, che
   e' una misura di scocca - e nessuno dei due rami reggeva: impilato nascondeva
   il testo di tre atti al 100%, e l'impaginazione da desktop, che si ottiene
   adottando `viewport-fit=cover` e passando a 852 di larghezza, ne nascondeva
   due sommari all'87-115%. Falliscono entrambi per la stessa ragione.
   Qui la domanda cambia: quando il viewport e' piu' largo che alto, immagine e
   testo si affiancano invece di impilarsi. `aspect-ratio` e non una larghezza,
   quindi vale a 734 come a 852 e non c'e' nessun numero da tenere allineato in
   otto punti. Misurato: testo irraggiungibile 0% su tutti e sei gli atti.
   `max-width: 767px` resta il confine di STACKED, che main.js legge dalla
   stessa media query: gli affiancati non sono un terzo ramo per il JS, i binari
   orizzontali restano spenti come nell'impilato. */
@media (max-width: 767px) and (min-aspect-ratio: 1/1),
       (max-height: 500px) and (min-aspect-ratio: 1/1) {
  /* E la barra torna a passare sopra, che impilati la fascia le cedeva i suoi
     pixel. E' una rinuncia dichiarata, non una dimenticanza: qui l'immagine e'
     una COLONNA alta quanto la finestra, e la finestra e' alta 283 punti. I 75
     che la cappa vorrebbe sono il 26% della colonna - lo stesso 26% che si
     starebbe cercando di scoprire - quindi cederli non guadagna niente, li
     sposta. In cambio su schermo basso la barra si toglie da sola al primo
     colpo verso il basso (aggiornaHead in web/main.js, `CORTO`): qui la
     copertura e' uno stato di passaggio, non fisso, ed e' proprio la differenza
     che rende il rimedio necessario nell'impilato e inutile qui. */
  .act__stage {
    grid-template-columns: 46% 1fr;
    grid-template-rows: 1fr;
    align-content: stretch;
    top: 0;
    height: 100svh;
  }

  /* Niente taglio d'angolo qui, ed e' una rinuncia dichiarata: affiancati il
     taglio cadrebbe sul bordo VERTICALE fra immagine e testo, che e' un'altra
     geometria da quella di DESIGN.md e non e' stata disegnata. Meglio assente
     che storto. Il taglio resta in verticale, dove la fascia ha il bordo
     orizzontale per cui e' stato pensato. */
  .act__canvas,
  .open__canvas,
  .act__video {
    grid-column: 1;
    grid-row: 1;
    width: 100%;
    height: 100%;
    --shear-y: 0px;
    clip-path: none;
  }

  .veil { grid-column: 1; grid-row: 1; height: 100%; }

  /* `overflow-y: auto` e' la rete, non il piano: se un testo non ci sta in 283
     punti si scorre dentro la sua colonna invece di sparire sotto il bordo di
     un palcoscenico incollato, che e' come spariva prima. */
  .act__copy {
    grid-column: 2;
    grid-row: 1;
    padding-block: 1rem;
    overflow-y: auto;
    max-height: 100%;
  }

  /* Gli atti orizzontali restano a palcoscenico statico e alto: l'immagine ci
     sta incollata dentro mentre i pannelli le scorrono accanto. */
  .act--h .act__stage {
    grid-template-columns: 46% 1fr;
    grid-template-rows: auto 1fr;
  }
  .act--h .act__canvas {
    grid-column: 1;
    grid-row: 1 / -1;
    position: sticky;
    top: 0;
    height: 100svh;
  }
  .act--h .panel-lead { grid-column: 2; grid-row: 1; }
  .act--h .act__track,
  .act--h .act__track--specs { grid-column: 2; grid-row: 2; }

  /* La soglia: i suoi tre figli vanno tenuti nella stessa griglia a due
     colonne, o la cornice - che non ha larghezza intrinseca - finisce in una
     colonna implicita larga zero. Misurato durante il prototipo:
     `grid-template-columns: 295.484px 0px 97.5156px`. */
  .act--open .act__stage {
    grid-template-columns: 46% 1fr;
    grid-template-rows: 1fr;
  }
  .act--open .open__frame {
    grid-column: 1;
    grid-row: 1;
    height: 100%;
    clip-path: none;
  }
  .act--open .open__sign,
  .act--open .scorri {
    grid-column: 2;
    grid-row: 1;
    place-self: center start;
  }
  .act--open .scorri { place-self: end start; }

  /* Su 283 punti di altezza il display da 33,75 mangia mezza colonna. */
  .display { font-size: clamp(1.5rem, 4.6vw, 2.1rem); }
}

/* --------------------------------------- impilato: il binario torna a scorrere

   Le due fasi orizzontali sono gli unici atti in cui il testo non e' una riga
   ferma ma un binario di pannelli. A desktop il palcoscenico resta incollato e
   il binario trasla su X; sotto i 768px la traslazione era spenta e i pannelli
   si impilavano in colonna, perche' il binario delle specifiche e' largo 1903px
   su un viewport da 375 e a qualunque posizione almeno un pannello restava
   bisecato da un bordo.

   Quella ragione e' caduta il giorno che la fascia ha smesso di essere un fondo
   a pieno campo ed e' diventata una striscia in cima: adesso sotto di lei c'e'
   una fascia di schermata che e' esattamente il posto dove far scorrere un
   binario, e i pannelli si tarano su 76vw invece che sulla larghezza intera.

   Impilati in colonna facevano un difetto peggiore di quello che evitavano: il
   binario e i pannelli hanno `z-index` 2 e 3 (vedi `.act__track` e
   `.panel-lead`), quindi salivano SOPRA la fotografia mentre si scorreva -
   testo su fotografia a giorno pieno, la cosa che questo foglio vieta ovunque
   altrove. Alzare l'indice del canvas l'avrebbe nascosto invece di risolverlo:
   i pannelli sarebbero spariti sotto l'immagine a meta' lettura.

   Col binario il problema non esiste: i pannelli non attraversano mai la
   fascia, le scorrono sotto in orizzontale.

   Solo in verticale (`max-aspect-ratio`) e solo a movimento consentito.
   Affiancati la fascia e' gia' una colonna e i pannelli hanno la loro,
   `governHorizontal` li lascia fermi; sotto reduced-motion main.js esce prima
   di montare il binario, quindi la colonna qui sopra resta l'unico layout che
   quel ramo puo' mostrare. Le due condizioni stanno nella stessa query e non
   annidate, come tutte le altre di questo foglio. */
@media (max-width: 767px) and (max-aspect-ratio: 1/1) and (prefers-reduced-motion: no-preference),
       (max-height: 500px) and (max-aspect-ratio: 1/1) and (prefers-reduced-motion: no-preference) {
  /* Torna un palcoscenico incollato come quello degli atti verticali, con la
     stessa riserva per la barra. L'altezza della sezione non e' piu' quella del
     contenuto: la scrive main.js dalla corsa del binario (governHorizontal),
     cosi' il rapporto fra gesto verticale e corsa orizzontale resta dichiarato
     in un punto solo. */
  .act--h .act__stage {
    position: sticky;
    top: var(--cappa-h);
    height: calc(100svh - var(--cappa-h));
    overflow: hidden;
    grid-template-rows: minmax(0, 1fr) auto auto;
  }

  .act--h .act__track,
  .act--h .act__track--specs {
    flex-direction: row;
    gap: clamp(1.25rem, 5vw, 2.5rem);
    /* Il bordo iniziale e' il margine di pagina e non il `min(42vw, 36rem)`
       della regola desktop: li' serve a lasciar posto al titolo fisso accanto
       al binario, qui il titolo sta nella riga sopra e quello spazio sarebbe
       mezza schermata di vuoto prima del primo pannello. */
    padding-inline: max(var(--pad-x), env(safe-area-inset-left))
                    max(var(--pad-x), 8vw);
    padding-block: 0 var(--pad-y);
    will-change: transform;
  }
  .act--h .act__track { align-items: center; }
  .act--h .act__track--specs { align-items: stretch; }

  /* Il titolo si alza e lascia respirare i pannelli. Impilato eredita
     `padding: var(--pad-y) ... 0`, cioe' tutto lo stacco sopra e niente sotto:
     il titolo galleggiava a 70 punti dalla fascia e il primo pannello gli
     partiva attaccato, con in mezzo la sola interlinea.
     Lo stesso `--pad-y` si divide fra i due lati. La SOMMA non cambia, ed e' la
     parte che conta: la riga di griglia e' `auto`, quindi tenerla identica
     lascia la fascia (`minmax(0, 1fr)`) e il binario esattamente dove stanno -
     si sposta il titolo dentro la sua riga, non il resto della schermata.
     55/45 e non a meta': sopra resta piu' spazio che sotto, cosi' il titolo sta
     piu' vicino ai pannelli che alla fotografia, che e' poi il gruppo a cui
     appartiene.
     Misurato a 430x932 sulla riga d'inchiostro e non sulla scatola: prima 59
     punti dalla fascia e MENO 5 dal primo pannello - il titolo ci entrava
     dentro - adesso 29 e 24. Fascia e binario restano a [95, 540] e
     [687, 932] in tutti e due i casi, che e' la prova che la riga non ha
     cambiato altezza. */
  .act--h .panel-lead {
    padding-block: calc(var(--pad-y) * .55) calc(var(--pad-y) * .45);
  }

  /* Le larghezze tornano quelle di sempre, che la colonna aveva riscritto a
     `min(100%, 30rem)`. Su un binario `100%` vuol dire un pannello per
     schermata: il bordo del successivo non si vede, e un binario di cui non si
     vede che continua non si scopre. A 76vw ne resta in campo una fetta. */
  .spec { width: min(76vw, 19rem); }
  .note { width: min(80vw, 23rem); }
}

/* ------------------------------------------------- scorri, movimento */

/* Il filo si disegna dall'alto verso il basso e poi si spegne: e' lo stesso
   gesto che si chiede di fare. `transform-origin: top` perche' altrimenti la
   riga crescerebbe dal centro in tutte e due le direzioni, che vuol dire il
   contrario.
   Le due condizioni stanno nella stessa query e non annidate: annidare un
   @media dentro un altro funziona sui browser aggiornati e non su tutti quelli
   che questo sito serve, e qui non c'e' niente da guadagnare a rischiarlo. */
@media (max-width: 767px) and (prefers-reduced-motion: no-preference),
       (max-height: 500px) and (prefers-reduced-motion: no-preference) {
  .scorri::after {
    transform-origin: top;
    animation: scorri 2.6s var(--ease) infinite;
  }
}

@keyframes scorri {
  0%   { transform: scaleY(0); opacity: 0; }
  22%  { opacity: 1; }
  62%  { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(1); opacity: 0; }
}

/* Sotto reduced-motion il richiamo sparisce del tutto invece di restare fermo.
   Li' la soglia non e' piu' un palcoscenico incollato (vedi il blocco
   reduced-motion piu' sopra: `.act__stage` diventa statico e alto quanto il suo
   contenuto), quindi la terza riga vuota non esiste e non c'e' nessun vuoto da
   spiegare. Sta dopo il blocco impilato perche' deve vincere per ordine. */
@media (max-width: 767px) and (prefers-reduced-motion: reduce),
       (max-height: 500px) and (prefers-reduced-motion: reduce) {
  .scorri { display: none; }

  /* E la fascia si riprende i pixel che aveva ceduto alla barra. Stessa ragione
     delle fasi orizzontali impilate: qui nessun palcoscenico e' incollato -
     `position: static` glielo toglie il blocco reduced-motion - quindi ogni
     atto e' una sezione che scorre, la barra le passa sopra per il tempo di un
     gesto e non c'e' nessuno stato fermo da scoprire. Riservarli lascerebbe
     una striscia di campitura vuota in cima a ognuno dei sei atti.
     `height: auto` e non solo `top`: il blocco impilato accorcia il
     palcoscenico di una cappa, e quel calcolo qui non vale niente - il
     palcoscenico e' alto quanto il suo contenuto, che e' piu' di una schermata.
     Sta qui e non nel blocco reduced-motion, che viene PRIMA dell'impilato e
     perderebbe per ordine. */
  .act__stage { top: auto; height: auto; }
}

/* ---------------------------------------------------------------- catalogo */

/* Otto pagine ferme: l'indice dei sette modelli e le sette schede. Vivono in
   questo foglio e non in uno loro per la stessa ragione gia' scritta per
   `.legale`, e perche' i tre pesi di Poppins stanno qui dentro come `data:` URI:
   un secondo foglio o li riduplica o resta senza font.
   Costo dichiarato: chi atterra sul catalogo da un motore scarica anche le
   regole dello scrollytelling, che qui non servono. Si accetta perche' e' un
   file solo, in cache per tutto il sito.

   ⚠️ **Sopra queste fotografie non va testo.** La tabella dei veli in DESIGN.md
   e' misurata sui fotogrammi all'ora blu, dove il pixel piu' chiaro sotto il
   testo sta a 180 su 255. Le 22 foto del catalogo sono a giorno pieno: il p99
   misurato va da 194 a 255, e meta' delle inquadrature ha cielo bianco o
   azzurro chiaro nel terzo alto. Un velo abbastanza forte da tenere il corpo
   sopra AA a 250 coprirebbe la fotografia invece di proteggerne il testo.
   Quindi: nome ed etichetta stanno SOTTO l'immagine, su campitura piena, dove il
   contrasto e' quello del resto del sito e non dipende da cosa c'e' nella foto. */

/* L'header delle pagine ferme. Sulla home `.head` nasce invisibile e la mostra
   main.js; qui non c'e' JavaScript, quindi la barra deve essere visibile da
   subito o non comparirebbe mai. `sticky` e non `fixed`: cosi' occupa la sua
   altezza nel flusso e il contenuto non ha bisogno di un margine che lo
   scavalchi. */
.head--ferma {
  position: sticky;
  inset: 0 auto auto auto;
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: none;
}

.head--ferma a { pointer-events: auto; }

/* Fondo pieno e non velatura: qui sotto non scorre una fotografia a pieno
   campo, scorre una pagina con la stessa campitura. Una sfumatura su fondo
   uguale a se stesso e' una riga di CSS che non si vede. */
.head--ferma::before {
  /* `content` e' gia' dichiarato su `.head::before` e questa regola non lo
     toglierebbe. Sta qui perche' prima-del-deploy.mjs cerca uno pseudo-elemento
     stilizzato senza `content` e non sa seguire la regola di partenza: meglio una
     riga ridondante che un controllo disinnescato. */
  content: '';
  height: 100%;
  background: var(--field);
  border-bottom: 1px solid rgb(255 255 255 / .12);
}

.head__nav { display: flex; align-items: center; gap: clamp(.75rem, 2.5vw, 1.75rem); }

/* Il link discreto accanto alla CTA. Stessa scala e stesso tracking del
   bottone, ma senza bordo e senza campitura: due bottoni pieni in una barra da
   tre elementi si annullano, e la conversione del sito resta una sola. */
.head__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--ink-dim);
  text-decoration: none;
  font-size: .8125rem;
  font-weight: 400;
  letter-spacing: .16em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color .35s var(--ease);
}

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

/* La voce della pagina corrente si segna con una riga sotto, non con un colore:
   il colore da solo non e' un'informazione per chi non lo distingue. */
.head__link[aria-current="page"] {
  color: var(--ink);
  box-shadow: inset 0 -1px 0 0 var(--ink);
}

/* La barra stretta. Misurata il 15/09/2026 su un viewport da 360px: con le due
   voci di prima la fila finiva a 364px contro 360 di schermo, cioe' sforava gia'
   di quattro pixel e la pagina aveva quattro pixel di scorrimento orizzontale che
   nessuno aveva notato. Aggiunta la terza voce, `Arredo`, lo sforo e' diventato
   ottanta.

   Qui si stringe tutto quello che si puo' stringere senza toccare due cose:
   l'altezza del bersaglio tattile del bottone, che resta 44px per il blocco a
   max-width:768px, e il fatto che `Parliamone` resti l'unico pieno. Si stringono
   invece il passo fra le voci, il corpo, la spaziatura fra lettere - che a .16em
   su un'etichetta maiuscola di otto caratteri vale sedici pixel di sola aria - e
   il margine laterale della barra, che qui non e' quello del contenuto.

   Il segno del marchio resta intero: `Eccelsa` scritto accanto al pittogramma e'
   il ritorno alla home, ed e' l'unico posto della pagina dove il nome compare. Si
   rimpicciolisce, non sparisce. */
@media (max-width: 27rem) {
  .head { padding-inline: .8rem; gap: .5rem; }
  .head__nav { gap: .55rem; }
  .head__link { font-size: .6875rem; letter-spacing: .06em; }
  /* Il bottone si stringe di corpo e di fianchi ma NON di altezza: `min-height:
     44px` arriva dal blocco a max-width:768px ed e' il bersaglio tattile minimo.
     Stringere l'altezza per far stare la riga sarebbe barattare un difetto di
     impaginazione con uno di accessibilita'. */
  .head__cta { font-size: .6875rem; letter-spacing: .05em; padding: 0 .55rem; }
  .lockup--sm { font-size: 1.05rem; }
}

/* Il gradino piu' stretto, per i 320px dei telefoni piccoli e delle finestre
   affiancate. Misurato: col blocco qui sopra la fila finiva a 359px, cioe'
   trentanove fuori. Qui sparisce anche l'ultimo margine e il passo fra le voci
   arriva al minimo leggibile. */
@media (max-width: 22.5rem) {
  .head { padding-inline: .6rem; gap: .35rem; }
  .head__nav { gap: .4rem; }
  .lockup--sm { font-size: .95rem; }
  .lockup { gap: .5em; }
}

/* La colonna del contenuto. 68rem e non "tutta la larghezza": oltre, la griglia
   arriva a cinque colonne e sette card ne lasciano due vuote nell'ultima riga. */
.catalogo,
.scheda,
.guida {
  max-width: 68rem;
  margin: 0 auto;
  padding: clamp(2.5rem, 7vh, 5rem) var(--pad-x) clamp(3rem, 8vh, 6rem);
}

/* `.cta` nasce a larghezza piena perche' nel modulo sta in colonna stretta. Qui
   sta in mezzo a una pagina larga, dove un bottone da 68rem non e' un bottone. */
.catalogo .cta,
.scheda .cta,
.guida .cta { width: auto; margin-top: 1.5rem; }

/* Etichetta maiuscola: la stessa scala che DESIGN.md fissa per il ruolo
   "etichette", .78-.8rem con tracking .12em. */
.etichetta {
  margin: 0 0 .9rem;
  font-size: .78rem;
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .55);
}

.catalogo__intro { margin-bottom: clamp(2.5rem, 6vh, 4rem); }
.catalogo__intro h1 { margin: 0 0 1.25rem; }
.catalogo__intro .lead { margin: 0; max-width: 44em; }

/* ------------------------------------------------------- griglia dell'indice */

.griglia {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1.25rem, 3vw, 2.25rem);
  /* 16rem e non 19: misurato a 1265px di viewport, dove la colonna del contenuto
     e' 962px e il varco 36px. Con 19rem servivano 984px per tre colonne, cioe'
     22 di troppo, e la griglia cadeva a due card da 462px l'una - due
     fotografie enormi e cinque modelli sotto la piega. Con 16rem le tre colonne
     entrano da 912px in su. */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
}

.card__link {
  display: block;
  color: inherit;
  text-decoration: none;
  border: 1px solid rgb(255 255 255 / .14);
  background: var(--field);
  transition: border-color .35s var(--ease);
}

.card__link:hover,
.card__link:focus-visible { border-color: rgb(255 255 255 / .42); }

/* Il ritaglio vive qui e non nel file: `overflow: hidden` piu' `transform` sulla
   figlia e' l'unico modo di far crescere l'immagine senza far crescere la card,
   che altrimenti spingerebbe le sei vicine a ogni passaggio del mouse. */
.card__quadro { display: block; overflow: hidden; }

.card__quadro img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform .6s var(--ease);
}

.card__link:hover .card__quadro img,
.card__link:focus-visible .card__quadro img { transform: scale(1.035); }

.card__testo { display: block; padding: 1.1rem 1.25rem 1.35rem; }

/* `h2` e non uno span: chi naviga per intestazioni deve trovare i sette modelli
   come indice della pagina, non un solo `h1` e poi il vuoto fino alla chiusura.
   Il margine predefinito dell'h2 va azzerato qui, e la scala e' quella della
   card, non quella dei titoli d'atto. */
.card__nome {
  display: block;
  margin: 0;
  font-size: 1.25rem;
  font-weight: 300;
  letter-spacing: .02em;
  line-height: 1.1;
}

/* L'etichetta e' l'unica cosa che distingue in griglia sette oggetti che da
   lontano si somigliano: sotto il nome, piu' piccola, ma non in grigio da nota a
   pie' di pagina. */
.card__etichetta {
  display: block;
  margin: .45rem 0 0;
  font-size: .8125rem;
  font-weight: 400;
  letter-spacing: .04em;
  color: var(--ink-dim);
}

/* ---------------------------------------------------------------- scheda */

.briciole {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .55em;
  margin-bottom: clamp(1.5rem, 4vh, 2.5rem);
  font-size: .78rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .55);
}

.briciole a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  /* 44px anche qui: e' l'unico modo di tornare all'indice senza il tasto
     indietro, e su un telefono una riga alta 17px non si prende. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.briciole a:hover { color: var(--ink); }

.scheda__testa h1 { margin: 0 0 .6rem; }
.scheda__testa .etichetta { margin-bottom: clamp(1.75rem, 4vh, 2.75rem); }

.scheda__apertura img,
.galleria img {
  display: block;
  width: 100%;
  height: auto;
}

.scheda__testo {
  margin: clamp(1.75rem, 4vh, 2.75rem) 0 0;
  max-width: 42em;
}

.galleria {
  list-style: none;
  margin: clamp(2rem, 5vh, 3.5rem) 0 0;
  padding: 0;
  display: grid;
  gap: clamp(1rem, 2.5vw, 1.75rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
}

/* La galleria ha due, tre o quattro fotografie a seconda del modello, e i
   formati sono misti - fra i master ci sono 5:3, 4:3 e 3:4. `align-items:
   start` invece dello stiramento predefinito: una verticale accanto a una
   orizzontale, tirate alla stessa altezza, si deformerebbero. */
.galleria { align-items: start; }

/* Il corpo lungo delle schede e la guida alla scelta dell'indice, dal 24/08/2026.
   Titoli, paragrafi e stile dei link stanno UNA VOLTA SOLA nel blocco
   "approfondimento" piu' sopra, insieme a quelli della home: erano tre classi con
   dichiarazioni identiche e tre margini diversi, cioe' un ruolo senza nome.
   Qui restano le due cose che valgono davvero solo per le pagine ferme: la colonna
   di lettura e il terzo livello di titolo. */

/* Stessa colonna della sezione della home, e per la stessa ragione: il contenitore
   delle pagine ferme e' largo 68rem, che va bene per una griglia di sette card e
   non per un paragrafo. A 68rem la riga arrivava a circa 118 caratteri, il doppio
   della finestra leggibile.
   `em` e non `rem` per restare coerenti con `.scheda__testo` che sta poco sopra:
   qui il corpo non cambia scala rispetto al contenitore, quindi le due unita' danno
   lo stesso risultato e la coerenza locale vale piu' della preferenza generale. */
.scheda__corpo,
.catalogo__guida {
  max-width: 42em;
  margin-top: clamp(2.5rem, 6vh, 4rem);
}

/* Il terzo livello esiste solo nella guida dell'indice, dove i sette modelli si
   raggruppano in tre famiglie. Sta sotto il secondo livello per corpo e sopra il
   corpo del testo: un titolo piu' piccolo del paragrafo che introduce non e' un
   livello, e' un livello mancante.
   ⚠️ Misurato e corretto il 24/08/2026. La prima scrittura era
   `clamp(1.0625rem, .35vw + .98rem, 1.2rem)`, che a 1280px dava 19,2px contro i 20
   del corpo: il titolo stava SOTTO il testo. Non si vedeva, perche' il peso 500 e
   il colore pieno lo facevano comunque leggere come titolo. Due `clamp()` con
   pendenze diverse si incrociano, e il punto in cui si incrociano non e' quello a
   cui stai guardando. */
.catalogo__sotto {
  margin: clamp(1.75rem, 4vh, 2.5rem) 0 0;
  font-size: clamp(1.2rem, .4vw + 1.1rem, 1.45rem);
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: .01em;
  color: var(--ink);
}

/* Il nome del modello dentro la guida. `--ink` pieno contro il corpo attenuato:
   e' l'unico segnale che serve, e sette nomi in grassetto colorato in mezzo a un
   paragrafo sarebbero sette macchie. */
.catalogo__par strong { font-weight: 500; color: var(--ink); }

.scheda__cta,
.catalogo__cta {
  margin-top: clamp(3rem, 8vh, 5.5rem);
  padding-top: clamp(2.5rem, 6vh, 4rem);
  border-top: 1px solid rgb(255 255 255 / .12);
}

.scheda__cta h2,
.catalogo__cta h2 { margin: 0 0 1rem; }
.scheda__cta .lead,
.catalogo__cta .lead { margin: 0; max-width: 38em; }

/* Prima e dopo. In cerchio, quindi non c'e' mai un lato spento: con sette
   schede il giro completo si fa senza tornare all'indice. */
.vicini {
  display: grid;
  gap: 1px;
  grid-template-columns: 1fr 1fr;
  margin-top: clamp(3rem, 8vh, 5.5rem);
  background: rgb(255 255 255 / .12);
  border-block: 1px solid rgb(255 255 255 / .12);
}

.vicini a {
  display: flex;
  flex-direction: column;
  gap: .4rem;
  min-height: 44px;
  padding: 1.35rem 1.25rem;
  background: var(--field);
  color: inherit;
  text-decoration: none;
  transition: background .35s var(--ease);
}

.vicini a:hover,
.vicini a:focus-visible { background: var(--brand); }

.vicini span {
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .55);
}

.vicini strong { font-size: 1.05rem; font-weight: 400; letter-spacing: .04em; }
.vicini__dopo { text-align: right; align-items: flex-end; }

/* ---------------------------------------------------- catalogo, movimento */

/* Il reveal e' l'unico movimento di queste pagine, ed e' tutto CSS: nessuna
   riga di JavaScript viene caricata qui. Dove `view()` non c'e' - oggi Safari e
   Firefox - non succede niente e il contenuto e' semplicemente visibile, che e'
   il comportamento giusto per una pagina che si consulta. Una pagina di
   catalogo che ha bisogno di uno script per mostrare il testo e' rotta. */
@keyframes catalogo-sali {
  from { opacity: 0; transform: translateY(1.25rem); }
  to   { opacity: 1; transform: none; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .card,
    .galleria li,
    .scheda__cta,
    .catalogo__cta {
      animation: catalogo-sali linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 55%;
    }
  }
}

@media (max-width: 560px) {
  /* Prima e dopo affiancati a 320px danno due colonne da 140px, e "SEPARATORI"
     con questo tracking non ci sta: si impilano. */
  .vicini { grid-template-columns: 1fr; }
  .vicini__dopo { text-align: left; align-items: flex-start; }
}

/* ---------------------------------------------------------------- biglietto */

/* Le pagine dei biglietti da visita, /biglietto-visita-NNN/. Le scrive
   tools/build-biglietti.py dal manifesto tools/biglietti.py, una per persona.

   Sono l'unica parte del sito progettata per essere aperta SOLO da telefono, e
   sempre nello stesso modo: qualcuno ha in mano un cartoncino, inquadra il QR e
   ha tre secondi di attenzione. Quindi niente scrollytelling, niente fotogrammi,
   niente header: una schermata sola, e sotto la piega solo il piede di legge.
   Non c'e' nessun `@media` per il desktop perche' non serve: la colonna e' larga
   27rem e su uno schermo grande resta al centro, che e' esattamente come deve
   comportarsi un biglietto da visita.

   Il pannello porta lo smusso di marca, dichiarato qui sopra l'elemento come
   vuole il commento in testa al file. E' l'unico punto in cui compare in queste
   pagine: sui sei bottoni si sarebbe ripetuto sei volte in una schermata, e un
   dispositivo che torna sei volte in 600px di altezza smette di essere un
   accento. Su un bottone avrebbe anche tagliato l'anello di fuoco, che qui gira
   su elementi alti 56px con 1px di bordo. */
.card {
  --shear-y:   26px;
  --shear-x:   calc(var(--shear-y) * var(--shear-ratio));
  --shear-cut: polygon(var(--shear-x) 0, 100% 0, 100% 100%, 0 100%, 0 var(--shear-y));

  /* Il passo fra i blocchi della scheda. E' una variabile perche' la nota
     sotto il bottone della rubrica deve sottrarlo per restare attaccata al
     bottone: scritto due volte, il giorno che cambia si scollerebbe. */
  --card-gap: clamp(1.4rem, 4.5vh, 2.1rem);

  display: grid;
  justify-items: center;
  gap: var(--card-gap);
  max-width: 27rem;
  margin: clamp(1rem, 4vh, 2.5rem) auto;
  padding: clamp(2.2rem, 6vh, 3rem) clamp(1.4rem, 6vw, 2.2rem) clamp(1.8rem, 5vh, 2.4rem);
  background: var(--field-up);
  border: 1px solid rgb(255 255 255 / .10);
  clip-path: var(--shear-cut);
  text-align: center;
}

/* Il margine laterale del pannello rispetta il ritaglio del notch: queste pagine
   portano lo stesso meta viewport `cover` del resto del sito, e un telefono in
   orizzontale ci porterebbe sopra l'angolo dello schermo. */
.card__foglio {
  padding-inline: max(1rem, env(safe-area-inset-left)) max(1rem, env(safe-area-inset-right));
}

.card .lockup { flex-direction: column; gap: .85em; text-align: center; }
.card .lockup__stack { text-align: center; }

/* Il filo di luce sotto il marchio e sopra i social: e' la stessa firma
   `linear-gradient` che separa gli atti nella home, ridotta a una riga. Separa
   senza chiudere, che e' quello che serve fra il marchio e un nome proprio. */
.card__filo {
  width: 100%;
  height: 1px;
  margin: 0;
  border: 0;
  background: linear-gradient(90deg, rgb(255 255 255 / 0), rgb(255 255 255 / .3), rgb(255 255 255 / 0));
}

.card__id { display: grid; gap: .5rem; }

/* Il nome e' l'h1 della pagina: e' il titolo del documento, e chi naviga per
   intestazioni deve trovarlo. `text-wrap: balance` perche' i cognomi lunghi
   andavano a capo lasciando una parola sola sulla seconda riga. */
.card__nome {
  margin: 0;
  font-size: clamp(1.85rem, 7.5vw, 2.4rem);
  font-weight: 300;
  letter-spacing: -.015em;
  line-height: 1.1;
  text-wrap: balance;
}

.card__mansione {
  margin: 0;
  font-size: .75rem;
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* La riga che compare solo sui numeri liberi: dice all'azienda, non alla
   persona. Corpo di paragrafo vero e non nota a margine, perche' e' il testo che
   spiega perche' il QR appena inquadrato non porta a nessuno. */
.card__nota {
  margin: 0;
  max-width: 30ch;
  font-size: .95rem;
  line-height: 1.55;
  color: var(--ink-dim);
}

.card__azioni { display: grid; gap: .55rem; width: 100%; }

/* Bottone a riga piena: icona, etichetta di cosa fa, valore leggibile.
   Il valore si legge PRIMA di toccarlo, ed e' voluto: su un biglietto da visita
   il numero e l'indirizzo servono anche a chi li vuole solo leggere o dettare a
   voce, non solo a chi tocca.
   56px e non 44: sono bersagli in colonna sotto il pollice, e i 44px di WCAG
   sono il minimo, non la misura giusta. */
.card__btn {
  display: flex;
  align-items: center;
  gap: .95rem;
  min-height: 56px;
  padding: .8rem 1.1rem;
  color: var(--ink);
  text-align: left;
  text-decoration: none;
  background: rgb(255 255 255 / .05);
  border: 1px solid rgb(255 255 255 / .16);
  transition: background .3s var(--ease), border-color .3s var(--ease);
}
.card__btn:hover,
.card__btn:focus-visible { background: var(--brand); border-color: var(--brand); }

.card__btn svg { flex: none; width: 21px; height: 21px; }

.card__btn__testo { display: grid; gap: .15rem; min-width: 0; }

.card__btn__eti {
  font-size: .625rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* `overflow-wrap: anywhere` e non `break-word`: un indirizzo di posta lungo non
   ha spazi dove andare a capo, e a 320px sfondava il bordo destro del pannello.
   Misurato su nome.cognome@eccelsapergoleoutdoor.it, che e' 38 caratteri. */
.card__btn__val {
  font-size: .95rem;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

/* Il bottone della rubrica e' il gesto che chiude la visita: chi salva il
   contatto non deve tornare qui mai piu'. Prende `.cta`, cioe' lo stesso bottone
   pieno del sopralluogo in home, perche' e' la stessa cosa - l'azione primaria
   della pagina - e non un bottone nuovo. */
.card .cta { margin-top: .2rem; }

/* La riga sotto il bottone della rubrica, e perche' quasi nessuno la vede.

   iOS apre il file nella rubrica da solo: il foglio "Nuovo contatto" copre lo
   schermo un istante dopo il tocco, e questa riga sarebbe rumore sotto un
   bottone che ha gia' funzionato. Android non ha quel foglio - non ce l'ha
   nessun browser Android - e scarica il file: il tocco sembra non aver fatto
   niente, e il contatto entra in rubrica solo se qualcuno apre la notifica di
   download. La riga serve a quel secondo li', e a nessun altro.

   Il taglio si fa in due mosse perche' in CSS non esiste "e' Android".
   `(hover: none) and (pointer: coarse)` tiene fuori i computer, dove un file
   scaricato si vede benissimo nella barra dei download. `@supports
   (-webkit-touch-callout: none)` tiene fuori WebKit, cioe' iOS: e' l'unico
   motore che dichiara quella proprieta' - Blink e Gecko rispondono di no,
   verificato su Chrome 148. Deve stare DOPO il `@media`, o non vince.

   Il giorno che Blink dichiarasse quella proprieta' la riga sparirebbe anche
   dagli Android, e si tornerebbe esattamente a com'e' oggi. E' il verso giusto
   in cui sbagliare: manca un testo utile, non ne compare uno falso.

   Il margine negativo la stacca dal passo della scheda e la attacca al bottone:
   e' la didascalia di quel bottone, non un blocco per conto suo. */
.card__cta-nota {
  display: none;
  margin: calc(.5rem - var(--card-gap)) 0 0;
  max-width: 34ch;
  font-size: .8rem;
  line-height: 1.45;
  color: var(--ink-dim);
}
@media (hover: none) and (pointer: coarse) {
  .card__cta-nota { display: block; }
}
@supports (-webkit-touch-callout: none) {
  .card__cta-nota { display: none; }
}

.card__social { display: flex; gap: .6rem; justify-content: center; }

/* Quadrati e non cerchi: nel marchio non c'e' una curva, e due tondi in fondo a
   una pagina fatta di parallelogrammi si vedono. */
.card__social a {
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  color: var(--ink);
  border: 1px solid rgb(255 255 255 / .16);
  background: rgb(255 255 255 / .05);
  transition: background .3s var(--ease), border-color .3s var(--ease);
}
.card__social a:hover,
.card__social a:focus-visible { background: var(--brand); border-color: var(--brand); }
.card__social svg { width: 23px; height: 23px; }

/* Il piede di legge e' lo stesso delle altre dodici pagine, ma li' e' una barra
   larga tutto lo schermo con i dati distribuiti in orizzontale. Qui la colonna e'
   larga 27rem: `space-between` distribuirebbe cinque blocchi su una riga che non
   c'e', lasciando buchi. Impilato e centrato, sotto il biglietto. */
.foot--card {
  flex-direction: column;
  justify-content: center;
  text-align: center;
  gap: .5rem;
  border-top: 0;
  padding-bottom: max(1.75rem, env(safe-area-inset-bottom));
}
.foot--card a { min-height: 0; padding-block: .35rem; }
