/* ============================================================================
   Pagine di lavoro: stile condiviso da tutte le pagine /lavori/<slug>/.
   Si carica DOPO fonts.css, tokens.css, style.css e assets/css/motion.r1.css,
   che è il foglio del movimento comune: qui restano solo le classi caso-* e le
   poche cose che il file condiviso non può sapere (la maschera dell'h1, che sta
   sopra la piega, i riempimenti di bottone fuori palette, e dalla rev 6 il
   modulo e il piede nella forma della homepage nuova).
   File pubblico: nei commenti nessun nome di cliente.
   Tutto ciò che serve solo alla revisione sta in anteprima.css, non qui.

   Rev 8 (2026-09-14), docs/lavori.md sezione 19. Sette richieste del
   committente, e quattro toccano questo file:
     l'occhiello sotto la lead ....... .caso-apertura__categoria
     più aria prima della chiusura ... .caso-mod + .sezione--tenue
     i due disegni si muovono ........ blocco 3 bis del MOVIMENTO
     la copertina ritagliata meglio .. .caso-copertina img (80% e 5/4)
   Le altre tre stanno nel markup: via il bottone dell'apertura, via la tavola
   in tipografia (e con lei le sue regole, uscite da qui), e la slide del naming
   riesportata dal PDF con il refuso corretto alla fonte.

   Rev 7 (2026-09-13), docs/lavori.md sezione 18. La pagina resta quella di UN
   lavoro solo, fatta di moduli opzionali uno per servizio. Cambiano tre cose:
   i moduli scendono da nove a SETTE (e-commerce e assistenza IT entrano dentro
   «Sviluppo web»); i due servizi che non hanno materiale da mostrare non hanno
   più una schermata finta ma un DISEGNO in pagina; e la chiusura, il modulo di
   contatto, il piede e i bottoni sono la home NEL CSS e non solo nel markup,
   con le regole copiate verbatim e marcate in due riquadri.

   Cosa chiede il committente, e dove sta:
     chiusura e piede identici ...... i due riquadri «COPIATO VERBATIM»
     via la maschera dalla chiusura . niente .mask sul .titolo-giga (markup)
     la tavola anche in fotografia .. .caso-figura--pagina (rev 8: resta lei sola)
     la griglia del profilo ......... img demo-profilo + .caso-elenco--ritmo
     il profilo in alto ............. .caso-esterno dentro .caso-testa
     desktop e telefono insieme ..... .caso-riga--schermo-telefono
     e-commerce e IT dentro il web .. .caso-sub, .caso-minuto
     strategia in cima .............. ordine del markup (nessuna regola)
     performance disegnato .......... .caso-disegno + .caso-annuncio
     funnel disegnato, non a imbuto . .caso-tempo

   Uscite in questo giro, con il markup che le usava: la classe `.riempi` sui
   bottoni (la forma del riempimento sta dentro `.bottone`, come sulla home) e
   la maschera tipografica del titolo di chiusura (sulla home non c'è, e qui
   tagliava le discendenti).
   Uscite nel giro precedente: la banda dell'invito di mezzo (.caso-invito*),
   il blocco d'uscita (.caso-uscita*), la figura più stretta del materiale
   costruito (.caso-figura--minore).
   Uscite nei giri precedenti: la costola e la griglia dello schedario, la riga
   esplicativa di modulo, lo sfondamento a destra, il ripiego a `span 4`,
   l'elenco degli spunti della chiusura, il link secondario accanto all'invito
   dell'apertura, i token del movimento, le pillole dell'apertura, la tessera a
   proporzione libera, le tre figure disegnate, la mappa dei servizi, la
   citazione, i crediti, le briciole, il bollo di riproduzione, la griglia a sei
   colonne, il details del perimetro, le card degli altri lavori, le celle dei
   numeri, il fondo alternato di modulo. Non sono in archivio qui: stanno in git
   e nella specifica.
   ========================================================================== */

/* ── Quello che resta di locale ───────────────────────────────────────────────
   I token del movimento non stanno più qui: --m-micro, --m-corto, --m-lungo,
   --m-reveal, --e-out, --e-inout e --e-posa arrivano da assets/css/motion.r1.css,
   che a 💎 M2 diventa il sistema comune. Le due hairline restano perché il file
   condiviso non le porta ancora: sono candidate a tokens.css insieme agli altri,
   e finché non ci sono lì vivono qui. */
:root {
  --hairline:       #E2E2E2;
  --hairline-forte: #CFCFCF;
  /* La misura unica della pagina. È quella della homepage nuova
     (demo-motion/demo.r1.css, `--d-max: 1240px`) e non quella della landing
     (1400): un testo su 1400 px è una riga da leggere girando la testa, e la
     pagina nuova ha già deciso che 1240 è la misura di casa. */
  --misura: 1240px;
  /* ⚠️ Rev 6: arriva il bordo dei campi, che docs/rev3-motion.md aveva lasciato
     fuori di proposito («la pagina dei lavori non ha campi da compilare; se un
     giorno ne avrà, il conto si rifà sul fondo che c'è, non si eredita il
     numero»). Il conto rifatto: #8A8A8A sta a 3,45:1 sul bianco del campo e a
     3,31:1 sul --bianco-sporco della fascia di chiusura. Tutti e due sopra il
     3:1 che WCAG 1.4.11 chiede al contorno di un comando. */
  --bordo-campo: #8A8A8A;
}

/* Testata sticky: il focus e le ancore non finiscono sotto (WCAG 2.4.11). */
html { scroll-padding-top: 6rem; }

/* Testo per il solo lettore di schermo. Serve all'avviso «si apre in una nuova
   scheda» (WCAG 3.2.5): la home nuova quel target lo mette senza dirlo, e qui
   la deroga si paga con una riga di markup invece che con un buco.
   `clip-path` e non `clip`: `clip` è deprecato e in alcuni motori disattiva la
   pronuncia dell'elemento invece di nasconderlo soltanto. */
.fuori-schermo {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════ LA MISURA ═════════
   Una sola, e ci si allinea tutto: la testata, il corpo della pagina e il piede.
   Con la testata a 1400 e il contenuto a 1240 il logo starebbe 80 px più a
   sinistra del titolo, che è il genere di disallineamento che si sente senza
   saperlo nominare. */
.caso-corpo,
.testata__interno,
.pie > .contenitore {
  width: min(var(--misura), 100% - var(--gutter) * 2);
  margin-inline: auto;
}

/* Il passo fra le sezioni è quello della homepage nuova, var(--s-6), non lo
   --s-7 di style.css: qui i moduli sono nove e un passo da 176 px fra l'ultimo
   e la chiusura aprirebbe un buco che sembra la fine della pagina. */
.sezione { padding-block: var(--s-6); }

/* ══════════════════════════════════════════════════════════ LA TESTATA ═════
   Rev 6: è quella della homepage nuova (demo-motion/demo.r1.css:239-291), non
   quella di style.css. Le regole stanno qui e non lì per la stessa ragione del
   modulo: style.css è condiviso con la landing, che ha la testata di prima, e
   riscriverla da lì cambierebbe una pagina che nessuno ha chiesto di cambiare.
   Al merge del 22/09 si decide una volta sola quale delle due vince.

   Quattro cose cambiano rispetto a style.css, e si vedono tutte:
   — la barra ha un'altezza dichiarata (72 px) invece di dipendere dal logo;
   — il logo scende da `clamp(160px, 15vw, 215px)` a 148 px fissi;
   — il filo sotto non è un `border-bottom` sempre presente ma un `::after` che
     si accende in dissolvenza quando la pagina si stacca: un bordo che appare
     e scompare sposta di 1 px tutto il contenuto sotto, un pseudo-elemento no;
   — le voci di menu perdono il maiuscoletto spaziato e tornano testo normale a
     15 px, col filetto in `currentColor` e non in viola.

   Le due classi di stato le mette assets/js/motion.r1.js sull'elemento con
   `data-testata`; senza JavaScript la testata resta ferma e visibile. */
:root { --d-testata: 72px; }

.testata {
  z-index: 40;
  background: rgba(255, 255, 255, 0.88);
  border-bottom: 0;
  transition: transform 240ms var(--e-inout);
}
.testata::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 1px;
  background: var(--hairline);
  opacity: 0;
  transition: opacity var(--m-micro) linear;
}
.testata--staccata::after { opacity: 1; }
.testata--nascosta { transform: translateY(-100%); }

.testata__interno {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--s-3);
  min-height: var(--d-testata);
  padding-block: 0;
}
.testata__logo { margin-right: auto; display: block; }
.testata__logo img { width: 148px; height: auto; }

.testata__nav { gap: var(--s-3); }
.testata__nav a {
  font-size: 0.9375rem;
  font-weight: var(--w-normal);
  letter-spacing: normal;
  text-transform: none;
  padding-block: 0.35em;
}
.testata__nav a::after {
  background: currentColor;
  height: 1.5px;
  transition: transform var(--m-corto) var(--e-out);
}
/* Sulla home la voce della sezione in cui ti trovi resta marcata, e
   `aria-current` lo dice anche a voce. Qui la regola c'è ma non si accende:
   una pagina di lavoro non È nessuna delle quattro sezioni della home, e
   marcarne una direbbe il falso. Resta scritta perché il giorno che una pagina
   di lavoro avrà una sua voce di menu, il disegno c'è già. */
.testata__nav a[aria-current="true"] { color: var(--viola-testo); }
.testata__nav a[aria-current="true"]::after { transform: scaleX(1); opacity: 0.45; }

/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  COPIATO VERBATIM DA prezzemolostudio/public/demo-motion/demo.r1.css     ║
   ║  Rev 7 (2026-09-13), docs/lavori.md sezione 18.                          ║
   ║                                                                          ║
   ║  DA DOVE VIENE. Le regole di questo riquadro e quelle del riquadro       ║
   ║  gemello in fondo al file (chiusura, modulo, piede) sono la copia        ║
   ║  letterale di `demo.r1.css`, riga per riga, con i loro commenti          ║
   ║  originali. Non sono state riscritte, adattate né «migliorate»: se una   ║
   ║  differisce da lì è un errore, non una scelta.                           ║
   ║                                                                          ║
   ║  PERCHÉ CI SONO. Nella rev 6 la chiusura e il piede erano stati copiati  ║
   ║  nel MARKUP ma non nel CSS, e il risultato è il difetto che il           ║
   ║  committente ha visto per primo: «hai solo copiato il testo, ma la       ║
   ║  grandezza è rimasta la vecchia». `style.css` — condiviso con la landing ║
   ║  e caricato prima di questo file — porta un `.titolo-giga` a `--t-giga`  ║
   ║  (fino a 160 px) e un `.bottone` a 1,125rem con padding 15/30, mentre la ║
   ║  home ha 5,5rem e 0,95rem con padding 0,85/1,6em. Stesso testo, stesse   ║
   ║  classi, altra pagina.                                                   ║
   ║                                                                          ║
   ║  DOVE FINIRANNO. ⚠️ A 💎 M2 (merge del 22/09) queste regole VANNO        ║
   ║  PROMOSSE NEL SISTEMA COMUNE, una volta sola, e sparite da qui. Oggi non ║
   ║  possono stare in `style.css`: quel file è condiviso con la landing, che ║
   ║  ha ancora la forma vecchia, e riscriverlo da qui cambierebbe una pagina ║
   ║  che nessuno ha chiesto di cambiare. La duplicazione è il prezzo di non  ║
   ║  toccare un file condiviso mentre due rami lavorano in parallelo, ed è   ║
   ║  lo stesso patto già scritto in docs/rev3-motion.md per i token.         ║
   ║                                                                          ║
   ║  UNA CONSEGUENZA DA SAPERE, non un effetto collaterale nascosto:         ║
   ║  `.bottone--pieno` della home è `--viola` con testo bianco (4,57:1),     ║
   ║  quello di `style.css` era `--viola-testo` (5,81:1). Tutti e due passano ║
   ║  il 4,5:1 di WCAG 1.4.3 per il testo normale, e il bottone è testo       ║
   ║  normale in grassetto. Si adotta il valore della home perché la          ║
   ║  richiesta è che i due blocchi siano lo stesso blocco; se un domani la   ║
   ║  soglia va alzata, si alza in un posto solo, e quel posto è la home.     ║
   ╚══════════════════════════════════════════════════════════════════════════╝ */

