/* =========================================================
   Emmetechnologic — sistema di design
   Registro chiaro e quieto, sul modello di biograph.com:
   fondo bianco, titoli in peso regolare, molta aria,
   raggi ampi, e il buio riservato alla sola scena d'apertura.
   ========================================================= */

:root {
  /* superfici */
  --paper:    #ffffff;
  --paper-2:  #f6f7f9;
  --paper-3:  #eef2f8;   /* tinta fredda appena percettibile */
  --night:    #0b0d10;   /* scene fotografiche */
  --night-2:  #1c1c1c;   /* fondo dello scrim dell'hero e sezione che lo raccoglie */

  /* inchiostro */
  --ink:        #27272c;
  --ink-muted:  #63636c;
  --ink-dim:    #6b6b74;   /* il piu chiaro che passa AA anche sul pannello freddo */
  --on-night:   #f2f4f6;
  --on-night-muted: #b9bfc6;
  /* Il menu dell'isola ha il suo grigio. L'isola non vira più col fondo, quindi
     le sue voci stanno anche sopra il bianco: lì --on-night-muted si ferma a
     3,3:1 e non regge. Questo tiene 4,81:1, e il bianco pieno resta libero per
     hover e voce attiva. */
  --on-isola:  #e1e4e7;

  /* tratto */
  --line:        rgba(39, 39, 44, .12);
  --line-strong: rgba(39, 39, 44, .26);
  --line-night:  rgba(255, 255, 255, .18);

  /* L'anello del fuoco è in due tinte, non in una. Il blu da solo non regge
     ovunque: misurato, sul vetro dell'isola sopra una sezione chiara il fondo
     composito è rgb(96,98,100) — il .65 di #0b0d10 sul bianco — e #1f6feb ci
     sta sopra a 1,32:1; sul pannello freddo #eef2f8 il composito è
     rgb(90,93,97) e fa 1,42:1; sulla scena Applicazioni, dove il velo copre la
     foto fra l'81 e l'83%, il fondo sotto l'anello del collegamento «Verifica
     il tuo componente» va da rgb(27,29,33) a rgb(53,57,60) e il blu sta fra
     2,52:1 e 3,63:1. WCAG 1.4.11 chiede 3:1 per un indicatore che non è testo.
     Il bianco copre esattamente dove il blu cede: 6,13:1 sul vetro, 11,69:1 sul
     pixel più chiaro della foto, 19,46:1 sul #0b0d10, 15,46:1 sul #1c1c1c. E
     dove cede il bianco — carta e pannello freddo, 1,12:1 — tiene il blu, che
     sul bianco fa 4,63:1. Fra loro le due tinte fanno 4,63:1, quindi l'anello
     si legge come anello anche se un giorno finisse su un mezzo tono dove
     nessuna delle due passa da sola. I numeri della scena sono del 23/09/2026,
     col velo a .74-.84, presi sui pixel della foto alle sette larghezze e
     senza barra di scorrimento; quelli che stavano qui — velo al 73-81%, blu
     fra 1,93 e 2,66, bianco a 8,95 — erano di un velo più vecchio. */
  --focus: #1f6feb;
  --focus-contro: #ffffff;

  /* Passata di vernice sui titoli di sezione: copertura piena in apertura,
     poi in calo come una spruzzata che si esaurisce.

     I due fondi sono tarati sul limite di WCAG AA per il TESTO GRANDE, 3:1.
     Gli h2 partono da 1.875rem = 30px, sopra i 24px oltre i quali la soglia
     è 3:1 e non 4.5: se un giorno quel minimo scende sotto i 24px questi
     valori vanno rialzati, perché la soglia applicabile cambia sotto i piedi.

     Fondi diversi perché la stessa alpha non rende lo stesso contrasto nei
     due versi: sul chiaro il vincolo è #1c1c1c sul pannello freddo #eef2f8
     (.48 → 3.03:1), sullo scuro è il bianco su #0b0d10 (.34 → 3.05:1).
     Con un valore solo le scene scure resterebbero a 4.9 e non al limite. */
  --velo-vernice: linear-gradient(104deg,
    #000 0%, #000 38%,
    rgba(0, 0, 0, .81) 62%,
    rgba(0, 0, 0, .59) 84%,
    rgba(0, 0, 0, .48) 100%);
  --velo-vernice-scuro: linear-gradient(104deg,
    #000 0%, #000 38%,
    rgba(0, 0, 0, .76) 62%,
    rgba(0, 0, 0, .48) 84%,
    rgba(0, 0, 0, .34) 100%);
  /* Terza taratura, e serve perché c'è un titolo che sotto non ha un fondo pieno
     ma una FOTOGRAFIA: quello della scena Applicazioni. Il .34 qui sopra vale
     «bianco su #0b0d10», e lì #0b0d10 non c'è — c'è robot-linea.jpg, una scena
     in alta chiave che sotto il testo arriva a rgb(255,255,255). Misurato contro
     i pixel veri, a 1440 quel titolo stava a 1,92:1 e a 320 a 1,19:1, non ai
     3,05 che il §4.2 gli attribuiva leggendo il token invece della foto.
     Col velo della scena riancorato al blocco di testo (vedi .showcase__scrim)
     il fondo composito più chiaro sotto il titolo è rgb(74,76,78): lì il fondo
     esatto per 3,00:1 è .4272, arrotondato per eccesso a .43, che rende 3,02.
     Fino al 23/09/2026 la coda era .40, esatta .3934 su rgb(65,66,69): quel
     giorno il velo è stato schiarito da .78 a .74 e la coda è salita con lui.
     Le due cose vanno insieme, e chi tocca il velo ricalcola la coda. Le tappe
     intermedie non sono a occhio, escono dalla forma della passata già in uso
     in questo file: v = 1 − k × (1 − coda), con k = 4/11 al 62% e k = 26/33
     all'84%. La stessa formula rende .81/.59 per la coda .48 e .76/.48 per la
     .34; con .43 dà .79 e .55. La taratura è presa sul pixel più chiaro
     possibile, il bianco pieno, quindi regge anche se un giorno la fotografia
     viene cambiata. */
  --velo-vernice-foto: linear-gradient(104deg,
    #000 0%, #000 38%,
    rgba(0, 0, 0, .79) 62%,
    rgba(0, 0, 0, .55) 84%,
    rgba(0, 0, 0, .43) 100%);

  /* tipografia: vedi docs/design/sistema-tipografico.md */
  --font-titoli: "Orbitron", "Segoe UI", system-ui, sans-serif;
  --font-testi:  "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Scala di spaziatura sulla sequenza di Fibonacci. Ogni gradino è il
     numero di Fibonacci più vicino al valore precedente, così gli scarti
     restano contenuti (max 1rem) e la scala resta coerente. I doppioni
     sono voluti: Fibonacci è più rada della scala di partenza. */
  --s-1: 0.3125rem;   --s-2: 0.5rem;   --s-3: 0.8125rem;  --s-4: 1.3125rem;
  --s-5: 1.3125rem;  --s-6: 2.125rem;  --s-7: 3.4375rem;  --s-8: 3.4375rem;
  --s-9: 5.5625rem;  --s-10: 5.5625rem; --s-11: 9rem; --s-12: 9rem;

  /* Rampe fluide. Partono a 64rem: sotto, tablet e mobile condividono lo
     stesso valore; sopra salgono con continuità fino a 90rem. */
  --sp-fianchi:   clamp(1.875rem, calc(6.010vw - 1.97125rem), 3.4375rem);   /* 30 → 55, unico valore fuori sequenza: voluto */
  --sp-fianchi-riquadri: clamp(0.8125rem, calc(10.096vw - 5.649375rem), 3.4375rem); /* 13 → 55 */
  --sp-sezione:   clamp(3.4375rem, calc(8.173vw - 1.793125rem), 5.5625rem);   /* 55 → 89 */
  --sp-sezione-unita: clamp(2.125rem, calc(5.048vw - 1.105625rem), 3.4375rem); /* 34 → 55 */

  /* Lo stacco fra la testata di una sezione e il suo corpo. Sta qui e non
     scritto inline perché è una decisione di sistema, non un numero di
     comodo: la testata apre la sezione, e il vuoto che la separa dal corpo
     deve restare leggibile come interno alla sezione. Perché lo resti va
     tenuto un gradino di Fibonacci sotto --sp-sezione a ogni larghezza —
     da qui 34 → 55 contro i 55 → 89 dello stacco fra sezioni, cioè lo
     stesso rapporto ovunque (34/55 = 55/89 = 0,618), perché le due rampe
     condividono le ancore 1024 → 1440. Il minimo non scende sotto i 34
     perché il gap interno della testata è 21px (--s-5): il vuoto sotto deve
     stare almeno un gradino più in alto, o l'ultima riga del lede si legge
     come un elemento in più della stessa pila.
     Che i numeri coincidano oggi con --sp-sezione-unita è la scala che a
     questa altezza è rada, non una dipendenza: sono due decisioni separate,
     una sul confine fra sezioni e una dentro la sezione, e vanno lasciate
     libere di divergere. */
  --sp-testata: clamp(2.125rem, calc(5.048vw - 1.105625rem), 3.4375rem); /* 34 → 55 */

  /* un solo raggio, largo, come nel riferimento */
  --r:    1rem;
  /* l'isola fa eccezione: squadrata, per lasciar leggere i vertici */
  --r-isola: 0.5rem;
  --r-sm: 0.5rem;

  --container: 81.25rem;
  --measure: 60ch;

  --t-fast: 180ms cubic-bezier(.2, .6, .3, 1);
  --t-base: 340ms cubic-bezier(.22, 1, .36, 1);

  /* L'isola che si riapre al passaggio del mouse è l'animazione più lunga del
     sito: 920px di larghezza, e la riga dentro scorre di 460. Su una corsa
     così --t-base non va: è una outQuint, e fa il 76% del cammino nel primo
     quarto del tempo — si legge come uno scatto seguito da un assestamento
     che non si vede. Questa è una outQuad: parte subito (19% nel primo
     decimo, quindi l'hover risponde) ma lascia un quarto della corsa alla
     seconda metà del tempo, dove il movimento si posa. */
  --e-isola: cubic-bezier(.25, .46, .45, .94);
  --t-isola-apre:  460ms;
  --t-isola-chiude: 360ms;

  /* Larghezze dell'isola: la compatta deve contenere logo, contesto e CTA.
     Misurate in `cqw`, cioè sulla larghezza utile del contenitore, e non in
     `100vw`: la viewport comprende la barra di scorrimento e ignora il
     padding del contenitore, quindi `100vw - 1.5rem` dava un'isola più larga
     dello spazio reale e la riga interna sbordava a destra.
     Aperta, l'isola è larga quanto il contenitore e basta: sono i fianchi di
     .island-wrap a decidere dove stanno i suoi bordi (vedi lì). Fino al
     23/09/2026 qui c'era anche un tetto di 73.75rem, 1180px, che la fermava
     da 1206px in su: da telefono e da tablet non mordeva mai, e da desktop
     l'isola adesso segue il contenuto dell'hero. */
  --island-w:         100cqw;
  /* Sotto la soglia del menu la compatta deve restare larga quanto l'aperta,
     altrimenti il tasto menu, che sta in fondo alla riga, finisce fuori dal
     ritaglio e diventa irraggiungibile: `.island__row` è larga quanto l'isola
     APERTA e il tasto ha `margin-left: auto`, mentre `.island` ritaglia con
     `overflow: hidden`. Con un tetto di 26.25rem il tasto usciva di 537px a
     1019px, e sotto quella soglia le voci sono `display: none`, quindi era
     l'unico comando rimasto: su touch, dove non c'è hover a riaprire l'isola,
     dopo il primo scorrimento non restava nessuna navigazione.
     Da desktop invece non c'è più niente da tenere dentro oltre al marchio, e
     si stringe sul suo ingombro (vedi l'override a 63.75rem). */
  --island-w-compact: var(--island-w);

  /* Larghezza del marchio, da cui si ricava quella della barra contratta.
     12rem = 192px, ed è il punto basso di leggibilità della riga «ROBOTIC
     AUTOMATION»: nel file sorgente (766px) le sue aste sono spesse 2px, che a
     questa scala rendono mezzo pixel CSS, cioè esattamente un pixel fisico su
     uno schermo a 2×. Sotto, l'asta non arriva più a coprire un pixel e le
     lettere si impastano: l'occhiello della R si chiude e l'anello della O
     perde il bianco pieno. */
  --marchio-w: 12rem;

  /* Vuoto uniforme fra il bordo dell'isola e ciò che contiene: 13px da
     desktop, 8 da tablet in giù, sulla rampa di sistema 1024 → 1440. */
  --island-pad: clamp(0.5rem, calc(1.202vw - 0.26928rem), 0.8125rem);

  /* L'altezza della barra è l'altezza utile della riga più il vuoto, due
     volte: scritta così resta coerente a ogni larghezza mentre il padding
     scorre. Da desktop i 2.375rem sono un'altezza scelta — nella riga non
     c'è più un comando che la detti, da quando il CTA è uscito dall'header —
     e tenerla ferma lascia la barra alta come prima. Da tablet in giù invece
     la detta il tasto menu, 2.75rem: lì il valore non è libero. */
  --bar-h: calc(2.375rem + var(--island-pad) * 2);
}

/* ============================ reset ============================ */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-testi);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.6;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  /* Nessuna stringa lunga (indirizzi email, URL) deve poter allargare la
     pagina. È una rete: oggi la più lunga, l'email del piè di pagina, è larga
     184px e a 320 ne ha 260. */
  overflow-wrap: break-word;
}

/* `height: auto` non è pignoleria. Gli attributi width/height dell'HTML
   arrivano come stile di presentazione, quindi l'altezza resta INCHIODATA al
   numero scritto nell'attributo mentre max-width accorcia la larghezza, e
   l'aspect-ratio che quegli stessi attributi porterebbero con sé non entra in
   gioco finché una delle due misure non è `auto`. robot-utensile.jpg dichiara
   900x1506 e a 1440px sta in una colonna di 432: usciva 432x1506 invece di
   432x722.9, alto il doppio del dovuto, a ogni larghezza provata (320, 390,
   768, 1024, 1280, 1440, 1920). Il marchio del piè di pagina, 766x79, quando
   stava a 148 di larghezza usciva 148x79 invece di 148x15.3: cinque volte più
   alto, con le lettere stirate. Le foto dentro .line__media e
   .showcase__media non erano toccate perché lì una regola più specifica fissa
   già width e height al 100% con object-fit, ed è per questo che il guasto si
   vedeva solo su quelle due. */
img, video, svg { display: block; max-width: 100%; height: auto; }
h1, h2, h3, h4, p, ul, ol, figure, blockquote, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; }

/* L'ingombro resta quello di prima, 5px: la fascia bianca non si aggiunge in
   fuori, riempie i 3px di stacco che prima lasciavano vedere il fondo. Dal
   bordo dell'elemento verso l'esterno sono 3px di bianco e poi 2px di blu —
   rasterizzata la dichiarazione su fondo isola, le righe escono
   rgb(96,98,100) ×3, blu, blu, bianco, bianco, bianco, poi l'elemento.
   I 5px contano perché .island ha overflow:hidden: il comando con meno
   margine è il tasto del menu, 8px dal bordo alto e dal basso dell'isola sia a
   375 sia a 768px. Cinque passano, sei no. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  box-shadow: 0 0 0 3px var(--focus-contro);
  border-radius: var(--r-sm);
}

/* Il fuoco d'arrivo su un blocco che non ha un'intestazione da mettere a
   fuoco: lo segna app.js con data-arrivo. Capitava al solo <footer>, dal
   collegamento «Azienda» del foglio. Dal 24/09/2026 il menu ha due voci,
   Emme Paint e Chi siamo, «Azienda» è uscita con le altre e nessun
   collegamento porta più a un blocco senza intestazione: la regola resta
   come rete per il prossimo, e le misure qui sotto sono di prima.
   Attorno a quel blocco il contorno non si può disegnare, perché tre lati su
   quattro cadono fuori dallo schermo. I fianchi, perché il footer va da un
   bordo all'altro: a 390×844 l'anello uscirebbe a −5 e a 395 contro i 390 di
   clientWidth, dove overflow-x: hidden sul body lo rade via. Il basso, perché
   il footer chiude la pagina: dal 24/09/2026, senza le colonne di link, è alto
   527,5px, il 63% della viewport, e il salto si ferma a fine corsa con il suo
   bordo basso su quello dello schermo, 849 contro 844.
   Al loro posto una fascia sul bordo alto, l'unico che resta in vista: 3px di
   blu e 3px di bianco, le stesse due tinte dell'anello e nello stesso ordine
   di lettura, larghe quanto il blocco e tutte dentro lo schermo. Misurata dal
   collegamento «Azienda» del foglio, uguale sulle due pagine: fra 316,5 e
   322,5 a 390×844, fra 284,7 e 290,7 a 375×812, fra 535 e 541 a 768×1024; a
   320×568 il footer è alto 578,7px, più della viewport, il salto lo porta
   allo scroll-margin e la fascia cade fra 84 e 90. Sempre sotto il bordo
   basso dell'isola, che sta a 73.
   Il contorno non si spegne, si fa trasparente: così in forced-colors, dove le
   ombre non vengono dipinte, il sistema lo ridipinge col proprio colore e
   l'indicatore non sparisce. E il raggio torna a zero, se no la fascia si
   assottiglia alle due estremità sui 0.5rem che la regola qui sopra applica a
   chiunque prenda il fuoco. */
[data-arrivo="blocco"]:focus-visible {
  outline-color: transparent;
  box-shadow: inset 0 3px 0 0 var(--focus), inset 0 6px 0 0 var(--focus-contro);
  border-radius: 0;
}

::selection { background: var(--ink); color: var(--paper); }

/* ============================ tipografia ============================ */

/* Titoli in Orbitron, mai in maiuscolo. Orbitron corre largo e pesa molto:
   i pesi scendono di un gradino, 600 sull'h1 e 500 da h2 in giù.
   La scala sta su una sola rampa, 1024 → 1440px, la stessa delle spaziature:
   sotto i 1024 tablet e mobile restano al minimo. Nessuno scalino. */
h1, h2, h3, h4 {
  font-family: var(--font-titoli);
  font-weight: 500;
  /* Tracking riportato a quello scritto nel sistema tipografico al §6.1:
     -.005em sui titoli, -.01em sull'h1. Qui erano rimasti i valori doppi,
     -.01em e -.02em, cioè metà della riduzione decisa passando a Orbitron.
     Misurato a 1440px faceva -0.4px sull'h2 da 40px invece di -0.2px e -1px
     sull'h1 da 50px invece di -0.5px. Orbitron ha montanti verticali e spalle
     strette, ed è il carattere per cui il tracking era stato alleggerito: a
     -1% in «Dalla geometria al ciclo ripetibile» la doppia l si salda, le
     coppie ti e ib di «ripetibile» perdono il vuoto fra i gambi, e in
     «Assemblaggio e messa in servizio» tocca alla doppia g. Sono due titoli
     veri della pagina ed entrambi scendono a -.005em, quindi è di loro che
     questa regola parla: l'unico titolo del sito in cui compaia la sequenza
     «all'» è invece l'h1 dell'hero, che il -.01em se lo tiene per la deroga
     scritta qui sotto — citarla qui non prova niente. Quel che la riduzione
     restituisce, misurato a 1440px: l'h2 «Dalla geometria al ciclo ripetibile»
     da 696,32 a 703,32px, l'h3 «Assemblaggio e messa in servizio» da 498,10 a
     502,42, e l'h1, che il doppio se lo tiene, da 951,74 a 968,74. Il difetto
     che quella riga del documento voleva evitare era proprio questo. */
  letter-spacing: -.005em;
  line-height: 1.14;
  text-transform: none;
  text-wrap: balance;
}

/* L'h1 tiene il doppio del tracking degli altri, -.01em contro -.005em: a 50px
   sono -0.5px, mezzo pixel che a quel corpo non chiude nulla e compatta un
   titolo che corre già largo. È la deroga scritta al §6.1, ed è l'unica. */
h1 { font-weight: 600; font-size: clamp(2.1875rem, 3.606vw - 0.12034rem, 3.125rem); line-height: 1.06; letter-spacing: -.01em; }  /* 35 → 50 */
h2 { font-size: clamp(1.875rem, 0.33644rem + 2.404vw, 2.5rem); line-height: 1.18; }   /* 30 → 40 */
h3 { font-size: clamp(1.4375rem, 0.82182rem + 0.962vw, 1.6875rem); line-height: 1.32; } /* 23 → 27 */
h4 { font-size: clamp(1rem, 0.84615rem + 0.24038vw, 1.0625rem); line-height: 1.35; }  /* 16 → 17 */

/* I titoli di sezione portano il velo di vernice. È una maschera e non un
   `background-clip: text` per due motivi. Agisce sul reso finale, quindi non
   litiga con la comparsa parola per parola: i titoli animati sono spezzati in
   span con opacità e traslazione proprie, e un fondo ritagliato sul testo del
   padre non si sarebbe composto con loro. E se un browser non la supporta il
   titolo resta pieno invece di sparire, perché il colore è dichiarato a parte.
   Sui fondi scuri parte dal bianco pieno, sui chiari dal #1c1c1c. */
.section h2,
.showcase h2 {
  color: var(--night-2);
  -webkit-mask-image: var(--velo-vernice);
          mask-image: var(--velo-vernice);
}
.on-night h2 {
  color: #fff;
  -webkit-mask-image: var(--velo-vernice-scuro);
          mask-image: var(--velo-vernice-scuro);
}
/* La scena Applicazioni è l'unica dove sotto il titolo non c'è un fondo dichiarato
   ma una fotografia, quindi il velo scuro tarato su #0b0d10 lì non vale e serve la
   sua taratura, --velo-vernice-foto. Il selettore è .showcase.on-night (0,2,1) e
   non .showcase (0,1,1), che pesa uguale a .on-night h2 qui sopra e perderebbe per
   ordine: è lo stesso motivo per cui più giù .on-night .arrow-link:hover porta il
   prefisso. Qui si cambia solo la maschera; il colore resta il #fff di .on-night h2,
   e resta quindi valida anche la riga di stampa che lo riporta a --ink. */
.showcase.on-night h2 {
  -webkit-mask-image: var(--velo-vernice-foto);
          mask-image: var(--velo-vernice-foto);
}

p { text-wrap: pretty; }