/* ── BOTTONI (demo.r1.css:178-235) ─────────────────────────────────────────
   Pill radius 100px, bordo 1px, fondo trasparente: è la sola forma tonda
   ammessa dal marchio. */
.bottone {
  position: relative;
  overflow: clip;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.85em 1.6em;
  border: 1.5px solid currentColor;
  border-radius: var(--raggio-pill);
  font-weight: var(--w-bold);
  font-size: 0.95rem;
  text-decoration: none;
  color: var(--nero);
  background: transparent;
  cursor: pointer;
  transition: background-color var(--m-micro) var(--e-inout),
              color var(--m-micro) var(--e-inout),
              border-color var(--m-micro) var(--e-inout);
}
.bottone--piccolo { padding: 0.6em 1.2em; font-size: 0.875rem; }
.bottone--pieno {
  background: var(--viola);
  border-color: var(--viola);
  color: #fff;
}

.bottone__t { position: relative; z-index: 1; display: block; }

/* Il riempimento sale da sinistra e il testo resta leggibile per tutta la
   transizione. Il roll-up del riferimento, con l'etichetta che esce e l'eco che
   entra, a metà strada mostra due mezze parole: su una CTA è il momento in cui
   la persona sta decidendo se cliccare, e non è il momento di togliere le
   parole. */
.bottone { isolation: isolate; }
.bottone::before {
  content: "";
  position: absolute;
  inset: 0;
  /* Dietro il contenuto: quando il testo non sta dentro uno span, come nel
     tasto Invia, un riempimento sopra lo copriva del tutto. */
  z-index: -1;
  border-radius: inherit;
  background: var(--viola);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--m-medio) var(--e-inout);
}
.bottone:hover::before,
.bottone:focus-visible::before { transform: scaleX(1); }
.bottone:hover, .bottone:focus-visible { color: #fff; border-color: var(--viola); }

/* Il bottone pieno fa il contrario: il fondo scuro entra sopra il violet. */
.bottone--pieno::before { background: #4B3F71; }
.bottone--pieno:hover, .bottone--pieno:focus-visible { border-color: #4B3F71; }

/* ⚠️ `--m-medio` (350ms) è l'unico token che la home usa qui e che
   `docs/rev3-motion.md` aveva lasciato fuori di proposito, perché da loro non
   lo usava nessun altro. Con il riempimento copiato verbatim serve, e viene
   dichiarato qui con il valore che ha lì. Senza, il `transition` cadrebbe sul
   valore iniziale e il riempimento comparirebbe di colpo. */
:root { --m-medio: 350ms; }

/* ── TIPOGRAFIA (demo.r1.css:148-176) ──────────────────────────────────────
   Come per l'hero, la scala di --t-giga è tarata su una colonna piena: qui i
   titoloni stanno in metà griglia accanto al modulo, e «Prezzemolo» a quella
   misura uscirebbe dalla colonna e finirebbe sopra i campi. */
.titolo-giga {
  font-size: clamp(2.25rem, 0.5rem + 5.2vw, 5.5rem);
  font-weight: var(--w-light);
  line-height: var(--lh-stretta);
  letter-spacing: var(--ls-stretta);
}
.titolo-giga strong { font-weight: var(--w-bold); }
.titolo-giga em { font-style: italic; font-weight: var(--w-light); }

.occhiello {
  font-size: var(--t-eyebrow);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--viola-testo);
  margin: 0 0 var(--s-2);
}

.lead {
  font-size: var(--t-lead);
  line-height: 1.35;
  max-width: 46ch;
}

.corpo { max-width: 62ch; }
.corpo--tenue { color: var(--testo-tenue); }

/* ⚠️ NON è una regola della home: è la riga che rimette il ritmo dei paragrafi
   della home dentro un blocco che qui vive in mezzo a `style.css`. Lì
   `p { margin: 0 0 var(--s-2) }` è una regola di base del foglio intero; qui
   una regola di base cambierebbe anche i micro paragrafi dei moduli, che non
   c'entrano. Quindi è ristretta al blocco copiato, e il risultato dentro la
   chiusura è identico. Lo stesso vale per il tetto di `.corpo--tenue`, che in
   `style.css` scende a `--t-small` e sulla home resta a 1rem. */
.contatti .lead,
.contatti .corpo { margin: 0 0 var(--s-2); }
.contatti .corpo--tenue { font-size: var(--t-body); }
/* Fine del riquadro copiato. Il gemello sta in fondo al file. */

/* ══════════════════════════════════════════════════════════ APERTURA ═══════
   Tre cose sole: copertina, titolo, invito. Un invito, non due. */

/* A tutta larghezza fino a 1440px, poi centrata in una banda da 1440: i file
   sono larghi 1440 e la soglia dell'ingrandimento è 1441, non 1600. Il numero
   sta anche nel `sizes` della copertina in index.html, e i due si muovono
   insieme. */
.caso-copertina {
  margin: 0 0 var(--s-4);
  background: var(--bianco-sporco);
}
.caso-copertina img {
  display: block;
  width: 100%;
  max-width: 1440px;
  margin-inline: auto;
  height: clamp(480px, 72vh, 800px);
  object-fit: cover;
  /* ⚠️ Rev 8, RICHIESTA DEL COMMITTENTE: «si tagliano troppo le ragazze in
     basso lasciando vedere solo le gambe». Era vero e il conto lo spiega: il
     file è 1440×900, la banda a 1440 px è alta 648, quindi si tagliano 252 px
     in verticale; con `40%` ne uscivano 101 dall'alto e 151 dal basso, e in
     questo scatto le persone sono distese CON LE GAMBE IN ALTO — le teste e le
     mani stanno in basso, fra 768 e 864 px. Il taglio dal basso toglieva
     esattamente le persone e lasciava in quadro le gambe.
     `80%`: il taglio si sposta in alto (202 px dall'alto, 50 dal basso), le tre
     allieve entrano intere con le mani sulla barra, e dell'arco resta la curva
     invece del soffitto. Fra l'arco e le persone si tengono le persone: il
     soffitto si vede lo stesso nella fotografia del team, più avanti.
     Il file non si tocca: il ritaglio 16/10 è giusto, sbagliato era dove lo si
     tagliava. (L'originale è un verticale 4312×6468, quindi un ritaglio nuovo
     sarebbe possibile: non serve.) */
  object-position: center 80%;
}
/* ⚠️ Sotto i 1000 px il problema si capovolge, ed è più grave. Un'altezza in
   `vh` su una colonna stretta non taglia in verticale, INGRANDISCE: a 390 px la
   banda è alta 608, la fotografia va scalata a 973 px di larghezza e se ne vede
   il 40%, cioè un pezzo di persona a 2,5×. Qui la copertina prende una
   PROPORZIONE invece di un'altezza: 5/4 a 390 px sono 312 px di banda, la
   fotografia si vede tutta in verticale e il taglio resta orizzontale e piccolo
   (il 22%, che è la riflessione nello specchio a sinistra). È la stessa
   immagine, letta alla misura del telefono invece che alla misura di un
   desktop rimpicciolito.
   `max-height: 70vh` è la cintura per le finestre basse e larghe (un tablet
   coricato): lì la proporzione tornerebbe a fare una banda più alta dello
   schermo, e il taglio verticale riprende con l'`object-position` di sopra. */
@media (max-width: 999.98px) {
  .caso-copertina img {
    height: auto;
    aspect-ratio: 5 / 4;
    max-height: 70vh;
  }
}

/* Regola unica per tutte le pagine di lavoro: il nome più lungo della home
   deve stare in 280px utili a 320px di larghezza. */
.caso-titolo {
  font-size: clamp(2rem, 1rem + 5.5vw, 7rem);
  font-weight: var(--w-light);
  line-height: .95;
  letter-spacing: var(--ls-stretta);
  overflow-wrap: break-word;
  margin: 0 0 var(--s-4);
}
.caso-titolo strong { font-weight: var(--w-bold); }
.caso-titolo em { font-style: italic; font-weight: var(--w-light); }

/* ⚠️ Rev 8: in questa riga c'era l'invito, adesso c'è la CATEGORIA.
   L'occhiello «Reformer pilates · Roseto degli Abruzzi» era sopra il titolo e
   il committente l'ha mandato sotto: la prima cosa che si legge deve essere il
   nome del cliente. Il posto scelto è sotto la LEAD e non sotto il titolo, e la
   ragione è che sotto il titolo la categoria si rimetterebbe in mezzo fra il
   nome e la frase che lo spiega — la stessa interruzione di prima, dieci
   centimetri più in basso. Sotto la lead l'ordine diventa: chi è, cosa gli
   abbiamo fatto, in che mestiere.
   Il posto libero è quello che lascia il bottone uscito nello stesso giro, e
   qui sta il guadagno: da 1060 px in su la categoria sta sulla stessa riga
   della lead, allineata a destra sulla stessa base, quindi la pagina non si
   allunga di una riga. Sotto i 1060 px tornano incolonnate, e la categoria
   resta comunque l'ultima cosa dell'apertura. */
@media (min-width: 1060px) {
  .caso-apertura__coda {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s-3) var(--s-5);
  }
  .caso-apertura__coda .lead { flex: 1 1 24rem; margin-bottom: 0; }
  .caso-apertura__coda .caso-apertura__categoria { flex: 0 0 auto; }
}
/* L'occhiello di base ha un margine sotto, perché di solito introduce quello
   che viene dopo. Qui non introduce niente: è l'ultima riga dell'apertura. */
.caso-apertura__categoria { margin: 0; }
.caso-apertura { padding-bottom: var(--s-5); }

/* ═══════════════════════════════════════════════════════════ I MODULI ══════
   Un modulo è una sezione con una testa e il suo contenuto. Niente altro.

   Il passo fra i moduli è quello che la homepage nuova mette fra le sezioni,
   var(--s-6): 112 px a 1440 e 56 a 390. */
/* Dentro il modulo il passo è uno solo, 32 px, e vale fra la testa e la prima
   figura come fra due figure.
   ⚠️ Il passo è un `gap` e non un `margin-top` sul fratello: `.caso-figura`
   azzera i propri margini con lo shorthand, ha la stessa specificità di una
   regola `.caso-mod > * + *` e viene dopo, quindi glielo mangerebbe. Col gap
   non c'è ordine che tenga. */
.caso-mod {
  display: grid;
  gap: var(--s-4);
  padding-block-start: var(--s-6);
}
.caso-figura + .caso-nota { margin: var(--s-2) 0 0; }

/* ⚠️ Rev 8, RICHIESTA DEL COMMITTENTE: «la sezione è appiccicata al modulo di
   contatto che segue». Era vero, e il conto dice perché: fra due moduli il
   passo è il `padding-block-start: var(--s-6)` del modulo che arriva, ma la
   chiusura non è un modulo, è una FASCIA CON UN FONDO. Il suo `--s-6` sta
   dentro la fascia, quindi il bordo del colore cominciava esattamente dove
   finiva l'ultima riga della linea del tempo: zero pixel di bianco fra le due.
   Il valore non è scelto, è preso dal ritmo che c'è già: lo stesso `--s-6` che
   separa due moduli, messo fuori dalla fascia. Sopra la fascia c'è il passo fra
   due sezioni, dentro c'è il passo della fascia — che è esattamente come la
   homepage nuova separa due sezioni (fondo di una, testa dell'altra), e qui non
   si vedeva perché i moduli hanno il padding da un lato solo.
   È scritta sul fratello e non sulla classe della chiusura perché è una regola
   di RITMO fra due blocchi, non una proprietà della chiusura: una pagina di
   caso che finisse con un altro blocco tenue avrebbe lo stesso problema. */
.caso-mod + .sezione--tenue { margin-block-start: var(--s-6); }

/* ── La testa di modulo ────────────────────────────────────────────────────
   Due cose, non tre: il nome del servizio (identico a quello della home) e il
   micro paragrafo, tetto 32 parole. Da 1000 px in su stanno affiancati e
   allineati in basso, come la homepage nuova fa con il titolo di sezione e la
   colonna che lo accompagna. */
.caso-testa { display: grid; gap: var(--s-2); }
@media (min-width: 1000px) {
  .caso-testa {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: end;
    column-gap: var(--s-6);
  }
}
.caso-mod__titolo {
  font-size: clamp(2rem, 1.2rem + 2.6vw, 4rem);
  font-weight: var(--w-bold);
  line-height: var(--lh-media);
  letter-spacing: var(--ls-stretta);
  margin: 0;
}
.caso-mod__micro {
  margin: 0;
  font-size: var(--t-body);
  line-height: var(--lh-larga);
  max-width: 46ch;
  color: var(--testo-tenue);
}

/* ── Le note di onestà ─────────────────────────────────────────────────────
   NON sono didascalie: non dicono cosa si vede, dicono cosa non è vero.
   ⚠️ Rev 6: NON SI VEDONO PIÙ IN PAGINA. Il committente ha chiesto che «questa
   pagina è un esempio costruito da noi» esca dalle didascalie visibili. Nel
   markup restano, con `class="caso-nota solo-anteprima" hidden`: le accende
   l'interruttore dei codici, che è spento di default. Non è un cavillo:
   il controllo di conformità del deploy continua a trovarle dov'erano (per
   ogni `img` col prefisso `demo-` la sezione deve avere una `.caso-nota` con
   la parola «esempio»), e chi giudica l'anteprima le legge accendendo
   l'interruttore. Le cifre inventate restano dichiarate dentro l'immagine e
   nell'`alt`.
   Questa regola resta perché la nota resta un elemento della pagina: su una
   pagina di caso vero, senza anteprima.css, resta nascosta — e lì non serve,
   perché non c'è niente di costruito da dichiarare. */
.caso-nota {
  max-width: 62ch;
  font-size: var(--t-small);
  color: var(--testo-tenue);
}

/* ── Il collegamento esterno, dove non fa concorrenza a un invito ──────────
   Il rimando al profilo o al sito del cliente sta in coda alla sezione a cui
   appartiene, in forma sobria, dove è un fatto e non una seconda strada.
   ⚠️ Rev 6, deroga del committente alla regola «niente target=_blank» di
   docs 3.1: i link ai profili e ai siti DEI CLIENTI si aprono in una scheda
   nuova, con `rel="noopener"` e con l'avviso `.fuori-schermo`. La freccia è
   `aria-hidden`: dice la stessa cosa a chi vede, senza ripeterla a voce. */
.caso-esterno {
  margin: var(--s-2) 0 0;
  font-size: var(--t-small);
  color: var(--testo-tenue);
}
.caso-esterno a { text-underline-offset: .2em; }

/* ═══════════════════════════════════ QUELLO CHE È SCRITTO, SI SCRIVE ═══════
   Un componente solo, tre tagli. `.caso-elenco` è una colonna di righe
   separate da un filetto, e ogni riga porta da uno a tre pezzi: un numero
   facoltativo, un termine, una riga di spiegazione facoltativa. Da lì escono:

     --fasi     il piano del modulo «strategia»: numero, titolo, una riga.
                È l'intero modulo, perché quel servizio non produce file da
                mostrare e una schermata finta di un fascicolo che non esiste
                si vede che è finta.
     --prova    la colonna che accompagna la schermata dei moduli costruiti:
                termine e una riga, tre voci.

   Si adatta a un altro cliente cambiando solo il testo: nessuna misura del
   componente dipende da quante voci ci sono o da quanto sono lunghe. */

.caso-elenco {
  list-style: none;
  margin: 0;
  padding: 0;
}
.caso-elenco > li {
  position: relative;
  padding-block: var(--s-2);
}
/* Il filetto è un ::before e non un `border-top` perché deve poter entrare in
   scena: il bordo non si anima senza far saltare il layout, un pseudo-elemento
   in scaleX sì. È lo STESSO gesto del filetto che si colora sotto un campo del
   modulo (`.campo::after`), non un movimento nuovo: la pagina ha un solo
   vocabolario e questa è una parola che già usa. */
.caso-elenco > li::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  background: var(--hairline-forte);
  transform-origin: left;
  transition: transform var(--m-lungo) var(--e-out);
}