/* Il sommario d'apertura è l'unico corpo di testo che scala con la finestra:
   16px fino a 1024 e 18 a 1440, come li vuole la tabella §4 del sistema
   tipografico. La rampa però stava sulle ancore sbagliate. Risolta la retta,
   `.96rem + .25vw` ha intercetta 15.36px e pendenza .0025 px/px: tocca i 16px a
   256px di finestra e il tetto a 1024, cioè finisce esattamente dove il sistema
   dice che deve cominciare. Lo dicevano le misure: 17.28px a 768, dove il testo
   doveva stare al minimo, e poi 17.92px identici a 1024, 1280, 1440 e 1920 —
   crescita zero lungo tutti i 416px della rampa dichiarata, e 17.92 invece dei
   18 in cima. Rifatta sull'intervallo giusto con le formule del sistema:
   pendenza (18 - 16)/416 = .0048077 px/px, cioè .48077vw, e intercetta
   16 - .0048077 × 1024 = 11.0769px, cioè .69231rem. Ora misura 16px a 768 e a
   1024, 16.5 a 1128, 17 a 1232, 17.5 a 1336 e 18 da 1440 in su. È lo stesso
   difetto già corretto sull'h4, che era rimasto ancorato a 300 → 925px. */
.lede {
  font-size: clamp(1rem, 0.69231rem + 0.48077vw, 1.125rem);  /* 16 → 18 */
  line-height: 1.6;
  color: var(--ink-muted);
  max-width: var(--measure);
}

.measure { max-width: var(--measure); }

/* Occhiello: IBM Plex Sans, corsivo, peso 300, 16px fissi — richiesta del
   committente del 23/09/2026, su tutti gli occhielli (l'hero non ne ha). Prima
   era Orbitron 500, sempre a 16px, con .14em di spaziatura, e la spaziatura
   serviva a staccarlo dal corpo: adesso lo stacca il corsivo, e le lettere
   larghe su un minuscolo corsivo non reggono, quindi è tolta e resta quella
   del testo.
   Il 300 è una deroga a «mai sotto il peso 400», dichiarata nel §3.3 del
   sistema tipografico con le misure. Vale solo qui, e il file del corsivo 300 è
   caricato apposta nel link di Google Fonts in index.html: senza, il browser
   ripiega sul 400 tondo e lo inclina a macchina.
   Lo stesso giorno era stato chiesto a 18px, per abbassarlo, ma 18 era più dei
   16 di partenza: riportato a 16. A parità di corpo cala davvero — la x scende
   da 9,28 a 8,19px, «Il processo» da 122,33 a 76,43px — e la riga resta di
   25,6px come quella dell'Orbitron, quindi nessun blocco cambia altezza. */
.eyebrow {
  font-family: var(--font-testi);
  font-size: 1rem;   /* 16px */
  font-style: italic;
  font-weight: 300;
  color: var(--ink);
}

/* apertura di paragrafo in inchiostro pieno e seguito in grigio:
   è il trattamento ricorrente del riferimento */
.lead-in { color: var(--ink); }

.num { font-variant-numeric: tabular-nums; }

/* ============================ layout ============================ */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--sp-fianchi);
}

/* Regola generica: fra due sezioni di colore diverso lo stacco è 5.5625rem.
   Dove il colore non cambia il confine si legge da solo e scende di un
   gradino, a 3.4375rem — lo dicono le due classi qui sotto. */
.section { padding-block: var(--sp-sezione); position: relative; }
.section--unita-sopra { padding-top: var(--sp-sezione-unita); }
.section--unita-sotto { padding-bottom: var(--sp-sezione-unita); }
.section--tint { background: var(--paper-2); }

/* Sotto #processo la scena Applicazioni non si appoggia al bordo della sezione:
   ci sale sopra di uno stacco intero, e resta a cavallo fra il fondo scuro e il
   bianco della pagina, staccata dal bordo bianco di .showcase. Richiesta del
   committente del 23/09/2026, data in pixel: 178 di padding di fondo alla
   sezione sopra, −89 di margine a quella sotto. Sono 2 e −1 volte --sp-sezione
   a 1440, e sono scritti come multipli del token e non come 11.125rem e
   −5.5625rem fissi perché scalino con lui come ogni altra spaziatura: misurati
   110 e −55 a 320 e a 1024, 151,85 e −75,92 a 1280, 178 e −89 a 1440 e a 1920.
   Il vuoto che si vede fra l'ultima riga del processo e la cima della scena è
   la differenza, cioè ancora un --sp-sezione: 55, 75,92 e 89, gli stessi numeri
   di prima alle stesse larghezze. Si è spostata la scena, non lo stacco. Quello
   che non coincide più con lei è il cambio di colore, che le cade dietro, un
   --sp-sezione sotto la sua cima.
   Il margine sta sull'involucro e collassa col margine nullo della sezione,
   0 + −89 = −89. La sezione cresce di quanto l'involucro risale, e quindi
   #applicazioni non si muove: offsetTop, altezza del documento e punto in cui
   atterra l'ancora sono misurati identici prima e dopo, alle stesse cinque
   larghezze con la finestra alta 900px. A 320×568 la scena si allunga, ma per
   il bordo e non per la risalita: vedi .showcase. La voce di menu attiva, che
   app.js ricava dagli offsetTop, cambia dove cambiava.
   Nessuno z-index: sezione e scena sono entrambe posizionate, e fra elementi
   posizionati senza z-index si dipinge sopra chi viene dopo nel documento.
   Verificato con elementFromPoint: nella fascia sormontata c'è la foto, ai suoi
   fianchi il fondo di #processo.
   Le due righe vanno insieme. Il padding doppio senza la risalita lascia 178px
   di vuoto sotto la sezione; la risalita senza il padding doppio porta la scena
   a filo dell'ultima riga del processo. */
.section--sormontata { padding-bottom: calc(var(--sp-sezione) * 2); }                /* 110 → 178 */
.section--sormontata + .showcase-wrap { margin-top: calc(var(--sp-sezione) * -1); }  /* −55 → −89 */

/* Sezione sul fondo dell'hero: stesso #1c1c1c dello scrim, così il video
   ci finisce dentro senza una linea di stacco. */
.section.on-night { background: var(--night-2); color: var(--on-night); }
.section.on-night .eyebrow,
.section.on-night .lead-in       { color: var(--on-night); }
.section.on-night .lede          { color: var(--on-night-muted); }
.section--cool { background: var(--paper-3); }

/* Lo stacco che tiene l'ancora fuori da sotto l'isola. La regola di prima,
   :where(section, footer)[id], si fidava del nome del tag: appena un id è
   finito su un blocco che section non è — #applicazioni sta su un
   div.showcase-wrap — quell'ancora è rimasta a 0 e il salto la portava a filo
   viewport, con i primi 77px mangiati dall'isola. A 1440 le sei di mezzo si
   fermano a 88 e passano libere: 88 sono i 64 di --bar-h più i 24 di 1.5rem,
   e l'isola finisce a y=77 perché parte dai 13 di --s-3 — restano 11px d'aria.
   Misurate a 1440×900: 88 su #processo, 88,3 su #applicazioni e #soluzioni,
   87,9 su #tecnologia, 87,8 su #assistenza, 88,4 su #contatto. Le due agli
   estremi lo stacco non lo consumano, e non perché la regola le manchi: #main
   apre il documento e sopra non c'è dove scorrere, #azienda lo chiude e quando
   il salto ci arriva la corsa è già finita — misurato a 1440×900 atterra a
   425,2, cioè i 900 della finestra meno i 474,4 del piè di pagina. Non è un
   guasto: oltre la fine non si scorre. Da telefono e tablet, dove il piè di
   pagina è più alto della finestra (1046,1 a 390×844, 1007,5 a 768×1024), la
   corsa basta e #azienda si ferma agli 84 che valgono lì.
   Quella somma non l'ho toccata, ho cambiato solo a chi arriva: la condizione
   adesso è dove sta l'elemento, non come si chiama. Un id su un figlio diretto
   di body o di main è un blocco di pagina, quindi un bersaglio di navigazione,
   e lo sarà anche il prossimo che finirà su un div. Così copre tutti e otto i
   bersagli dei link interni (#main, #processo, #applicazioni, #soluzioni,
   #tecnologia, #assistenza, #contatto, #azienda) e nessuno degli altri
   ventisei id della pagina, che stanno più in fondo: campi del form, gradienti
   dell'svg, bottoni del ciclo. A gradienti e bottoni lo stacco non serve
   davvero; ai campi del modulo invece sì, ed è la regola qui sotto. La riga
   che stava qui diceva il contrario — «88px di vuoto forzato sopra il campo
   sbagliato» — ed era falsa due volte: quel vuoto non è vuoto, sopra il campo
   ci stanno l'isola e l'etichetta, e senza stacco il campo non resta dov'è, ci
   finisce sotto. #main e #hero lo prendono ma stanno a y=0, dove il salto si
   appiattisce sullo zero: oggi non cambia niente e li copre se un domani sopra
   ci finirà qualcosa.
   Dal 24/09/2026 il menu porta solo ad altre pagine, e degli otto restano
   collegati #main, dal salto al contenuto, #processo, da «Come funziona»
   nell'hero della home, e #contatto: la regola non cambia e copre ancora gli
   altri cinque. */
:where(body, main) > [id] { scroll-margin-top: calc(var(--bar-h) + 1.5rem); }

/* I campi del modulo non sono bersagli di navigazione, ma il fuoco ci arriva
   lo stesso: a invio fallito app.js chiama firstInvalid.focus(), e il browser
   porta in vista l'elemento che lo prende. Come ce lo porta dipende da dov'è.
   Se è del tutto fuori dalla vista lo centra, e allora si vede; se è anche
   solo per un pixel dentro, allinea il bordo più vicino, cioè il suo bordo
   alto a quello della finestra. Senza stacco quel bordo è y=0, e l'isola
   arriva a 73 da telefono e tablet, 67 a 1024, 77 a 1440: il campo, alto 46,
   ci finisce sotto tutto intero. Misurato prima di questa regola, su sei
   finestre da 390×640 a 1440×900 e quattro posizioni di partenza ciascuna:
   24 casi su 30 con il campo interamente coperto, a ogni larghezza — non è
   un guaio delle sole finestre basse.
   Lo stacco dell'ancora qui sopra, --bar-h più 24, non basterebbe: l'etichetta
   sta 33,6px più in alto del campo (25,6 di riga più gli 8 di --s-2 del
   .field), quindi a 88 il campo si vedrebbe e la sua domanda no, con 22,6 dei
   suoi 25,6 dietro l'isola. Con --s-7, 55, lo stacco diventa 115 da telefono e
   tablet, 109 a 1024, 119 a 1440; e siccome isola e stacco pendono dallo
   stesso --bar-h, il conto si chiude uguale a ogni larghezza: l'etichetta
   atterra sempre 8,4px sotto il bordo dell'isola — misurati 81,6 contro 73 a
   390, 75,4 contro 67 a 1024, 85,4 contro 77 a 1440. Sopra il campo non resta
   vuoto: ci stanno l'isola e l'etichetta, e l'unica aria sono quegli 8,4. */
.field input,
.field select,
.field textarea { scroll-margin-top: calc(var(--bar-h) + var(--s-7)); }
/* La domanda sugli addetti, dal brief del 30/09/2026, è l'unica etichetta del
   modulo che va su due righe: da telefono, fino a 430px misurati, e da 460px
   in su ne basta una. Con lo stacco qui sopra la prima riga finiva dietro
   l'isola: misurato a 390×640 e a 320×568, col campo in errore che parte in
   cima alla finestra, l'etichetta atterrava a 55,7 contro i 73 dell'isola.
   Il campo si ferma una riga più in basso, e l'etichetta torna 8,2px sotto
   l'isola, come le altre. Dove sta su una riga sopra restano 25,6px d'aria in
   più, che non costano niente. */
.field--domanda-lunga select { scroll-margin-top: calc(var(--bar-h) + var(--s-7) + 1.6rem); }

/* testata di sezione centrata, come nel riferimento; da mobile a sinistra, più sotto */

/* Il margine sotto era un clamp(3rem, 5vw, 5.25rem) scritto qui a mano: una
   rampa 48 → 84px che il termine 5vw ancora a 960 → 1680, quindi fuori dalle
   ancore 1024 → 1440 del sistema, e con due estremi che non sono gradini
   della sequenza. Cresceva anche dove tutto il resto si è già fermato:
   misurati 72px a 1440 e 84px a 1680, contro gli 89px a cui --sp-sezione
   resta inchiodata da 1440 in su. A schermo largo fra testata e corpo
   restavano 5px di differenza rispetto allo stacco fra due sezioni diverse:
   indistinguibili, e la testata smetteva di leggersi come parte della
   sezione che apre. Ora il valore viene da --sp-testata, 34 → 55 sulle
   ancore giuste: misurati 34 a 1024, 46,92 a 1280, 55 a 1440 e 55 a 1680,
   sempre il 61,8% di --sp-sezione, che alle stesse larghezze vale 55, 75,92,
   89 e 89. La rampa si ferma dove si ferma il resto del sistema. */
.section__head {
  display: grid;
  justify-items: center;
  text-align: center;
  gap: var(--s-5);
  max-width: 44rem;
  margin: 0 auto var(--sp-testata);
}
.section__head .lede { text-align: center; }

/* variante allineata a sinistra: dove il contenuto è una tabella o il
   modulo, e nella Storia di Chi siamo, dove la testata sta in cima alla prima
   delle due colonne */
.section__head--start {
  justify-items: start;
  text-align: left;
  margin-inline: 0;
}
.section__head--start .lede { text-align: left; }

/* Da mobile le testate centrate vanno a sinistra, come la variante qui sopra:
   richiesta del committente del 24/09/2026, sulla home e su Chi siamo.
   «Mobile» è tutto quello che sta sotto i 1024px, perché qui la tablet si
   considera mobile (sistema delle spaziature §1); da 1024 in su restano
   centrate. Fra 768 e 1023 la testata, larga al più 44rem, parte dal bordo
   del contenitore come il resto della sezione. */
@media (max-width: 63.9375rem) {
  .section__head { justify-items: start; text-align: left; margin-inline: 0; }
  .section__head .lede { text-align: left; }
}

.skip-link {
  position: absolute;
  left: var(--s-4); top: var(--s-4);
  z-index: 100;
  padding: var(--s-3) var(--s-4);
  background: var(--ink); color: var(--paper);
  border-radius: var(--r-sm);
  font-weight: 500;
  transform: translateY(-160%);
  transition: transform var(--t-fast);
}
.skip-link:focus-visible { transform: none; }

/* ======================= isola dinamica ======================= */

.island-wrap {
  position: fixed;
  top: var(--s-3);
  left: 0; right: 0;
  z-index: 60;
  display: flex;
  justify-content: center;
  padding-inline: var(--s-3);
  pointer-events: none;
  /* fa da contenitore di riferimento per le larghezze qui sopra */
  container-type: inline-size;
}
/* Da desktop l'isola ha i fianchi del contenuto dell'hero: dal 23/09/2026, su
   richiesta del committente, il contenitore prende --sp-fianchi come l'hero, e
   l'isola aperta, larga quanto il contenitore, sta a filo del titolo a sinistra
   e della riga dei dati a destra a ogni larghezza da 1020px in su. Misurato
   senza barra di scorrimento: 30 → 990 a 1020, 55 → 1385 a 1440, 55 → 1865 a
   1920, cioè 960, 1330 e 1810px. Con la barra classica, a 1440, è 55 → 1370:
   di nuovo a filo, perché hero e isola perdono la barra allo stesso modo.
   Prima l'isola arrivava a 1180px e lì si fermava: a 1440 stava 75px dentro il
   testo per lato, a 1920 ne stava 315. Fra 1020 e 1270 invece era più larga
   del contenuto, a 13px dai bordi, e allinearla la stringe fino a 28px per
   lato, a 1206. Le voci restano lontane dal marchio. Dal 24/09/2026 sono due,
   «Emme Paint» a sinistra e «Chi siamo» a destra, e il punto più stretto è
   sempre a 1020: 274,55px fra «Emme Paint» e il marchio, 290 fra il marchio e
   «Chi siamo». Con tre voci per parte erano 63,45 e 61,34.
   Sotto i 63.75rem no. Lì il marchio sta al centro e il tasto del menu a
   destra, e il tetto del marchio si ricava da 100cqw (vedi .island__brand):
   con i 30px dell'hero, sotto i 408px di finestra il marchio scenderebbe sotto
   i 192 che lo tengono leggibile, e a 360 da 178 a 144. */
@media (min-width: 63.75rem) {
  .island-wrap { padding-inline: var(--sp-fianchi); }
}

.island {
  pointer-events: auto;
  width: var(--island-w);
  min-height: var(--bar-h);
  padding: var(--island-pad);
  border: 0;
  border-radius: var(--r-isola);
  /* La riga va stirata all'altezza utile, altrimenti il suo align-items
     non ha spazio su cui centrare: finché conteneva il CTA da 2.375rem
     riempiva il box da sé, uscito quello si accorciava alle sole voci e si
     appoggiava in alto, mentre il marchio resta centrato in assoluto. */
  display: flex;
  /* Fondo unico. L'isola non cambia colore scorrendo: resta vetro scuro
     sopra l'hero e sul corpo chiaro. Con il fondo restano fermi anche
     anello, marchio e voci — un fondo scuro immobile non regge un contenuto
     che vira all'inchiostro.
     Il vetro è a .65 e non a .55: sul bianco .55 rendeva rgb(121,122,124) e
     nessun grigio ci stava sopra a 4,5:1 — nemmeno il bianco pieno, fermo a
     4,30. A .65 rende rgb(96,98,100) e il menu respira. Sull'hero la
     differenza è di due livelli su 255: si paga tutto sulle sezioni chiare. */
  --anello-vertice: rgba(255, 255, 255, .45);
  --anello-corsa:   rgba(255, 255, 255, .14);
  background: rgba(11, 13, 16, .65);
  backdrop-filter: blur(1.25rem) saturate(1.4);
  -webkit-backdrop-filter: blur(1.25rem) saturate(1.4);
  overflow: hidden;
  position: relative;
  /* l'unica cosa che si anima è la larghezza: fondo e anello sono fermi.
     Qui sta la chiusura; l'apertura allunga la durata nella regola :hover. */
  transition: width var(--t-isola-chiude) var(--e-isola);
}

/* L'anello: un filo da 1px pieno ai vertici e smorzato sulle corse lunghe.
   Basta una sfumatura orizzontale perché la barra è bassa e larga, e tutti
   e quattro gli angoli stanno quindi nelle due estremità. Dipinto da uno
   pseudo-elemento con maschera in esclusione: `border-image` non convive con
   `border-radius`, e a un bordo vero un gradiente non si può dare. Il box
   resta identico perché l'anello non occupa spazio. */
.island::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(to right,
    var(--anello-vertice) 0%,
    var(--anello-vertice) 4%,
    var(--anello-corsa) 16%,
    var(--anello-corsa) 84%,
    var(--anello-vertice) 96%,
    var(--anello-vertice) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
}

/* La riga resta sempre larga quanto l'isola aperta. Restringendo la pillola
   il contenuto viene ritagliato, non ricomposto: l'animazione tocca il box
   dell'isola e basta, invece di rifare il layout di ogni figlio. */
.island__row {
  display: flex;
  align-items: center;
  gap: var(--s-5);
  /* l'anello è dipinto da uno pseudo-elemento e non occupa spazio: qui non
     c'è più niente da scontare oltre al padding */
  width: calc(var(--island-w) - var(--island-pad) * 2);
  flex: 0 0 auto;
  padding-inline: var(--s-3);
  justify-content: space-between;
}

/* Contratta, l'isola cambia soltanto larghezza: il fondo è lo stesso dello
   stato aperto, perché il colore dell'header non si muove con lo scorrimento. */
.island[data-state="compact"] { width: var(--island-w-compact); }
/* Aprendo si prende più tempo che chiudendo: l'apertura è il gesto che si
   guarda, la chiusura deve solo togliersi di mezzo. */
.island[data-state="compact"]:hover,
.island[data-state="compact"]:focus-within {
  width: var(--island-w);
  transition-duration: var(--t-isola-apre);
}

/* Il marchio è ancorato al centro dell'ISOLA, non della riga.
   La riga ha larghezza fissa e viene ritagliata quando l'isola si stringe:
   un marchio centrato lì dentro resterebbe al centro della barra aperta e
   finirebbe fuori dal ritaglio, cioè sparirebbe proprio nello stato in cui
   dev'essere l'unica cosa visibile. Ancorato all'isola invece la segue
   mentre si contrae, e ci arriva con una traslazione, senza rifare il
   layout della riga a ogni fotogramma. */
.island__brand {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  z-index: 1;
  /* `left: 50%` senza `right` lascia al marchio la sola metà destra dell'isola
     per dimensionarsi: da contratta erano 115px su 230, e il marchio si
     rimpiccioliva invece di restare della sua misura. Con `max-content` la
     misura è quella del contenuto e il tetto qui sotto è l'unica cosa che la
     limita. */
  width: max-content;
}
/* Il logo resta della stessa misura nei due stati: animarne la larghezza
   ricomponeva il flex della riga a ogni fotogramma, ed era l'ultima cosa che
   restava a far scattare l'animazione. */
/* Il tetto serve da mobile: il marchio è centrato e il tasto menu sta a destra,
   quindi sui telefoni più stretti il marchio pieno gli finirebbe addosso.
   Lo spazio riservato per lato è il padding della riga (--s-3), il tasto
   (2.75rem) e uno stacco (--s-3), simmetrico perché il centro resti il centro.
   La versione precedente scontava il tasto ma non il padding della riga, e
   lasciava zero: non si vedeva solo perché il marchio era già strozzato dal
   `left: 50%` qui sopra. Ora il tetto governa davvero, e con il marchio a
   12rem morde solo sotto i ~374px: a 360 scende a 178. */
.island__brand {
  max-width: calc(100cqw - var(--island-pad) * 2 - (var(--s-3) * 2 + 2.75rem) * 2);
}
.island__brand img { display: block; width: var(--marchio-w); max-width: 100%; height: auto; }

.island__nav {
  display: none;
  align-items: center;
  gap: var(--s-5);
  /* uscita: corta e senza attesa, così le voci spariscono prima che il
     ritaglio dell'isola le venga addosso */
  transition: opacity 140ms linear;
}
/* Voci in Orbitron maiuscolo, al corpo del marchio invece che del testo.
   0.71875rem = 11.5px: le maiuscole di Orbitron stanno a .721 del corpo,
   quindi rendono 8.29px, gli 8.31 misurati sulla riga "EMMETECHNOLOGIC" del
   logo. È la seconda deroga dichiarata al pavimento dei 16px — vedi
   docs/design/sistema-tipografico.md §3.2.
   Il tracking di .06em non è un vezzo: a questo corpo le forme squadrate di
   Orbitron in maiuscolo si chiudono, e senza aria le parole si impastano.
   Il padding verticale non sposta il testo di una virgola, porta solo l'area
   cliccabile a 24px, il minimo di WCAG 2.2 per un bersaglio. */
.island__nav a {
  text-decoration: none;
  font-family: var(--font-titoli);
  font-size: 0.71875rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .06em;
  line-height: 1;
  padding-block: 0.4rem;
  color: var(--on-isola);
  white-space: nowrap;
  transition: color var(--t-fast);
}
.island__nav a:hover,
.island__nav a[aria-current="true"],
.island__nav a[aria-current="page"] { color: var(--on-night); }

@media (min-width: 63.75rem) {
  .island__nav { display: flex; }
  .island[data-state="compact"] .island__nav { opacity: 0; pointer-events: none; }
  /* Le voci entrano a corsa quasi finita. Non stanno ferme mentre l'isola si
     apre: la riga ha larghezza fissa e scorre con il bordo sinistro, 535px in
     tutto a 1440. Comparendo a 220ms ne restano da fare 134, un quarto della
     corsa, e invece di guardarle attraversare la barra le si vede posarsi.
     Durata scelta perché finiscano insieme alla larghezza, a 460ms. Da quando
     l'isola aperta ha i fianchi dell'hero la corsa cresce con la finestra —
     355px a 1020, 775 a 1920 — e il quarto che resta cresce con lei; fino al
     23/09/2026, a 1440, erano 460 e 115. */
  .island[data-state="compact"]:hover .island__nav,
  .island[data-state="compact"]:focus-within .island__nav {
    opacity: 1;
    pointer-events: auto;
    transition: opacity 240ms ease 220ms;
  }
  /* Da tastiera no. Entrando col tab il fuoco è già su una voce, e farla
     aspettare 220ms vuol dire tenere invisibile per 220ms l'elemento che si
     sta guardando. Chi arriva col mouse guarda la barra aprirsi; chi arriva
     col tab guarda dove sta il fuoco. */
  .island[data-state="compact"]:focus-within .island__nav {
    transition: opacity 160ms ease;
  }
}

/* Sotto i 63.75rem nell'isola non c'è spazio per logo, CTA e menu insieme:
   il CTA vive nel menu e nell'hero. Selettore più forte di .btn. */
/* sotto la soglia del menu l'altezza la detta il tasto da 2.75rem */
@media (max-width: 63.6875rem) { :root { --bar-h: calc(2.75rem + var(--island-pad) * 2); } }
/* Da lì in su il tasto sparisce e la compatta si stringe sul solo marchio, con
   una misura che dal marchio si ricava invece di essere scritta a mano: i
   14.375rem di prima venivano dal logo da 148px e non erano stati rifatti
   quando è passato a 244, così la barra contratta lo rimpiccioliva. */
@media (min-width: 63.75rem) {
  :root { --island-w-compact: calc(var(--marchio-w) + var(--island-pad) * 2 + var(--s-4) * 2); }
}

.island-toggle {
  flex: 0 0 auto;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem; height: 2.75rem;
  background: none;
  border: 1px solid var(--line-night);
  border-radius: var(--r-isola);
  color: var(--on-night);
  cursor: pointer;
}
@media (min-width: 63.75rem) { .island-toggle { display: none; } }

.island-toggle__bars { display: grid; gap: 4px; width: 15px; }
.island-toggle__bars span { height: 1.5px; background: currentColor; transition: transform var(--t-fast), opacity var(--t-fast); }
.island-toggle[aria-expanded="true"] .island-toggle__bars span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.island-toggle[aria-expanded="true"] .island-toggle__bars span:nth-child(2) { opacity: 0; }
.island-toggle[aria-expanded="true"] .island-toggle__bars span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

.sheet {
  position: fixed;
  top: calc(var(--bar-h) + var(--s-5));
  left: var(--s-3); right: var(--s-3);
  z-index: 59;
  padding: var(--s-4) var(--s-5) var(--s-5);
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: rgba(255, 255, 255, .97);
  backdrop-filter: blur(1.25rem);
  -webkit-backdrop-filter: blur(1.25rem);
  box-shadow: 0 24px 60px rgba(39, 39, 44, .16);
  display: grid;
  /* Le misure di questo commento e dei due qui sotto sono del foglio a sette
     voci. Dal 24/09/2026 le voci sono due più il tasto, e il pannello è alto
     214,19px, da 81 a 295,19: a 844×390 ci sta intero, senza barra, e il tetto
     morde solo sotto i 308px di finestra. Tetto, overflow e scroll-padding
     restano, perché tornano a servire appena la lista si allunga o il testo
     si ingrandisce.
     Il pannello è fisso: se non entra nello schermo non c'è scorrimento di
     pagina che lo riporti in vista, perché resta fermo mentre la pagina gli
     sfila sotto. Il contenuto misura 424,56px e il bordo alto sta a 81 —
     i 60 di --bar-h più i 21 di --s-5 — quindi il fondo cadeva a 506, e
     serviva una viewport alta almeno altrettanto. A 844×390, l'iPhone in
     orizzontale, «Azienda» era tagliata a metà e «Parliamo del tuo pezzo»
     finiva a 483, 93px sotto il bordo dello schermo: irraggiungibile, ed è
     l'unico invito all'azione del menu, che sotto la soglia dei 63.75rem è
     anche l'unica navigazione rimasta.
     Il tetto toglie a 100svh le tre misure che stanno sopra e sotto il
     pannello: i 60 della barra, i 21 dello stacco da essa e i 13 di --s-3,
     gli stessi che lo tengono staccato dai fianchi, così il vuoto che lo
     incornicia è uguale sui tre lati. Fa 296px a 390 di viewport e 281 a 375;
     da 519px in su non morde più e resta la geometria di prima, 424,56px e
     nessuna barra di scorrimento.
     svh e non dvh perché è la viewport più corta, quella con le barre del
     browser tutte fuori: così il pannello ci sta in ogni caso, e soprattutto
     non cambia altezza sotto le dita mentre lo si scorre. È anche l'unità già
     in uso per l'hero.
     Il padding resta qui, sul contenitore che scorre, e non va spostato su un
     involucro interno: è la ragione per cui i 21px di coda restano dentro
     l'area scorribile e a fine corsa il tasto conserva il suo cuscino — 21,94
     misurati fra il suo bordo e quello del pannello — invece di essere rasato
     contro l'angolo arrotondato. I 21 in testa fanno lo stesso a corsa ferma.
     overscroll-behavior chiude il travaso: finita la lista il gesto si ferma
     lì e non prosegue sulla pagina sottostante, che scorrerebbe dietro un
     pannello immobile dando l'impressione di un comando che scappa. */
  max-height: calc(100svh - var(--bar-h) - var(--s-5) - var(--s-3));
  /* overflow-x dichiarato a mano, e non lasciato al suo valore iniziale.
     La cascata dell'overflow dice che se un asse resta `visible` e l'altro
     no, il `visible` diventa `auto`: dichiarando qui sotto il solo overflow-y
     ci si è ritrovati anche overflow-x: auto, e non per modo di dire —
     getComputedStyle(.sheet).overflowX tornava "auto". Non è un asse vuoto,
     perché qualcosa da scorrere c'è: il tasto ha white-space: nowrap e non
     scende sotto la sua larghezza, che coi 21 di padding per parte fa lo
     scrollWidth del pannello. Appena il riquadro scende sotto quella misura
     compare una seconda barra, orizzontale, dipinta sul vetro dentro gli
     angoli arrotondati, e il pannello si scorre su due assi: misurato col
     foglio a sette voci, a 280px di finestra, offsetHeight − clientHeight − 2
     = 15px e l'altezza esterna saliva da 425 a 440. È lo zoom del browser al
     400% su una finestra stretta, la condizione in cui la 1.4.10 chiede che
     tutto resti usabile.
     Dal 01/10/2026 il tasto dice «Parliamo del tuo prodotto», e non scende
     sotto i 231,18px: lo scrollWidth è 273, e la barra comparirebbe da 300px
     di finestra in giù dove le barre si sovrappongono, da 315 in giù dove sono
     classiche, perché lì la barra della pagina si porta via altri 15px. Con
     «pezzo» erano 210,45, 252, 279 e 294.
     hidden e non clip: con l'altro asse a auto la cascata trasformerebbe
     comunque il clip in hidden, tanto vale scrivere quello che si ottiene.
     E non si perde niente di leggibile: a 290px il tasto sborda di 11,18px la
     colonna del testo ma resta 9,82px dentro il bordo del pannello, perché
     quello sbordo se lo prende il padding destro da 21; a 280 lo tocca, 0,18px
     oltre, e il ritaglio non si vede. Da 305 in su il tasto è largo quanto la
     colonna. */
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;

  /* Da quando questo è un riquadro di scorrimento il ritaglio cade sulla
     padding box, e quello che sporge dai bordi sparisce. Il contorno del
     fuoco sporge: 2px di tratto a 3px di distacco, quindi arriva 5px oltre la
     scatola della voce — misurato con un Tab vero, outlineWidth 2px e
     outlineOffset 3px. E lo scorrimento automatico del fuoco non gli lascia
     posto: Chrome porta la scatola a filo del riquadro e si ferma lì.
     Misurato a 844×390, dove il tetto morde e restano 129px da scorrere:
     scendendo col Tab «Azienda» si ferma a −0,06px dal bordo basso, risalendo
     «Soluzioni» si ferma a 0,19px da quello alto. In tutti e due i casi i 5px
     di contorno cadono fuori dal ritaglio e la voce che ha il fuoco resta
     senza il segno che dice dove sta il fuoco — su un pannello che sotto la
     soglia dei 63.75rem è l'unica navigazione, è il segno che serve di più.
     Di fianco il problema non c'è: lì i 5px stanno dentro i 21 di padding.
     scroll-padding è lo stacco che il riquadro chiede a chi ci scorre dentro,
     ed è il posto giusto dove tenerlo: non sposta niente in pagina, entra in
     gioco solo quando è lo scorrimento a decidere dove fermarsi. Con --s-2 le
     stesse due voci si fermano a 7,94 e 8,19px dai bordi: i 5px di contorno
     ci stanno tutti e restano circa 3px d'aria fra il contorno e il vetro.
     Gli 8 e non i 5 di --s-1, che sarebbero la misura esatta del contorno,
     perché con quelli la misura sotto tornava 4,94 — 0,06px rasati via dal
     frazionario dell'altezza del contenuto — e un contorno appoggiato al
     bordo sembra comunque un errore. */
  scroll-padding-block: var(--s-2);
}
.sheet[hidden] { display: none; }
/* Le voci del foglio sono in Orbitron dal 24/09/2026, su richiesta del
   committente: il carattere delle voci dell'header da desktop, ma a 16px.
   Dell'header prendono il carattere e il peso, 500 come ogni titolo sotto
   l'h1, e non il resto. Il corpo da 11,5px è una deroga dell'header (sistema
   tipografico §3.2) e il maiuscolo un'eccezione circoscritta a lui (§3.1): non
   si estendono. Il tracking è il -.005em delle altre parole in Orbitron a
   16px, le etichette di .facts dt e .spec-row dt, e non il .06em
   dell'header, che serve al maiuscolo a 11,5px. L'interlinea resta quella
   del corpo, 25,6px: il foglio resta alto 214,19px. */
.sheet a:not(.btn) {
  text-decoration: none;
  padding-block: var(--s-3);
  border-bottom: 1px solid var(--line);
  font-family: var(--font-titoli);
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: -.005em;
  color: var(--ink-muted);
}
.sheet a:not(.btn):last-of-type { border-bottom: 0; }
.sheet .btn { margin-top: var(--s-4); justify-content: center; }
@media (min-width: 63.75rem) { .sheet { display: none !important; } }

/* ============================ bottoni ============================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 2.75rem;
  padding: 0 var(--s-5);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font: inherit;
  font-size: 1rem;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
.btn:active { transform: translateY(1px); }

.btn--primary { background: var(--ink); color: var(--paper); }
.btn--primary:hover { background: #000; }

.btn--ghost { border-color: var(--line-strong); color: var(--ink); }
.btn--ghost:hover { border-color: var(--ink); background: rgba(39, 39, 44, .04); }

/* varianti per i fondi scuri */
.on-night .btn--primary { background: var(--paper); color: var(--ink); }
.on-night .btn--primary:hover { background: #fff; }
.on-night .btn--ghost { border-color: var(--line-night); color: var(--on-night); }
.on-night .btn--ghost:hover { border-color: var(--on-night); background: rgba(255, 255, 255, .08); }

.btn--sm { min-height: 2.375rem; padding-inline: var(--s-4); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }
.btn__arrow { transition: transform var(--t-fast); }
.btn:hover .btn__arrow { transform: translateX(3px); }

.arrow-link {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  text-decoration: none;
  font-weight: 500;
  font-size: 1rem;
  padding-bottom: var(--s-1);
  border-bottom: 1px solid var(--line-strong);
  transition: border-color var(--t-fast);
}
.arrow-link:hover { border-color: currentColor; }
.arrow-link svg { transition: transform var(--t-fast); }
.arrow-link:hover svg { transform: translateX(3px); }
.on-night .arrow-link { border-color: var(--line-night); }
/* Sul buio il filetto va riscritto anche in hover, se no non si muove. Le due
   regole pesano uguale — `.arrow-link:hover` e `.on-night .arrow-link` sono
   entrambe 0,2,0 — e la seconda sta dopo: vince lei anche col mouse sopra.
   Misurato: la freccia scorreva dei suoi 3px e il filetto restava a
   rgba(255,255,255,.18), cioè 1,78:1 sul #1c1c1c della sezione e 1,68:1 sul
   #0b0d10 della scena a figura intera — lo stesso identico grigio del riposo.
   Sul chiaro lo stesso gesto porta il filetto da 1,69:1 a 14,86:1, ed è quel
   salto che qui mancava: con currentColor si arriva a 15,46:1 e 17,65:1.
   Anteponendo `.on-night` la regola sale a 0,3,0 e non dipende più dall'ordine,
   come il gemello `.on-night .btn--ghost:hover` poco sopra. */
.on-night .arrow-link:hover { border-color: currentColor; }

/* ============================ hero ============================ */

.hero {
  position: relative;
  height: 100svh;
  overflow: hidden;
  background: var(--night-2);
  color: var(--on-night);
}

.hero__stage { position: absolute; inset: 0; }
.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__media video,
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  filter: brightness(.82) contrast(1.06);
}

.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(to top,
      #1c1c1c 0%,
      rgba(28, 28, 28, .99) 10%,
      rgba(28, 28, 28, .88) 26%,
      rgba(28, 28, 28, .62) 45%,
      rgba(28, 28, 28, .32) 66%,
      rgba(28, 28, 28, .10) 85%,
      rgba(28, 28, 28, 0) 100%),
    linear-gradient(to right, rgba(28, 28, 28, .68) 0%, rgba(28, 28, 28, .14) 54%, transparent 80%);
}

.hero__content { position: absolute; inset: 0; z-index: 2; display: flex; align-items: flex-end; min-width: 0; }
/* Le voci della griglia devono poter scendere sotto la loro larghezza minima:
   senza, una parola lunga del titolo — «all'automazione» sono 292px a 35px —
   tiene larga la colonna e il testo esce dallo schermo invece di andare a capo.
   Con `min-width: 0` la colonna si stringe e la parola si spezza. */
.hero__grid, .hero__grid * { min-width: 0; }
/* «all'automazione» a 35px sono 292px: su un telefono stretto non ci sta in
   colonna e, senza un appiglio, esce dallo schermo. `hyphens: auto` dà al
   browser il punto dove spezzare con il trattino; `anywhere` è la rete sotto,
   perché `break-word` da solo non entra nel calcolo della larghezza minima e
   quindi non serve a niente qui. */
.hero__inner h1 { hyphens: auto; overflow-wrap: anywhere; }
.hero__grid { width: 100%; padding-bottom: var(--sp-sezione-unita); display: grid; gap: var(--s-8); }

/* Sotto gli 80rem l'hero impagina in colonna e il contenuto entra nel flusso.
   Serve perché lo stacco in testa lo spinga davvero in basso: finché il blocco
   resta ancorato al fondo di una scatola alta 100svh, un padding-top cresce
   all'insù nel vuoto e non muove una riga (misurato: spostamento 0). Con il
   contenuto nel flusso l'hero si allunga quando il contenuto non ci sta,
   invece di tagliare le card.

   Va tolto dal flusso anche `.hero__stage`, non solo `.hero__content`: il
   contenuto gli sta dentro, e un figlio in flusso dentro un padre assoluto
   non porta comunque altezza al nonno. Reso statico lo stage, video e velo
   si agganciano direttamente a `.hero`, che è già `position: relative`. */
@media (max-width: 79.9375rem) {
  .hero { height: auto; min-height: 100svh; display: flex; flex-direction: column; }
  .hero__stage { position: static; flex: 1 1 auto; display: flex; flex-direction: column; }
  .hero__content { position: relative; flex: 1 1 auto; align-items: stretch; }
  /* Lo stacco in testa è 144; quello che avanza va fra titolo e card, non tutto
     in coda. Su un tablet in verticale l'hero è alto 1024 e il contenuto ne
     occupa 340: lasciato com'era, sotto le card restavano 540px di niente. Le
     card scendono al fondo, che è poi il posto che hanno da 1280 in su. */
  .hero__grid { padding-top: var(--s-12); align-content: space-between; }
}

/* L'hero non sta nel contenitore centrato: va a tutta larghezza e tiene
   il proprio padding, così il testo respira dai bordi dello schermo. */
.hero .hero__grid { max-width: none; padding-inline: var(--sp-fianchi); }

@media (min-width: 80rem) {
  /* Occhiello, titolo e sottotitolo prendono tutta la larghezza; solo
     pulsanti e riga dati si dividono l'ultima riga, come nel riferimento.
     `display: contents` promuove i figli di .hero__inner a celle di questa
     griglia, senza toccare il markup. */
  /* .hero .hero__inner batte la regola display:grid che sta più sotto */
  .hero .hero__inner { display: contents; }
  .hero__grid {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    row-gap: var(--s-5);
    column-gap: clamp(1.5rem, 3vw, 3rem);
  }
  .hero h1,
  .hero__lede    { grid-column: 1 / -1; }
  /* Titolo e sottotitolo occupano le righe 1 e 2: l'ultima è la 3, non la 4.
     Erano la 4 quando sopra c'era anche l'occhiello. */
  .hero__actions { grid-column: 1; grid-row: 3; }
  .facts         { grid-column: 2; grid-row: 3; }
}

.hero__inner { display: grid; gap: var(--s-5); }

/* Il titolo dell'hero sta su una riga perché il corpo scala con la finestra
   alla stessa velocità della larghezza disponibile, non per un nowrap a
   soglia. Sotto i ~38.5rem va a capo da solo. */

.hero__lede { max-width: 54ch; color: var(--on-night-muted); }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-2); }

/* Da telefono i due pulsanti prendono tutta la larghezza. La soglia è dove
   smettono di stare affiancati: insieme misurano 419,54px, quindi si
   affiancano da ~480px di finestra in su. A 31rem la transizione avviene
   mentre ci stanno già con 16px d'avanzo, e non si passa mai da «affiancati
   stretti» a «impilati larghi». Era 30rem finché il pulsante diceva «Parliamo
   del tuo pezzo» e i due misuravano 399: col «prodotto» del 01/10/2026 a 480
   ci stavano per 0,46px, un niente che un altro motore di testo si mangia. */
@media (max-width: 30.9375rem) {
  .hero__actions { display: grid; }
  .hero__actions .btn { width: 100%; }
}

/* Riga di dati con filetti verticali, come nel riferimento. Come tutte le
   griglie del file parte da una colonna sola: le tre card si affiancano da
   47.5rem, che è dove la colonna arriva a 219px e titoletto e microcopy
   stanno ciascuno su una riga (il più lungo misura 216px). Sotto quella
   soglia si impilerebbero le parole, non le card. */