.caso-elenco__t { display: block; }
.caso-elenco__d { display: block; }

/* ⚠️ Rev 8: `--parole`, `.caso-tavola` e `.caso-tavola__titolo` SONO USCITI DA
   QUI. Erano la tavola delle parole chiave ricostruita in tipografia, che la
   rev 6 aveva montato per togliere dalla pagina un refuso che stava dentro una
   fotografia. Il refuso adesso è corretto alla fonte (il testo del PDF è testo
   vero: si è corretta la parola e si è riesportata la pagina), quindi la
   fotografia non ha più niente di sbagliato in quadro e il committente ha
   scelto lei. Due varianti della stessa tavola erano un confronto da decidere,
   non un contenuto: decisa, una delle due esce. Sta in git, non in archivio
   qui. */

/* --fasi: il numero non è un elenco puntato travestito. È `aria-hidden`
   perché l'ordine lo porta già `<ol>`, e a voce «zero uno Prima il nome»
   sarebbe rumore. `tabular-nums` così le cifre stanno incolonnate. */
/* Tre colonne da 760 px in su, due sotto: il numero non prende mai una riga
   sua, o quattro mosse diventano dodici righe su un telefono. Il posto dei tre
   pezzi si scrive esplicitamente, così il cambio di griglia è una riga sola. */
.caso-elenco--fasi > li {
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr);
  column-gap: var(--s-2);
  row-gap: var(--s-1);
  padding-block: var(--s-3);
}
.caso-elenco--fasi .caso-elenco__n { grid-area: 1 / 1; }
.caso-elenco--fasi .caso-elenco__t { grid-area: 1 / 2; }
.caso-elenco--fasi .caso-elenco__d { grid-area: 2 / 2; }
@media (min-width: 760px) {
  .caso-elenco--fasi > li {
    grid-template-columns: 5rem minmax(0, 1.15fr) minmax(0, 1fr);
    align-items: baseline;
    column-gap: var(--s-4);
  }
  .caso-elenco--fasi .caso-elenco__d { grid-area: 1 / 3; }
}
.caso-elenco--fasi .caso-elenco__n {
  font-size: clamp(1.5rem, 1.1rem + 1.1vw, 2.125rem);
  font-weight: var(--w-light);
  line-height: var(--lh-media);
  letter-spacing: var(--ls-stretta);
  color: var(--testo-tenue);
  font-variant-numeric: tabular-nums;
}
.caso-elenco--fasi .caso-elenco__t {
  font-size: clamp(1.375rem, 1rem + 1.2vw, 2rem);
  font-weight: var(--w-bold);
  line-height: var(--lh-media);
  letter-spacing: var(--ls-stretta);
}
.caso-elenco--fasi .caso-elenco__d {
  font-size: var(--t-body);
  line-height: var(--lh-larga);
  color: var(--testo-tenue);
}

/* --prova: la colonna scritta accanto alla schermata. Da 1000 px in su si
   stira all'altezza della figura e le tre voci si distribuiscono: così i
   filetti scandiscono la stessa altezza dell'immagine invece di ammucchiarsi
   in cima lasciando un buco sotto. */
.caso-elenco--prova { display: grid; }
.caso-elenco--prova > li {
  display: grid;
  gap: 6px;
  padding-block: var(--s-3);
}
/* Un gradino sopra il corpo del testo, non due: la colonna accompagna la
   schermata e non le fa concorrenza, ma a 16 px scompariva accanto a una
   figura larga 725. */
.caso-elenco--prova .caso-elenco__t {
  font-size: clamp(1rem, 0.9rem + 0.3vw, 1.25rem);
  font-weight: var(--w-bold);
  line-height: var(--lh-media);
  letter-spacing: var(--ls-stretta);
}
.caso-elenco--prova .caso-elenco__d {
  font-size: var(--t-small);
  line-height: var(--lh-larga);
  color: var(--testo-tenue);
}
@media (min-width: 1000px) {
  .caso-elenco--prova { align-content: space-between; }
}
/* Sotto i 1000 px la colonna scende sotto la schermata e non ha più un'altezza
   da riempire: lì il passo si stringe, perché quello che su desktop è respiro
   accanto a una figura, su telefono è solo pagina in più. */
@media (max-width: 999.98px) {
  .caso-elenco--prova > li { padding-block: var(--s-2); }
}
/* Rev 7: la colonna di prova può portare un numero, e lo porta solo dove il
   numero serve a legare la riga a un segno del disegno accanto (il modulo 06:
   01, 02, 03 sono gli stessi tre bolli disegnati sugli anelli). È
   `aria-hidden` nel markup, perché a voce «zero uno chi passa davanti» sarebbe
   rumore e l'ordine lo porta già `<ol>`. Dove il numero non c'è, niente
   cambia: è una riga di griglia che non viene occupata. */
.caso-elenco--prova .caso-elenco__n {
  display: block;
  font-size: var(--t-eyebrow);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-eyebrow);
  color: var(--viola-testo);
  font-variant-numeric: tabular-nums;
}

/* ── --ritmo: come si tiene un profilo ─────────────────────────────────────
   Rev 7, modulo 04. Il committente ha chiesto di far vedere «il ritmo del
   lavoro (piano editoriale, cadenza, formati)» senza inventare numeri di
   risultato. È la colonna scritta che sta accanto alla griglia del profilo,
   e porta il corpo di `.caso-tempo`, non quello di `.caso-elenco--prova`: lì
   la colonna accompagna una schermata larga e non le fa concorrenza, qui è il
   contenuto principale del modulo accanto a un telefono stretto, e a 14 px
   sarebbe una didascalia lunga.
   Si distribuisce sull'altezza della figura per la stessa ragione di --prova:
   tre voci ammucchiate in cima a una colonna alta 615 px lasciano un buco. */
.caso-elenco--ritmo > li { padding-block: var(--s-3); }
.caso-elenco--ritmo .caso-elenco__t {
  font-size: clamp(1.25rem, 1rem + 0.7vw, 1.75rem);
  font-weight: var(--w-bold);
  line-height: var(--lh-media);
  letter-spacing: var(--ls-stretta);
}
.caso-elenco--ritmo .caso-elenco__d {
  margin-top: 6px;
  font-size: var(--t-body);
  line-height: var(--lh-larga);
  color: var(--testo-tenue);
  max-width: 52ch;
}
@media (min-width: 1000px) {
  .caso-elenco--ritmo { display: grid; align-content: space-between; }
}

/* ── Il sottotitolo dentro un modulo ───────────────────────────────────────
   Rev 7. Da quando tre servizi stanno in una sezione sola (05 Sviluppo web),
   il modulo ha bisogno di dire dove comincia un pezzo nuovo senza aprire un
   secondo titolo grande: due `h2` a 64 px nella stessa sezione sarebbero due
   sezioni. È un `h3` in forma di occhiello, cioè il segno più piccolo che la
   pagina ha già. Il livello di intestazione resta corretto per chi naviga per
   titoli: h1 → h2 del modulo → h3 del pezzo. */
.caso-sub { margin: 0 0 var(--s-3); }

/* ── Il blocco piccolo ─────────────────────────────────────────────────────
   Rev 7, l'assistenza IT dentro «Sviluppo web». Il committente: «non merita
   una sezione grande: una riga o un blocco piccolo». È un servizio che si
   compra fidandosi, non guardando, e un modulo con titolo, micro paragrafo e
   schermata finta gli dava il peso di un progetto. Un filetto, un'etichetta e
   una riga. */