.facts { display: grid; gap: var(--s-5); }
@media (min-width: 47.5rem) { .facts { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 80rem)   { .facts { display: flex; gap: 0; } }

.facts div {
  display: grid;
  gap: 0.125rem;
  align-content: start;
}
@media (min-width: 80rem) {
  /* Blocco compatto contro il bordo destro. Sotto gli 80rem manca la
     larghezza per tenerlo accanto ai pulsanti senza spezzare le righe:
     lì torna sotto al testo, a tutta larghezza e a 1rem pieni. */
  .facts { margin-left: auto; }
  .facts div { padding-inline: clamp(0.75rem, 1.4vw, 1.5rem); border-left: 1px solid var(--line-night); }
  .facts div:first-child { padding-left: 0; border-left: 0; }
  .facts div:last-child { padding-right: 0; }
}

/* Il tracking sta uguale a quello della regola base dei titoli, -.005em:
   questo dt è Orbitron peso 500, stessa famiglia e stesso peso dell'h4, e
   finché la regola base era a -.01em il valore scritto qui a mano coincideva
   con lei. Dimezzato il tracking dei titoli (sistema-tipografico.md §6.1),
   -.01em qui sopravviveva da solo: l'unico Orbitron del sito col doppio del
   tracking di sistema fuori dall'h1, che il doppio ce l'ha per deroga
   dichiarata. Allargare di cinque millesimi di em costa poco e non rompe
   niente — misurato a 1440px, dove il dt sta a 14,112px per la deroga qui
   sotto, «Nessuna opera muraria» passa da 181,66 a 183,13px, «Ciclo senza
   presidio» da 153,68 a 155,09 e «9 assi» da 46,84 a 47,26; a 16px pieni i
   tre scarti sono 1,68, 1,59 e 0,48px. La riga dati nel suo insieme cresce di
   1,48px e nessun nodo esce dal bordo: controllato a 1280, 1360, 1440, 1630 e
   1920, zero rect oltre il clientWidth in tutti e cinque. */
.facts dt { font-family: var(--font-titoli); font-size: 1rem; font-weight: 500; letter-spacing: -.005em; }
.facts dd { font-size: 1rem; color: var(--on-night-muted); }

/* Solo affiancate ai pulsanti: né il titoletto né il microcopy devono
   andare a capo, e lo spazio non basta per tenerli a 1rem pieni finché la
   finestra non supera i ~101.875rem. Il corpo scala con la finestra e non
   scende mai sotto i 0.875rem. È la prima delle DUE deroghe dichiarate al
   pavimento dei 16px — l'altra sono le voci di menu, la regola .island__nav a.
   Qui c'era «alla riga 451», e la riga 451 non è più quella da un pezzo: un
   numero di riga scade a ogni riga aggiunta sopra, il selettore no. Vedi
   docs/design/sistema-tipografico.md §3.2, che le elenca entrambe. */
@media (min-width: 80rem) {
  .facts dt,
  .facts dd { font-size: clamp(0.875rem, .98vw, 1rem); white-space: nowrap; }
}

@media (max-width: 62.4375rem) {
  .hero__scrim {
    background: linear-gradient(to top,
      #1c1c1c 0%, rgba(28, 28, 28, .97) 14%, rgba(28, 28, 28, .82) 40%, rgba(28, 28, 28, .55) 75%, rgba(28, 28, 28, .42) 100%);
  }
}

/* ============================ processo ============================ */

/* ============================== il ciclo ==============================

   Otto fasi che si richiudono. Una sola marcatura per due disegni: fino a
   63.9375rem è una scala verticale, col filo che scende di tappa in tappa;
   da 64rem in su le stesse otto voci si dispongono sull'anello e le loro
   descrizioni passano al perno, al centro.

   Le descrizioni sull'anello non ci stanno, e non è una resa: otto blocchi
   di testo a 16px attorno a un cerchio si sovrappongono, e il pavimento dei
   16 non si tocca (sistema-tipografico §3.2). Restano nel documento, le
   legge chi usa uno screen reader, e compaiono nel perno al passaggio o al
   fuoco — che è poi il senso del disegno: il dato sta al centro. */

/* Il ciclo non ha più un margine proprio in cima, e la ragione è il
   collasso dei margini. Ne aveva uno — --s-8, che da 64rem saliva a --s-9 —
   ed essendo il fratello subito successivo a .section__head dentro lo stesso
   .container, i due margini adiacenti collassavano sul maggiore: vinceva
   sempre il ciclo. Misurato fra il fondo della testata e la cima del ciclo:
   55px a 320, 390, 768 e 1023, 89px a 1024, 1280, 1440, 1680 e 2560. Il
   margine della testata, che nel frattempo valeva 34, 46,92 e 55, non è mai
   arrivato a schermo: qui --sp-testata era scritto e non applicato. E a 1440
   quegli 89px pareggiavano il padding di --sp-sezione, misurato 89px sulla
   stessa sezione — cioè lo stacco fra testata e corpo era grande quanto
   quello fra una sezione e la successiva, che è il guasto preciso per cui
   --sp-testata è stato introdotto.
   Tolto il margine, il vuoto lo detta la testata e basta: misurati 34px a
   320, 390, 768, 1023 e 1024, 46,92 a 1280, 55 a 1440, 1680 e 2560.
   L'anello non resta stretto, e da quando il cerchio è cresciuto resta anzi
   largo. La targhetta più alta sta 39,16px sotto la cima di .ciclo a 1024,
   47,44 a 1280 e 52,60 a 1440 e oltre: non è più lo stesso numero a ogni
   larghezza, perché adesso dipende dal lato del quadrato. Vale 0,14·S − 50,43,
   dove 50,43px è l'altezza della targhetta, che da S non dipende. Erano 25,73
   costanti finché S era 544 fissi. Fra l'ultima riga del lede e il primo testo
   restano quindi 73,16px a 1024, 94,36 a 1280 e 107,60 a 1440, dove prima
   erano 59,73 · 72,65 · 80,73.
   Attenzione, perché quei 107,60 a 1440 SUPERANO gli 89px che separano la
   sezione dalla scena che la segue — dal 23/09/2026 non più il padding di
   fondo, salito a 178, ma quanto ne resta scoperto dopo che la scena ci è
   risalita sopra di 89 (vedi .section--sormontata). Lo stacco dentro la
   sezione è tornato più grande di quello fra una sezione e la successiva,
   cioè esattamente l'inversione per cui
   --sp-testata è stato introdotto e che questo commento racconta qui sopra di
   aver riparato. È una conseguenza forzata del cerchio più grande chiesto dal
   committente il 23/09/2026, non una scelta di impianto: la banda vuota sopra
   la targhetta 01 vale 0,14·S e cresce col quadrato, e il cerchio grande senza
   quella banda non si può avere.
   Si compenserebbe con un margine negativo di 0,14·S − 76,16 su .ciclo__scena
   — 13,44px a 1024, 26,88 a 1440 — che riporta il vuoto ai valori di prima.
   Non è stato fatto: rimette in gioco un margine che questo stesso commento
   racconta di aver tolto dopo averlo studiato, ed è una decisione di disegno
   da prendere con il committente, non una riparazione da fare per conto suo. */
.ciclo__scena { position: relative; }

.ciclo__tappe { list-style: none; margin: 0; padding: 0; }

/* — la scala — */
.ciclo__tappa { position: relative; padding: 0 0 var(--s-6) var(--s-7); }
.ciclo__tappa::before {   /* il filo che lega le tappe */
  content: "";
  position: absolute; left: 0.8125rem; top: 1.25rem; bottom: -0.25rem;
  width: 1px; background: rgba(255, 255, 255, .18);
}
.ciclo__tappa:last-child::before { display: none; }
/* Il nodo sta all'altezza del numero, non della riga: 0.5rem più mezzo nodo
   cade sui 13px, e la maiuscola del numero ha il suo centro a 12.8. */
.ciclo__tappa::after {    /* il nodo */
  content: "";
  position: absolute; left: 0.5rem; top: 0.5rem;
  width: 0.625rem; height: 0.625rem; border-radius: 50%;
  background: var(--night-2); border: 1.5px solid rgba(255, 255, 255, .45);
}
.ciclo__tappa--chiave::after { background: var(--on-night); border-color: var(--on-night); }

/* La manina sta con l'anello, non qui. Fino a 63.9375rem il bottone non è un
   comando: click, mouseenter e focus passano tutti da attiva(), che apre con
   `if (anelloVisibile.matches)` e sotto la soglia esce subito — misurato a
   390px, il perno resta su «Un unico flusso di dati» dopo tutti e tre. La
   manina prometteva una risposta che non arriva, ed era rimasta quaggiù da
   sola: l'altro segnale di passaggio, .ciclo__tappa:hover .ciclo__nome che va
   a #fff, stava già dentro il media query dell'anello. Tolta la dichiarazione
   il cursore torna a `default` (misurato spegnendola con `cursor: revert`):
   la freccia sopra del testo, che sotto la soglia è tutto quello che il
   bottone è. */
.ciclo__bottone {
  display: block; width: 100%;
  margin: 0; padding: 0; border: 0; background: none;
  font: inherit; color: inherit; text-align: inherit;
}
/* Il bottone del ciclo tiene il suo anello: sta sempre e solo sul #1c1c1c
   della sezione, dove il bianco fa 15,46:1, e lo stacco di 0.5rem è quello che
   lo tiene lontano dal testo della fase. Quello che va spento è l'ombra della
   regola generale: `:where(…)` la lascia a 0,1,0 contro i 0,2,0 di questa, ma
   qui si riscrivono solo outline e offset, e senza questa riga si vedrebbero
   due anelli concentrici — la fascia bianca a 3px dal bordo e l'anello bianco
   a 8. */
.ciclo__bottone:focus-visible { outline: 2px solid var(--on-night); outline-offset: 0.5rem; box-shadow: none; border-radius: 2px; }

.ciclo__n {
  display: block;
  font-family: var(--font-titoli); font-size: 1rem; font-weight: 500;
  letter-spacing: .14em; color: var(--on-night-muted);
  transition: color var(--t-fast);
}
/* I nomi delle fasi sono in Orbitron dal 23/09/2026, su richiesta del
   committente, alla stessa grandezza di prima: 1.0625rem, 17px. Prima non
   dichiaravano la famiglia ed ereditavano IBM Plex Sans dal corpo, mentre il
   numero sopra di loro e il titolo del perno, che ripete il nome della fase
   puntata, erano già in Orbitron: adesso le tre cose parlano con la stessa
   voce.
   Il peso scende da 600 a 500, e non è un ritocco di gusto. Il sistema vuole
   «600 sull'h1, 500 da h2 in giù» (sistema-tipografico.md §2 e §4), e ogni
   Orbitron del sito che non sia l'h1 sta a 500 — compreso il titolo del perno
   qui accanto, che a 600 c'era già stato ed era stato riportato a 500 proprio
   per questa regola. Tenere il 600 cambiando solo la famiglia avrebbe rifatto
   lo stesso difetto. Il tracking a -.005em è quello dei titoli in Orbitron
   (§6.1), lo stesso di .facts dt e del titolo del perno.
   Orbitron corre largo e sull'anello le targhette sono larghe 10.5rem fisse,
   quindi si è misurato: la parola più lunga, «Digitalizzazione», passa da
   124,7px a 144,6 e resta dentro i 168 della targhetta con 23,4px di margine.
   Nessuno sforo a nessuna delle sette larghezze dell'audit, da 320 a 1920, e
   nessuna targhetta che tocchi l'anello o un'altra targhetta. Vanno a capo in più due nomi soli: «Finitura
   e lucidatura» sull'anello, che è centrata sul suo ancoraggio e cresce di
   11,22px sopra e sotto, e «Generazione tracciati» sulla scala a 320px.
   La targhetta 01 resta alta 50,43px, quindi la banda sopra l'anello misurata
   nel commento in testa alla sezione non si muove. */
.ciclo__nome {
  display: block; margin: var(--s-2) 0;
  font-family: var(--font-titoli);
  font-size: 1.0625rem; font-weight: 500; letter-spacing: -.005em;
  line-height: 1.32; color: var(--on-night);
  transition: color var(--t-fast);
}
.ciclo__desc { display: block; font-size: 1rem; line-height: 1.5; color: var(--on-night-muted); }

/* l'anello non esiste finché non c'è lo spazio per disegnarlo */
.ciclo__anello { display: none; }
.ciclo__corsa  { fill: none; stroke: url(#sfumaCiclo); stroke-width: 2.5; stroke-linecap: round; }
.ciclo__rientro{ fill: none; stroke: rgba(255, 255, 255, .28); stroke-width: 1.5; stroke-dasharray: 5 9; stroke-linecap: round; }
.ciclo__nodo   { fill: var(--night-2); stroke: rgba(255, 255, 255, .45); stroke-width: 1.5; transition: fill var(--t-fast), stroke var(--t-fast); }
.ciclo__nodo--vivo { fill: var(--on-night); stroke: var(--on-night); }

/* il perno: chiusa della scala fin qui, centro dell'anello da 64rem */
.ciclo__perno { margin-top: var(--s-6); }
.ciclo__perno-titolo {
  /* Il titolo apre il blocco. L'occhiello «Il perno» che gli stava sopra è
     stato tolto su richiesta del committente, e con lui se n'è andata la
     ragione del margine in cima: serviva a staccare dal sovratitolo, e non
     c'è più niente da cui staccarsi. Resta il margine sotto, che è il vuoto
     verso la descrizione.
     Il corpo scende da 23 → 27px a 18 → 22px, e con questo il titolo del
     perno smette di dichiararsi gemello dell'h3: non è una testata di
     sezione, è la didascalia al centro dell'anello, e alla scala di prima
     schiacciava la descrizione che gli sta sotto a 16px.
     Il calo chiude da solo una vecchia grana. A 27px «Un unico flusso di
     dati» andava a capo, e il perno, che è centrato sull'anello, si abbassava
     di una riga: bastava passare il mouse su una fase perché il blocco
     ballasse. Rimisurato sulle otto fasi più lo stato di riposo, a 1024, 1280
     e 1440, il titolo sta sempre su una riga e l'altezza del blocco è ferma a
     132,77 · 136,02 · 138,04px — ed è su quel numero che è tarata la
     larghezza del perno dentro l'anello, qui sotto nel media query.
     Peso 500 come vuole sistema-tipografico.md §4 («600 sull'h1, 500 da h2 in
     giù»): essendo un <p> la regola su h1–h4 non lo raggiunge e va scritto
     qui, e per la stessa ragione va scritto qui anche il tracking, che resta
     quello di prima. */
  margin: 0 0 var(--s-3);
  font-family: var(--font-titoli); font-weight: 500;
  font-size: clamp(1.125rem, 0.50962rem + 0.962vw, 1.375rem);   /* 18 → 22 */
  letter-spacing: -.005em;
  line-height: 1.32; color: var(--on-night);
}
.ciclo__perno-testo { margin: 0; font-size: 1rem; line-height: 1.5; color: var(--on-night-muted); }

.ciclo__ritorno {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin: var(--s-6) 0 0; padding-top: var(--s-5);
  border-top: 1px dashed rgba(255, 255, 255, .3);
  font-size: 1rem; color: var(--on-night-muted);
}
.ciclo__ritorno b { color: var(--on-night); font-weight: 600; }
.ciclo__ritorno span[aria-hidden] { font-size: 1.25rem; line-height: 1; }

/* — l'anello — */
/* `screen and` non è un vezzo, è quello che tiene l'anello fuori dalla carta.
   Senza, questo blocco si applica anche alla stampa: su A4 verticale non si
   vedrebbe, perché l'area utile è 741px e sta sotto i 64rem, ma su A4
   orizzontale sono 1045px e l'anello scatterebbe. Sulla carta sarebbe un
   disastro doppio. La corsa è dipinta con un gradiente bianco e il rientro
   con un bianco al 28%: su fondo bianco, niente. E le otto descrizioni qui
   dentro vengono nascoste con clip-path, perché sull'anello le racconta il
   perno — solo che il perno ne mostra una alla volta, e su un foglio di carta
   non c'è nessuno a passarci sopra il mouse. Si stamperebbe un quadrato vuoto
   di 644,84px — il clamp del lato risolto sui 1045px dell'A4 orizzontale, non
   più i 544 fissi di quando il quadrato non scalava — con otto etichette
   attorno e nessuna descrizione, per 800,28px di ingombro complessivo.
   Con `screen` la stampa resta sulla scala verticale, che ha il filo e i nodi
   disegnati, tiene le descrizioni in chiaro, e soprattutto si lascia spezzare
   fra una pagina e l'altra: un cerchio in posizionamento assoluto, no. */
@media screen and (min-width: 64rem) {
  /* Il quadrato tiene l'anello; le targhette escono dai suoi fianchi, ed è
     voluto. Il cerchio è stato ingrandito su richiesta del committente, perché
     il testo al centro stava stretto: era 544px fissi a ogni larghezza da
     1024 in su, adesso va da 640 a 736px, fluido fra 1024 e 1440 come tutto
     il resto del sistema.
     Le targhette non sporgono di più: sporgono di meno, e si calcola. Quella
     di destra parte all'86% del quadrato ed è larga 10.5rem, quindi esce di
     168 − 0,14·S — da 91,84px a 544 si passa a 78,4 a 640 e 64,96 a 736.
     L'ingombro totale del disegno, S + 2·(168 − 0,14·S) = 0,72·S + 336, va
     da 727,68px a 796,8 e 865,92. Il punto stretto è 1024, dove l'area utile
     del contenitore è 949px: restano 76,1px liberi per lato. */
  .ciclo__scena {
    width: min(clamp(40rem, 25.23063rem + 23.077vw, 46rem), 100%); aspect-ratio: 1;
    margin-inline: auto;
  }
  .ciclo__anello { display: block; position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }

  .ciclo__tappa { position: absolute; width: 10.5rem; padding: 0; }
  .ciclo__tappa::before, .ciclo__tappa::after { display: none; }
  .ciclo__nome { margin: 0.15rem 0 0; }
  /* Da qui in su il bottone comanda davvero — il perno segue la fase puntata,
     misurato: a 1024 e a 1440 un mouseenter sulla terza tappa porta il titolo
     del perno da «Un unico flusso di dati» a «Generazione tracciati» — quindi
     la manina dice il vero solo qui. */
  .ciclo__bottone { cursor: pointer; }
  .ciclo__tappa:hover .ciclo__nome,
  .ciclo__bottone:focus-visible .ciclo__nome { color: #fff; }
  .ciclo__bottone[aria-current="true"] .ciclo__n { color: var(--on-night); }

  /* La descrizione esce dalla vista ma non dal documento: la porta il perno. */
  .ciclo__desc {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap; border: 0;
  }

  /* otto ancoraggi su un raggio del 36%, testo sempre orizzontale */
  .ciclo__tappa--0 { left: 50%;   top: 14%;   transform: translate(-50%, -100%); text-align: center; }
  .ciclo__tappa--1 { left: 75.5%; top: 24.5%; transform: translate(0, -50%); }
  .ciclo__tappa--2 { left: 86%;   top: 50%;   transform: translate(0, -50%); }
  .ciclo__tappa--3 { left: 75.5%; top: 75.5%; transform: translate(0, -50%); }
  .ciclo__tappa--4 { left: 50%;   top: 86%;   transform: translate(-50%, 0); text-align: center; }
  .ciclo__tappa--5 { left: 24.5%; top: 75.5%; transform: translate(-100%, -50%); text-align: right; }
  .ciclo__tappa--6 { left: 14%;   top: 50%;   transform: translate(-100%, -50%); text-align: right; }
  .ciclo__tappa--7 { left: 24.5%; top: 24.5%; transform: translate(-100%, -50%); text-align: right; }

  /* Il perno sta dentro il cerchio con un vuoto dichiarato: 55px da 1440 in
     su, 34px da 1024 in giù, fluido in mezzo. Sono due gradini della scala
     Fibonacci, chiesti dal committente il 23/09/2026 — nello stesso giro erano
     prima 34 e 21, poi alzati di un gradino.
     Quel vuoto è la distanza MINIMA fra il blocco di testo e il bordo interno
     del tratto, non la distanza sui fianchi: in un rettangolo dentro un
     cerchio il punto più vicino al bordo sono gli spigoli. È la lettura
     confermata dal committente. Quindi la larghezza si ricava inscrivendo il
     blocco in un cerchio di raggio R − vuoto, e non togliendo due volte il
     vuoto alla corda orizzontale.
     I numeri. La corsa ha raggio 300 su un viewBox di 1000 e tratto 2,5,
     quindi il bordo interno sta a 0,29875·S: 191,20px a 1024 e 219,88 a 1440.
     L'altezza del blocco è ferma — la tengono il titolo su una riga e il
     min-height di 6em della descrizione — e vale 132,77px a 1024 e 138,04 a
     1440, misurata su tutte e otto le fasi più lo stato di riposo. Da lì la
     semilarghezza: √((191,20 − 34)² − 66,385²) = 142,4952 a 1024 e
     √((219,88 − 55)² − 69,02²) = 149,7386 a 1440, cioè 284,99 e 299,48px.
     In CSS gli estremi sono arrotondati a 17.812rem e 18.717rem, cioè 284,99
     e 299,47: l'arrotondamento va nel verso sicuro, perché un blocco più
     stretto lascia più vuoto e non meno. Misurato dal vivo, il minimo vale
     34,00px a 1024, 46,92 a 1280 e 55,00 a 1440. Sui fianchi, dove il cerchio
     è più largo del blocco, ne avanza molto di più: 48,70px a 1024 e 70,14 a
     1440.

     ATTENZIONE, la scorta è finita. Con la colonna a 284,99px la descrizione
     più lunga — quella di riposo, «La geometria acquisita all'inizio…» —
     occupa 4 righe, cioè esattamente il pavimento di 6em (96px a interlinea
     24). Finché ci sta, l'altezza del blocco non si muove e il vuoto è quello
     dichiarato. Ma UNA PAROLA IN PIÙ in quel testo lo porta a 5 righe,
     l'altezza sale di 24px e il vuoto minimo a 1440 scende da 55 a 49,63.
     Prima di allungare il testo del perno bisogna allargare il cerchio o
     rifare questa clamp. Col vuoto precedente di 34/21 la colonna era
     313,44 → 345,12px, le righe erano 3 e la scorta era una.

     Il 56% di prima dei due giri dava 304,63px fissi, con 10,2px di vuoto sui
     fianchi ma −13,88 sugli spigoli a 1024 e −25,03 a 1440: gli angoli del
     blocco uscivano dal cerchio. Oggi il vuoto c'è ed è quello chiesto, ma la
     colonna è tornata più stretta di allora: −19,64px a 1024 e −5,15 a 1440.
     Per ridarle la larghezza che aveva col vuoto di 34/21, tenendo questo di
     55/34, servirebbe un cerchio da 683,5 → 806,2px invece di 640 → 736. Ci
     starebbe — l'ingombro a 1024 sarebbe 828,1px contro i 949 di area utile —
     ma è una decisione del committente e non è stata presa. */
  .ciclo__perno {
    position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: clamp(17.812rem, 15.58431rem + 3.481vw, 18.717rem);   /* 284,99 → 299,47px */
    margin: 0; text-align: center;
  }
  /* il testo cambia al passaggio: l'altezza no, o l'anello ballerebbe */
  .ciclo__perno-testo { min-height: 6em; }

  .ciclo__ritorno { justify-content: center; margin-top: var(--s-7); }
}

/* Il rimando sotto il ciclo, «La scansione 3D come servizio a sé». Stava
   centrato con uno stile scritto nell'HTML, che nessuna media query batte:
   da mobile va a sinistra come le testate (vedi .section__head), quindi è
   passato qui. */
.ciclo__rimando { margin-top: var(--s-9); text-align: center; }
@media (max-width: 63.9375rem) { .ciclo__rimando { text-align: left; } }

/* ========================= scena fotografica ========================= */

/* Il bordo bianco da 5px è del committente, 23/09/2026, e lavora in coppia con
   la risalita della scena su #processo (vedi .section--sormontata): dove la
   scena sta sopra il fondo scuro della sezione la stacca da lui, più giù, sul
   bianco della pagina, ci si confonde. Per questo è --paper e non un #fff
   scritto a mano: è la pagina che si vede attraverso. Resta 5px a ogni
   larghezza — è uno spessore, non una spaziatura, e 5 è già il primo gradino
   della scala.
   Con box-sizing: border-box sta dentro la scena, ma la colonna del testo
   perde 10px e ogni soglia di a capo sale di 10px esatti:
   il titolo prende una quarta riga sotto i 312px invece che sotto i 302, il
   collegamento va a capo sotto i 310 invece che sotto i 300. Su un telefono,
   che parte da 320, non cambia quindi nessun a capo. Misurato senza barra di
   scorrimento, come su un telefono: qui stava scritto che fra 320 e 326px il
   titolo prendeva la riga in più e che la scena a 320×568 cresceva da 522,55 a
   551,72px, ma erano misure prese in un iframe con la barra classica da 15px,
   dove «320» vuol dire 305 di layout. Niente sfora, misurato coi rect.
   Il bordo sposta anche i pixel della foto che stanno sotto il testo: i
   contrasti rimisurati sono nel commento di .showcase__scrim.
   Niente altezza minima, anche questo su richiesta del committente e dello
   stesso giorno. La scena era alta almeno 92svh — 828px a 1440×900, 942 su un
   tablet in verticale, 776 su un telefono da 390×844 — e adesso è alta quanto
   il suo testo più i 10px del bordo: 453,77px a 1440×900, 443,67 a 768×1024,
   501,45 a 390×844, misurati senza barra di scorrimento. La foto la riempie
   comunque tutta, con object-fit: cover. Quello che cambia è il velo: la sua
   sfumatura sta sopra il blocco di testo, il blocco di testo adesso arriva fino
   in cima, e la sfumatura cade fuori dal riquadro. Il velo copre così la foto
   intera, da .74 in cima a .84 in fondo: la foto si vede ovunque al 16-26%.
   Era .78-.88, cioè il 12-22%, e il committente l'ha trovato troppo scuro;
   più chiaro di così la cima non va, vedi .showcase__scrim. Per ridare aria
   alla foto servirebbe spazio sopra il testo, cioè di nuovo altezza. */
.showcase {
  position: relative;
  display: grid;
  align-items: end;
  overflow: hidden;
  background: var(--night);
  color: var(--on-night);
  border: 0.3125rem solid var(--paper);   /* 5px */
  border-radius: var(--r);
}
.showcase__media { position: absolute; inset: 0; z-index: 0; }
.showcase__media img { width: 100%; height: 100%; object-fit: cover; }
/* Il velo che tiene leggibile il testo sopra la fotografia. Stava su tutta la
   scena, con le tappe in percentuale — .88 al 2%, .30 al 40%, niente dal 78% in
   su — e il guasto è che quelle percentuali sono dell'altezza della SCENA, mentre
   il testo sta in fondo ed è alto per conto suo. Dove cade il testo dentro la
   sfumatura dipende dal rapporto fra i due, e quel rapporto cambia a ogni
   larghezza: una sfumatura in percentuale non può garantire niente al testo, e
   infatti non garantiva niente.

   Le misure sono prese contro i PIXEL VERI della foto e non contro i token,
   perché qui i token non dicono niente: sotto c'è robot-linea.jpg, una scena in
   alta chiave che sotto il testo arriva a rgb(255,255,255), e il #0b0d10 di
   .showcase non si vede mai. A 1440 l'occhiello cadeva fra il 40,2 e il 43,4%
   dal fondo, dove l'alpha vale .273-.298: fondo composito rgb(168,176,181),
   2,00:1 contro i 4,5 richiesti. Il lede fra il 15,1 e il 22,6%, alpha
   .566-.684: rgb(115,118,120), 2,47:1. A 320, dove il titolo va a capo quattro
   volte e il blocco di testo occupa l'81% della scena, l'occhiello finiva al 71%
   dal fondo, dove l'alpha è .053: rgb(230,240,241), 1,05:1, cioè invisibile.

   Adesso il velo è ancorato al BLOCCO DI TESTO: sta dentro .showcase__content,
   che è l'unico elemento in flusso di una griglia con align-items: end, quindi è
   già una fascia a tutta larghezza alta quanto il testo più le sue spaziature e
   appoggiata al fondo della scena. La scatola del velo è quella, allungata in
   su di --velo-sfumatura per spegnersi in gradiente invece che su un bordo. Il
   fondo sta a .84 e il punto più scarico — il bordo alto del blocco, sopra
   l'occhiello — non scende mai sotto .74, a qualunque larghezza. Su bianco
   pieno .74 dà rgb(74,76,78): l'occhiello e il collegamento a #f2f4f6 tengono
   7,82:1 e il lede a #b9bfc6 tiene 4,65:1. Più chiaro di così la cima non va,
   ed è il lede a deciderlo: il suo 4,5:1 sul bianco pieno cade a .7314, e a
   .73 scende a 4,48. Il fondo non ha un limite suo: sta sempre sotto la cima,
   quindi può scendere fino a .74 e la garanzia resta quella. Fino al
   23/09/2026 i due valori erano .88 e .78, che sul bianco pieno davano
   rgb(65,66,69), 9,10:1 e 5,42:1. Il committente ha trovato il velo troppo
   scuro e sono scesi entrambi di .04; con loro la coda di --velo-vernice-foto
   è salita da .40 a .43, per tenere il titolo a 3:1 sul fondo nuovo.

   Misurati sulla pagina viva a 320, 390, 768, 1024, 1280, 1440 e 1920, i
   peggiori erano 9,67:1 sull'occhiello, 6,55:1 sul lede, 12,23:1 sul
   collegamento e 3,56:1 sul titolo. Il 23/09/2026 la scena è cambiata quattro
   volte: il bordo bianco di .showcase ha tolto 5px per lato alla foto e alla
   colonna del testo, l'occhiello è passato a IBM Plex Sans corsivo 300 a 16px,
   più corto dell'Orbitron di prima e alto uguale, la scena si è ristretta ai
   fianchi della sezione sotto e ha perso l'altezza minima, che ritaglia la
   foto su un riquadro più basso. Rimisurati dopo tutti e quattro, alle stesse
   larghezze e senza barra di scorrimento, con la foto decodificata in un
   canvas e il velo composto riga per riga, all'ancora di #applicazioni e con
   la scena a filo del fondo della finestra, i peggiori erano 9,56:1
   sull'occhiello, 6,54:1 sul lede, 12,24:1 sul collegamento e 3,65:1 sul
   titolo, e il velo sopra il testo non scendeva sotto .792. I 5,82 che per il
   titolo stavano scritti qui venivano dall'iframe di misura, la cui barra da
   15px a «320» lascia 305 di layout e manda il titolo a capo una volta in più.
   Col velo schiarito, stesso metodo e stesse larghezze, i peggiori sono
   8,22:1 sull'occhiello, 5,64:1 sul lede, 10,70:1 sul collegamento e 3,60:1
   sul titolo, tutti a 320px tranne il collegamento, a 768; il velo sopra il
   testo non scende sotto .752. Il titolo sta sopra il 3:1 che vale per lui,
   testo grande.
   Da quando la scena non ha più altezza minima il velo la copre tutta: il
   blocco di testo arriva fino in cima, e la sfumatura che lo allunga verso
   l'alto cade fuori dal riquadro. Sulla foto il velo va da .74 in cima a .84 in
   fondo. Qui stava scritto che la banda ne copriva il 55-73% lasciando
   scoperto il terzo alto: era vero con i 92svh, non lo è più.

   --velo-sfumatura sale 89 → 144px con le formule del sistema delle spaziature:
   pendenza (144-89)/416 = .132212, coefficiente 13.221vw, intercetta
   89 − .132212 × 1024 = −46,38px = −2,899rem. Sono i due gradini alti di
   Fibonacci, --s-9 e --s-11.

   z-index: -1 e non 1. Dentro .showcase__content, che è position: relative con
   z-index: 2 e quindi apre un contesto di sovrapposizione, un elemento
   posizionato si dipinge SOPRA i blocchi non posizionati — .container e
   .showcase__inner non lo sono — e il velo coprirebbe il testo che deve
   scoprire. A -1 scende sotto di loro e resta comunque sopra la foto, che sta in
   un contesto fratello a z-index 0. */
.showcase__scrim {
  --velo-sfumatura: clamp(5.5625rem, calc(13.221vw - 2.899rem), 9rem);   /* 89 → 144 */
  position: absolute;
  inset: calc(-1 * var(--velo-sfumatura)) 0 0 0;
  z-index: -1;
  background: linear-gradient(to top,
    rgba(11, 13, 16, .84) 0%,
    rgba(11, 13, 16, .74) calc(100% - var(--velo-sfumatura)),
    rgba(11, 13, 16, 0) 100%);
}
.showcase__content { position: relative; z-index: 2; padding-block: clamp(3.5rem, 9vh, 7rem); }
.showcase__inner { display: grid; gap: var(--s-5); max-width: 38rem; }
.showcase__inner .lede { color: var(--on-night-muted); }

/* La scena ha i fianchi della sezione sotto: dal 23/09/2026, su richiesta del
   committente, l'involucro fa da .container — stessa larghezza massima di
   81.25rem, stesso --sp-fianchi — e la scena, bordo compreso, sta a filo delle
   schede di Soluzioni a ogni larghezza. Misurato senza barra di scorrimento:
   30→290 a 320, 30→994 a 1024, 125→1315 a 1440, 365→1555 a 1920, gli stessi
   bordi del contenuto sotto al centesimo. Prima i fianchi erano
   --sp-fianchi-riquadri, e la scena era più larga di 17px per lato fino a 1024,
   di 6,5 a 1280, di 70 a 1440 e di 310 a 1920, dove non si fermava ai 1300px
   del contenitore.
   I 13px che da telefono stavano fuori passano dentro, sul contenitore del
   testo: il margine esterno sale da 13 a 30 e quello interno scende da 30 a 13.
   La somma è la stessa, quindi fino a 1280 il testo non si muove di un pixel —
   stessa colonna, stesse righe, stessa altezza della scena, misurate a sette
   larghezze. Da 1440 in su rientra di 60px, 5 di bordo più 55 di padding,
   perché sta dentro una scena che adesso finisce dove finisce il contenuto:
   prima era lui ad allinearsi al contenuto, e la scena gli sporgeva attorno. */
.showcase-wrap {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--sp-fianchi);
}
.showcase .container { padding-inline: var(--sp-fianchi-riquadri); }

/* ============================ linee prodotto ============================ */

.lines { display: grid; gap: var(--s-9); }

/* Affiancate, le due schede devono condividere le righe. Senza, basta una riga
   di titolo in più in una colonna — e succede: accanto all'etichetta «Coming
   soon», «Carteggiatura e lucidatura» sta su due righe da 1104px in giù — da
   1129 con una barra di scorrimento classica, che ruba 15px al layout ma non ai
   vw dei corpi — fino agli 880 dove le schede si impilano, e senza subgrid
   tutto ciò che le sta sotto scenderebbe di quella riga, 30,36px a 1024,
   rispetto all'altra colonna. Misurato a passo di 1px il 23/09/2026: qui si
   parlava ancora di
   «In arrivo», l'etichetta di prima, larga 98,64px contro i 132,88 di quella di
   adesso, e di «attorno ai 1000px». Con `subgrid` le sei
   righe sono le stesse per entrambe: media, occhiello, titolo, testo, sigle,
   collegamento. Emme Sand ne usa le prime quattro: non ha le sigle dei modelli e,
   dal 24/09/2026, nemmeno il collegamento. Dove `subgrid` non c'è la dichiarazione viene ignorata e si
   torna al comportamento di prima: sfalsate, non rotte.

   Attenzione: il numero di righe è scritto a mano. Aggiungendo un figlio a
   .line va aggiornato anche qui. */
@media (min-width: 55rem) {
  .lines {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: repeat(6, auto);
    column-gap: var(--s-8);
    row-gap: var(--s-4);
  }
  .line { grid-row: 1 / -1; grid-template-rows: subgrid; row-gap: var(--s-4); }
  /* Qui c'era `.line > .arrow-link { grid-row: 6; }`: la seconda scheda non ha
     le sigle dei modelli, e senza quella riga il suo collegamento sarebbe salito
     di un posto, disallineato da quello di Emme Paint. Il 24/09/2026 il committente
     ha tolto il collegamento di Emme Sand, «Segnala il tuo processo», e quello di
     Emme Paint il sesto posto lo prende da sé, perché è il sesto figlio. */
}

.line { display: grid; align-content: start; gap: var(--s-4); }

.line__media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--paper-2);
  border-radius: var(--r);
  overflow: hidden;
  display: grid;
  place-items: center;
  margin-bottom: var(--s-3);
}
.line__media img { width: 100%; height: 100%; object-fit: cover; }

.line__empty { display: grid; gap: var(--s-3); justify-items: center; text-align: center; padding: var(--s-6); color: var(--ink-dim); }
.line__empty svg { opacity: .55; }

/* Il titolo si stringe e va a capo dentro di sé invece di spingere l'etichetta
   sulla riga sotto: con `flex-basis: 0` il calcolo della riga usa la larghezza
   minima del titolo, non quella che vorrebbe. Sotto una certa larghezza nemmeno
   il minimo ci sta accanto all'etichetta, e allora sì che l'etichetta va a capo.
   Quella soglia la detta la larghezza dell'etichetta, quindi si sposta col suo
   testo, e va rimisurata ogni volta che il testo cambia. Misurata a passo di
   1px sulla scheda Emme Sand, che è l'unica a portarne una, senza barra di
   scorrimento come su un telefono: «In arrivo», larga 98,64px, restava accanto
   al titolo fino a 348px e andava a capo a 347; «Coming soon», larga 132,88px,
   che l'ha sostituita il 23/09/2026, resta accanto fino a 382 e va a capo a
   381. A 390px, una delle larghezze dell'audit, sta quindi ancora accanto. Qui
   stavano scritti 363/362 e 397/396, con la conclusione opposta su 390: erano
   presi nell'iframe di misura, la cui barra classica da 15px sposta ogni
   soglia di altrettanto. Sotto la soglia non è un guasto: è il ripiego
   previsto da questa stessa regola. Il «~330px» di una versione ancora
   precedente era impreciso comunque. */
.line__title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); }
.line__title h3 { flex: 1 1 0; min-width: min-content; }