.caso-minuto {
  display: grid;
  gap: var(--s-1);
  padding-top: var(--s-3);
  border-top: 1px solid var(--hairline-forte);
}
@media (min-width: 760px) {
  .caso-minuto {
    grid-template-columns: 14rem minmax(0, 1fr);
    column-gap: var(--s-4);
    align-items: baseline;
  }
}
.caso-minuto__titolo { margin: 0; }
.caso-minuto__testo {
  margin: 0;
  font-size: var(--t-body);
  line-height: var(--lh-larga);
  color: var(--testo-tenue);
  max-width: 62ch;
}

/* ═════════════════════════════ QUELLO CHE SI DISEGNA, SI DISEGNA ═══════════
   Rev 7, moduli 06 e 07. Il committente ha chiesto di far vedere quei due
   servizi «con i mezzi del disegno, non con una schermata inventata»: le due
   schermate finte (`demo-annuncio`, `demo-email`) sono uscite da public/.
   Le forme sono due e sono diverse apposta — «non farli uguali»:
     .caso-disegno + .caso-annuncio   06: una mappa di SPAZIO (a chi arriva)
                                      più l'annuncio smontato in tipografia
     .caso-tempo                      07: una riga di TEMPO (cosa arriva, quando)
   Nessuna delle due porta un numero, e non è una rinuncia: un numero qui
   sarebbe inventato, e la pagina ne ha già abbastanza di dichiarato.
   ========================================================================= */

/* ── Il disegno in SVG ─────────────────────────────────────────────────────
   L'SVG sta nel markup e non in un file: è quindici elementi, cambia colore
   col resto della pagina perché usa i token, e un file in più sarebbe una
   riga in più nell'elenco dei condivisi del deploy per 700 byte.
   Il quadro ha lo stesso bordo e lo stesso fondo tenue di una figura, perché
   nella riga sta al posto di una figura: se galleggiasse nel bianco la riga
   sembrerebbe sbilanciata. */
.caso-disegno {
  margin: 0;
  border: 1px solid rgba(17, 17, 17, .06);
  background: var(--bianco-sporco);
}
.caso-disegno svg { display: block; width: 100%; height: auto; }
.d-anello { fill: none; stroke: var(--hairline-forte); stroke-width: 1; }
.d-raggio { stroke: var(--hairline-forte); stroke-width: 1; }
.d-centro { fill: var(--viola); }
/* I bolli hanno il fondo del quadro, non il bianco: appoggiati sull'anello
   devono interromperlo, e un bianco su fondo tenue si vedrebbe come un alone. */
.d-bollo {
  fill: var(--bianco-sporco);
  stroke: var(--nero);
  stroke-width: 1.2;
}
.d-num {
  fill: var(--nero);
  font-family: var(--font);
  font-size: 14px;
  font-weight: var(--w-bold);
  font-variant-numeric: tabular-nums;
}
.d-eti {
  fill: var(--testo-tenue);
  font-family: var(--font);
  font-size: 13px;
  letter-spacing: .14em;
  text-transform: uppercase;
}
/* La presa del mouse su un anello. Un tratto da un pixel non si punta: queste
   sono le stesse tre circonferenze con un tratto trasparente spesso 26, e
   `pointer-events: stroke` dice che a raccogliere il puntatore è la fascia del
   tratto e non il disco dentro — altrimenti la presa dell'anello più largo
   coprirebbe le altre due.
   ⚠️ `fill: none` non è pulizia: un `<circle>` senza `fill` dichiarato è NERO,
   e tre dischi neri coprirebbero il disegno.
   Nessun `f-` da stilare qui: le regole del fuoco nominano `.d-anello`,
   `.d-bollo` e `.d-num`, mai la classe di gruppo da sola, quindi la presa resta
   trasparente qualunque cosa succeda. */
.d-presa {
  fill: none;
  stroke: transparent;
  stroke-width: 26;
  pointer-events: stroke;
}

/* ── L'annuncio smontato ───────────────────────────────────────────────────
   Quattro pezzi, ognuno con l'etichetta di che mestiere fa. Non è il facsimile
   di un annuncio: è l'annuncio aperto, che è la cosa che un cliente nuovo non
   ha mai visto e che spiega perché un annuncio costa. Si adatta a un altro
   cliente cambiando quattro righe di testo e zero misure. */
.caso-annuncio__p {
  display: grid;
  gap: 6px;
  padding-block: var(--s-3);
  border-top: 1px solid var(--hairline);
}
@media (min-width: 760px) {
  .caso-annuncio__p {
    grid-template-columns: 20rem minmax(0, 1fr);
    column-gap: var(--s-4);
    align-items: baseline;
  }
}
.caso-annuncio__e {
  font-size: var(--t-eyebrow);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--testo-tenue);
}
.caso-annuncio__t {
  font-size: var(--t-lead);
  font-weight: var(--w-light);
  line-height: 1.35;
  max-width: 42ch;
}
.caso-annuncio__g {
  font-size: clamp(1.75rem, 1.1rem + 2vw, 3rem);
  font-weight: var(--w-bold);
  line-height: var(--lh-media);
  letter-spacing: var(--ls-stretta);
}
/* Il bottone è disegnato, non è un comando: non è un <button>, non prende il
   fuoco e non porta da nessuna parte. Ha la pillola del marchio perché è quello
   che si vedrebbe nell'annuncio vero — «le fotografie hanno lo spigolo,
   l'interfaccia ha la pillola», e questo è un pezzo di interfaccia disegnato. */
.caso-annuncio__b {
  justify-self: start;
  padding: 0.7em 1.6em;
  border: 1.5px solid currentColor;
  border-radius: var(--raggio-pill);
  font-size: 0.95rem;
  font-weight: var(--w-bold);
}

/* ── La linea del tempo ────────────────────────────────────────────────────
   Rev 7, modulo 07, e la forma è una decisione presa e motivata (docs 18):
   NIENTE IMBUTO. L'imbuto è un grafico di quantità — la sua larghezza dichiara
   quante persone entrano e quante restano — e quei numeri non ce li abbiamo.
   La linea del tempo dichiara solo l'ordine e l'attesa, che sono le due cose
   che abbiamo davvero progettato.
   Quattro momenti in fila da 900 px in su, incolonnati sotto. Il binario è lo
   stesso filetto di `.caso-elenco`, con in più un bollo sul punto di partenza
   di ogni tratta: quattro tratte affiancate si leggono come una riga sola
   scandita, che è esattamente quello che una sequenza è. */
.caso-tempo {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-4);
}
@media (min-width: 900px) {
  .caso-tempo {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0;
    column-gap: var(--s-3);
  }
}
.caso-tempo > li {
  position: relative;
  display: grid;
  gap: 6px;
  align-content: start;
  padding-top: var(--s-3);
}
.caso-tempo > li::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  background: var(--hairline-forte);
  transform-origin: left;
  transition: transform var(--m-lungo) var(--e-out);
}
/* Il bollo sta SOPRA il filetto e non dentro, così non si muove quando il
   filetto entra in scena: un segno che scivola insieme alla linea che sta
   disegnando sembra un errore di disegno. */
.caso-tempo > li::after {
  content: "";
  position: absolute;
  top: -4px;
  left: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--viola);
}
.caso-tempo__q {
  font-size: var(--t-eyebrow);
  font-weight: var(--w-bold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--viola-testo);
}
.caso-tempo__t {
  font-size: clamp(1.25rem, 1rem + 0.7vw, 1.75rem);
  font-weight: var(--w-bold);
  line-height: var(--lh-media);
  letter-spacing: var(--ls-stretta);
}
.caso-tempo__d {
  font-size: var(--t-small);
  line-height: var(--lh-larga);
  color: var(--testo-tenue);
}

/* ── Un anello a fuoco, un passo a fuoco ───────────────────────────────────
   Rev 9, seconda metà della richiesta sui due disegni. Passando sopra un anello
   — o sopra la riga che lo spiega — quell'anello si accende con la sua etichetta
   e gli altri si attenuano. Stessa cosa sui quattro passi della linea del tempo.

   TUTTO IN CSS, NIENTE JAVASCRIPT. Lo stato «ci sto sopra» e lo stato «ha il
   fuoco» sono due pseudo-classi, e il pezzo che mancava — legare un anello del
   disegno a una riga che sta in un altro sottoalbero — lo fa `:has()` sul
   contenitore della riga. Senza JavaScript funziona; su un motore che `:has()`
   non lo conosce non funziona e non succede niente, perché il disegno e le sue
   tre righe restano quelli di prima, tutti leggibili.

   ⚠️ ATTENUARE NON VUOL DIRE SBIADIRE IL TESTO. Il modo ovvio sarebbe
   `opacity: .3` su tutto il resto, e su una riga di testo lo si paga in
   contrasto: `--testo` #333 al 30% su bianco scende sotto il 4,5:1, e un testo
   che diventa illeggibile perché il mouse è due centimetri più in là non è una
   raffinatezza. Quindi si attenua per colore e ci si ferma su `--testo-tenue`
   #6B6B6B, che è 5,33:1 sul bianco della pagina e 5,08:1 sul bianco sporco del
   quadro. Il SEGNO — anelli, bolli, filetti — si attenua davvero, perché è un
   segno e non deve essere letto.

   ⚠️ TUTTO IL BLOCCO STA SOTTO `prefers-reduced-motion: no-preference`, e
   l'attenuazione è la ragione: a movimento ridotto la pagina è ferma e completa,
   e «completa» qui vuol dire che non c'è niente di attenuato. Spegnendo il
   blocco intero si ottiene esattamente quello — tutto a fuoco — senza dover
   disfare a mano una proprietà alla volta come tocca fare più sotto con gli
   stati di partenza del movimento. L'anello di fuoco della tastiera, invece,
   sta FUORI di qui: quello non è movimento e non si spegne mai. */

.caso-elenco--prova > li:focus-visible,
.caso-tempo > li:focus-visible {
  /* Sul bianco della pagina --viola sta a 4,59:1, sopra il 3:1 che WCAG 1.4.11
     chiede a un indicatore di fuoco. Lo scarto tiene l'anello staccato dal
     filetto della riga, che è dello stesso colore quando la riga è a fuoco. */
  outline: 3px solid var(--viola);
  outline-offset: 6px;
}