.badge {
  display: inline-flex; align-items: center;
  padding: 0.125rem var(--s-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  font-size: 1rem; font-weight: 500;
  letter-spacing: .06em;
  color: var(--ink-muted);
}

.line__models { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.line__models li {
  padding: var(--s-1) var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font-size: 1rem;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

/* ============================ specifiche ============================ */

/* Testata e tabella a sinistra, foto a destra: dal 24/09/2026, su richiesta del
   committente. Prima la colonna stretta da 27rem teneva testata e foto, e la
   tabella stava da sola nella colonna larga. Le larghezze sono rimaste ai loro
   contenuti: la foto tiene i suoi 27rem, 432 × 722,88px, e la tabella la sua
   colonna, 388px a 1024, 613,23 a 1280, 614 da 1440 in su, dove adesso sta
   anche la testata, che prima era larga 432. La foto parte a filo
   dell'occhiello, 0px di scarto misurato. Da tablet in giù vale l'ordine del
   documento: testata, tabella, foto.
   .spec-figure ha perso i 55px di margine in testa, che la staccavano dalla
   testata sopra di lei nella stessa colonna: adesso è una cella sua, e da
   tablet in giù dalla tabella la stacca il gap della griglia. Fra testata e
   tabella c'è --sp-testata, misurato 34 · 46,92 · 55 a 1024, 1280 e 1440: la
   testata ha ripreso il margine di tutte le altre, perché lo
   `style="margin-bottom:0"` che lo azzerava serviva quando la tabella le stava
   accanto, non sotto. */
.spec-layout { display: grid; gap: var(--s-9); }
@media (min-width: 61.25rem) {
  .spec-layout { grid-template-columns: minmax(0, 1fr) minmax(0, 27rem); gap: var(--s-11); align-items: start; }
}

.spec-figure { border-radius: var(--r); overflow: hidden; }

.spec-table { border-top: 1px solid var(--line); }
.spec-row {
  display: grid; gap: var(--s-1) var(--s-5);
  padding-block: var(--s-4);
  border-bottom: 1px solid var(--line);
}
@media (min-width: 38.75rem) { .spec-row { grid-template-columns: minmax(0, 14rem) minmax(0, 1fr); align-items: baseline; } }
/* Le etichette in Orbitron dal 24/09/2026, su richiesta del committente: peso
   500 come ogni titolo sotto l'h1, e il tracking di .facts dt e dei nomi delle
   fasi. Misurate a 320, 390, 768, 1024, 1280, 1440 e 1920: nessuna va a capo
   nella colonna da 14rem, nemmeno «Alimentazione prodotto». */
.spec-row dt { font-family: var(--font-titoli); font-size: 1rem; font-weight: 500; letter-spacing: -.005em; color: var(--ink-dim); }
.spec-row dd { font-size: 1rem; font-variant-numeric: tabular-nums; }
/* Tecnologia sta sul fondo scuro di Processo dal 24/09/2026, e i colori girano
   come nelle altre sezioni scure: le etichette nel chiaro dei nomi delle fasi,
   --on-night, 15,46:1 sul #1c1c1c; i valori nel grigio delle descrizioni del
   ciclo e delle card dell'hero, --on-night-muted, 9,20:1; i filetti nel bianco
   al 18%. Il committente ha chiesto le etichette bianche: sono il bianco dei
   testi di questo sito, #f2f4f6, e non il #fff dei titoli, perché è un token e
   in stampa torna inchiostro da solo — il #fff andrebbe rincorso a mano, come
   già tocca all'h2. */
.on-night .spec-table,
.on-night .spec-row { border-color: var(--line-night); }
.on-night .spec-row dt { color: var(--on-night); }
.on-night .spec-row dd { color: var(--on-night-muted); }

/* ============================ assistenza ============================ */

.offer { display: grid; gap: var(--s-7); }
@media (min-width: 51.25rem) { .offer { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-8); } }
.offer__item { display: grid; gap: var(--s-3); align-content: start; padding-top: var(--s-5); border-top: 1px solid var(--line); }
.offer__item p { color: var(--ink-muted); font-size: 1rem; }

/* ============================ chi siamo ============================ */

/* L'hero di Chi siamo è quello della home senza pulsanti né card, su richiesta
   del committente del 24/09/2026: titolo e sottotitolo in basso a sinistra.
   Da 80rem in su ci pensa già la regola della home, che ancora il blocco al
   fondo. Sotto no: lì il contenuto torna nel flusso con 144px in testa, e
   `space-between` manda le card al fondo e lascia il titolo in cima. Senza le
   card la griglia ha una riga sola, `space-between` ripiega su `start`, e il
   titolo restava attaccato ai 144px con il video vuoto sotto. Con `end` scende
   al fondo: misurato, l'ultima riga del sottotitolo sta a 34px dal fondo
   dell'hero da 320 a 1024, cioè il padding della griglia, e a 46,92 a 1280. */
@media (max-width: 79.9375rem) {
  .hero--pagina .hero__grid { align-content: end; }
}
/* Lo sfondo dell'hero di Chi siamo è un fotogramma fermo, la scrivania
   dell'ufficio (vedi il commento in chi-siamo.html). Con `cover`, su un
   telefono in verticale del fotogramma si vede un quarto scarso: 499px su
   1920 a 390×844. L'insegna sta fra x 963 e 1400. Al 50% se ne vedeva il 56%;
   al 64% è intera a ogni telefono misurato, da 320×568 a 430×932, con l'iMac
   grande sotto. Da 768 in su se ne vede di più, 810px a 768×1024, e la
   posizione conta meno. */
.hero--pagina .hero__media img { object-position: 64% 50%; }
/* Il velo della home qui non va. È alto quanto la finestra, perché copre due
   righe di titolo, due di sottotitolo, pulsanti e card, ed è tarato su un
   video chiaro: il suo primo fotogramma ha luminanza media 173 su 255,
   questo 70,9. Sulla scrivania spegneva quasi tutto. Misurato sui pixel a
   1440×900, in valori medi su 255: il piano scendeva da 79 a 33, a un passo
   dai 28 del velo pieno, e l'iMac da 93 a 52.
   Il testo di Chi siamo sta tutto nei 200px più bassi dell'hero e, da
   desktop, nei primi 604px da sinistra. Il velo si ancora a quel blocco, in
   rem come il testo, e non all'altezza della finestra. È tarato sul bianco
   pieno, come quello della scena Applicazioni, così regge anche se la foto
   cambia: sotto il sottotitolo non scende sotto .767, dove sul bianco per il
   4,5:1 ne servono .738, e sotto il titolo non scende sotto .46, dove per il
   3:1 del testo grande ne servono .39. Sopra i 36rem è trasparente, e da
   40rem da sinistra la maschera lo porta al 35%, perché lì il testo non
   arriva. Vale a ogni larghezza: `.hero--pagina .hero__scrim` pesa più
   della variante da telefono della home, `.hero__scrim` sotto i 62.4375rem.
   Misurato sui pixel veri, da 320 a 1920: titolo da 5,46:1 in su,
   sottotitolo da 6,31:1; sul bianco pieno 3,56 e 4,98. A 1440×900 il piano
   della scrivania resta a 64 e l'iMac a 88. Se cambia il testo dell'hero,
   questi numeri vanno rifatti. */
.hero--pagina .hero__scrim {
  background: linear-gradient(to top,
    rgba(28, 28, 28, .86) 0,
    rgba(28, 28, 28, .76) 9rem,
    rgba(28, 28, 28, .42) 13rem,
    rgba(28, 28, 28, .12) 24rem,
    rgba(28, 28, 28, 0) 36rem);
  -webkit-mask-image: linear-gradient(to right, #000 40rem, rgba(0, 0, 0, .35) 60rem);
          mask-image: linear-gradient(to right, #000 40rem, rgba(0, 0, 0, .35) 60rem);
}

/* La Storia è senza foto, su richiesta del committente del 24/09/2026: la
   foto era robot-cabina.jpg, la stessa della scheda Emme Paint. Lo stesso giorno,
   sempre su sua richiesta, da 1024 in su è andata su due colonne a sinistra
   con 55px fra l'una e l'altra: --s-7, fisso, perché il numero l'ha dato lui.
   Poi la testata è salita in cima alla prima colonna e la chiusa in fondo
   alla seconda, e la seconda parte dall'alto, senza vuoto sopra: prima
   stavano centrate sopra e sotto il racconto.
   Le due colonne sono due blocchi dell'HTML, .storia__colonna: a sinistra
   testata e primi due paragrafi, a destra gli altri quattro e la chiusa.
   Il racconto è diviso in due, e la divisione è scritta a mano. È quella che
   il browser sceglieva da solo lasciando scorrere tutto su due colonne, a ogni
   larghezza da 1024 a 1920, ma col pareggio automatico il blocco teneva sotto
   un avanzo suo, 11,8px a 1440 e 3,3 a 1280, che si sommava allo stacco con
   la timeline; e ogni browser pareggia a modo suo. Se cambia il testo, la
   divisione va ricontrollata.
   Misurato: la seconda colonna parte alla stessa altezza dell'occhiello, a
   2,0px dalla cima, e a 55px dalla prima a ogni larghezza, con e senza barra.
   Le colonne finiscono insieme da 1440 in su, a 480,7 e 480,8px; più stretta
   la destra è più lunga, di 17px a 1280 e di 70 a 1024. Ciascuna resta dentro
   la misura di lettura: 454,5px a 1024, 47ch, e 567 da 1280 in su, 59ch
   contro i 60 della misura; il tetto, due misure più lo stacco, oggi non
   morde, perché il contenitore si ferma a 1190.
   Da mobile le due colonne tornano una sotto l'altra, e il row-gap le stacca
   come due paragrafi: 21px fra il secondo e il terzo come fra tutti gli altri,
   55 fra l'ultimo e la chiusa. La sezione resta identica: 1412,6 a 390. Da
   desktop è alta 627,3px a 1440 e 630,8 a 1024, contro 1077,2 e 929 quando
   era tutta centrata; lo stacco con la timeline resta 110 a 1440, 93,85 a
   1280 e 68 da 1024 in giù. */
.storia { display: grid; row-gap: var(--s-4); }
.storia__racconto { display: grid; gap: var(--s-4); max-width: var(--measure); }
.storia__racconto p { color: var(--ink-muted); }
@media (min-width: 64rem) {
  .storia {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--s-7);
    max-width: calc(var(--measure) * 2 + var(--s-7));
  }
}
/* La chiusa del racconto, «Dalla geometria al processo. Dal processo a un
   ciclo completo di automazione.», è un'affermazione e non un paragrafo: sta in
   Orbitron 500 sulla rampa dell'h3, 23 → 27px, con il peso dei titoli sotto
   l'h1. È un ruolo dichiarato nel sistema tipografico §4.
   Le due frasi sono due blocchi, bilanciati uno per uno: `text-wrap: balance`
   su tutto il paragrafo, col <br> in mezzo, lasciava «automazione.» da sola.
   Da 1024 in su stanno in fondo alla seconda colonna, e la prima va su una
   riga, la seconda su due, misurato a 1024, 1280, 1440 e 1920. Fra 768 e 1023, nei
   44rem, una riga ciascuna; da telefono vanno su due o tre. */
.storia__chiusa {
  margin: var(--s-7) 0 0;
  max-width: 44rem;
  font-family: var(--font-titoli);
  font-size: clamp(1.4375rem, 0.82182rem + 0.962vw, 1.6875rem);  /* 23 → 27, la rampa dell'h3 */
  font-weight: 500;
  line-height: 1.32;
  letter-spacing: -.005em;
  color: var(--ink);
}
.storia__chiusa span { display: block; text-wrap: balance; }

/* La timeline ha due forme.

   Quella di partenza è un elenco dentro un riquadro scuro, ed è quella che
   vede chi non ha JavaScript, chi ha «Riduci movimento» o una finestra più
   bassa di 34rem, e la stampa. Il riquadro fa come la scena Applicazioni
   (sistema delle spaziature §3): l'involucro ha i fianchi del contenitore e
   il margine interno è --sp-fianchi-riquadri. Da mobile no: il riquadro sta a
   13px dai bordi, con 21 dentro ai lati e 34 in alto e in basso, com'è la
   card della forma animata prima di aprirsi (vedi «La card da mobile», più
   sotto). Lo stacco sotto lo dà il Contatto. Quello sopra è 55 + 55, dal
   committente il 24/09/2026: --sp-sezione-unita in fondo alla Storia, che è
   bianca come il fondo attorno al riquadro, e altrettanto in testa
   all'involucro. Misurato dalla Storia:
   68px da telefono e da tablet, 93,85 a 1280, 110 a 1440; dal Contatto 55 da
   telefono e 89 a 1440.

   La colonna dell'anno è larga 7,25 volte il corpo dell'anno. L'intervallo
   più largo, «2024–2025», misura 7,2111em (396,61px a 55px). Con i 17rem di
   prima, «2023–2024» andava su due righe anche a 1440. Il corpo e la colonna
   leggono la stessa variabile, così non si scollano: 246,5px a 768, 398,75 a
   1440. */
.tl {
  --tl-zoom: 60;
  --tl-passo: 50;
  --tl-h0: 62;  /* altezza del riquadro stretto, in % della scena: vedi la forma animata */
  /* i fianchi del riquadro, fuori e dentro: quelli delle sezioni e dei
     riquadri, e da mobile 13 e 21px (vedi «La card da mobile») */
  --tl-fianchi: var(--sp-fianchi);
  --tl-dentro: var(--sp-fianchi-riquadri);
  /* 34 → 55, e sui telefoni più stretti quanto lascia la riga: vedi .tl__anno */
  --tl-anno: min(clamp(2.125rem, calc(5.048vw - 1.105625rem), 3.4375rem),
                 calc((100vw - 2 * (var(--tl-fianchi) + var(--tl-dentro))) / 7.25));
  max-width: var(--container);
  margin-inline: auto;
  padding-top: var(--sp-sezione-unita);
  padding-inline: var(--tl-fianchi);
}
.tl__riquadro {
  background: var(--night-2);
  color: var(--on-night);
  border-radius: var(--r);
}
.tl__interno { padding: var(--sp-sezione) var(--tl-dentro); }
.tl__tappe { margin-top: var(--sp-testata); border-top: 1px solid var(--line-night); }
.tl__tappa {
  display: grid; gap: var(--s-3);
  padding-block: var(--s-6);
  border-bottom: 1px solid var(--line-night);
}
@media (min-width: 48rem) {
  .tl__tappa { grid-template-columns: calc(var(--tl-anno) * 7.25) minmax(0, 1fr); column-gap: var(--s-7); align-items: baseline; }
  .tl__tappa > :not(.tl__anno) { grid-column: 2; }
  .tl__anno { grid-row: span 2; }
}
/* L'anno è un numero da vetrina, in Orbitron 500 fra 34 e 55px, sulle stesse
   ancore di tutto il resto. Da telefono sta a 34 perché «2024–2025» chiede
   7,2111 volte il suo corpo, 245,2px a 34, e a 55 non ci starebbe. Sui
   telefoni più stretti scende ancora, con il min() su .tl, che lo lega alla
   riga dell'elenco: la finestra meno 13 + 21 per parte, 252px a 320. Nel
   riquadro aperto la riga è più larga, la finestra meno 30 per parte, 260 a
   320, e il min() tiene la più stretta. L'anno resta a 34 fino a 314,5px di
   finestra, e sotto scende. Fino al 24/09/2026 la riga dell'elenco era di
   234px a 320, il min()
   mordeva sotto i 332 e a 320 portava l'anno a 32,28: senza, i tre
   intervalli andavano a capo dopo il trattino. Colori del buio del sito: anni
   e nomi in --on-night, 15,46:1 sul #1c1c1c, descrizioni in --on-night-muted,
   9,20:1. */
.tl__anno {
  font-family: var(--font-titoli);
  font-size: var(--tl-anno);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -.005em;
  font-variant-numeric: tabular-nums;
  color: var(--on-night);
}
/* I nomi delle tappe li ha chiesti più piccoli il committente, da mobile, il
   24/09/2026: erano l'h3 del sito, 23 → 27px. Adesso sono 18 → 27 sulle
   stesse ancore: 18 da mobile, 23,54 a 1280, 27 da 1440 in su come prima.
   Misurato nel riquadro aperto e nell'elenco, col nome tutto attaccato del
   01/10/2026: i due «Emmetechnologic × Curve Robot» su due righe da 320 a
   375, e tutti i nomi su una riga da 390 in su. Il 18 è stato scelto il
   24/09/2026, col nome ancora staccato e la card aperta ancora staccata dai
   bordi: allora a 19 e a 20 i due nomi lunghi andavano su due righe anche a
   414. È un ruolo del sistema tipografico, §4. */
.tl__tappa h3 {
  font-size: clamp(1.125rem, 2.16346vw - 0.25962rem, 1.6875rem);  /* 18 → 27 */
  color: var(--on-night);
}
.tl__testo {
  max-width: 44ch;
  font-size: clamp(1rem, 0.69231rem + 0.48077vw, 1.125rem);  /* 16 → 18, come il lede */
  color: var(--on-night-muted);
}
.tl__barra { display: none; }

/* La seconda forma è quella chiesta dal committente il 24/09/2026 sul modello
   della seconda sezione di zoah.com: il riquadro parte stretto, si allarga a
   tutto schermo, e dentro le tappe si danno il cambio. La accende app.js, che
   scrive data-tl="vivo" e --tl-n, il numero delle tappe, e a ogni scorrimento
   aggiorna --tl-z, da 0 a riquadro chiuso a 1 a tutto schermo. Sta sotto
   `screen` perché la stampa resti l'elenco.

   La corsa è di 60svh per lo zoom più 50svh per tappa, 360svh con sei tappe:
   la traccia è alta 460svh, 4140px a 1440×900. Misurato a 1440×900: il
   riquadro parte a 1036,8×558, cioè il 72% per il 62% come su zoah; a metà
   zoom è 1238,4×729 con gli angoli a 8px; a un sesto della corsa è 1440×900
   con gli angoli a zero. Da lì ogni tappa ha un sesto del resto.
   La larghezza di partenza è il 72% ma non più del contenuto del contenitore,
   1190px: da 1653px in su il riquadro stretto ha gli stessi fianchi delle
   sezioni, invece di allargarsi oltre. Da mobile parte più larga: vedi «La
   card da mobile», più sotto.

   Il testo non si rimpicciolisce mai. Il riquadro cambia misura, il
   contenuto no: si allarga una scala e non la si zooma con `transform`, che
   per tutta la corsa dello zoom avrebbe portato i 16px del corpo a 11,5.

   In alto l'isola copre la fascia fino a 77px a 1440. Il margine interno in
   testa cresce con lo zoom, da 55 a riquadro chiuso a isola più 34 a tutto
   schermo, 111px a 1440: il titolo parte sempre sotto l'isola. Da mobile
   parte da 34 e arriva a 107, isola più 34: vedi «La card da mobile».

   Le tappe stanno tutte nella stessa cella, così la cella è alta quanto la
   più alta e cambiare tappa non sposta la barra. Misurato a riquadro aperto,
   senza barra di scorrimento e accendendo le tappe una per una: nessuna
   trabocca, e il vuoto più stretto fra una tappa e la barra è 62,56px, a
   320×568, con la tappa del 2023–2024; 111,36 a 360×640, 124,86 a 375×667,
   225,24 a 390×844, 175,74 a 1024×768. Nel riquadro stretto non se ne accende
   nessuna: vedi app.js.

   Il riquadro stretto, centrato in una scena alta 100svh, lascia sopra di sé
   (100 − --tl-h0) / 2 = 19svh. Prima che la scena si fermi quel vuoto si
   sommava allo stacco della Storia: 215px da telefono e 260 a 1440. Il
   committente il 24/09/2026 l'ha voluto 55 + 55, come nell'elenco, quindi la
   traccia risale di 19svh meno --sp-sezione-unita: −116px a 1440×900, e il
   riquadro stretto arriva a 110px dalla Storia, a 93,85 a 1280 e a 68 da
   tablet e da telefono. Il riquadro resta centrato, come su zoah: a scena
   ferma comincia a 19svh dall'alto, 171px a 1440×900, sotto l'isola che
   finisce a 77. Nella risalita la parte trasparente della scena passa sopra
   la coda della Storia: la scena non prende il puntatore, lo prende solo il
   riquadro, e la chiusa resta selezionabile. Misurato con elementFromPoint
   sulla sua ultima riga, a scena sovrapposta: risponde la chiusa. */
@media screen {
  .tl[data-tl="vivo"] {
    max-width: none;
    padding: 0;
    margin-top: calc(var(--sp-sezione-unita) - (100 - var(--tl-h0)) * .5svh);
    height: calc((100 + var(--tl-zoom) + var(--tl-passo) * var(--tl-n, 6)) * 1svh);
  }
  .tl[data-tl="vivo"] .tl__scena {
    position: sticky; top: 0;
    height: 100svh;
    display: grid; place-items: center;
    overflow: hidden;
    pointer-events: none;
  }
  /* il fondo attorno al riquadro scurisce mentre il riquadro si allarga, come
     su zoah: a tutto schermo non si vede più, ma a metà zoom evita che il
     riquadro scuro si muova su una striscia bianca */
  .tl[data-tl="vivo"] .tl__scena::before {
    content: "";
    position: absolute; inset: 0;
    background: var(--night-2);
    opacity: var(--tl-z, 0);
  }
  .tl[data-tl="vivo"] .tl__riquadro {
    position: relative;
    width: calc(var(--tl-w0) + (100% - var(--tl-w0)) * var(--tl-z, 0));
    height: calc(var(--tl-h0) * 1% + (100 - var(--tl-h0)) * 1% * var(--tl-z, 0));
    border-radius: calc(var(--r) * (1 - var(--tl-z, 0)));
    overflow: hidden;
    pointer-events: auto;
    --tl-w0: min(72%, var(--container) - var(--sp-fianchi) * 2);
  }
  .tl[data-tl="vivo"] .tl__interno {
    height: 100%;
    max-width: var(--container);
    margin-inline: auto;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    row-gap: var(--s-6);
    padding: calc(var(--s-7) + (var(--s-3) + var(--bar-h) + var(--s-6) - var(--s-7)) * var(--tl-z, 0)) var(--sp-fianchi) var(--s-7);
  }
  .tl[data-tl="vivo"] .tl__tappe { margin: 0; border: 0; display: grid; align-items: center; }
  /* Si spegne con l'opacità e non con `visibility`: le tappe spente restano
     nell'albero di accessibilità, e un lettore di schermo le legge tutte e sei
     di fila senza dover scorrere la pagina. */
  .tl[data-tl="vivo"] .tl__tappa {
    grid-area: 1 / 1;
    grid-template-columns: minmax(0, 1fr);
    padding: 0; border: 0;
    opacity: 0;
    transform: translateY(var(--s-3));
    transition: opacity 600ms var(--e-isola), transform 600ms var(--e-isola);
  }
  .tl[data-tl="vivo"] .tl__tappa > * { grid-column: 1; grid-row: auto; }
  .tl[data-tl="vivo"] .tl__tappa.is-attiva { opacity: 1; transform: none; }
  /* La barra ripete gli anni per l'occhio: è aria-hidden nell'HTML. Le
     etichette stanno a 16px e compaiono da 57,5rem, 920px: «2023–2024» chiede
     86,21px, e la soglia è nata quando anche da mobile il riquadro partiva al
     72%, che a 768 gliene dava 71. L'etichetta andava a capo a riquadro
     chiuso e tornava su una riga aprendosi, e la barra cambiava altezza a
     metà zoom. Sotto restano i sei filetti.
     Dal 24/09/2026 da mobile il riquadro stretto è largo quanto la finestra
     meno 13px per parte, e la colonna basterebbe già da 651px: 105,83 a 768,
     131,16 a 920. La soglia non è stata spostata, perché non era chiesto: è
     segnalato nel README. */
  .tl[data-tl="vivo"] .tl__barra {
    display: grid;
    grid-template-columns: repeat(var(--tl-n, 6), minmax(0, 1fr));
    gap: var(--s-3);
    font-variant-numeric: tabular-nums;
  }
  .tl__barra li { display: grid; gap: var(--s-2); color: var(--on-night-muted); transition: color var(--t-fast); }
  .tl__barra li::after { content: ""; height: 2px; background: var(--line-night); transition: background-color var(--t-fast); }
  .tl__barra li.is-attiva { color: var(--on-night); }
  .tl__barra li.is-attiva::after,
  .tl__barra li.is-passata::after { background: var(--on-night); }
}
@media screen and (max-width: 57.4375rem) {
  .tl__barra span { display: none; }
}

/* La card da mobile. Il committente il 24/09/2026 l'ha chiesta così, sotto i
   1024px, tablet compresa: finché è una card è larga tutto lo spazio che c'è,
   con dentro 34px in alto e in basso e 21 ai lati, e poi si apre a tutto
   schermo, dove ai lati i margini sono 30. Vale nelle due forme; sta sotto
   `screen`, e la stampa resta com'era.
   Lo spazio che c'è è la finestra meno il margine laterale della sezione,
   che lo stesso giorno il committente ha chiesto di abbassare da 30 a 13px:
   --tl-fianchi. Il riquadro stretto parte da lì invece che dal 72%, e resta
   alto il 62%: a 390×844 è 364×523, da 13 a 377, a 320×568 294×352. Da
   lì si apre come da desktop: a metà zoom sta a 6,5px dai lati, a tutto
   schermo ha gli angoli a zero, e la scena attorno scurisce con lui.
   Dentro, 34 e 21 a riquadro chiuso, --tl-dentro; aperto, 30 ai lati, i
   --sp-fianchi dell'hero, e 34 in basso, che il committente non ha dato e
   resta quello della card. In alto i 34 si contano dall'isola, che copre la
   fascia fino a 73px: a riquadro chiuso il titolo sta 34 sotto il bordo del
   riquadro, a tutto schermo a 107 dal bordo dello schermo.
   Nell'elenco l'involucro passa da 30 a 13 e il margine interno a 34 e 21,
   com'è la card chiusa. Lo stacco dalla Storia resta 55 + 55, 68 da mobile.
   Il primo giro, lo stesso giorno, aveva preso i 34 e i 21 per margini fuori
   dalla card e i 13 per quelli dentro: la card si apriva dal 72% e si
   fermava a 21px dai lati e a 34 dal fondo e dall'isola, e a 320×568 sotto la
   tappa più lunga restavano 23,1px. Adesso, misurato senza barra e
   accendendo le tappe una per una, ne restano 62,56.
   È a soglia, e non su rampa, perché è un cambio di struttura: da mobile il
   riquadro stretto è largo quanto la sezione, da 1024 in su parte dal 72%.
   È dichiarato nel sistema delle spaziature, §3. */
@media screen and (max-width: 63.9375rem) {
  .tl { --tl-fianchi: var(--s-3); --tl-dentro: var(--s-5); }
  .tl__interno { padding-block: var(--s-6); }
  .tl[data-tl="vivo"] .tl__riquadro { --tl-w0: calc(100% - var(--tl-fianchi) * 2); }
  .tl[data-tl="vivo"] .tl__interno {
    padding:
      calc(var(--s-6) + (var(--s-3) + var(--bar-h)) * var(--tl-z, 0))
      calc(var(--tl-dentro) + (var(--sp-fianchi) - var(--tl-dentro)) * var(--tl-z, 0))
      var(--s-6);
  }
}

/* ============================ emme paint ============================ */

/* L'hero di Emme Paint è quello di Chi siamo, chiesto identico dal
   committente il 24/09/2026: stesso velo, titolo e sottotitolo in basso a
   sinistra. Cambia la foto, il fotogramma a 19,20s del video della home, e
   con lei l'inquadratura: il 64% di Chi siamo è tarato sull'insegna della
   scrivania, e qui porterebbe via la tazza. Al 50%, da telefono resta la
   pistola con il fondo della tazza: a 390×844 si vede la fascia fra 710 e
   1210 dei 1920px del fotogramma, a 320×568 quella fra 656 e 1264.
   Il contrasto è misurato sui pixel veri, col filtro dell'hero e il velo
   composto sopra, su ogni pixel dei rettangoli del testo, a dodici larghezze
   da 320 a 1920: titolo da 3,92:1 in su, a 320, e sottotitolo da 5,31:1. Il
   sottotitolo è stato accorciato per questo: nella prima versione a 320
   andava su cinque righe, il titolo saliva dove il velo è più leggero e il
   sottotitolo si fermava a 4,51. Se cambia il testo dell'hero, questi numeri
   vanno rifatti. */
.hero--paint .hero__media img { object-position: 50% 50%; }

/* Le sei fasi del ciclo di verniciatura usano l'elenco dell'Assistenza,
   .offer, dentro un <ol>: tre colonne da 51.25rem, una sotto. Stanno sul
   fondo scuro, dove .offer non era mai stato, e i colori girano come nelle
   altre sezioni scure: i filetti nel bianco al 18%, i testi nel grigio delle
   descrizioni del ciclo, --on-night-muted. Il numero è quello delle fasi del
   ciclo della home, .ciclo__n: Orbitron 500 a 16px con .14em di spaziatura,
   nello stesso grigio. */
.fasi__n {
  display: block;
  font-family: var(--font-titoli); font-size: 1rem; font-weight: 500;
  letter-spacing: .14em; color: var(--ink-dim);
}
.on-night .fasi__n { color: var(--on-night-muted); }
.on-night .offer__item { border-color: var(--line-night); }
.on-night .offer__item p { color: var(--on-night-muted); }

/* ============================ contatto ============================ */

/* Testo e modulo stanno fianco a fianco da 74rem, 1184px, e non più da
   58,75rem: dal 24/09/2026 il modulo va su due colonne e vuole i suoi 38rem,
   e a 940 accanto a lui il testo avrebbe avuto 128px. A 1184 alla colonna del
   testo restano 352,77px, 437,23 a 1280 e 438 da 1440, col contenitore pieno.
   Anche al minimo l'attacco sta su tre righe da una quarantina di battute. I
   recapiti, che stavano sotto l'attacco, dallo stesso giorno sono nel piè di
   pagina, e la colonna è alta 229,17px contro i 388,38 del modulo, a 1440. Fra
   940 e 1183 le due metà ora si impilano, come su tablet e telefono. */
.contact { display: grid; gap: var(--s-9); }
@media (min-width: 74rem) { .contact { grid-template-columns: minmax(0, 1fr) minmax(0, 38rem); gap: var(--s-11); align-items: start; } }

/* Il modulo va su due colonne dal 24/09/2026, su richiesta del committente:
   nome e telefono in cima, sotto l'email a tutta riga, poi le due domande, e
   consenso e bottone di nuovo a tutta riga. Le mezze celle le dichiara l'HTML
   con .field--mezza. Ogni altro figlio prende la riga intera, così un campo
   aggiunto domani nasce largo e non si infila accanto a un altro.

   Le colonne partono da 40rem, 640px, dove ognuna ha 279,5px. Ci sta la voce
   più lunga delle tendine, «Carteggiatura e lucidatura», che con padding e
   freccia ne chiede 263,98: sotto, il testo scelto verrebbe tagliato. E ci sta
   su una riga il più lungo dei messaggi delle mezze celle, quello del
   telefono, 274,29: con la soglia a 620 andava a capo fino a 629. Il tetto a
   38rem tiene le colonne a 293,5px anche quando il modulo sta sotto il testo,
   fino a 1183, invece di allargarle a metà pagina.

   `align-items: start` perché la riga la detta la cella più alta. Con nome
   valido e telefono in errore la cella del nome veniva stirata a 113,19px, e
   le sue righe con lei: l'etichetta da 25,59 a 42,39, il campo da 46 a 62,8,
   cioè 16,8px più in basso e più alto del vicino. Così ogni cella resta alta
   quanto il suo contenuto e i due campi partono alla stessa quota. */
.form { display: grid; gap: var(--s-4); max-width: 38rem; }
@media (min-width: 40rem) {
  .form { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
  .form > :not(.field--mezza) { grid-column: 1 / -1; }
}
.field { display: grid; gap: var(--s-2); }
.field label { font-size: 1rem; font-weight: 500; }

.field input, .field select, .field textarea {
  width: 100%; min-height: 2.875rem;
  padding: 0 var(--s-4);
  background: var(--paper);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  color: var(--ink);
  font: inherit; font-size: 1rem;
  transition: border-color var(--t-fast);
}
/* Il campo del prodotto, dal brief del 30/09/2026, con il segnaposto «In una
   riga: cosa produci e cosa vorresti verniciare o carteggiare». È alto tre
   righe, 104,78px, perché il segnaposto deve leggersi intero e un textarea
   non lo stringe, lo taglia: misurato, a 320 va su tre righe, da 360 a 520 su
   due, da 640 su una. L'interlinea è quella del corpo, 25,6px. */
.field textarea {
  padding-block: var(--s-3);
  line-height: 1.6;
  resize: vertical;
}
.field select {
  appearance: none; padding-right: var(--s-7);
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-muted) 50%), linear-gradient(135deg, var(--ink-muted) 50%, transparent 50%);
  background-position: calc(100% - 1.25rem) 1.3125rem, calc(100% - 0.9375rem) 1.3125rem;
  background-size: 0.3125rem 0.3125rem, 0.3125rem 0.3125rem; background-repeat: no-repeat;
}
/* Il grigio dell'hover è l'invito a scrivere rivolto a un campo che sta a
   posto: non deve poter cancellare la segnalazione di un errore. Senza il
   :not() la cancella, perché la cascata guarda la specificità prima
   dell'ordine — .field input:hover pesa (0,2,1) e batte .field--invalid input,
   che pesa (0,1,1) pur stando due righe più sotto. Misurato dopo un invio a
   vuoto: a riposo il bordo è rgb(192, 57, 43), e appena il puntatore arriva
   sul campo da correggere diventa rgb(107, 107, 116), cioè --ink-dim. Il rosso
   si spegne proprio dove si va a rimediare. Escludendo qui i campi già
   segnalati le due regole non si incontrano più, e quella dell'errore resta
   leggera com'era: niente !important, che in questo foglio è riservato agli
   interruttori generali, e nessun doppione di classe da decifrare.
   Il caso gemello del fuoco non esiste: il fuoco è disegnato dall'outline di
   :focus-visible, che non tocca il border-color — verificato, con il campo in
   errore e a fuoco il bordo resta rgb(192, 57, 43). */
.field:not(.field--invalid) input:hover, .field:not(.field--invalid) select:hover,
.field:not(.field--invalid) textarea:hover { border-color: var(--ink-dim); }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-dim); }
.field--invalid input, .field--invalid select, .field--invalid textarea { border-color: #c0392b; }
.field__error { font-size: 1rem; color: #c0392b; }
.field__error[hidden] { display: none; }

/* Il consenso sta a 12px: terza deroga al pavimento dei 16, voluta dal
   committente il 24/09/2026 insieme al testo, e dichiarata nel sistema
   tipografico §3.2. A 12px non c'è l'esenzione del testo grande, la soglia è
   4,5:1: il grigio --ink-muted tiene 5,55:1 sul #f6f7f9 della sezione, e
   «Privacy Policy», sottolineato e più scuro come l'ha chiesto, 13,87:1. A
   distinguerlo dal resto della frase è la sottolineatura, non il colore da solo
   (WCAG 1.4.1).
   Il selettore è .field .check (0,2,0) e non .check (0,1,0): .field label
   (0,1,1) pesava di più e dettava corpo e peso dell'etichetta, e il 12px
   restava 16. Finché qui c'era scritto 1rem i due valori coincidevano e la gara
   non si vedeva. Il peso lo detta ancora lei, 500: era già così, e non l'ho
   toccato.
   La casella era alta 46px e non 18: .field input le dava il min-height dei
   campi di testo, e il quadratino, disegnato al centro della scatola, stava a
   metà del blocco — visto a 1280, con due righe di testo — invece che sulla
   prima riga, dove il margine in alto voleva metterlo. Con min-height: 0 è
   18 × 18, e il margine la centra sulla prima riga da 19,2px: 0,01px di scarto
   misurato, da 320 a 1920. */
.field .check { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--s-3); align-items: start; font-size: 0.75rem; color: var(--ink-muted); }
.check input { width: 1.125rem; height: 1.125rem; min-height: 0; margin-top: calc((0.75rem * 1.6 - 1.125rem) / 2); accent-color: var(--ink); }
.check a { color: var(--ink); text-decoration: underline; text-underline-offset: .2em; }

/* Il segnale rosso degli altri campi sulla casella del consenso non attecchisce:
   con appearance:auto il controllo lo disegna il motore, che azzera bordo e
   padding prima di dipingerlo. Misurato con .field--invalid addosso al campo:
   la regola .field--invalid input la seleziona davvero (matches() lo conferma),
   ma sulla casella border-top-width resta 0px e border-top-style none, mentre
   l'input dell'email nello stesso identico stato mostra 1px rgb(192, 57, 43).
   Il consenso era quindi l'unico dei quattro campi a restare muto a schermo.
   Il segnale va allora messo dove il motore non comanda, e l'etichetta è il
   posto giusto anche per un'altra ragione: il controllo del consenso non è la
   casella da sola, è la casella più la frase che dice a cosa si acconsente.
   Senza scostamento il filetto cade esattamente dove cade il bordo rosso degli
   altri campi — misurato a 306px di larghezza, l'etichetta occupa da 30 a 261,
   gli stessi 231px del riquadro dell'email — quindi la colonna del modulo resta
   allineata e le sei segnalazioni si leggono come la stessa cosa.
   Sull'etichetta e non sulla casella anche per non litigare con il fuoco:
   l'outline è la penna con cui :focus-visible disegna il suo anello, e su un
   elemento solo ce n'è una sola. Così i due segnali convivono, il rosso attorno
   al blocco e il blu attorno alla casella che il tabulatore ha raggiunto. */
.field--invalid .check { outline: 1px solid #c0392b; border-radius: var(--r-sm); }

/* L'esca per i robot: un campo che chi compila a mano non vede e non raggiunge,
   e che un programma che riempie moduli compila comunque. Se arriva pieno,
   l'invio si scarta (app.js). Nascosto col ritaglio e non con display: none,
   che molti di quei programmi riconoscono e saltano: misurato 1 × 1px con
   clip-path inset(50%), fuori dall'albero di accessibilità per l'aria-hidden
   sul contenitore e fuori dal tabulatore per il tabindex -1 sul campo, così
   non ci inciampa nemmeno chi usa la tastiera o un lettore di schermo. Il nome
   è «website», un campo che un robot si aspetta, e autocomplete="off" tiene
   lontano il riempimento automatico del browser. Da solo non basta: il giorno
   che il modulo avrà un destinatario, lo stesso controllo va rifatto sul
   server, perché un robot che invia dritto all'indirizzo del modulo da qui non
   passa. */
.form__esca {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.form__note {
  padding: var(--s-4);
  border: 1px solid var(--line);
  border-left: 2px solid var(--ink);
  border-radius: var(--r-sm);
  background: var(--paper-2);
  font-size: 1rem; color: var(--ink-muted);
}
.form__note[hidden] { display: none; }
/* La nota si scopre vuota e si riempie 100 ms dopo: è così che l'annuncio parte
   davvero, e il perché sta per esteso in app.js. Qui serve solo che in quella
   finestra non lampeggi un riquadro bordato senza niente dentro, quindi finché
   il testo non arriva la nota sta senza bordo e senza padding, alta zero
   (misurato: 0px, e del modulo resta il solo gap di 21px per un decimo di
   secondo). È una classe e non :empty perché la stessa finestra, al secondo
   invio, serve a rileggere un testo identico: lì la scatola c'è già, deve
   restare intera e ferma dov'è, e a tenerla ferma è app.js che le blocca
   l'altezza misurata. */
.form__note--attesa { padding: 0; border: 0; }

/* ============================ calcolatore ROI ============================ */

/* La pagina /ottieni-informazioni-roi-calcolatore, sul modello di
   «Supercharger per il tuo business» di Tesla: a sinistra i risultati in due
   riquadri grigi con dentro un grafico su bianco, a destra il titolo e i
   parametri. Da desktop i risultati restano fermi mentre i parametri
   scorrono; da mobile, sotto i 1024px come in tutto il sito, vengono titolo,
   risultati e parametri, uno sotto l'altro.
   Non è nel menu: si raggiunge solo dall'indirizzo, per scelta.
   La sezione non ha un hero sotto l'isola, quindi in cima le serve lo spazio
   della barra fissa: la barra più il suo scostamento dall'alto, più lo stacco
   unito fra sezioni. */
.roi { padding-top: calc(var(--bar-h) + var(--s-3) + var(--sp-sezione-unita)); }

.roi__griglia {
  display: grid;
  gap: var(--sp-testata);
  grid-template-areas: "testa" "risultati" "parametri";
}
.roi__testa      { grid-area: testa; display: grid; gap: var(--s-5); }
.roi__risultati  { grid-area: risultati; display: grid; gap: var(--s-5); align-content: start; min-width: 0; }
.roi__parametri  { grid-area: parametri; display: grid; gap: var(--s-6); align-content: start; min-width: 0; }
.roi__griglia > * { min-width: 0; }

/* Da 1024 i parametri vanno in una colonna di 26rem, 416px, la larghezza del
   pannello di Tesla in proporzione al contenitore; il resto va ai risultati,
   557px a 1024 e 719 a 1440 col contenitore pieno. Il titolo e il sommario
   sono centrati come in quel modello, e da mobile a sinistra (§3.4). */
@media (min-width: 64rem) {
  .roi__griglia {
    grid-template-columns: minmax(0, 1fr) minmax(0, 26rem);
    grid-template-areas: "risultati testa" "risultati parametri";
    grid-template-rows: auto 1fr;
    column-gap: var(--sp-testata);
    row-gap: var(--s-7);
  }
  .roi__testa { text-align: center; justify-items: center; }
  .roi__testa .lede { text-align: center; }
}

/* I risultati restano fermi solo dove ci stanno interi. Una colonna
   appiccicata più alta della finestra lascerebbe la coda irraggiungibile
   finché non finisce la sezione. Misurato: la colonna è alta 933px a 1024 e
   989 da 1440 in su, e si ferma a 88 e 98px dall'alto; con 21px d'aria sotto
   servono 1108px di finestra, 69.25rem. Su un portatile da 900 di altezza
   quindi le due colonne scorrono insieme, e le loro altezze si equivalgono:
   1050px i parametri a 1440. Se i riquadri crescono, la soglia si rifà. */
@media (min-width: 64rem) and (min-height: 69.25rem) {
  .roi__risultati {
    position: sticky;
    top: calc(var(--bar-h) + var(--s-3) + var(--s-5));
    align-self: start;
  }
}

.roi__testa h1 { hyphens: auto; overflow-wrap: anywhere; }

/* ----- risultati ----- */

.roi__riquadro {
  display: grid;
  gap: var(--s-4);
  padding: var(--s-5);
  background: var(--paper-2);
  border-radius: var(--r);
}
/* I titoli dei riquadri e dei gruppi di parametri: Orbitron 500, sotto l'h3,
   18 → 21px sulla rampa 1024 → 1440 (pendenza 3/416). */
.roi__titolo-ris,
.roi__gruppo {
  font-family: var(--font-titoli);
  font-size: clamp(1.125rem, 0.66346rem + 0.72115vw, 1.3125rem);
  font-weight: 500;
  line-height: 1.32;
  letter-spacing: -.005em;
  color: var(--ink);
}
/* Il velo di vernice degli h2 qui si toglie. Non sono titoli di sezione ma
   intestazioni di riquadro, e a 18 → 21px stanno sotto i 24px oltre i quali il
   velo è tarato: lì la soglia è 4,5:1 e non 3. Col velo, «anni» in coda al
   titolo scendeva a metà grigio. */
.roi .roi__titolo-ris { color: var(--ink); -webkit-mask-image: none; mask-image: none; }
.roi__sintesi { display: grid; gap: var(--s-1); color: var(--ink-muted); }
.roi__sintesi .num { color: var(--ink); font-weight: 500; }

.roi__grafico {
  display: grid;
  gap: var(--s-4);
  padding: var(--s-5);
  background: var(--paper);
  border-radius: var(--r-sm);
}
.roi__legenda { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5); color: var(--ink-muted); }
.roi__legenda li { display: inline-flex; align-items: center; gap: var(--s-2); }
.roi__segno { display: inline-block; width: 1.3125rem; height: 0.1875rem; border-radius: 2px; }
/* I colori del grafico sono i due inchiostri del sito: --ink per quello che
   conta, il risparmio dopo il rientro e il costo con Emme Paint; --ink-dim per
   il resto. Contro il bianco fanno 14,7:1 e 5,28:1, sopra il 3:1 che WCAG
   1.4.11 chiede a un segno grafico. La linea dell'investimento è tratteggiata,
   così le due linee grigie non si distinguono per il solo colore. */
.roi__segno--investimento { background: repeating-linear-gradient(90deg, var(--ink-dim) 0 0.3125rem, transparent 0.3125rem 0.5rem); }
.roi__segno--risparmio    { background: linear-gradient(90deg, var(--ink-dim) 0 40%, var(--ink) 40%); }
.roi__segno--manuale      { background: var(--ink-dim); height: 0.8125rem; border-radius: 3px; }
.roi__segno--robot        { background: var(--ink); height: 0.8125rem; border-radius: 3px; }

/* La curva: un SVG stirato sulla larghezza, coi tratti che non si stirano
   (vector-effect), e le etichette dell'asse in HTML, a 16px. */
.roi__linea { position: relative; height: clamp(10rem, 2.61538rem + 11.53846vw, 13rem); }   /* 160 → 208 */
.roi__linea svg { width: 100%; height: 100%; overflow: visible; }
.roi__base   { stroke: var(--line-strong); stroke-width: 1; }
.roi__invest { stroke: var(--ink-dim); stroke-width: 1.5; stroke-dasharray: 5 4; }
.roi__prima  { fill: none; stroke: var(--ink-dim); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.roi__dopo   { fill: none; stroke: var(--ink); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.roi__punto {
  position: absolute;
  width: 0.8125rem; height: 0.8125rem;
  margin: -0.40625rem 0 0 -0.40625rem;
  border: 2px solid var(--ink);
  border-radius: 50%;
  background: var(--paper);
}
.roi__punto[hidden] { display: none; }

/* Il riquadro anno per anno. La guida è un filetto tratteggiato alto quanto il
   grafico; il mirino è il punto sulla curva, grigio prima del rientro e pieno
   dopo, come la curva. Il riquadro è bianco con un'ombra leggera, come in
   Tesla, e i suoi testi stanno a 16px come tutto il resto. */
.roi__linea { cursor: crosshair; touch-action: pan-y; }
.roi__linea:focus-visible { outline-offset: 0.5rem; }
.roi__guida {
  position: absolute; top: 0; bottom: 0;
  width: 0;
  border-left: 1px dashed var(--ink-dim);
  pointer-events: none;
}
.roi__mirino {
  position: absolute;
  width: 0.8125rem; height: 0.8125rem;
  margin: -0.40625rem 0 0 -0.40625rem;
  border: 2px solid var(--paper);
  border-radius: 50%;
  background: var(--ink-dim);
  box-shadow: 0 0 0 1px var(--ink-dim);
  pointer-events: none;
}
.roi__mirino--attivo { background: var(--ink); box-shadow: 0 0 0 1px var(--ink); }
.roi__tooltip {
  position: absolute;
  z-index: 2;
  display: grid;
  gap: var(--s-1);
  width: max-content;
  max-width: min(17rem, 100%);
  padding: var(--s-3) var(--s-4);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  box-shadow: 0 0.5rem 1.3125rem rgba(39, 39, 44, .12);
  color: var(--ink-muted);
  pointer-events: none;
}
.roi__tooltip b { font-weight: 500; color: var(--ink); }
.roi__tooltip-anno { font-weight: 500; color: var(--ink); }
.roi__guida[hidden], .roi__mirino[hidden], .roi__tooltip[hidden] { display: none; }
.roi__asse { position: relative; height: 1.6rem; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.roi__asse span { position: absolute; top: 0; transform: translateX(-50%); white-space: nowrap; }
.roi__asse .roi__tacca--prima  { transform: none; }
.roi__asse .roi__tacca--ultima { transform: translateX(-100%); }

/* Le barre: per ogni voce il costo di oggi e quello con Emme Paint, uno sotto
   l'altro. Il tratto è largo in proporzione al più alto dei quattro, nello
   spazio che resta tolti 7rem per l'importo, che a 16px arriva a 104px con
   «1.234.567 €». */
.roi__barre { display: grid; gap: var(--s-5); }
.roi__gruppo-barre { display: grid; gap: var(--s-2); }
.roi__gruppo-barre dt { font-weight: 500; }
.roi__gruppo-barre dd { display: grid; gap: var(--s-1); }
.roi__barra { display: flex; align-items: center; gap: var(--s-3); min-height: 1.6rem; color: var(--ink-muted); }
.roi__tratto {
  flex: none;
  width: calc((100% - 7rem) * var(--quota, 0));
  min-width: 2px;
  height: 0.8125rem;
  border-radius: 3px;
  background: var(--ink-dim);
  transition: width var(--t-base);
}
.roi__barra--robot .roi__tratto { background: var(--ink); }
.roi__barra--robot { color: var(--ink); }
.roi__nota-barre { color: var(--ink-muted); }

.roi__avvertenza { margin-top: var(--sp-testata); color: var(--ink-muted); max-width: var(--measure); }

.roi__annuncio {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ----- parametri ----- */

.roi__prodotto {
  display: grid;
  gap: var(--s-2);
  padding: var(--s-5);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--paper-2);
  color: var(--ink-muted);
}
.roi__prodotto-nome { font-family: var(--font-titoli); font-weight: 500; color: var(--ink); }
.roi__collegamento {
  justify-self: start;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: .2em;
}

.roi__blocco { display: grid; gap: var(--s-5); margin: 0; padding: var(--s-5) 0 0; border: 0; border-top: 1px solid var(--line); min-width: 0; }
.roi__blocco > legend { float: left; width: 100%; padding: 0; }
.roi__blocco > legend + * { clear: both; }

.roi__scelta { display: grid; gap: var(--s-3); margin: 0; padding: 0; border: 0; min-width: 0; }
.roi__scelta > legend { padding: 0; margin-bottom: var(--s-3); }
.roi__etichetta { font-weight: 500; color: var(--ink); }

/* I pulsanti del volume sono radio, come le colonnine di Tesla: un gruppo con
   una scelta sola, che le frecce percorrono. Il cerchio è nascosto col
   ritaglio e non con display: none, così resta il controllo che prende il
   fuoco e la tastiera; l'anello lo disegna la casella che gli sta accanto. */
.roi__pulsanti { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-2); }
.roi__pulsanti label { position: relative; display: block; }
.roi__pulsanti input {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  margin: 0; opacity: 0; cursor: pointer;
}
.roi__pulsanti span {
  display: flex; align-items: center; justify-content: center;
  min-height: 2.875rem;
  padding: 0 var(--s-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--paper);
  font-variant-numeric: tabular-nums;
  transition: border-color var(--t-fast), background var(--t-fast), box-shadow var(--t-fast);
}
.roi__pulsanti input:hover + span { border-color: var(--ink-dim); }
.roi__pulsanti input:checked + span { border-color: var(--ink); background: var(--paper-2); box-shadow: inset 0 0 0 1px var(--ink); font-weight: 500; }
.roi__pulsanti input:focus-visible { outline: none; box-shadow: none; }
.roi__pulsanti input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 3px; box-shadow: inset 0 0 0 1px var(--ink), 0 0 0 3px var(--focus-contro); }

.roi__altro { display: grid; gap: var(--s-2); }
.roi__altro[hidden] { display: none; }

.roi__campo { display: grid; gap: var(--s-2); }
.roi__riga-etichetta { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3); }
.roi__ripristina {
  flex: none;
  min-height: 1.5rem;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: .2em;
  cursor: pointer;
}
.roi__ripristina[hidden] { display: none; }

.roi__cursore { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--s-4); }
.roi__cursore input[type="range"] { width: 100%; min-height: 1.5rem; margin: 0; accent-color: var(--ink); cursor: pointer; }

/* La casella con l'unità accanto, come il «0.09 €/kWh» di Tesla. */
.roi__unita { display: inline-flex; align-items: center; gap: var(--s-2); color: var(--ink-muted); }
.roi__unita input {
  width: 6.5rem; min-height: 2.875rem;
  padding: 0 var(--s-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--paper);
  color: var(--ink);
  font: inherit; font-size: 1rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.roi__unita input:hover { border-color: var(--ink-dim); }
.roi__unita span { min-width: 2.75rem; }

.roi__capacita { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--s-3); align-items: start; color: var(--ink-muted); cursor: pointer; }
.roi__capacita input { margin-top: calc((1.6rem - 1.125rem) / 2); }

.roi__avanzati { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.roi__avanzati summary {
  display: flex; align-items: center; justify-content: space-between;
  min-height: 2.875rem;
  padding-block: var(--s-3);
  font-family: var(--font-titoli);
  font-weight: 500;
  cursor: pointer;
  list-style: none;
}
.roi__avanzati summary::-webkit-details-marker { display: none; }
.roi__avanzati summary::after { content: "+"; font-family: var(--font-testi); font-size: 1.3125rem; line-height: 1; color: var(--ink-muted); }
.roi__avanzati[open] summary::after { content: "−"; }
.roi__avanzati-corpo { display: grid; gap: var(--s-3); padding-bottom: var(--s-5); }
.roi__sottogruppo { margin-top: var(--s-3); color: var(--ink-muted); }
.roi__coppia { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); flex-wrap: wrap; }
.roi__avanzati .btn { justify-self: start; margin-top: var(--s-3); }

.roi__invito { justify-self: stretch; }

/* ============================ footer ============================ */

.footer { border-top: 1px solid var(--line); padding-block: var(--sp-sezione); background: var(--paper); }
/* Il piè di pagina tiene solo il blocco del marchio, dal 24/09/2026 su
   richiesta del committente: le tre colonne di link, Soluzioni, Azienda e
   Contatti, non ci sono più. Ripetevano le voci dell'header, e i Contatti
   anche il telefono e l'email che il blocco ha già. Con loro il piè di pagina
   è tornato nel contenitore, filetto legale compreso: a 1440 il contenuto va
   da 125 a 1315, gli stessi bordi delle sezioni. L'altezza scende da 1173 a
   527,5px a 390 e da 563 a 557 a 1440.
   Da 1024 in su il blocco è centrato, marchio, descrizione e dati, e ogni riga
   sta a 0,00px dal centro del contenitore. La descrizione si bilancia:
   centrata andava a capo in 459 + 165px, così in 314 + 311. Da mobile, sotto
   i 1024px, va a sinistra come i testi del resto del sito (CONTESTO §3), e la
   descrizione torna al `pretty` di tutti i paragrafi. */
.footer__marchio { display: grid; justify-items: center; text-align: center; }
.footer__marchio > p { text-wrap: balance; }
@media (max-width: 63.9375rem) {
  .footer__marchio { justify-items: start; text-align: left; }
  .footer__marchio > p { text-wrap: pretty; }
}
/* Il marchio ha la misura di quello dell'header, --marchio-w, dal 24/09/2026
   su richiesta del committente. Era a 9.25rem, 148px, da uno stile scritto
   nell'HTML: sotto i 192 che il token dichiara come soglia di leggibilità
   della riga «ROBOTIC AUTOMATION», dove le aste del file rendevano 0,39px,
   meno di un pixel fisico anche a 2×. Adesso è 192 × 19,8 a ogni larghezza, e
   il piè di pagina cresce di 4,5px. Da telefono l'header lo stringe sotto i
   374px, a 178 a 360 e a 138 a 320, per far posto al tasto del menu; qui il
   tasto non c'è, e a 320 il contenitore ne ha 260. */
.footer__marchio img { width: var(--marchio-w); }
/* I dati dell'azienda stanno qui dal 24/09/2026, su richiesta del committente:
   erano nel Contatto, sotto l'attacco, e adesso chiudono il blocco del
   marchio. Prendono il passo del piè di pagina e non quello della sezione:
   21px dal testo, come il testo dal marchio, e 13px fra le righe. Il filetto
   sopra non c'è: nel Contatto staccava i recapiti dall'attacco, e qui non ha
   niente da staccare. Il grigio è quello della descrizione, 5,95:1 sul
   bianco, e il nome resta in inchiostro, 14,86:1. I due collegamenti tengono
   il filetto sotto: stanno in riga, separati da un punto, con il colore e il
   corpo del testo, e senza non si distinguerebbero. L'orario, --ink-dim in
   corsivo 300, sul bianco sale da 4,92 a 5,28:1.

   Il CAP è legato alla città con due spazi indivisibili nell'HTML: quando il
   blocco stava in una colonna di 198–225px, fra 820 e 900, la riga si
   spezzava fra «48015» e «Cervia (RA)». Oggi il blocco ha tutto il
   contenitore e l'indirizzo sta su una riga da 320 in su; a 320 va a capo
   solo la riga di telefono ed email, e l'email scende intera. */
.footer__facts { display: grid; gap: var(--s-3); margin-top: var(--s-5); color: var(--ink-muted); }
.footer__facts strong { color: var(--ink); }
.footer__facts a { border-bottom: 1px solid var(--line-strong); }
.footer a {
  text-decoration: none; color: var(--ink-muted); font-size: 1rem;
  /* `anywhere` e non `break-word`: solo il primo riduce la larghezza
     minima intrinseca, che è ciò che allarga la colonna di una griglia, e
     .footer__marchio lo è. Oggi è una rete: a 320 l'email, larga 184px, sta
     nei 260 del contenitore anche senza. Quando c'erano le colonne di link,
     senza questa regola l'email spingeva la pagina di 0.3125rem. */
  overflow-wrap: anywhere;
}
.footer a:hover { color: var(--ink); }
.footer__legal {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--s-3);
  margin-top: var(--s-9); padding-top: var(--s-5);
  border-top: 1px solid var(--line);
  font-size: 1rem; color: var(--ink-dim);
}

/* ======================= animazioni: stato iniziale ======================= */

.js-motion [data-anim="rise"] { opacity: 0; transform: translateY(20px); }
.js-motion [data-anim="reveal"] { clip-path: inset(0 0 100% 0); }
/* 1650 è la lunghezza dei 315° della corsa su un raggio di 300 */
.js-motion [data-anim="anello"] { stroke-dasharray: 1650; stroke-dashoffset: 1650; }
.js-motion [data-hero] { opacity: 0; transform: translateY(18px); }

/* Questi due stati mancavano, e l'elenco qui sopra è l'unica cosa che vale dal
   primo paint: tutto il resto lo scrive GSAP, che arriva quando arriva. Finché
   non arriva, i 20 [data-anim-item] — le 9 righe di .spec-table, gli 8 bottoni
   del ciclo, le 3 voci dell'offerta, 1237 caratteri — stanno a opacità 1, e poi
   spariscono sotto il gsap.set() che li azzera. Misurato ricaricando con lo
   scorrimento ripristinato sulla tabella delle specifiche, a 1440x900: 394
   caratteri dentro la vista leggibili dal fotogramma a t=1 ms e spariti a t=18
   con i due file GSAP in cache, a t=105 saltandola (i 42 KB di gsap.min.js e
   ScrollTrigger.min.js da cdnjs chiudono a 103-107 ms). Dichiarati qui partono
   già nascosti e il lampo non c'è: rimisurato, zero caratteri visibili dentro la
   vista prima che il trigger scatti.
   I 24px non sono i 20px delle risalite per distrazione: 24 è quello che
   gsap.set scrive sugli item, ed è quello che va copiato, altrimenti al primo
   fotogramma di GSAP il testo scatta invece di partire da fermo.
   Il -7% del parallasse è agganciato al valore dell'attributo apposta: lo
   spostamento lo decide la JS leggendo data-parallax, quindi se quel 7 cambia il
   selettore smette di agganciare e si torna al comportamento di oggi, invece di
   pre-posizionare l'immagine di un numero sbagliato. Senza questa riga l'unica
   fotografia di scena del sito saltava del 7% della sua altezza nell'istante in
   cui GSAP partiva: 57,96px quando era alta 828 a 1440×900, 31,08 da quando la
   scena non ha più altezza minima e la foto è alta 444. Va in coppia con lo
   `y: 0` che sta in app.js sulla fromTo del parallasse: senza quello GSAP somma
   i due valori e lo spostamento raddoppia, -115,92px allora e -62,16 oggi. */