@media (prefers-reduced-motion: no-preference) {

  .d-anello, .d-bollo, .d-num,
  .caso-elenco--prova > li, .caso-elenco--prova .caso-elenco__n,
  .caso-tempo > li::before, .caso-tempo > li::after,
  .caso-tempo__q, .caso-tempo__t {
    transition: color var(--m-micro) var(--e-out),
                fill var(--m-micro) var(--e-out),
                stroke var(--m-micro) var(--e-out),
                background-color var(--m-micro) var(--e-out);
  }
  /* ⚠️ Il filetto della linea del tempo ha già una transizione sua, sul
     `transform`, ed è quella con cui entra in scena: la riga qui sopra la
     sostituirebbe e il binario comparirebbe di colpo. Si riscrivono tutte e
     due insieme. */
  .caso-tempo > li::before {
    transition: transform var(--m-lungo) var(--e-out),
                background-color var(--m-micro) var(--e-out);
  }

  /* ── 06, gli anelli ─────────────────────────────────────────────────────
     Prima si attenua tutto, poi si riaccende il gruppo impegnato: due passi
     invece di dodici regole, una per combinazione. */
  .caso-fuochi:has(:is(.f-1, .f-2, .f-3):is(:hover, :focus-visible)) .d-anello { stroke: var(--hairline); }
  .caso-fuochi:has(:is(.f-1, .f-2, .f-3):is(:hover, :focus-visible)) .d-bollo { stroke: var(--hairline-forte); }
  .caso-fuochi:has(:is(.f-1, .f-2, .f-3):is(:hover, :focus-visible)) .d-num { fill: var(--testo-tenue); }
  .caso-fuochi:has(:is(.f-1, .f-2, .f-3):is(:hover, :focus-visible)) .caso-elenco--prova > li { color: var(--testo-tenue); }
  .caso-fuochi:has(:is(.f-1, .f-2, .f-3):is(:hover, :focus-visible)) .caso-elenco--prova .caso-elenco__n { color: var(--testo-tenue); }

  /* Il gruppo a fuoco. `:is(.d-anello, .d-bollo).f-N` pesa (0,5,0) contro i
     (0,4,0) dell'attenuazione qui sopra: vince per specificità e non per
     ordine, così resta giusto anche se qualcuno sposta un blocco.
     Le due righe per gruppo scrivono `fill` e `color` insieme: la prima serve
     al numero dentro l'SVG, la seconda alla riga scritta accanto, e una
     proprietà che non c'entra con l'elemento non fa niente. */
  .caso-fuochi:has(.f-1:is(:hover, :focus-visible)) :is(.d-anello, .d-bollo).f-1 { stroke: var(--viola); stroke-width: 2; }
  .caso-fuochi:has(.f-1:is(:hover, :focus-visible)) :is(.d-num, li).f-1 { fill: var(--nero); color: var(--testo); }
  .caso-fuochi:has(.f-1:is(:hover, :focus-visible)) li.f-1 .caso-elenco__n { color: var(--viola-testo); }
  .caso-fuochi:has(.f-1:is(:hover, :focus-visible)) li.f-1::before { background: var(--viola); }

  .caso-fuochi:has(.f-2:is(:hover, :focus-visible)) :is(.d-anello, .d-bollo).f-2 { stroke: var(--viola); stroke-width: 2; }
  .caso-fuochi:has(.f-2:is(:hover, :focus-visible)) :is(.d-num, li).f-2 { fill: var(--nero); color: var(--testo); }
  .caso-fuochi:has(.f-2:is(:hover, :focus-visible)) li.f-2 .caso-elenco__n { color: var(--viola-testo); }
  .caso-fuochi:has(.f-2:is(:hover, :focus-visible)) li.f-2::before { background: var(--viola); }

  .caso-fuochi:has(.f-3:is(:hover, :focus-visible)) :is(.d-anello, .d-bollo).f-3 { stroke: var(--viola); stroke-width: 2; }
  .caso-fuochi:has(.f-3:is(:hover, :focus-visible)) :is(.d-num, li).f-3 { fill: var(--nero); color: var(--testo); }
  .caso-fuochi:has(.f-3:is(:hover, :focus-visible)) li.f-3 .caso-elenco__n { color: var(--viola-testo); }
  .caso-fuochi:has(.f-3:is(:hover, :focus-visible)) li.f-3::before { background: var(--viola); }

  /* ── 07, i quattro passi ────────────────────────────────────────────────
     Qui il passo e la sua etichetta sono lo stesso elemento, quindi non serve
     legare niente: `:has()` sull'elenco dice solo «qualcuno è impegnato».
     ⚠️ La regola del passo a fuoco ripete il `:has()` dell'attenuazione: senza,
     peserebbe (0,2,1) contro i (0,2,2) dell'attenuazione e perderebbe proprio
     sul passo che deve accendere. */
  .caso-tempo:has(> li:is(:hover, :focus-visible)) > li::before { background: var(--hairline); }
  .caso-tempo:has(> li:is(:hover, :focus-visible)) > li::after { background: var(--hairline-forte); }
  .caso-tempo:has(> li:is(:hover, :focus-visible)) > li .caso-tempo__q { color: var(--testo-tenue); }
  .caso-tempo:has(> li:is(:hover, :focus-visible)) > li .caso-tempo__t { color: var(--testo-tenue); }

  .caso-tempo:has(> li:is(:hover, :focus-visible)) > li:is(:hover, :focus-visible)::before { background: var(--viola); }
  .caso-tempo:has(> li:is(:hover, :focus-visible)) > li:is(:hover, :focus-visible)::after { background: var(--viola); }
  .caso-tempo:has(> li:is(:hover, :focus-visible)) > li:is(:hover, :focus-visible) .caso-tempo__q { color: var(--viola-testo); }
  .caso-tempo:has(> li:is(:hover, :focus-visible)) > li:is(:hover, :focus-visible) .caso-tempo__t { color: var(--testo); }
}

/* ── Le righe e le figure ──────────────────────────────────────────────────
   Una figura per riga. Due per riga solo per i verticali: due orizzontali
   affiancate tornerebbero francobolli.

   Le righe in `fr` PROPORZIONALI ALLA PROPORZIONE pareggiano le altezze senza
   ritagliare: un 16/9 e un 1/1,4 diventano 1.778fr e 0.716fr, cioè 867 e 349 px
   con la STESSA altezza e zero ritaglio. Chi monta una riga nuova calcola gli
   `fr` dalle due proporzioni (la larghezza diviso l'altezza) e non li sceglie a
   occhio. */
.caso-riga { display: grid; gap: var(--s-3); }

@media (min-width: 1000px) {
  .caso-riga--due         { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .caso-riga--slide-ritta { grid-template-columns: 1.778fr 0.716fr; }
  /* La riga «prova + layout» dei moduli costruiti: la schermata a sinistra,
     la colonna scritta a destra. 1,2fr e 0,8fr su 1240 con 32 di gap danno
     725 e 483 px, e 725 è il numero scritto nel `sizes` di quelle quattro
     immagini: i due si muovono insieme. */
  .caso-riga--prova {
    grid-template-columns: 1.2fr 0.8fr;
    column-gap: var(--s-4);
    align-items: stretch;
  }
  /* Rev 7, modulo 05: la schermata larga e quella del telefono nella stessa
     riga, ed è la richiesta «desktop e telefono insieme». Gli `fr` sono di
     nuovo proporzionali alla PROPORZIONE e non scelti a occhio: 16/10 = 1,6 e
     9/16 = 0,5625. Su 1240 con 24 di gap fanno 900 e 316 px, e tutte e due
     alte 562: le due figure combaciano sopra e sotto, che è la differenza fra
     un accostamento e un collage. I due numeri stanno anche nei `sizes` di
     quelle due immagini, e si muovono insieme. */
  .caso-riga--schermo-telefono {
    grid-template-columns: 1.6fr 0.5625fr;
    align-items: start;
  }
  /* Rev 7, modulo 04: la schermata del profilo accanto alla colonna che dice
     con che ritmo lo teniamo. Il telefono è STRETTO apposta — 0,5625fr contro
     1,4fr, cioè 346 px su 1240 con 32 di gap — perché una schermata di profilo
     si guarda alla misura in cui si guarda un profilo: a 608 px una griglia da
     tre colonne diventa un mosaico da parete e smette di dire «telefono». */
  .caso-riga--profilo {
    grid-template-columns: 0.5625fr 1.4fr;
    column-gap: var(--s-4);
    align-items: stretch;
  }
}
@media (max-width: 999.98px) {
  .caso-riga--profilo > div > .caso-figura { max-width: 420px; }
}
/* Sotto i 1000 le due misure si incolonnano, e la schermata del telefono non
   deve stirarsi a tutta la colonna: a 950 px un 9/16 sarebbe alto 1.690. Si
   ferma alla larghezza del suo file e resta a sinistra, dove comincia la
   colonna del testo. */
@media (max-width: 999.98px) {
  .caso-riga--schermo-telefono > .caso-figura--verticale { max-width: 360px; }
}

/* Sotto i 1000 una figura per riga, tranne i verticali che restano a due fino
   ai 600 px: sotto quella soglia due colonne darebbero 170 px, e una pagina di
   sito a 170 px non si legge. */
@media (min-width: 600px) and (max-width: 999.98px) {
  .caso-riga--due { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ANGOLI VIVI. Una foto con lo spigolo vivo si legge come fotografia, una con
   l'angolo smussato si legge come scheda di interfaccia, e su una pagina dove
   la fotografia è il prodotto vince la prima. Restano curve le pillole, cioè i
   bottoni: in una riga, le fotografie hanno lo spigolo, l'interfaccia ha la
   pillola.

   Il filo che tiene il bordo di una fotografia chiara su fondo bianco è un
   bordo vero da 1 px a .06 di opacità, non un `outline`: quello è il canale
   dell'indicatore di focus. Con `box-sizing: border-box` sta dentro
   l'`aspect-ratio` e non sposta niente. */
.caso-figura { margin: 0; min-width: 0; }
.caso-figura > :first-child {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 0;
  border: 1px solid rgba(17, 17, 17, .06);
  object-fit: cover;
  object-position: center;
  background: #E9E9E9;
}
.caso-figura--media > :first-child     { aspect-ratio: 3 / 2; }       /* fotografie */
.caso-figura--verticale > :first-child { aspect-ratio: 9 / 16; }      /* storie, reel, pagine mobili */
.caso-figura--slide > :first-child     { aspect-ratio: 16 / 9; }      /* slide di presentazione */
.caso-figura--pagina > :first-child    { aspect-ratio: 1.41 / 1; }    /* A4 orizzontale */
.caso-figura--ritta > :first-child     { aspect-ratio: 1 / 1.4; }     /* poster, stampati */
/* Le schermate costruite sono esportate in 16/10, cioè nella proporzione della
   figura. `object-position: top center` serve solo alle schermate che un
   giorno arrivassero più alte del quadro. */
.caso-figura--schermo > :first-child {
  aspect-ratio: 16 / 10;
  object-position: top center;
}
/* Sotto i 1000 px una figura --ritta prende la riga intera e si ferma alla
   larghezza del suo file: il poster esce da un PDF ma il webp è largo 720, e a
   1024 px di viewport verrebbe disegnata il 33% più grande della sorgente. */
@media (max-width: 999.98px) {
  .caso-figura--ritta > :first-child { max-width: 720px; margin-inline: auto; }
}

/* La figura a tutta larghezza: sta FUORI da `.caso-corpo`, cioè figlia diretta
   della sezione, e prende la larghezza del corpo del documento. Niente
   `100vw`, quindi la barra di scorrimento non entra nel conto e non c'è modo
   di far comparire uno scorrimento orizzontale.
   L'immagine si ferma a 1440 px, che è il file più grande che abbiamo. */
.caso-figura--piena > :first-child {
  max-width: 1440px;
  margin-inline: auto;
}

/* Le didascalie sono uscite tutte: quello che si vede sta negli `alt`, che sono
   scritti bene, non hanno tetto di parole e servono a chi usa un lettore di
   schermo. Questa regola resta perché l'ECCEZIONE è viva: una didascalia si
   scrive solo se aggiunge un fatto che il titolo e il micro paragrafo non
   portano (un formato, un materiale, un vincolo, una data, un credito), e in
   tutta la pagina non ne possono stare più di due. */
.caso-figura figcaption {
  margin-top: var(--s-1);
  font-size: var(--t-eyebrow);
  color: var(--testo-tenue);
  max-width: 42ch;
}

/* ── I reel ───────────────────────────────────────────────────────────────
   ⚠️ Questo blocco era, fino alla rev 6, il commento «un video vero si monta
   così, mai autoplay e mai loop». I video adesso ci sono — quattro, nel modulo
   02 «content creation», in `lavori/modello/video/` accanto ai loro poster — e
   partono da soli in loop quando entrano in vista. IL PRINCIPIO NON È CAMBIATO:
   i comandi li dà chi guarda. È cambiato che il comando adesso è UNO, ed è il
   bottone di pausa qui sotto, che non è un ornamento. Il markup, i pesi, le
   quattro clip e le misure prese in prova stanno in docs/rev6-reel.md; il
   comportamento lo governa assets/js/reel.r1.js.

   Il <video> non ha regole sue: prende il quadro come qualsiasi altro primo
   figlio di .caso-figura (larghezza 100%, aspect-ratio 9/16, bordo, cover).
   Qui serve solo il riferimento per il bottone, che sta dentro la figura. */
.caso-reel { position: relative; }

/* Il comando di pausa, e non è un ornamento: un video che parte da solo e gira
   in loop oltre i cinque secondi senza un modo per fermarlo è una 2.2.2 di
   livello A mancata, e questa pagina un domani sarà pubblica.
   ⚠️ DECISIONE DEL COMMITTENTE, 2026-09-13: «pausa non ne ho bisogno, non serve
   che gli utenti mettano in pausa». Il bottone non si toglie — sarebbe la
   conformità a saltare, non un ornamento — ma cambia forma, e la forma adottata
   costa zero a chi guarda: PER IL MOUSE NON ESISTE. Niente comparsa al
   passaggio del mouse (la regola `:hover` è uscita) e `pointer-events: none`
   finché non ha il focus, così non resta nemmeno un bersaglio invisibile da
   premere per sbaglio nell'angolo del reel. Chi naviga da tastiera o con un
   lettore di schermo lo raggiunge con Tab e in quel momento lo vede.
   La visibilità è su :focus e non su :focus-visible: un bersaglio che ha il
   focus e non si vede è un bersaglio invisibile anche quando il focus è
   arrivato da un lettore di schermo. */
.reel-pausa {
  position: absolute;
  right: var(--s-2);
  bottom: var(--s-2);
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(17, 17, 17, .6);
  color: #fff;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--m-micro) var(--e-out);
}
.reel-pausa__segno { width: 18px; height: 18px; fill: currentColor; }
.reel-pausa__via { display: none; }
.caso-reel--in-pausa .reel-pausa__barre { display: none; }
.caso-reel--in-pausa .reel-pausa__via { display: block; }

/* Due soli stati in cui si vede, e nessuno dei due è il passaggio del mouse.
   `caso-reel--in-pausa` resta perché quello stato si raggiunge SOLO da questo
   bottone, cioè solo da tastiera o da lettore di schermo: senza, chi ha fermato
   un video e ha tabulato via si troverebbe un reel fermo e nessun comando
   visibile per farlo ripartire. Per il mouse non cambia niente, perché il mouse
   in quello stato non ci arriva. */
.caso-reel--in-pausa .reel-pausa,
.reel-pausa:focus { opacity: 1; pointer-events: auto; }

.reel-pausa:focus-visible { outline: 3px solid var(--viola); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) { .reel-pausa { transition: none; } }

/* ── Il rimando alla home ──────────────────────────────────────────────────
   Era una sezione sua, alta 400 px, a una schermata dalla chiusura: due inviti
   appaiati fanno esitare invece di far scegliere. Adesso è una riga sola nella
   colonna tipografica della chiusura, lontana dal bottone e dal modulo. NON è
   un invito a scrivere: è navigazione, e per questo è un link. */
.caso-tutti {
  margin: var(--s-4) 0 0;
  font-size: var(--t-small);
  font-weight: var(--w-bold);
}
.caso-tutti a { text-underline-offset: .2em; }

/* ⚠️ Rev 8: `.caso-azioni` È USCITA DA QUI con l'unico bottone che la usava.
   Il committente ha tolto «Parliamone» dall'apertura, e gli inviti a scrivere
   restano due: la testata e la chiusura. La regola serviva a una cosa sola —
   un bottone a tutta larghezza sotto i 720 px — e i due bottoni che restano
   non stanno dentro questo componente: quello della testata è piccolo per
   costruzione, quello della chiusura lo governa il riquadro copiato dalla
   home. Una classe senza elementi è una riga che il prossimo legge e cerca.
   Sta in git, non in archivio qui. */

/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  SECONDO RIQUADRO COPIATO VERBATIM DA demo-motion/demo.r1.css (:820-935) ║
   ║  Rev 7. Vale parola per parola quello che dice il riquadro in cima al    ║
   ║  file: copia letterale, e a 💎 M2 va promossa nel sistema comune e       ║
   ║  sparisce da qui.                                                        ║
   ║                                                                          ║
   ║  ⚠️ Rev 7, LE SETTE RIGHE CHE NELLA REV 6 MANCAVANO. Il blocco era già   ║
   ║  qui, ma `style.css` continuava a vincere su sette dichiarazioni che la  ║
   ║  home NON HA — quindi non c'era niente da sovrascrivere e nessuno se ne  ║
   ║  era accorto guardando il codice. Si vedono tutte a schermo, ed erano il ║
   ║  «campi e piede diversi» del committente. Stanno in fondo a questo       ║
   ║  blocco, sotto il titolo «I SETTE PAREGGI».                              ║
   ╚══════════════════════════════════════════════════════════════════════════╝

   Rev 6: struttura, classi e comportamento sono quelli della homepage nuova
   (prezzemolostudio/public/demo-motion/, `index.html` sezione «contatti» e
   `demo.r1.css` dalla riga 829). Le regole stanno qui e non in style.css
   perché style.css è condiviso con la landing, che ha ancora i campi col
   riquadro arrotondato: sovrascriverlo da lì cambierebbe una pagina che
   nessuno ha chiesto di cambiare. Al merge del 22/09 si decide una volta sola
   quale delle due forme vince, e questa parte sparisce da qui.

   ⚠️ IL MODULO NON INVIA, e non finge. La CSP di questa cartella ha
   `form-action 'none'` e `connect-src 'self'`: il `<form>` non ha `action`, e
   non ha nemmeno `novalidate`, quindi quello che si vede è la validazione
   nativa del browser — `required`, `type="email"`, la spunta del consenso —
   cioè comportamento di interfaccia vero senza una riga di JavaScript.
   `modulo.js` NON va collegato: fa una POST vera al webhook dei contatti e
   ogni prova diventerebbe un contatto finto nel CRM.
   ========================================================================= */

.contatti__asterisco { width: 44px; margin-bottom: var(--s-2); }
/* Il titolo giga ha line-height 0.82: senza un respiro esplicito la riga
   successiva gli finisce addosso. */
.contatti .titolo-giga { margin-bottom: var(--s-3); }
.griglia-2 { display: grid; gap: var(--s-5); }
@media (min-width: 1000px) {
  .griglia-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-6); }
  .contatti .griglia-2 { align-items: start; }
}

.modulo { display: grid; gap: var(--s-2); }
.campo { display: grid; gap: 0.35rem; position: relative; }
.campo label { font-size: var(--t-small); font-weight: var(--w-bold); }
.campo__nota { font-weight: var(--w-normal); color: var(--testo-tenue); }

.campo input,
.campo textarea {
  font: inherit;
  color: inherit;
  background: var(--bianco);
  border: 0;
  border-bottom: 1.5px solid var(--bordo-campo);
  border-radius: 0;
  padding: 0.7em 0.1em;
  width: 100%;
}
.campo textarea { resize: vertical; }

/* ── Le etichette flottanti ────────────────────────────────────────────────
   ⚠️ BLOCCO GEMELLO, e la copia è il punto: questo pezzo esiste due volte
   identico — in demo-motion/demo.r1.css e in lavori/caso.css. Il modulo della
   chiusura è LO STESSO oggetto sulle due pagine (docs 17.2), e due copie che
   divergono sono un modulo che si comporta in due modi. Chi tocca una riga qui
   la tocca anche di là.

   COSA FA: l'etichetta parte al posto del testo, dentro al campo, e quando il
   campo prende il fuoco o contiene qualcosa si rimpicciolisce e sale nello
   spazio che il padding le tiene libero in cima.

   ZERO JAVASCRIPT, ed è una misura e non un risparmio: lo stato «contiene
   qualcosa» il browser lo sa già (`:placeholder-shown`), e saperlo da CSS vuol
   dire che è giusto anche nei tre casi in cui una classe scritta a mano dal
   JavaScript arriva tardi o non arriva — il riempimento automatico, il
   ricaricamento con i campi ripescati dal browser, e il ritorno indietro dalla
   cache di navigazione. Una versione a JavaScript avrebbe dovuto riascoltare
   tutti e tre; questa non ha niente da riascoltare.

   L'ETICHETTA RESTA UNA `<label for>` e non diventa un `placeholder`: un
   segnaposto sparisce mentre scrivi e non è un nome accessibile affidabile. Il
   `placeholder=" "` del markup accende solo `:placeholder-shown`: è uno spazio
   e non dice niente a nessuno.

   `campo--flottante` È UNA CLASSE CHE DICE SÌ. Il modo ovvio sarebbe stato
   escludere («tutti i campi tranne il consenso»), e regge finché il modulo non
   cambia: un controllo senza segnaposto — spunta, radio, select — soddisfa
   `:not(:placeholder-shown)` sempre, e con la logica per esclusione erediterebbe
   lo stato flottante in silenzio il giorno che lo si aggiunge. Qui un campo
   entra nel meccanismo solo se qualcuno ce lo ha scritto.

   `pointer-events: none` È DELIBERATO: senza, l'etichetta sta sopra il campo e
   il clic se lo prende lei. Con, il clic attraversa e arriva al campo — che è
   tutta l'area cliccabile che serve, perché l'etichetta ci sta sopra.

   `font-size: 1rem` (16 px) sui controlli NON È DECORATIVO: sotto i 16 px iOS
   ingrandisce la pagina da sé quando il campo prende il fuoco, e poi non la
   rimpicciolisce più. Era già così per eredità (`font: inherit` da `--t-body`);
   adesso è scritto, perché adesso è un vincolo.

   NIENTE SALTI DI ALTEZZA: l'etichetta è fuori dal flusso e fra i due stati
   cambiano solo `top`, `font-size` e colore. E l'etichetta è ancorata IN ALTO
   con un valore fisso, mai a `top: 50%`: quando la validazione appende
   `.campo__errore` il contenitore cresce, e con `50%` l'etichetta scenderebbe
   insieme a lui.

   CONTRASTI, sul bianco del campo: a riposo `--testo-tenue` #6B6B6B sta a
   5,33:1, da flottante `--viola-testo` #6B5C99 a 5,81:1. Tutti e due sopra il
   4,5:1, e il secondo conta doppio perché da flottante l'etichetta è a 12 px. */
.campo.campo--flottante > label {
  position: absolute;
  left: 0.1em;
  /* 1.6rem è il padding in cima del campo, cioè esattamente il punto in cui
     comincia quello che scrivi: a riposo l'etichetta sta sulla riga del testo. */
  top: 1.6rem;
  max-width: calc(100% - 0.2em);
  font-size: 1rem;
  font-weight: var(--w-normal);
  line-height: var(--lh-larga);
  color: var(--testo-tenue);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
  transition: top var(--m-corto) var(--e-out),
              font-size var(--m-corto) var(--e-out),
              color var(--m-corto) var(--e-out);
}
.campo.campo--flottante > input,
.campo.campo--flottante > textarea {
  font-size: 1rem;
  line-height: var(--lh-larga);
  /* Lo spazio in cima è quello in cui l'etichetta sale: senza, si
     sovrapporrebbe a quello che stai scrivendo. */
  padding: 1.6rem 0.1em 0.5rem;
}
.campo.campo--flottante > input:focus + label,
.campo.campo--flottante > input:not(:placeholder-shown) + label,
.campo.campo--flottante > textarea:focus + label,
.campo.campo--flottante > textarea:not(:placeholder-shown) + label {
  top: 0.15rem;
  font-size: 0.75rem;
  font-weight: var(--w-bold);
  color: var(--viola-testo);
}
/* ⚠️ I due pseudo del riempimento automatico stanno in DUE regole separate e
   non in coda alla virgolata qui sopra: un selettore sconosciuto invalida TUTTO
   l'elenco in cui si trova, e `:autofill` senza prefisso i motori vecchi non lo
   conoscono. Separati, chi non lo conosce butta via solo la riga sua.
   A cosa servono, visto che un valore riempito fa già scattare
   `:not(:placeholder-shown)`: all'ANTEPRIMA. Mentre si passa sopra una voce del
   menù di riempimento il testo si vede già nel campo ma `value` è ancora vuoto,
   quindi il segnaposto risulta ancora mostrato e l'etichetta grande resterebbe
   sopra il testo in anteprima. Il riempimento vero, quello confermato, funziona
   anche senza queste due regole: è stato provato. */
.campo.campo--flottante > input:-webkit-autofill + label {
  top: 0.15rem;
  font-size: 0.75rem;
  font-weight: var(--w-bold);
  color: var(--viola-testo);
}
.campo.campo--flottante > input:autofill + label {
  top: 0.15rem;
  font-size: 0.75rem;
  font-weight: var(--w-bold);
  color: var(--viola-testo);
}
/* Un campo riempito dal browser resta un campo di questo modulo: senza questa
   riga Chrome gli dipinge sopra il suo fondo azzurrino, che sotto una hairline
   viola si legge come un errore. Il testo resta il nostro, non il suo. */
.campo.campo--flottante > input:-webkit-autofill,
.campo.campo--flottante > input:-webkit-autofill:hover,
.campo.campo--flottante > input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 100px var(--bianco) inset;
  -webkit-text-fill-color: var(--testo);
  caret-color: var(--testo);
}
/* In errore l'etichetta prende il rosso del messaggio che le sta sotto: #A5281B
   sta a 7,19:1 sul bianco del campo. La virgolata nomina `input`/`textarea` non
   per vezzo ma per peso: le regole dello stato flottante qui sopra hanno una
   specificità di (0,3,2), e un `.campo--errore > label` secco (0,3,1) perderebbe
   proprio sul campo pieno, che è l'unico caso in cui un errore si vede. */