.js-motion [data-anim-item] { opacity: 0; transform: translateY(24px); }
.js-motion [data-parallax="7"] { transform: translateY(-7%); }

.js-motion .word {
  display: inline-block;
  opacity: 0;
  transform: translateY(.36em);
}
.word-mask { display: inline-block; overflow: hidden; vertical-align: top; padding-block: .06em; }

/* ======================= moto ridotto ======================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    /* anche i ritardi: azzerare la durata e lasciare un delay vorrebbe dire
       far aspettare, senza animare, chi ha chiesto di non animare */
    transition-delay: 0s !important;
    animation-delay: 0s !important;
  }
  .js-motion [data-anim],
  .js-motion [data-hero],
  .js-motion [data-anim-item],
  .js-motion .word { opacity: 1 !important; transform: none !important; clip-path: none !important; }
}

/* ======================= stampa: il contenuto c'è comunque ======================= */

/* La stampa fotografa il DOM nello stato in cui si trova, e gli stati iniziali
   delle animazioni sono invisibili: chi apre la pagina e manda in stampa senza
   aver scorso si porta via l'hero e poi pagine bianche. Misurato a 1280x900 con
   scrollY 0, a pagina appena caricata: opacità calcolata 0 su #soluzioni h2
   .word, #soluzioni .lede, .spec-row, .offer__item, #contactForm e
   .ciclo__bottone; l'immagine in `reveal` è tagliata a inset(0 0 100%), cioè
   ridotta a zero; l'anello del ciclo ha stroke-dashoffset 1650px su una corsa
   lunga 1649.3px, quindi la linea è tutta fuori dal tratto.
   Scrivere qui `opacity: 1` e basta non servirebbe, perché quei valori non
   vengono da questo foglio ma da GSAP, che li mette inline: `.spec-row` porta
   `style="... transform: translate(0px, 24px); opacity: 0;"` già prima che il
   suo ScrollTrigger scatti. L'inline batte la regola normale, ma non quella
   importante: nella cascata l'importante d'autore sta sopra l'inline normale,
   e così una sola riga rimedia sia agli stati iniziali scritti sopra sia a
   quelli scritti da GSAP.
   `transform` e `clip-path` vanno azzerati insieme all'opacità: senza, le
   parole dei titoli resterebbero spinte di .36em dentro la maschera che le
   taglia e l'immagine resterebbe ritagliata pur essendo opaca.
   Il rimedio sta nel foglio e non in JavaScript di proposito: vale anche per
   il «salva come PDF», per chi stampa prima che app.js abbia finito, e non
   dipende da `beforeprint`, che non tutti i browser hanno sempre mandato.
   Qui si parla solo di far comparire il contenuto: colori e sfondi della
   stampa sono un'altra faccenda. */