.campo.campo--flottante.campo--errore > input + label,
.campo.campo--flottante.campo--errore > textarea + label { color: #A5281B; }

@media (prefers-reduced-motion: reduce) {
  .campo.campo--flottante > label { transition: none; }
}
/* La hairline del campo si colora da sinistra quando il campo prende il fuoco:
   è l'unico movimento del modulo, e dice dove stai scrivendo. È lo stesso
   gesto dei filetti di `.caso-elenco`. */
.campo::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 1.5px;
  background: var(--viola);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 220ms var(--e-out);
  pointer-events: none;
}
/* Sui campi il rettangolo di focus è di troppo: il campo è già un rettangolo,
   e l'anello ne disegna un secondo appena fuori. L'indicatore qui è la barra
   sotto al campo, che si colora da sinistra e si ingrossa: sta sopra il 3:1
   richiesto e occupa più area di un bordo da 1px, che è la soglia di WCAG. */
.campo input:focus-visible,
.campo textarea:focus-visible { outline: none; }
.campo:focus-within::after { transform: scaleX(1); block-size: 3px; }
.campo:focus-within input,
.campo:focus-within textarea { border-bottom-color: var(--viola); }
/* La casella del consenso non ha una barra sotto: lì l'anello resta. */
.campo--consenso input:focus-visible { outline: 3px solid var(--viola); outline-offset: 3px; }
.campo--consenso::after { display: none; }

.campo--consenso {
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--s-1);
  margin-top: var(--s-2);
}
.campo--consenso input {
  /* 24px netti: sotto, il bersaglio non rispetta il minimo di WCAG 2.5.8. */
  inline-size: 24px;
  block-size: 24px;
  margin: 0;
  accent-color: var(--viola);
}
.campo--consenso label { font-weight: var(--w-normal); font-size: var(--t-small); color: var(--testo-tenue); }
/* Il messaggio di errore prende tutta la riga: dentro la colonna della
   checkbox ridisegnerebbe la griglia e staccherebbe la casella dalla sua
   etichetta. Non lo scrive nessuno finché il modulo non invia, e resta qui
   perché la pagina di un caso vero collegherà modulo.js, che lo scrive. */