@media print {
  .js-motion [data-anim],
  .js-motion [data-hero],
  .js-motion [data-anim-item],
  .js-motion .word,
  /* l'hero non aspetta uno ScrollTrigger, sbiadisce con lo scorrimento: chi
     stampa dopo aver letto fin giù lo troverebbe a opacità 0 come il resto */
  .js-motion .hero__content,
  /* La foto della scena Applicazioni non entra in questo elenco per un
     data-anim — non ne ha — ma per la parallasse, che è l'unica animazione
     agganciata allo scrub e quindi l'unica il cui stato dipende da dove si era
     arrivati a leggere: GSAP le scrive inline translate(0%, ±7%) e il segno lo
     decide lo scorrimento. Stampato due volte lo STESSO documento, la foto —
     alta 542px sul foglio — è finita a 789.1px partendo dalla cima e a 865.0px
     partendo dal fondo: 75.9px, cioè 20.1mm di scarto fra due copie identiche.
     Azzerata la trasformazione cade a 827.0px, che è esattamente il punto di
     mezzo fra le due, cioè il posto suo. */
  .js-motion [data-parallax] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    /* la corsa dell'anello è spostata fuori di tutta la sua lunghezza:
       riportata a 0 il cerchio torna intero */
    stroke-dashoffset: 0 !important;
  }
}

/* ============================ stampa ============================

   Fin qui il foglio non aveva una riga per la carta, e sulla carta metà del
   sito spariva. Il motivo: i browser stampano di default SENZA i fondi — la
   casella «Grafica di sfondo» del pannello di stampa nasce spenta — ma CON i
   colori del testo. Il #1c1c1c di #processo e il #0b0d10 di .showcase non
   arrivano mai sul foglio; il #f2f4f6 che ci stava sopra sì. Fa 1,10:1, e
   --on-night-muted 1,85:1.

   Chrome ci prova da solo e non basta: Blink passa per Color::Dark() ogni
   testo la cui distanza al quadrato dal bianco sta entro 65025 (255²).
   Misurato sul PDF di stampa, il bianco pieno degli h2 esce rgb(171,171,171)
   e si ferma a 2,30:1, --on-night esce rgb(159,161,162) e si ferma a 2,59:1.
   Sotto il 3:1 anche per il testo grande — e Firefox e Safari quella pezza
   non la mettono affatto, lì restano gli 1,10 e 1,85 di partenza. Non ci si
   appoggia.

   Il criterio di tutto il blocco: la pagina deve venire UGUALE con la
   casella dei fondi accesa o spenta. Per questo i fondi scuri non vengono
   soltanto lasciati cadere, vengono dichiarati bianchi: chi spunta la
   casella non deve ritrovarsi l'inchiostro scuro di qui sotto sopra un
   fondo scuro.

   Tutte le misure che seguono sono prese su A4 verticale con i margini di
   default: area utile 741px di larghezza — sotto i 64rem, quindi il ciclo
   stampa la scala verticale e non l'anello — e 1045px di altezza, per un
   documento alto 9928px, undici pagine.
   ================================================================= */

@media print {

  /* Il grosso si ripara ridefinendo i token, invece di rincorrere i
     selettori uno per uno: --on-night e --on-night-muted sono letti da
     trenta dichiarazioni sparse fra hero, ciclo e scena Applicazioni, più
     una scritta a mano nell'HTML: lo `style=` dell'occhiello «Applicazioni»,
     cioè il <p class="eyebrow"> dentro .showcase__inner. Si cerca così e non
     per numero di riga — il rimando è già scaduto due volte, prima diceva 274
     e poi 316 mentre l'elemento stava altrove, e ogni riga aggiunta sopra lo
     falsifica di nuovo. Quella dichiarazione inline una regola di foglio non
     la raggiungerebbe senza !important; la variabile sì.

     I due inchiostri sono quelli del sito, non due grigi inventati, e sono
     scelti anche perché Chrome li lasci in pace: --ink dista 137833 dal
     bianco e rende 14,86:1, --ink-muted dista 70281 e rende 5,95:1, tutti e
     due oltre la soglia dei 65025. Attenzione però che --ink-muted ha solo
     l'8% di margine: schiarendolo anche di poco Chrome ricomincerebbe a
     scurirlo per conto suo, e il colore stampato non sarebbe più quello
     dichiarato — è già quello che succede a --ink-dim (#6b6b74, distanza
     63129), che sulla carta esce rgb(29,29,32) invece del suo grigio.

     --line-night è il filetto bianco al 18%: sulla carta è niente. Prende il
     posto del suo gemello chiaro. */
  :root {
    --on-night:       var(--ink);
    --on-night-muted: var(--ink-muted);
    --line-night:     var(--line);

    /* Il velo di vernice esce di scena, e non per semplificare. Le sue alpha
       sono tarate sui fondi dello SCHERMO (sistema-tipografico §4.2: .48
       contro il pannello freddo, .34 contro il fondo notte) e in stampa quei
       fondi non ci sono più. Rifatto il conto su carta bianca con
       l'inchiostro scuro, la coda del velo scuro rende rgb(182,182,183),
       cioè 2,03:1, e quella del velo chiaro rgb(151,151,154), 2,91:1: il
       velo si riporterebbe dietro da solo esattamente il guasto che questo
       blocco ripara. Senza maschera i titoli stanno a 14,86:1 e 17,04:1. */
    --velo-vernice:       none;
    --velo-vernice-scuro: none;
    /* Il terzo velo esce di scena per lo stesso motivo degli altri due, e a
       maggior ragione: la sua coda .43 è tarata sul fondo composito della
       fotografia, rgb(74,76,78), che su carta non esiste nemmeno come idea —
       la foto lì scende nel flusso e diventa una figura, col testo sotto. */
    --velo-vernice-foto:  none;
  }

  /* I fondi scuri dichiarati bianchi, non lasciati cadere: è questa la riga
     che tiene la pagina uguale con la «Grafica di sfondo» accesa. Stessa
     ragione per i due veli sfumati: sono fondi, quindi di default non si
     stampano, ma accesi coprirebbero di scuro il testo che qui sopra
     abbiamo appena fatto scuro. */
  .hero,
  .section.on-night,
  .showcase { background: #fff; color: var(--ink); }
  .hero__scrim,
  .showcase__scrim { display: none; }

  /* Il titolo delle sezioni scure era #fff pieno: 1,00:1 sulla carta, 2,30:1
     dopo la pezza di Chrome. È l'unico colore del gruppo scritto a mano e
     non preso da un token, quindi va detto qui. */
  .on-night h2 { color: var(--ink); }

  /* L'isola non si stampa. Chrome ripete gli elementi in position: fixed su
     OGNI pagina — verificato con una prova apposta, quattro pagine su
     quattro — quindi qui sarebbe comparsa in cima a tutte e undici, addosso
     al testo. E non servirebbe a niente: il marchio è il PNG bianco, che su
     carta bianca non c'è; il vetro scuro è un fondo e cade; le voci a
     --on-isola #e1e4e7 arrivano a 3,16:1 dopo la pezza di Chrome, sotto il
     4,5:1 che il sistema tipografico §3.2 chiede espressamente per quella
     deroga a 11,5px. Con l'isola se ne va anche il foglio del menu, che è
     fisso pure lui: chi stampa col menu aperto oggi si porta dietro un
     pannello bianco su tutte le pagine. E il salto al contenuto, che è un
     comando e su carta non è nulla. */
  .island-wrap,
  .sheet,
  .skip-link { display: none !important; }

  /* Il video dell'hero è la voce più cara del PDF e non ha niente da dire su
     carta. Chrome non stampa il filmato: stampa il fotogramma su cui si
     trovava nell'istante in cui è partita la stampa — nella prova il secondo
     10,94 — e lo incorpora come raster da 2253x3278. Misurato togliendolo
     dal DOM: il PDF passa da 8,14 MB a 0,90 MB. Il video da solo pesava
     7,24 MB, l'89% del file, per un fotogramma preso a caso.
     Con il video se ne va anche l'altezza: .hero è alto 100svh, che in
     stampa sono 621px dei 1045 della pagina, spesi quasi tutti per il
     filmato. E i 144px di stacco in testa servivano a spingere il contenuto
     giù dentro una scena alta quanto lo schermo: senza la scena non
     spingono più niente, sono solo bianco in cima al foglio. */
  .hero__media { display: none; }
  .hero { height: auto; min-height: 0; }
  .hero__stage,
  .hero__content { position: static; }
  .hero__grid { padding-top: 0; }

  /* La scena Applicazioni è una fotografia con il testo sopra, tenuto
     leggibile da un velo sfumato. Il velo è un fondo e sulla
     carta cade: il testo resterebbe appoggiato alla foto nuda e, ora che è
     scuro, sopra una foto scura sarebbe illeggibile come prima, solo al
     contrario. Quindi la foto scende nel flusso e diventa una figura, con il
     testo sotto invece che sopra. La foto resta: ha un alt che descrive una
     macchina vera, è contenuto e non decorazione. */
  .showcase { display: block; }
  .showcase__media { position: static; }
  .showcase__media img { height: auto; }
  .showcase__content { position: static; }

  /* La scala del ciclo è tenuta insieme da un filo e da otto nodi, e sono
     scritti a mano in bianco trasparente invece che con i token: il filo al
     18%, l'anello dei nodi al 45%, il tratteggio sopra la riga del ritorno
     al 30%. Sulla carta sono tre modi diversi di non esserci — erano quattro
     finché le fasi in sviluppo portavano il loro anello al 26%, tolto il
     23/09/2026 insieme a tutte le diciture. Stesse proporzioni, ribaltate
     sull'inchiostro: il nodo torna un dischetto di carta con l'anello
     scuro, e quello della fase chiave resta pieno — la sua regola sta più
     su nel file, quindi va riscritta qui dopo quella generica o il fondo
     bianco se la mangerebbe.
     Due di questi tre però erano ridipinti con `background`, che è
     esattamente la cosa che questo blocco ha imparato a non poter stampare:
     con la casella dei fondi spenta Chrome il rettangolo lo scrive lo stesso,
     ma in bianco. Letto dentro il PDF: i sette fili da 1x106px a x=43 escono
     tutti con `1 1 1 rg`, sette su sette invisibili, e il dischetto della fase
     chiave resta un anellino da /LW 1 su 9px di diametro, cioè identico a
     quello di tutte le altre. Il bordo invece è inchiostro e sul foglio ci
     arriva. Quindi il filo passa da fondo a border-left di 1px — stesso
     pixel, perché il box è largo 1px e box-sizing è border-box — e il nodo
     della fase chiave si riempie ingrossandogli il bordo fino a metà dei suoi
     0.625rem: il tratto esce con /LW 5 su un cerchio di 5px, che copre tutti e
     10 i px del dischetto. Il fondo del filo se ne va invece di restare
     accanto al bordo, altrimenti chi la casella la spunta se li ritroverebbe
     sovrapposti: due velature al 28% compongono 48%, e il filo verrebbe quasi
     il doppio più scuro che a casella spenta. Il fondo del nodo chiave invece
     resta, perché lì il colore è pieno e sovrapporlo a sé stesso non cambia
     niente. */
  .ciclo__tappa::before { background: none; border-left: 1px solid rgba(39, 39, 44, .28); }
  .ciclo__tappa::after { background: #fff; border-color: rgba(39, 39, 44, .55); }
  .ciclo__tappa--chiave::after { background: var(--ink); border-color: var(--ink); border-width: 0.3125rem; }
  .ciclo__ritorno { border-top-color: rgba(39, 39, 44, .38); }

  /* L'ultimo bianco su bianco rimasto, e sta fuori dalle tre sezioni scure:
     .btn--primary è fondo d'inchiostro con testo --paper, e caduto il fondo
     resta il bianco, che Chrome porta a rgb(171,171,171), 2,30:1. Su carta
     un pulsante non si preme: resta il filetto a dire dov'era. Quello
     dell'hero non c'entra, lì vale .on-night .btn--primary, che è già scuro
     su chiaro. */
  .btn--primary { background: none; color: var(--ink); border-color: var(--line-strong); }

  /* Le interruzioni di pagina, misurate sull'impaginato con 1045px di altezza
     utile: la scheda Emme Paint è alta 805px e cadeva a cavallo fra la pagina 3
     e la 4, Emme Sand 748px fra la 4 e la 5, la tappa 02 del ciclo fra la 1 e la
     2, la terza colonna del piè di pagina fra la 9 e la 10. Nessuna di queste
     supera l'altezza di una pagina, quindi chiedere di non spezzarle costa al
     massimo un po' di bianco in coda alla pagina precedente. Le altre voci
     dell'elenco non sono state colte in fallo in questa impaginazione ma sono
     la stessa specie di unità, e basta una riga di copy in più per spostarle.
     Su un blocco più alto della pagina la regola viene ignorata dal browser,
     quindi non può fare danni. */
  .line,
  .ciclo__tappa,
  .offer__item,
  .spec-row,
  .field,
  .facts div,
  .footer__marchio,
  img { break-inside: avoid; }

  /* Un titolo non chiude una pagina da solo, e un paragrafo non lascia una
     riga orfana di qua e una vedova di là.
     .section__head stava in questo elenco e ne è uscita. Su un contenitore
     `break-after: avoid` non vuol dire «il titolo non resta solo»: vuol dire
     «il blocco che viene dopo la testata deve stare sulla stessa pagina», e il
     blocco che viene dopo è tutta la sezione. Prova A/B sullo stesso
     documento, A4 coi margini di default, 784pt di area utile: con la regola
     la testata di #soluzioni veniva spinta alla pagina seguente insieme alle
     sue due schede, e la pagina 4 restava con tre righe alte 54pt, il 6,9% del
     foglio, per un documento di 12 pagine. Tolta la riga, la stessa pagina 4
     porta nove righe su 254pt e il documento chiude a 11. Il titolo resta
     attaccato al suo sommario lo stesso: a tenercelo è la riga qui sotto su
     h1-h4, che è il posto dove va detto. */
  h1, h2, h3, h4,
  .eyebrow { break-after: avoid; }
  p, li { orphans: 3; widows: 3; }

  /* Gli URL dopo il testo NON si stampano, ed è una scelta misurata e non una
     dimenticanza: la pagina ha 32 collegamenti, 26 dei quali sono àncore
     interne (#processo, #soluzioni…) che su un foglio non portano da nessuna
     parte, 2 sono il marchio che punta a «/», e i 4 che restano sono tel: e
     mailto:, che mostrano già il numero e l'indirizzo come proprio testo
     visibile. La regola classica
         a[href^="http"]::after { content: " (" attr(href) ")"; }
     non troverebbe un solo collegamento esterno da annotare, e la sua
     variante su tutti gli href stamperebbe ventisei volte «(#qualcosa)».
     Se un domani compariranno link esterni veri, è qui che va aggiunta. */
}