.campo--consenso .campo__errore { grid-column: 1 / -1; }
.campo--errore input,
.campo--errore textarea { border-bottom-color: #C0392B; }
.campo__errore { color: #A5281B; font-size: var(--t-small); margin: 0.2rem 0 0; }

/* L'esca per i bot: fuori dallo schermo, mai display:none, che alcuni bot
   riconoscono. */
.esca { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.modulo .bottone { justify-self: start; margin-top: var(--s-2); }
.modulo__nota { margin: var(--s-1) 0 0; font-size: var(--t-small); color: var(--testo-tenue); }
.modulo__nota code { font-size: .95em; }

/* Il piede: quello della homepage nuova, che non è quello di style.css. Le
   differenze sono tre e si vedono: il filetto verde più sottile, i dati su
   quattro colonne uguali invece che su `auto-fit`, e i profili separati da una
   hairline invece che appoggiati al vuoto. */
.pie { padding-block: var(--s-5) var(--s-4); border-top: 1px solid var(--hairline); }
.pie__alto {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  padding-bottom: var(--s-3);
  margin-bottom: 0;
  border-bottom: 1.5px solid var(--verde);
}
.pie__alto p { margin: 0; }
.pie__dati {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-3);
  padding-top: var(--s-3);
  font-size: var(--t-small);
  color: var(--testo-tenue);
}
.pie__dati strong { color: var(--testo); }
.pie__dati a { color: inherit; }
@media (min-width: 720px) { .pie__dati { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.social {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin: var(--s-4) 0 0;
  padding: var(--s-3) 0 0;
  border-top: 1px solid var(--hairline);
}
.social a {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  text-decoration: none;
  font-size: var(--t-small);
  font-weight: var(--w-bold);
}
.social a:hover { color: var(--viola-testo); }

/* ── I SETTE PAREGGI ───────────────────────────────────────────────────────
   Sette dichiarazioni che `style.css` porta e la home NON ha. Non si
   sovrascrive un valore diverso: si SPEGNE una regola in più, e per farlo la
   si deve nominare. È il motivo per cui nella rev 6 il blocco «era già
   copiato» e a schermo non lo era.
   Ogni riga dice cosa si vedeva prima. */

/* 1. La textarea della home è alta cinque righe e basta (`rows="5"`);
      style.css:445 le impone 120 px di minimo, e il campo del messaggio
      risultava più alto di quello della home. */
.campo textarea { min-height: auto; }

/* 2. L'etichetta del consenso: style.css:459 la porta a interlinea 1,5, la
      home la lascia a 1,6 come tutto il resto del modulo. Su due righe di
      testo sono 3 px, ma il blocco chiude più stretto. */
.campo--consenso label { line-height: var(--lh-larga); }

/* 3-4. Il piede alto: style.css:483-491 spinge i due occhielli ai due estremi
      della riga (`justify-content: space-between`) e stacca il filetto verde
      con 32 px di margine. Sulla home stanno attaccati a sinistra con un gap
      di 24, e sotto il filetto non c'è margine ma il padding di `.pie__dati`.
      È la differenza più visibile del piede. */
.pie__alto { justify-content: flex-start; margin-bottom: 0; }

/* 5. I dati del piede: style.css:500 li porta a interlinea 1,7; sulla home
      restano a 1,6, cioè all'interlinea del corpo. Su quattro colonne di tre
      righe l'una fanno 12 px di altezza in più per colonna. */
.pie__dati { line-height: var(--lh-larga); }

/* 6. I paragrafi dentro i dati: style.css:502 li azzera, la home li lascia al
      ritmo dei paragrafi (`p { margin: 0 0 var(--s-2) }`). Si copia, anche se
      è un'inezia, perché il patto di questo riquadro è che una differenza sia
      un errore e non una scelta: chi confronta le due pagine non deve trovarne
      nemmeno una da spiegare. */
.pie__dati p { margin: 0 0 var(--s-2); }

/* 7. L'esito del modulo: la home lo tiene sempre in pagina, vuoto, con
      `role="status"`, e gli dà solo margine e corpo del testo; style.css:473 in
      più gli riserva `min-height: 1.5em`, cioè 24 px di vuoto permanente sotto
      il tasto Invia. Qui il messaggio non lo scrive nessuno (modulo.js non è
      collegato), quindi quei 24 px erano vuoto e basta. */
.modulo__esito { margin: var(--s-2) 0 0; font-size: var(--t-small); min-height: 0; }
.modulo__esito--ok { color: #1E7A4C; }
.modulo__esito--ko { color: #A5281B; }

/* ⚠️ L'UNICA COSA CHE NON SI COPIA, ed è misurata, non opinata. Sulla home il
   tasto «Invia» è l'unico `<button>` della pagina, e `demo.r1.css` non gli dà
   né `font-family` né `line-height`: un `<button>` NON eredita il carattere dal
   documento, quindi si prende il default del browser. Misurato con il DevTools
   Protocol sulla home: `font-family: Arial`, `line-height: normal`, alto 45 px,
   mentre i tre bottoni-link della stessa pagina sono Open Sauce, interlinea
   1,6, alti 41 e 52. È una svista della home, non una scelta: il marchio ha un
   carattere solo e il tasto che chiude il modulo non può essere l'unico pezzo
   di pagina in Arial. Qui `style.css` lo copre già con `font: inherit`, e NON
   si toglie: il nostro «Invia» è Open Sauce e alto 52, cioè uguale agli altri
   bottoni di questa pagina E ai tre bottoni-link della home.
   Prezzo: 7 px di differenza fra il nostro tasto e quello della home.
   ⚠️ VOCE PER IL MERGE DEL 22/09: aggiungere `font: inherit` a `.bottone` in
   `demo.r1.css`. Finché non è fatto, questa è l'unica divergenza non voluta fra
   i due blocchi, ed è dichiarata qui perché nessuno la «aggiusti» al contrario.
   Fine del secondo riquadro copiato. */

/* ══════════════════════════════════════════════════════ MOVIMENTO ═════════
   Il movimento condiviso sta in assets/css/motion.r1.css: il reveal, la
   maschera tipografica, il riempimento delle pill (.riempi), le regole di
   Lenis. Qui restano le cose che quel file non può sapere.
   ========================================================================= */

/* ── 1. La maschera dell'h1, in CSS puro ─────────────────────────────────────
   Sta sopra la piega, entrata.js è `defer`, e lo stato nascosto che arriva dopo
   il primo paint si vede come un lampo.
   ⚠️ Una `.riga` = una riga visiva, sempre: `overflow: clip` taglia la scatola,
   non la riga di testo, e un contenuto che va a capo dentro una `.riga` si
   sovrappone invece di nascondersi. */
@keyframes caso-parola-sale {
  from { transform: translateY(135%); }
  to   { transform: none; }
}
.mask--apertura .parola {
  animation: caso-parola-sale 1100ms var(--e-posa) both;
}
.mask--apertura .riga:nth-child(1) .parola:nth-child(2) { animation-delay: 100ms; }
.mask--apertura .riga:nth-child(2) .parola:nth-child(1) { animation-delay: 200ms; }
.mask--apertura .riga:nth-child(2) .parola:nth-child(2) { animation-delay: 300ms; }
.mask--apertura .riga:nth-child(2) .parola:nth-child(3) { animation-delay: 400ms; }
.mask--apertura .riga:nth-child(2) .parola:nth-child(4) { animation-delay: 500ms; }

/* ── 2. Il wipe delle immagini ───────────────────────────────────────────────
   `clip-path: inset(0 0 12% 0)` → `inset(0)`: sostituisce la dissolvenza, e su
   una foto vera scopre il quadro invece di schiarirlo. L'opacità resta 1
   sempre.
   La copertina non lo prende: è l'LCP, sta sopra la piega, e il wipe non deve
   partire prima che l'immagine sia decodificata.
   ⚠️ Lo stato nascosto sta SOTTO `.js-anima` e non nello stato base: senza
   JavaScript la pagina deve essere ferma e completa, non vuota. */
.caso-figura > img { transition: clip-path var(--m-lungo) var(--e-out); }
.js-anima .caso-figura.anima > img { clip-path: inset(0 0 12% 0); }
.js-anima .caso-figura.anima.dentro > img { clip-path: inset(0); }
/* Una riga porta al massimo due figure, quindi basta un passo di ritardo. */
.js-anima .caso-riga > .anima:nth-child(2) { transition-delay: 70ms; }

/* ── 3. I filetti degli elenchi che entrano ──────────────────────────────────
   Stessa regola del wipe e per la stessa ragione: senza JavaScript i filetti
   ci sono e basta. Con JavaScript partono da scaleX(0) e si scrivono da
   sinistra quando l'elenco entra in quadro, uno dietro l'altro. Non è un
   secondo tipo di movimento: è il gesto del filetto del campo, che il modulo
   della chiusura porta in pagina, riusato dove serve dire «questo elenco si
   sta scrivendo adesso».

   ⚠️ Rev 7: `:is(.caso-elenco, .caso-tempo)` e non due blocchi gemelli. Il
   binario della linea del tempo è lo stesso filetto, entra con lo stesso
   gesto e si spegne con le stesse regole: scriverlo due volte vorrebbe dire
   ricordarsi di aggiornarne due il giorno che cambia, e uno dei due sarebbe
   quello dimenticato sotto `prefers-reduced-motion`. */
.js-anima :is(.caso-elenco, .caso-tempo).anima > li::before { transform: scaleX(0); }
.js-anima :is(.caso-elenco, .caso-tempo).anima.dentro > li::before { transform: scaleX(1); }
.js-anima :is(.caso-elenco, .caso-tempo).anima.dentro > li:nth-child(2)::before { transition-delay: 70ms; }
.js-anima :is(.caso-elenco, .caso-tempo).anima.dentro > li:nth-child(3)::before { transition-delay: 140ms; }
.js-anima :is(.caso-elenco, .caso-tempo).anima.dentro > li:nth-child(4)::before { transition-delay: 210ms; }
.js-anima :is(.caso-elenco, .caso-tempo).anima.dentro > li:nth-child(n + 5)::before { transition-delay: 280ms; }

/* ── 3 bis. I due disegni che si scrivono ────────────────────────────────────
   Rev 8, richieste 4 e 6 del committente: i moduli 06 e 07 non devono più
   essere due figure ferme. La regola della casa resta quella di
   docs/rev3-motion.md: UN SOLO TIPO DI MOVIMENTO. Non se ne aggiunge uno: si
   riusa il gesto che la pagina ha già, il filetto che si scrive da un capo
   all'altro (`.caso-elenco > li::before`, `.campo::after`). Qui il filetto è
   un tratto di SVG e si scrive con `stroke-dashoffset`, che è lo stesso
   movimento sulla stessa cosa — una linea che arriva alla sua lunghezza.
   Quello che cambia fra i due, e che il committente ha chiesto fosse diverso,
   NON è il gesto: è la grammatica.

     06, LA MAPPA. Il tratto è curvo e chiuso. Il raggio esce dallo studio e
     i tre anelli si chiudono in ordine, dal più stretto al più largo: dice
     che un raggio si allarga a giri, che è il mestiere che il disegno mostra.
     I ritardi sono regolari (0, 220, 440 ms) perché in una mappa i giri sono
     equidistanti per costruzione.

     07, LA LINEA DEL TEMPO. Il tratto è dritto e non torna. I quattro binari
     si scrivono nella direzione in cui si legge e i ritardi CRESCONO — 0, 140,
     380, 760 ms — come crescono le attese scritte sopra i titoli: subito, il
     giorno dopo, dopo una settimana, poi più niente. L'ultimo è anche il più
     lento a scriversi (`--m-reveal` invece di `--m-lungo`): è l'attesa prima
     del silenzio. Qui il ritardo non è ritmo, è contenuto, ed è la ragione per
     cui il passo fisso di 70 ms degli elenchi non vale su questo blocco.

   ⚠️ Le lunghezze dei tratteggi sono le circonferenze VERE (2πr con r 56, 112 e
   168) e la lunghezza vera del raggio (√(119²+119²) = 168,3), arrotondate per
   eccesso: un valore più corto lascerebbe un buco nell'anello chiuso. Non si usa
   `pathLength`, che su `<circle>` non è dato per scontato su tutti i motori.
   ⚠️ Come per il wipe, lo stato di partenza sta SOTTO `.js-anima`: senza
   JavaScript il disegno è completo e fermo, non vuoto. */
.d-anello, .d-raggio { transition: stroke-dashoffset var(--m-reveal) var(--e-out); }
.js-anima .caso-disegno.anima .d-anello,
.js-anima .caso-disegno.anima .d-raggio { stroke-dashoffset: var(--d-lung); }
.js-anima .caso-disegno.anima.dentro .d-anello,
.js-anima .caso-disegno.anima.dentro .d-raggio { stroke-dashoffset: 0; }
.d-raggio      { --d-lung: 169; stroke-dasharray: 169; }
.d-anello--1   { --d-lung: 352; stroke-dasharray: 352; }
.d-anello--2   { --d-lung: 704; stroke-dasharray: 704; }
.d-anello--3   { --d-lung: 1056; stroke-dasharray: 1056; }
.js-anima .caso-disegno.anima.dentro .d-anello--1 { transition-delay: 0ms; }
.js-anima .caso-disegno.anima.dentro .d-anello--2 { transition-delay: 220ms; }
.js-anima .caso-disegno.anima.dentro .d-anello--3 { transition-delay: 440ms; }

/* I quattro ritardi della linea del tempo, che sovrascrivono il passo fisso
   degli elenchi. Vengono dopo il blocco 3 e hanno la stessa specificità: è
   l'ordine a decidere, ed è dichiarato qui perché non lo si scopra spostando
   una riga. */
.js-anima .caso-tempo.anima > li:nth-child(4)::before { transition-duration: var(--m-reveal); }
.js-anima .caso-tempo.anima.dentro > li:nth-child(2)::before { transition-delay: 140ms; }
.js-anima .caso-tempo.anima.dentro > li:nth-child(3)::before { transition-delay: 380ms; }
.js-anima .caso-tempo.anima.dentro > li:nth-child(4)::before { transition-delay: 760ms; }

/* ── 3 ter. E si riscrivono ogni volta che rientrano ─────────────────────────
   Rev 9. Il committente ha chiesto se i due disegni si possono mettere in loop.
   No: un movimento infinito su una pagina che si legge si porta dietro un
   comando di pausa (WCAG 2.2.2) e costa disegno continuo per sempre. Al suo
   posto si riscrivono ogni volta che la sezione rientra in quadro, e il perché
   sta per esteso in cima ad assets/js/disegni.r1.js.

   QUI SERVE UNA RIGA SOLA, e serve per non far vedere il contrario del disegno.
   Il file toglie `.dentro` quando il disegno è uscito del tutto, e togliere lo
   stato farebbe TORNARE INDIETRO l'anello lungo la sua transizione: mezzo
   secondo di tratto che si cancella. `.d-fermo` azzera le durate per il tempo
   di un fotogramma, che è quanto basta a riportare tutto al punto di partenza
   di colpo. Le durate le mette sempre qualcun altro — `--m-reveal` sugli
   anelli, `--m-lungo` sui filetti, e `.anima` da motion.r1.css sul blocco
   intero — quindi la si scrive con abbastanza peso da vincerle tutte e tre. */
.js-anima .d-fermo.anima,
.js-anima .d-fermo.anima .d-anello,
.js-anima .d-fermo.anima .d-raggio,
.js-anima .d-fermo.anima > li::before { transition: none; }

/* ── 4. I riempimenti dei bottoni ────────────────────────────────────────────
   ⚠️ Rev 7: QUESTO PEZZO È USCITO DA QUI e sta nel riquadro copiato verbatim
   dalla home, in cima al file. Fino alla rev 6 la forma del riempimento veniva
   da `.riempi` di motion.r1.css e il colore da qui: due metà, e la misura del
   bottone restava quella di `style.css`. Adesso il bottone è per intero quello
   della home — forma, misura, colore e riempimento — e la classe `.riempi`
   esce dal markup, perché sulla home non c'è: lì il `::before` sta dentro
   `.bottone`. `.riempi` resta in motion.r1.css per le altre pagine che la
   usano; questa non la usa più. */

/* ── 5. Spegnere tutto ───────────────────────────────────────────────────────
   `prefers-reduced-motion: reduce` non è una versione degradata: è la stessa
   pagina senza ingressi, cioè stato finale immediato. entrata.js si ferma da sé
   e `js-anima` non arriva, quindi il reveal e il wipe non esistono; motion.r1.js
   non accende Lenis e non nasconde la testata. Qui si spengono le cose che
   vivono in CSS puro, e le altre per sicurezza.
   ⚠️ tokens.css azzera le transizioni con `!important`, ma NON i `transform`
   che stanno nello stato di partenza: una regola che mette `scaleX(0)` senza
   transizione lascerebbe il filetto invisibile per sempre. Per questo ogni
   stato di partenza va disfatto a mano, qui sotto. */
@media (prefers-reduced-motion: reduce) {
  .mask--apertura .parola { animation: none; transform: none; }
  .js-anima .anima,
  .js-anima .anima.dentro,
  .js-anima .mask .parola {
    transform: none;
    transition: none;
    transition-delay: 0s;
  }
  .js-anima .caso-figura.anima > img,
  .js-anima .caso-figura.anima.dentro > img { clip-path: none; }
  .caso-figura > img { transition: none; }
  .js-anima :is(.caso-elenco, .caso-tempo).anima > li::before,
  .js-anima :is(.caso-elenco, .caso-tempo).anima.dentro > li::before {
    transform: none;
    transition: none;
    transition-delay: 0s;
  }
  .caso-elenco > li::before,
  .caso-tempo > li::before { transition: none; }
  /* Stessa trappola dei filetti, su un'altra proprietà: `tokens.css` azzera le
     transizioni ma non lo `stroke-dashoffset` dello stato di partenza, e un
     anello con l'offset a 1056 senza transizione resterebbe invisibile per
     sempre. Si disfa a mano, come tutto il resto. */
  .js-anima .caso-disegno.anima .d-anello,
  .js-anima .caso-disegno.anima .d-raggio,
  .js-anima .caso-disegno.anima.dentro .d-anello,
  .js-anima .caso-disegno.anima.dentro .d-raggio {
    stroke-dasharray: none;
    stroke-dashoffset: 0;
    transition: none;
    transition-delay: 0s;
  }
  .d-anello, .d-raggio { transition: none; }
  .campo::after { transition: none; }
  .testata { transition: none; }
  .testata::after { transition: none; }
  .testata__nav a::after { transition: none; }
  .testata--nascosta { transform: none; }
}
/* Con Save-Data il wipe non serve a niente: è mezzo secondo di lavoro della GPU
   per scoprire un'immagine che chi ha chiesto di risparmiare dati sta ancora
   scaricando. */
@media (prefers-reduced-data: reduce) {
  .js-anima .caso-figura.anima > img { clip-path: none; }
}

/* ── Stampa ───────────────────────────────────────────────────────────────── */

@media print {
  .testata { position: static; backdrop-filter: none; transform: none; }
  /* Il modulo non si stampa: su carta un campo da compilare non si compila, e
     sono 600 px di rettangoli vuoti in fondo al foglio. */
  .salta, .social, .modulo { display: none; }
  .caso-mod, .sezione { padding-block: 1.5rem; }
  .sezione--tenue { background: none; }
  .caso-testa { display: block; }
  .caso-figura, .caso-riga { break-inside: avoid; }
  .caso-elenco > li, .caso-tempo > li { break-inside: avoid; }
  .caso-disegno, .caso-annuncio__p, .caso-minuto { break-inside: avoid; }
  .caso-elenco > li::before { transform: none; }
  h2, h3, .occhiello, .caso-mod__titolo { break-after: avoid; }
  /* La nota di onestà non si stacca mai dalla figura che dichiara: su carta una
     dichiarazione a pagina voltata non dichiara niente. */
  .caso-nota { break-before: avoid; }
  .caso-figura > :first-child { max-height: 60vh; }
  .caso-copertina img { height: 8cm; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .8em; overflow-wrap: anywhere; }

  /* Niente movimento in stampa, e niente stato nascosto: una pagina stampata da
     un browser che ha `js-anima` addosso perderebbe le figure traslate. */
  .js-anima .anima,
  .js-anima .mask .parola { transform: none; }
  .mask--apertura .parola { animation: none; transform: none; }
  .js-anima .caso-figura.anima > img { clip-path: none; }
  .js-anima :is(.caso-elenco, .caso-tempo).anima > li::before { transform: none; }
  .js-anima .caso-disegno.anima .d-anello,
  .js-anima .caso-disegno.anima .d-raggio { stroke-dasharray: none; stroke-dashoffset: 0; }
}
