/* ── I caratteri, ospitati QUI ───────────────────────────────────────────────
 * ⚠️ Erano su `fonts.googleapis.com`, e non era solo una dipendenza: quel
 * collegamento manda a Google l'indirizzo IP di CHIUNQUE apra una pagina di
 * Argo — compresi il cantiere e l'ente di certificazione, che entrano da fuori.
 * Argo si vende come «tutto resta in UE», ed e' lo stesso vincolo per cui
 * `sorveglianza.py` rifiuta un DSN non europeo. Un font remoto lo smentiva a
 * ogni caricamento.
 *
 * ⚠️ E senza i caratteri sul disco l'offline non esiste: la pagina si aprirebbe
 * coi ripieghi di sistema, cioe' con un'altra faccia.
 *
 * Barlow Condensed e IBM Plex sono OFL: ospitarli e' permesso.
 * Solo `latin` e `latin-ext` — 14 file, 388 KB. Cirillico e vietnamita erano
 * altri 20 file per lingue che Argo non parla.
 * Si rifanno con `strumenti/prendi-caratteri.sh`.
 * ────────────────────────────────────────────────────────────────────────── */
/* latin-ext */
@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("caratteri/barlow-condensed-500-latin-ext.8c35f80d9e5a.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("caratteri/barlow-condensed-500-latin.24f826a7cf9c.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("caratteri/barlow-condensed-600-latin-ext.ee77e8f678d5.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("caratteri/barlow-condensed-600-latin.ba4513495282.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("caratteri/ibm-plex-mono-400-latin-ext.8450d5944de2.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("caratteri/ibm-plex-mono-400-latin.79936b18df9f.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("caratteri/ibm-plex-mono-500-latin-ext.fa8d8838b94a.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("caratteri/ibm-plex-mono-500-latin.b1c8a895f5fd.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url("caratteri/ibm-plex-sans-400-latin-ext.f0e2925b3fa6.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url("caratteri/ibm-plex-sans-400-latin.b2c9031d9fd6.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url("caratteri/ibm-plex-sans-500-latin-ext.f0e2925b3fa6.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url("caratteri/ibm-plex-sans-500-latin.b2c9031d9fd6.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-stretch: 100%;
  font-display: swap;
  src: url("caratteri/ibm-plex-sans-600-latin-ext.f0e2925b3fa6.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-stretch: 100%;
  font-display: swap;
  src: url("caratteri/ibm-plex-sans-600-latin.b2c9031d9fd6.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Il sistema visivo di Argo — nato dal marchio, non da un modello preso altrove.
 *
 * L'idea: le schermate di Argo somigliano ai DISEGNI che i suoi utenti guardano
 * tutto il giorno. Filetti sottili, scritte tecniche in maiuscolo, valori in
 * carattere a larghezza fissa, e il CARTIGLIO — il riquadro che sta in basso a
 * destra su ogni tavola, con commessa, revisione e data. Non e' decorazione: e'
 * l'oggetto piu' familiare del loro mestiere.
 *
 * ⚠️ Due mondi, di proposito:
 *   - L'INGRESSO e' scuro, come il marchio: e' la soglia, e si ricorda.
 *   - Il LAVORO sara' chiaro: dentro ci vanno i disegni, che sono carta bianca.
 *     Un disegno su fondo nero non si legge come lo legge chi lo stampa.
 */

:root {
  /* Dal marchio, misurati: non ce n'e' uno scelto a occhio. */
  --fondo:       #10202B;   /* blu-nero marino, il fondo dell'icona */
  --fondo-alto:  #16303F;   /* la superficie sollevata */
  --carta:       #F2EFE9;   /* bianco caldo, il segno dell'icona */
  --tenue:       #90A6B6;   /* testo secondario */
  --fioco:       #8496A6;   /* etichette, unita', note */
  /* ⚠️ Misurato, non scelto: #64798A dava **3,04:1** sulla superficie sollevata,
     sotto il 4,5:1 che l'AA chiede per il testo piccolo — e le ETICHETTE sono
     tutte a 13 px. Questo valore tiene la stessa tinta e la stessa saturazione e
     arriva a 4,51:1. Il conto si rifa' con /tmp/contrasto.py, e il criterio e'
     che la coppia peggiore (fioco su --fondo-alto) passi. */
  --linea:       #2B4459;   /* i filetti del disegno: righelli, separatori tenui */
  /* ⚠️ ⚠️ **IL CONTORNO NON E' UN FILETTO, e fino al 13.09.2026 avevano lo stesso
     colore.** `--linea` faceva due mestieri: il capello fra due righe dello
     stesso elenco — decorazione, come il reticolo — e il BORDO che dice dove
     finisce una scheda, un campo, un bottone che ha solo il contorno. Il secondo
     porta un'informazione, e WCAG 1.4.11 gli chiede 3:1 sui colori che ha
     accanto: qui #2B4459 faceva 1,64:1 sul fondo e 1,36:1 sul sollevato, sulla
     carta chiara #CBD5DA 1,30:1 e 1,43:1. Un campo si trovava perche' ci si
     ricordava dov'era.
     ⚠️ **Due token, e non un filetto piu' scuro.** Scurire `--linea` avrebbe
     scurito anche righelli e separatori: la carta da disegno sarebbe diventata
     una griglia di gabbie. Il filetto resta tenue; il contorno si vede.
     ⚠️ Chi non sa quale dei due scrivere sceglie `--contorno`: un bordo troppo
     visibile e' un difetto di gusto, uno invisibile e' un difetto di accesso.
     ⚠️ E sta SOTTO il testo piu' tenue (`--fioco`): un contorno che contrasta
     quanto una parola smette di essere un bordo e diventa una riga di
     scrittura. Il mandato proponeva #4E7086: misurato, 3,15:1 sul fondo ma
     **2,61:1 sul sollevato**, cioe' dentro una scheda il campo spariva di nuovo.
     Le due soglie, sui due fondi e nelle due tavolozze, le rimisura
     `prove/test_contrasto.py` a ogni corsa: i numeri qui sono note. */
  --contorno:    #5B7D93;   /* marino: 3,80:1 sul fondo, 3,14:1 sul sollevato */
  --reticolo-fine:    #16293607;  /* quasi invisibile: si sente, non si guarda */
  --reticolo-marcato: #1B33440F;
  --ossido:      #C4553F;   /* l'accento: la matita rossa sulle misure */
  --ossido-alto: #DC6E56;
  /* L'ossido e' un accento, non il fondo dei pulsanti: bianco su ossido fa
     4,45:1, sotto il 4,5 richiesto anche a 18px peso 600. Come
     TESTO sul marino fa 3,73:1. Serve una seconda voce per gli errori e i
     collegamenti — che sono testo piccolo e sono proprio le parole che chi
     sbaglia deve riuscire a leggere. */
  --ossido-testo: #D27D6C;
  /* ⚠️ L'hover deve contrastare PIU' del riposo, non meno. Al primo giro
     `a:hover` andava sull'ossido pieno (#C4553F): **3,09:1**, cioe' passare il
     dito sopra un collegamento lo rendeva MENO leggibile. La griglia lo dice
     esplicitamente — «compreso lo stato hover» — e il rilievo era giusto.
     Qui il riposo sta a 4,51:1 e l'hover a 6,04:1. */
  --ossido-vivo: #DD9C8F;
  /* ⚠️ L'ossido con del bianco sopra da' 4,45:1 — sotto i 4,5 richiesti, e il
     conto accanto alla voce del menù e' testo a 12 px, non il fondo di un
     bottone. Questo tono ne da' 6,58:1. Rilievo del revisore su E1b, misurato
     sui colori calcolati dal browser: la difesa che c'era guardava il TESTO
     delle voci e non il numero. */
  --ossido-fondo: #A33A26;
  /* ⚠️ L'hover del pulsante pieno. MISURATO, e prima non lo era da nessuno:
     bianco su `--ossido-alto` fa 3,28:1, cioe' il pulsante piu' importante
     della pagina passava sotto l'AA proprio nel momento in cui ci si sta per
     cliccare sopra. Il foglio la regola ce l'aveva gia' scritta due righe piu'
     su — «l'hover: 6,02:1, piu' del riposo» — e il pulsante pieno era l'unico
     posto dove andava al contrario, schiarendo. #8C3120 fa 8,15:1. */
  --ossido-cupo: #8C3120;
  /* ⚠️ **IL COLORE DEL TESTO DI UN AVVISO, e cambia con la superficie.**
     Misurato il 06.09.2026 sulla pagina d'ingresso SERVITA — che non estende il
     guscio, quindi non ha `body.lavoro` e resta sulla tavolozza scura: il
     messaggio che dice «hai sbagliato la password» usciva a **2,26:1**. Cioe'
     l'unica frase che quella pagina esiste per mostrare era quella che non si
     leggeva.
     La causa e' un token usato per il mestiere sbagliato: `.avviso` prendeva
     `--ossido-fondo`, che si chiama «fondo» perche' e' un FONDO — giusto come
     testo sulla carta chiara, illeggibile sul marino. Qui il ruolo si dichiara
     una volta e ogni tavolozza lo riempie col proprio tono. */
  --avviso-testo: var(--ossido-testo);
  --verde:       #4E9A78;   /* fatto — bordi e fondi */
  /* ⚠️ Il verde per il TESTO e' un altro: #4E9A78 su una superficie sollevata
     sta a 4,07:1, sotto il 4,5 che serve. Misurato, non stimato. */
  --verde-testo: #78C7A2;   /* 8,30:1 sul fondo, 6,86:1 sul sollevato */
  --ambra-testo: #C79A3E;   /* 6,43:1 sul fondo scuro */
  --ambra:       #C79A3E;   /* da guardare */

  --tocco: 48px;            /* ⚠️ il bersaglio minimo: a bordo si tocca CON I GUANTI */
  --tocco-legame: 44px;     /* un titolo o una cella non si ingrossano fino a 48 */
  /* ⚠️ ⚠️ **LA MISURA DI LETTURA, e non e' «65 caratteri» scritti a mano.**
     `1ch` e' la larghezza della cifra ZERO, che in IBM Plex Sans e' piu' larga
     della media delle lettere: misurato il 06.09.2026 contando i caratteri che
     cadono su ogni riga resa, `53ch` da' **71 caratteri** — dentro la banda di
     lettura 45-75 — mentre `68ch` ne dava 94 e `78ch` ne dava 101.
     ⚠️ Il numero sta QUI e una volta sola: quattordici regole del foglio
     portavano quattordici numeri diversi, tutti scelti credendo che `ch` fosse
     un carattere, e tutti sbagliati per eccesso del 30% circa. Un numero che si
     ricopia e' un numero che si sbaglia.
     ⚠️ E si RIMISURA: `prove/test_misura_di_lettura.py` rende ogni regola del
     foglio che dichiara una misura in `ch` e conta i caratteri sullo schermo. */
  --misura-di-lettura: 51ch;
  --filetto: 1px;
  /* ⚠️ L'altezza del ponte era scritta a mano in QUATTRO punti — la sua
     `min-height`, il tetto del banco, e due volte nella fiancata. Quattro copie
     dello stesso numero sono quattro occasioni di cambiarne tre. */
  --ponte: 62px;

  /* ── LA SCALA DEI CORPI ───────────────────────────────────────────────────
   * ⚠️ **Misurato l'08.09.2026 sulle pagine SERVITE: erano VENTI corpi
   * distinti** — 11 12 13 13,5 14 14,4 14,5 15 15,2 16 16,8 17 18 18,7 19 20
   * 21 24 25 32. I sei con la virgola non sono decisioni di nessuno: sono `em`
   * e `%` moltiplicati dentro a un annidamento, cioe' il corpo di un testo
   * deciso da DOVE sta invece che da COSA E'. Fra 13,5 e 14 non c'e' una
   * differenza che qualcuno possa vedere: c'e' solo l'assenza di una scelta.
   *
   * Qui i gradini sono otto, interi, e ogni regola del foglio ne cita uno.
   * ⚠️ `--scala-dei-corpi` non serve al foglio — nessuna regola la legge.
   * Serve al CANCELLO, che rifiuta qualunque corpo reso non sia un gradino.
   * Un elenco che nessuno controlla torna a venti da solo: e' successo qui.
   */
  --t-nota:     13px;   /* unita', note a margine — mai un'informazione da sola */
  --t-minuto:   14px;   /* etichette dense, intestazioni di tabella */
  --t-piccolo:  15px;   /* testo secondario, il sottotitolo di una riga */
  --t-corpo:    16px;   /* il testo */
  --t-voce:     18px;   /* voci di elenco, comandi, sottotitoli */
  --t-terzo:    21px;   /* h3 */
  --t-secondo:  25px;   /* h2 */
  --t-primo:    31px;   /* h1 */
  --t-cifra:    38px;   /* la sola cifra che una schermata mette in mostra */
  --scala-dei-corpi: 13, 14, 15, 16, 18, 21, 25, 31, 38;

  /* ── LA SCALA DEGLI SPAZI ─────────────────────────────────────────────────
   * ⚠️ Lo spazio dice il RAGGRUPPAMENTO: stretto dentro un gruppo, largo fra
   * due gruppi. Con quattordici valori scritti a mano — 6, 10, 13, 14, 18, 20,
   * 22, 26, 28 — non lo dice piu': due cose lontane 14 px e due lontane 18
   * sembrano lontane uguale, e chi guarda smette di fidarsi della distanza.
   * Base 4. Sette gradini, e nessuna regola nuova ne inventa un ottavo.
   */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s6: 24px; --s7: 32px; --s8: 48px;

  /* ── ⚠️ LE RICETTE FUORI DALLA SCALA, DICHIARATE QUI ──────────────────────
   * Il mandato UX98 le vuole «dichiarate, non sparse», e il giudizio 8,9
   * (rilievo 8) ha detto dove: l'elenco stava dentro la PROVA, cioe' fuori dal
   * posto in cui le si incontra. Sta qui, e `test_gli_SPAZI_passano_tutti_dalla
   * _SCALA` lo LEGGE da qui: una ricetta che sparisce dal foglio e resta scritta
   * qui e' una prova rossa, e uno spazio fuori scala senza la sua riga qui pure.
   * Forma, una per riga: RICETTA · <selettore> · <proprieta'> · <perche'>
   *
   * RICETTA · .solo-lettori · margin · la ricetta del «si sente, non si vede»: una scatola di 1 px tirata fuori dal flusso, e il margine negativo che la toglie anche da li'. I tre numeri sono lo stesso numero.
   * RICETTA · .nascosto · margin · la stessa ricetta, con clip rect(0 0 0 0) per i browser vecchi
   * RICETTA · .visivamente-nascosto · margin · la stessa ricetta, terza copia
   * RICETTA · .rotta > .macro > p.macro-nome · margin · la stessa ricetta: sulla plancia il nome della macro resta per chi ascolta e sparisce per chi guarda
   * RICETTA · .intestazione .etichetta > a · padding-block · il BERSAGLIO allargato: 14 + 20 + 14 = 48, il tocco, senza alzare la riga
   * RICETTA · .intestazione .etichetta > a · margin-block · e il margine negativo che restituisce alla riga l'altezza che aveva
   * RICETTA · mark.da-argo, mark.non-verificato, mark.dalla-domanda, mark.tolto · padding · in em e non in px: l'evidenziato respira in proporzione al testo che evidenzia, a qualunque corpo
   * RICETTA · .spiegazione-capitoli .elenco-forfait · padding-left · il rientro di un elenco si misura in em: e' la larghezza del suo segno, non uno spazio del reticolo
   * RICETTA · .capitolo-spiegato .famiglie-spiegate ul · padding-left · lo stesso rientro, stessa ragione
   * RICETTA · .capitolo-spiegato .voci-principali, .capitolo-spiegato .famiglie-spiegate, .capitolo-spiegato .motivazioni-integrali, .capitolo-spiegato .punti-deboli · padding-left · lo stesso rientro, stessa ragione
   * RICETTA · .capitolo-spiegato .progettazione-voci · padding-left · lo stesso rientro, stessa ragione
   */
  /* ⚠️ UX98 (18.09.2026): I RAGGI SONO QUATTRO, PER RUOLO. Il foglio dice «i
   * disegni non hanno angoli tondi» e aveva dodici raggi scritti a mano su 49
   * dichiarazioni (8, 0, 999, 6, 4, 10, 2, 7, 3 e tre composti): due angoli
   * quasi uguali che non lo sono dicono che nessuno ha deciso. Adesso: spigolo
   * vivo (disegni, campi, comandi di solo contorno), 4 (tessere, riquadri, i
   * piccoli), 8 (pieghe, allegati, le bolle), pillola. Il passaggio e' stato
   * fatto per VALORE — 2 e 3 a 4; 6, 7, 10 e 12 a 8 — e va rivisto per ruolo a
   * occhio. Lo tiene fermo `test_i_RAGGI_sono_quattro_e_passano_dai_token`.
   * ⚠️ Le OMBRE no, e per una ragione misurata: due delle cinque forme portano
   * un colore di tavolozza (`--ossido-vivo`, `--contorno`), e un token scritto
   * qui risolverebbe quel colore sulla RADICE, non su `body.lavoro` che lo
   * ridefinisce — la stessa trappola dei token dichiarati in una tavolozza sola. */
  --raggio-0: 0;  --raggio-1: 4px;  --raggio-2: 8px;  --raggio-pieno: 999px;
  /* ⚠️ UX98 (18.09.2026): TRE MISURE CHE NON SONO SPAZIO, e per questo non
   * stanno nella scala. Ognuna e' accoppiata a qualcos'altro nel foglio: un
   * numero scritto a mano in UNO dei due posti li fa scivolare senza rumore.
   * • `--segno` e' il SEGNO che dice «questo conta»: la barra dell'avviso, il
   *   filetto di `aria-current`, il bordo dell'ambra. Venticinque dichiarazioni
   *   e tre imbottiture che gli si allineano (`calc(var(--s3) + var(--segno))`).
   * • `--casella-scelta` e' il LATO della casella di spunta: la nota sotto
   *   l'etichetta rientra di quel lato piu' un gradino, e la casella lo porta due
   *   volte (larghezza e altezza), in tre punti del foglio.
   * • `--colonna-misura` e' la colonna della misura sul telefono: la riga
   *   accanto vale `calc(100% - var(--colonna-misura))`. Erano due 58 sciolti. */
  --segno: 3px;
  --casella-scelta: 26px;
  --colonna-misura: 58px;
  /* ⚠️ UX98 (18.09.2026): LE OMBRE SONO TRE, PER RUOLO — piu' un filetto che
   * si disegna con l'ombra e non e' un'ombra. Erano cinque forme scritte a mano
   * e nessun token: `box-shadow` e' la proprieta' con cui si inventa la
   * profondita' a occhio, e due sollevamenti diversi dicono due piani diversi.
   * • `--ombra-tavola`  la tavola sollevata della soglia (l'unico sollevamento
   *   vero del prodotto: le pagine di lavoro sono piatte, e restano piatte).
   * • `--ombra-premuto`  l'anello interno del comando premuto: non sposta
   *   niente al clic, dove un bordo vero muoverebbe la riga.
   * • `--ombra-acceso`   il secondo pixel del bordo del filtro acceso (D60: il
   *   filtro acceso si riconosce dal BORDO, non dal fondo).
   * ⚠️ IL COLORE NON STA NEL TOKEN, sta al punto d'uso — `var(--ombra-premuto)
   * currentColor`. Un token di `:root` che contenesse `var(--ossido-vivo)`
   * risolverebbe quel colore SULLA RADICE e non su `body.lavoro`, che lo
   * ridefinisce: e' la trappola gia' scritta accanto ai raggi. Il token porta la
   * forma (il ruolo), la tavolozza porta il colore.
   * ⚠️ E il quarto NON e' un'ombra: e' il filetto a destra della colonna
   * ferma, disegnato con `box-shadow` perche' con `border-collapse: collapse` i
   * bordi li dipinge la tabella e non seguono la cella appiccicata (misurato).
   * Ha il nome di cio' che fa, non di come e' fatto.
   * ⚠️ ⚠️ E DAL GIRO 3 (18.09) IL NOME NON BASTA PIU'. Il revisore: «e' di fatto
   * una quarta ombra fuori dalla famiglia; il ≤ 3 e' rispettato per il nome, non
   * per il numero». Adesso la prova conta la GEOMETRIA: solleva chi ha una
   * sfocatura, chi e' esterna, chi e' spostata su tutti e due gli assi. Questo
   * e' `inset`, senza sfocatura, fermo sull'asse verticale: non puo' dire
   * «questo e' piu' in alto» comunque lo si chiami. Mettici un `blur` e la
   * prova cade. */
  --ombra-tavola: 0 30px 70px -34px #000, 0 0 0 6px #0D1A23;
  --ombra-premuto: inset 0 0 0 2px;
  --ombra-acceso: inset 0 0 0 var(--filetto);
  --filetto-della-colonna-ferma: inset calc(-1 * var(--filetto)) 0 0;
  /* ⚠️ UX98 giro 3 (18.09), rilievo 4 del giudizio 7,5 · IL GRADINO SOTTO IL
   * PONTE DOPO UN SALTO D'ANCORA. `--s4` e un filetto: il filetto e' il pixel
   * che lo scorrimento si mangia. Il browser ferma lo scorrimento sul pixel
   * intero, e con un bersaglio a una quota frazionaria lo porta SU: misurato
   * dal giudice 15,9 px a 360 e 15,6 a 1440 al posto di 16, con la regola
   * giusta per costruzione. Col filetto il gradino misura fra 16 e 17. */
  --gradino-dell-ancora: calc(var(--s4) + var(--filetto));
}

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

a { color: var(--ossido-testo); }
/* ⚠️ ⚠️ **`:not(.azione):not(.salta)` — perche' questa regola RIDIPINGE
 * L'INCHIOSTRO E LASCIA LA CARTA.** Vale per i legami dentro il testo, che
 * stanno sul fondo della pagina. Un legame che porta il PROPRIO fondo — un
 * comando pieno, il salto al contenuto — riceveva un colore scelto per la carta
 * e finiva su rosso scuro.
 * ⚠️ Misurato il 09.09.2026 sulla superficie chiara, dove `--ossido-vivo` e'
 * `#A04332` e `--ossido-fondo` e' `#A33A26`: **1,05:1**, cioe' praticamente lo
 * stesso colore. Il bianco che quegli elementi hanno a riposo fa **6,58:1**.
 * · «Salta al contenuto» e' la PRIMA fermata della tastiera su ogni pagina:
 *   a fuoco e sotto il mouse spariva.
 * · `a.azione` faceva **1,30:1** negli stessi stati — `.azione:hover` cambia il
 *   FONDO e non l'inchiostro, quindi la regola generica glielo ridipingeva.
 * ⚠️ E' la terza volta che questa stessa regola colpisce un elemento con la sua
 * carta (dopo `.filo a` e l'anello di `:focus-visible`, corretti il 06 e
 * l'08.09). La forma e' sempre quella: **una regola che cambia UNA delle due
 * meta' di un contrasto va scritta per gli elementi di cui conosce anche
 * l'altra meta'.**
 * ⚠️ E bloccava la condizione 5 di `rilascia-argo.sh` per QUALUNQUE ramo: il
 * giro sano dei sabotaggi pretende ZERO guasti, e questo c'era. */
/* ⚠️ ⚠️ **`:where()` E NON `:not()`, e la differenza mi e' costata un giro.**
   Scrivendo `a:not(.azione):not(.salta):hover` avevo alzato la specificita' da
   (0,1,1) a **(0,3,1)** — ogni `:not()` conta come una classe. La regola generica
   ha cosi' cominciato a BATTERE i componenti che prima la battevano:
   `.lenti .lente.scelta` e' (0,3,0), e sul passaggio del mouse la sua scritta
   bianca diventava `--ossido-vivo` sul proprio fondo `--ossido-cupo` — **1,30:1**.
   Cioe' la correzione contro «l'inchiostro ridipinto» aveva RESO PIU' FORTE la
   regola che lo ridipinge.
   `:where()` contribuisce **zero** specificita': l'esclusione resta e il peso
   torna quello di partenza, (0,1,1), sotto a chiunque porti la propria carta.
   ⚠️ E questo dice anche che l'elenco `.azione`, `.salta` non deve crescere: con
   `:where()` un componente che dichiara il proprio colore vince da se'. **Una
   difesa scritta come elenco di eccezioni invecchia; scritta come peso, no.** */
a:where(:not(.azione):not(.salta)):hover { color: var(--ossido-vivo); }
/* ⚠️ ⚠️ **L'ANELLO NON E' `currentColor`, ed e' la causa che stava sotto il
 * difetto del salto al contenuto.** Un contorno del colore del testo dell'elemento
 * lega una soglia di NON-testo (3:1) al colore di un testo, e per di piu' misurato
 * sul fondo sbagliato: l'anello si disegna FUORI, sulla pagina, non sul fondo del
 * legame. Un legame bianco su fondo rosso — il salto al contenuto — dava cosi' un
 * anello bianco sulla carta chiara: **1,15:1**, misurato sul servito il
 * 06.09.2026. Non era un caso isolato ma una regola che aspettava il caso.
 * ⚠️ `var(--carta)` e' l'inchiostro della tavolozza attiva ed e' gia' cio' che
 * usano tutte le altre regole di fuoco del foglio: qui si smette di essere
 * l'eccezione. Misurato dopo: 14,48:1 su tutt'e due le superfici. */
a:focus-visible { outline: 2px solid var(--carta); outline-offset: 2px; }
/* ⚠️ **UN LEGAME DENTRO UN AVVISO STA SU UN'ALTRA CARTA, e `--ossido-testo` era
 * misurato su quella normale.** Il fondo di `.avviso` e' l'ossido al 12%: sopra
 * quel velo il legame «Scrivila adesso» usciva a **3,44:1** — misurato sul
 * servito a 360 px l'08.09.2026, sulla pagina del preventivo. E' lo stesso
 * errore di forma che il 06.09 aveva colpito il TESTO dell'avviso: un colore
 * scelto su una superficie e usato su un'altra. `--avviso-testo` esiste gia'
 * per questo — ogni tavolozza ci mette il tono che regge sulla propria carta —
 * e qui lo prende anche il legame, non solo la frase attorno. */
.avviso a { color: var(--avviso-testo); text-decoration-thickness: from-font; }
/* ⚠️ UX98 (18.09.2026): AL PASSAGGIO UN TESTO SI LEGGE MEGLIO, MAI PEGGIO. Qui
 * l'ossido vivo faceva 5,47:1 contro i 7,11:1 del riposo (lavoro, sul fondo): il
 * dito che arriva trovava la parola piu' sbiadita. Il passaggio va alla carta,
 * il tono piu' scuro della scala; lo tiene fermo
 * `prove/test_ux98_disegno_comune.py::test_il_PASSAGGIO_non_rende_meno_leggibile_un_TESTO`. */
.avviso a:hover { color: var(--carta); }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--fondo);
  color: var(--carta);
  font: 16px/1.6 "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* ── Le tre voci della tipografia ─────────────────────────────────────────
 * Condensata maiuscola per le ETICHETTE: e' la scrittura dei cartigli.
 * Plex Sans per il testo. Plex Mono per i VALORI: sigle, revisioni, misure —
 * cose che si leggono in colonna e devono incolonnarsi.                    */
.etichetta {
  font-family: "Barlow Condensed", "IBM Plex Sans", sans-serif;
  font-weight: 600;
  font-size: var(--t-nota);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fioco);
}
.valore {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
}

/* ── I TITOLI: il LIVELLO decide come si vedono ────────────────────────────
 * ⚠️ **Misurato l'08.09.2026 sulle pagine servite, ed era rotto in tre modi.**
 * Il foglio non aveva NESSUNA regola di base per `h1`…`h4`: c'erano solo regole
 * su casi particolari, e dove non arrivavano vinceva il predefinito del
 * browser. Risultato, sulle stesse pagine:
 *   · `h1` usciva in DUE corpi (24 px e 32 px) — cioe' lo stesso livello si
 *     vedeva in due modi;
 *   · `h2` in QUATTRO (13, 19, 20 e 24 px) e in DUE famiglie, e a 24 px era
 *     grande quanto un `h1`: un titolo di sezione poteva essere piu' importante
 *     del titolo della pagina;
 *   · `h2` a 13 px era piu' PICCOLO del testo che gli sta sotto.
 * Un livello che non si vede non e' una gerarchia: e' una decorazione. Chi
 * legge si orienta con la dimensione, non con l'HTML.
 *
 * La regola, da qui in poi: il livello decide corpo, famiglia e peso.
 *   h1, h2 → Condensata: sono i titoli del FOGLIO, la scritta del cartiglio.
 *   h3, h4 → Plex Sans: sono titoli DENTRO il testo, e si leggono come testo.
 * Le eccezioni dichiarate (una riga d'elenco, una scheda) restano e vincono per
 * specificita': sono decisioni, non buchi.
 * ⚠️ `.etichetta` continua a vincere quando un titolo E' un'occhiello — quello
 * e' un ruolo, non un livello, ed e' scritto una riga piu' su.
 */
h1, h2, h3, h4 {
  margin: 0 0 var(--s3);
  /* ⚠️ 1,15: sotto, le maiuscole accentate della condensata si toccano con la
     riga sopra — misurato su «PERCHÉ» a 31 px. */
  line-height: 1.15;
  text-wrap: balance;
}
h1, h2 { font-family: "Barlow Condensed", "IBM Plex Sans", sans-serif; font-weight: 600; }
h3, h4 { font-family: "IBM Plex Sans", system-ui, sans-serif; font-weight: 600; }
h1 { font-size: var(--t-primo);   letter-spacing: .03em; }
h2 { font-size: var(--t-secondo); letter-spacing: .02em; }
h3 { font-size: var(--t-terzo);   letter-spacing: 0; }
h4 { font-size: var(--t-voce);    letter-spacing: 0; }

/* ── Il foglio: fondo a griglia da carta millimetrata, quasi invisibile ─── */
.foglio {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--s6);
  /* Carta millimetrata: reticolo fine, e una linea marcata ogni cinque — come la
     carta vera. ⚠️ Al primo giro era un reticolo da 96px in tinta piena: sembrava
     una fantasia da fondale, non carta da disegno. Qui il fine e' quasi invisibile
     e il marcato appena percettibile: si sente, non si guarda. */
  background-image:
    linear-gradient(var(--reticolo-fine) var(--filetto), transparent var(--filetto)),
    linear-gradient(90deg, var(--reticolo-fine) var(--filetto), transparent var(--filetto)),
    linear-gradient(var(--reticolo-marcato) var(--filetto), transparent var(--filetto)),
    linear-gradient(90deg, var(--reticolo-marcato) var(--filetto), transparent var(--filetto));
  background-size: 18px 18px, 18px 18px, 90px 90px, 90px 90px;
  background-position: center;
}
.foglio > * { -webkit-mask-image: none; mask-image: none; }

/* ── La tavola: il riquadro dove si lavora ────────────────────────────── */
.tavola {
  width: 100%;
  max-width: 430px;
  background: var(--fondo-alto);
  border: var(--filetto) solid #34526B;
  box-shadow: var(--ombra-tavola);
}

/* ── Il cartiglio: la striscia in basso, come su ogni tavola vera ─────── */
.tavola > .corpo { padding: var(--s7) var(--s7) var(--s7); }

.cartiglio {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--s1) var(--s4);
  border-top: var(--filetto) solid var(--linea);
  padding: var(--s3) var(--s7) var(--s4);
}
.cartiglio .voce { display: flex; flex-direction: column; gap: var(--s1); }
/* ⚠️ `.tavola .cartiglio`, cioe' SOLO l'ingresso. Il cartiglio dell'ingresso ha
   due colonne e la seconda si legge a destra, come su una tavola vera; quello
   delle pagine di lavoro ne ha quattro, e la stessa regola gli allineava a
   destra la seconda e la quarta — «UTENTE admin» a destra e «REVISIONE» a
   sinistra, senza nessuna logica. Si vede solo guardando la pagina. */
.tavola .cartiglio .voce:nth-child(even) { text-align: right; }
.cartiglio .valore { font-size: var(--t-nota); color: var(--tenue); }

/* ── I campi ──────────────────────────────────────────────────────────── */
.campo { display: flex; flex-direction: column; gap: var(--s2); margin-bottom: var(--s4); }
.campo input {
  min-height: var(--tocco);
  padding: 0 var(--s4);
  background: var(--fondo);
  border: var(--filetto) solid var(--fioco);
  color: var(--carta);
  font: 16px/1 "IBM Plex Sans", sans-serif;   /* 16px: sotto, iOS ingrandisce da solo */
  border-radius: var(--raggio-0);                            /* i disegni non hanno angoli tondi */
}
/* ⚠️ Il fuoco NON e' rosso: il rosso qui vuol dire «guarda questo, c'e' un
   problema». Un campo che si illumina di rosso appena apri la pagina sembra un
   errore prima ancora che tu abbia scritto qualcosa. */
/* ⚠️ **TUTT'E TRE i campi, non solo l'`<input>`.** Il 06.09.2026 un `<select>`
 * dentro un `.campo` non era nominato da nessuna regola di fuoco: prendeva il
 * contorno nero del browser, che sulla tavolozza marina fa **1,39:1** — un
 * anello che non si vede sul comando che si sta usando. `<input>` e
 * `<textarea>` avevano ognuno la sua riga, `<select>` no, e nessuno se n'era
 * accorto perché nessuna prova guardava gli anelli. */
.campo input:focus-visible,
.campo select:focus-visible,
.campo textarea:focus-visible {
  outline: 2px solid var(--carta);
  outline-offset: 1px;
  border-color: var(--carta);
}
/* ⚠️ ⚠️ **UNA REGOLA SOLA PER TUTTI I SEGNAPOSTO, e prima erano TRE.**
   `.campo input`, `.chiedi-al-volo input`, `.scrivi textarea`: tre copie legate
   a tre contenitori, e il quarto campo non stava in nessuno dei tre. Il segnaposto
   di `input#cerca` — «titolo, codice del cantiere, nome del file» — restava col
   grigio PREDEFINITO del browser, `#757575`, che sulla carta fa **4,41:1**:
   sotto il 4,5 che l'AA chiede al testo piccolo, e nessuno l'aveva scelto.
   `--fioco` fa **4,98:1** ed e' tarato per tema, quindi vale anche sulla soglia
   scura senza una seconda dichiarazione.
   ⚠️ E' la forma gia' vista tre volte in due giorni: **una regola scritta N volte
   per N contenitori manca sempre il contenitore N+1.** Si scrive per la
   PROPRIETA' — «ogni segnaposto e' vestito da Argo» — non per i posti dove ci si
   e' ricordati di metterla.
   ⚠️ Emerso solo il 09.09, e non perche' fosse nuovo: la pagina della commessa
   interrompeva la misura prima di arrivarci, per la navigazione alta un pixel.
   **Un guasto che ferma il misuratore nasconde quelli che vengono dopo di lui.** */
/* ⚠️ ⚠️ **OGNI CAMPO E' VESTITO DA ARGO, ovunque sia — e prima non era vero.**
   Argo vestiva i campi con regole legate al CONTENITORE: `.campo input`,
   `.chiedi-al-volo input`, `.scrivi textarea`. Un campo fuori da quei gusci —
   e ce ne sono: i filtri delle lenti in `chiedi.html` usano
   `<label><span>…</span><input>` — restava vestito dal BROWSER: testo a
   13,33 px e **1,15:1** di contrasto, cioe' illeggibile, e nessuno l'aveva
   scelto.
   ⚠️ Non emergeva sulle pagine servite perche' quello stato si raggiunge solo
   con una lente attiva, che il banco non apre. L'ha trovato il CAMPIONARIO,
   facendo esattamente il mestiere per cui esiste: mostrare i componenti dove le
   pagine non arrivano. 86 guasti su 86 stavano li'.
   ⚠️ **`:where()` per non aggiungere specificita'**: cosi' questa regola vale
   solo dove non parla nessun altro, e `.campo input` continua a vincere. E'
   scritta sulla PROPRIETA' — «un campo si veste» — non sui posti in cui ci si e'
   ricordati di metterla, che e' la forma di difetto gia' pagata tre volte in due
   giorni (i segnaposto qui sotto, i pieghevoli, i contenitori che scorrono). */
input:where(:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="submit"]):not([type="button"]):not([type="range"]):not([type="color"])),
select,
textarea {
  color: var(--carta);
  background: var(--fondo-alto);
  border: var(--filetto) solid var(--fioco);
  border-radius: var(--raggio-0);
  min-height: var(--tocco);
  padding: var(--s2) var(--s4);
  font: var(--t-corpo)/1.4 "IBM Plex Sans", sans-serif;
}

/* ⚠️ E l'ANELLO DEL FUOCO per la stessa ragione: era dichiarato solo su
   `.campo input:focus-visible`, quindi un campo fuori da quel guscio prendeva
   l'anello predefinito del browser — **1,14:1** sulla soglia scura, contro il 3
   che un segno non testuale richiede. Chi gira con la tastiera non vedeva dove
   si trovava. `--carta` e' il segno su tutt'e due le superfici, quindi l'anello
   si vede di qua e di la' senza una seconda dichiarazione. */
/* ⚠️ Qui l'elenco delle esclusioni e' PIU' CORTO che per il testo, e non e'
   una svista: una spunta non ha testo da misurare, ma un anello del fuoco ce
   l'ha eccome. Copiando l'elenco dell'altra regola avevo tolto l'anello
   proprio a spunte e radio, che sulla soglia scura restavano a **1,14:1**.
   **Due esclusioni diverse per due proprieta' diverse: la stessa lista usata
   per tutt'e due e' giusta al massimo per una.** */
input:where(:not([type="hidden"]):not([type="submit"]):not([type="button"])):focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--carta);
  outline-offset: 1px;
}

::placeholder { color: var(--fioco); }

/* E12: una riga per area, le stesse tre colonne anche sul telefono. */
.matrice-aree { margin-block: 1.5rem; }
.area-del-ruolo {
  min-width: 0;
  margin: 0 0 1rem;
  padding: .5rem 0 1rem;
  border: 0;
  border-bottom: var(--filetto) solid var(--linea);
}
.area-del-ruolo legend { padding: 0; font-weight: 600; }
.livelli-area { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .5rem; }
.livelli-area label {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: var(--tocco);
  padding: .5rem .25rem;
  border: var(--filetto) solid var(--contorno);
  border-radius: var(--raggio-0);
  cursor: pointer;
}
.livelli-area label:hover,
.livelli-area label:has(input:checked) { border-color: var(--carta); }
.livelli-area label:has(input:focus-visible) { outline: 2px solid var(--carta); outline-offset: 2px; }
.livelli-area input[type="radio"] { width: 1.25rem; height: 1.25rem; min-height: 0; margin: 0; flex: 0 0 auto; }
.livelli-area span { overflow-wrap: anywhere; }

/* ── D64 · i tre livelli nel modulo della persona ─────────────────────────
 * Una riga per livello — il nome e la spiegazione dopo il trattino — non tre
 * colonne come la matrice: qui il testo e' lungo e a 360 px tre colonne
 * schiacciano le parole. Django rende i radio dentro un <div> per scelta:
 * `display: contents` lo toglie di mezzo, e la griglia vede le etichette.
 * ⚠️ Il radio e' largo `--tocco` come le caselle degli avvisi: il bersaglio
 * misurato dal cancello e' l'input, non l'etichetta. */
.livelli-persona { display: grid; gap: var(--s2); }
.livelli-persona > div { display: contents; }
.livelli-persona label {
  display: flex; align-items: center; gap: var(--s3);
  min-height: var(--tocco); padding: var(--s1) var(--s3);
  border: var(--filetto) solid var(--contorno); border-radius: var(--raggio-0); cursor: pointer;
}
.livelli-persona label:hover,
.livelli-persona label:has(input:checked) { border-color: var(--carta); }
.livelli-persona label:has(input:focus-visible) { outline: 2px solid var(--carta); outline-offset: 2px; }
.livelli-persona input[type="radio"] { width: var(--tocco); height: var(--tocco); min-height: 0; margin: 0; flex: 0 0 auto; }
/* Nella riga della persona i tre livelli stanno uno accanto all'altro, e il
 * numero del cellulare ha il suo campo con il suo pulsante. */
.gesti-persona .livelli-persona { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); }
.gesti-persona .livelli-persona form { display: contents; }
.gesti-persona .campo input[type="tel"] { min-height: var(--tocco); max-width: 14rem; }

button.entra {
  width: 100%;
  min-height: var(--tocco);
  margin-top: var(--s2);
  /* ⚠️ **`--ossido-fondo`, e cosi' sparisce un'esenzione su cui questo bottone
     si reggeva.** Il bianco sull'ossido pieno da' 4,45:1 — sotto il 4,5 dell'AA
     — e passava solo perche' il corpo era 19 px, cioe' «testo grande», dove la
     soglia scende a 3:1. Un'esenzione che dipende da UN PIXEL di corpo e' una
     norma rispettata per caso: l'08.09.2026, portando il bottone sulla scala
     (18 px), e' decaduta e due prove l'hanno presa. Rimettere il pixel sarebbe
     stato aggiustare il termometro. Qui il colore regge da solo, 6,58:1, e il
     corpo torna a essere una scelta di disegno invece di un vincolo di legge. */
  background: var(--ossido-fondo);
  color: #fff;
  border: none;
  border-radius: var(--raggio-0);
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600;
  font-size: var(--t-voce);
  letter-spacing: .1em;
  text-transform: uppercase;
  cursor: pointer;
}
button.entra:hover { background: var(--ossido-cupo); }
button.entra:focus-visible { outline: 2px solid var(--carta); outline-offset: 2px; }

/* ── L'avviso d'errore: dice cosa è successo e cosa fare ──────────────── */
.avviso {
  border-left: var(--segno) solid var(--ossido);
  /* ⚠️ Il fondo e' TINTO, non carta pura: il testo va misurato su QUESTO, non
     sul bianco. `--ossido-testo` ci da' 4,05:1 — sotto la norma — e il commento
     che diceva 4,96 contava sul fondo sbagliato. Rilievo di un revisore,
     calcolato dal browser sui colori risolti. Qui si usa il tono piu' scuro. */
  background: color-mix(in srgb, var(--ossido) 12%, transparent);
  /* ⚠️ Il RUOLO, non il tono: ogni superficie riempie `--avviso-testo` col
     proprio. Prima qui c'era `--ossido-fondo` fisso, giusto sulla carta e
     illeggibile sul marino — 2,26:1 sulla pagina d'ingresso servita. */
  color: var(--avviso-testo);
  padding: var(--s3) var(--s4);
  margin-bottom: var(--s4);
  font-size: var(--t-piccolo);
}

/* ⚠️ UX98 (16.09), rilievo S3 · IL RIEPILOGO DEGLI ERRORI STA IN CIMA.
 * Il modulo respinto partiva dalla cima della pagina e il primo errore stava
 * sotto lo schermo: il riepilogo lo dice qui, con i collegamenti ai campi.
 * Stessa veste dell'avviso: è un errore che chiede un gesto. */
.riepilogo-errori {
  border-left: var(--segno) solid var(--ossido);
  background: color-mix(in srgb, var(--ossido) 12%, transparent);
  color: var(--avviso-testo);
  padding: var(--s3) var(--s4);
  margin: 0 0 var(--s4);
}
.riepilogo-errori ul { margin: var(--s2) 0 0; padding-left: var(--s4); }
.riepilogo-errori a { color: inherit; }

/* ── Il segno in cima ─────────────────────────────────────────────────── */
.testata { display: flex; align-items: center; gap: var(--s4); margin-bottom: var(--s6); }
.testata svg { width: 46px; height: 46px; flex: none; }
.testata h1 {
  margin: 0;
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600;
  font-size: var(--t-primo);
  letter-spacing: .04em;
  line-height: 1;
}
.testata p { margin: var(--s1) 0 0; font-size: var(--t-minuto); color: var(--tenue); }

/* ── Il plotter: i filetti si disegnano, una volta sola, all'apertura ──── */
@media (prefers-reduced-motion: no-preference) {
  .tavola { animation: tira-il-filetto .45s ease-out both; }
  @keyframes tira-il-filetto {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
  }
}

/* ══════════════════════════════════════════════════════════════════════════
 * IL LAVORO — la superficie chiara
 *
 * L'ingresso qui sopra e' scuro perche' e' la soglia. Da qui in poi si sta su
 * CARTA: dentro ci vanno disegni, sigle, tabelle di targhette, cose che chi
 * lavora stampa e porta a bordo. Un disegno su fondo nero non si legge come lo
 * legge chi lo tiene in mano.
 *
 * ⚠️ Non e' un secondo sistema grafico: sono gli STESSI token con i ruoli
 * ribaltati. --carta resta «il segno», --fondo resta «il supporto». Cosi ogni
 * componente gia' scritto (campi, bottoni, cartiglio) funziona di la' e di qua
 * senza una riga in piu'.
 * ══════════════════════════════════════════════════════════════════════════ */
body.lavoro {
  /* ⚠️ I controlli NATIVI seguono la carta, non la soglia. `base.html` dichiara
     `<meta name="color-scheme" content="dark">` per l'ingresso scuro, e senza
     questa riga il browser disegnava sulla carta chiara caselle, bottoni dei
     file e lettori audio del tema SCURO: la casella VUOTA era un quadrato pieno
     grigio (rgb 59,59,59 su 251,250,247), e coi guanti «pieno» si legge
     «scelto». Audit UX del 15.09.2026, rilievo di sistema S4 su tredici
     pagine; misurato sulla lista cavi: luce della casella vuota 65/255.
     La conversazione, che ha la sua tavolozza doppia, lo ridice piu' avanti
     con piu' specificita' e vince. */
  color-scheme: light;
  --fondo:       #F2EFE9;
  --fondo-alto:  #FBFAF7;
  --carta:       #10202B;
  --tenue:       #45606F;
  --fioco:       #5F6F79;   /* 4,53:1 sulla carta: era #7A8C97, cioe' 3,04:1 */
  --ossido-testo: #B54C38;  /* 4,96:1: l'ossido pieno come testo si ferma a 3,88:1 */
  /* ⚠️ Sulla carta chiara l'avviso vuole il tono PIU' SCURO, e i due che
     sembravano bastare NON bastano — misurati dal browser sul fondo tinto vero,
     non su quello che i vecchi commenti supponevano:
       `--ossido-testo` (#B54C38)  3,43:1
       `--ossido-fondo` (#A33A26)  4,37:1   ← ci mancava poco, e «poco» e' sotto
       `--ossido-cupo`  (#8C3120)  vedi la prova, che lo ricalcola a ogni corsa
     Il commento che diceva 4,05 e quello che diceva 4,96 erano tutt'e due
     sbagliati: contavano su un fondo che l'avviso non ha. */
  --avviso-testo: var(--ossido-cupo);
  --ossido-vivo:  #A04332;  /* l'hover: 6,02:1, piu' del riposo */
  /* ⚠️ E QUI STA LA SUPERFICIE VERA delle lenti. `/chiedi/` vive dentro
     `body.lavoro`, che e' CHIARA: il verde e l'ambra da schermo scuro la'
     stanno a 1,92:1 e 2,48:1. Avevo misurato il mondo sbagliato, e la prova
     pure, perche' leggeva la prima definizione in `:root`. Rilievo di un
     revisore, ed era il difetto che si vede a occhio nudo. */
  --verde-testo: #186043;   /* 6,55:1 sul fondo chiaro, 7,20:1 sul sollevato */
  --ambra-testo: #7A570F;   /* 5,72:1 sul fondo chiaro, 6,29:1 sul sollevato */
  /* ⚠️ ⚠️ **`--ambra` NON ERA RIDICHIARATO QUI, e il filo ambra usava sulla carta
     chiara il valore tarato per il fondo SCURO** (#C79A3E): 2,25:1 sulla carta,
     cioe' sotto il 3:1 che WCAG 1.4.11 chiede a un bordo che porta informazione.
     Non l'ha creato il passaggio a `--contorno` del 13.09 — quello l'ha peggiorato
     da 1,73 a 1,39 nel confronto col bordo vicino, e cosi' l'ha reso visibile.
     ⚠️ E il filo NON PUO' vincere per luminanza contro un bordo neutro: scurendo
     l'ambra sale il contrasto sul fondo e SCENDE quello contro il contorno —
     convergono. Il massimo misurato e' 1,82:1, con nessun valore a 3. Per questo
     il riquadro si distingue per TINTA e AREA (il fondo tenue, sotto) e non per
     un filo di 1px che compete con un altro filo.
     ⚠️ Il tema scuro resta #C79A3E: li' fa 6,83:1 sul fondo ed e' giusto.
     ⚠️ Altri SEI token di colore non sono ridichiarati nel tema chiaro
     (--ossido, --ossido-alto, --ossido-cupo, --ossido-fondo, --ponte, --verde):
     e' una classe, non un caso. Censita il 13.09, non chiusa — ognuno va misurato
     sulla carta prima di toccarlo. */
  --ambra:       #A8740F;   /* 3,54:1 sulla carta, 3,89:1 sul sollevato */
  --linea:       #CBD5DA;   /* decorazione: 1,30:1 sul fondo, e per un righello va bene */
  /* Il contorno sulla carta: la stessa tinta ardesia del filetto, abbastanza
     scura da reggere 3:1 anche sul fondo, che e' il piu' scuro dei due. */
  --contorno:    #778A92;   /* carta: 3,14:1 sul fondo, 3,45:1 sul sollevato */
  --reticolo-fine:    #10202B08;
  --reticolo-marcato: #10202B12;
}

/* La conversazione regge entrambe le tavolozze. ``light-dark`` tiene ogni
   coppia nello stesso posto; il valore chiaro di riserva qui sopra resta
   utilizzabile anche da un browser che non conosce ancora la funzione. */
/* ⚠️ E la seguono anche le NOVE DOMANDE PRONTE (`.domanda-pronta`): sono la
   stessa area della conversazione, e dalla chat a una lente la tavolozza si
   ribaltava (audit UX del 15.09.2026, Opus S14). I contrasti delle lenti nel
   tema scuro sono misurati da `verifiche/ux-chiedi-quanti/schermata.py`. */
body.lavoro:has(> .banco > :is(.dialogo, .domanda-pronta)) { color-scheme: light; }
@supports (color: light-dark(#fff, #000)) {
  body.lavoro:has(> .banco > :is(.dialogo, .domanda-pronta)) {
    --fondo: light-dark(#F2EFE9, #10202B);
    --fondo-alto: light-dark(#FBFAF7, #16303F);
    --carta: light-dark(#10202B, #F2EFE9);
    --tenue: light-dark(#45606F, #90A6B6);
    --fioco: light-dark(#5F6F79, #8496A6);
    --ossido-testo: light-dark(#B54C38, #D27D6C);
    --ossido-vivo: light-dark(#A04332, #DD9C8F);
    --ossido-fondo: light-dark(#A33A26, #B84A34);
    --ossido-cupo: light-dark(#8C3120, #BC4C34);
    --avviso-testo: light-dark(#8C3120, #D27D6C);
    --verde-testo: light-dark(#186043, #78C7A2);
    --ambra-testo: light-dark(#7A570F, #C79A3E);
    --ambra: light-dark(#A8740F, #C79A3E);
    --linea: light-dark(#CBD5DA, #2B4459);
    --contorno: light-dark(#778A92, #5B7D93);
  }
}
:root[data-theme="dark"] body.lavoro:has(> .banco > :is(.dialogo, .domanda-pronta)),
body.lavoro[data-theme="dark"]:has(> .banco > :is(.dialogo, .domanda-pronta)) { color-scheme: dark; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) body.lavoro:not([data-theme="light"]):has(> .banco > :is(.dialogo, .domanda-pronta)) {
    color-scheme: dark;
  }
}

/* ── Il ponte: la barra in cima, sempre uguale, sempre nello stesso posto ── */
/* ⚠️ `fixed`, non `sticky`: `body.lavoro` e' alto una schermata e lascia
   uscire il banco dalla propria griglia quando la pagina e' lunga. Un elemento
   appiccicato li' si fermerebbe alla fine del `body`, esattamente come faceva la
   fiancata prima della correzione dell'08.09. Tolto dal flusso, il ponte conserva
   lo STESSO ingombro con il `padding-top` del corpo: 62 px, cioe' `--ponte`.
   Sul telefono il campo di Argo forma una seconda riga: il conto usa i due
   bersagli, l'imbottitura e il filetto che ne determinano davvero l'altezza,
   senza copiare un altro numero. */
body.lavoro {
  --ponte-reso: var(--ponte);
  padding-top: var(--ponte-reso);
}
/* ⚠️ ⚠️ **UX98 (18.09.2026): IL CONTO DIMENTICAVA IL GRADINO FRA LE DUE RIGHE.**
   Il conto diceva 109 (48 + 48 + 12 + 1) e il ponte reso ne misura 121 a 360,
   390 e 700 px: nello stesso `@media` la regola `.ponte { gap: var(--s3) }`
   (quella del marchio che cede la parola) viene DOPO `row-gap: 0` e lo riporta a
   12. Dodici pixel del contenuto finivano sotto il ponte su ogni pagina del
   telefono — la prima riga della plancia compresa — e ogni àncora con
   `scroll-margin-top` atterrava a 4 px dal ponte invece che a 16 (misurato sul
   servito, `verifiche/ux98-disegno-comune/`). Adesso il conto e' quello del
   reso: riga, gradino, riga, imbottitura, filetto. Lo tiene fermo
   `prove/test_ux98_disegno_comune.py`, che confronta il token con l'altezza
   RESA a otto larghezze. */
@media (max-width: 759px) {
  body.lavoro:has(> .ponte .chiedi-al-volo) {
    --ponte-reso: calc(var(--tocco) + var(--s3) + var(--tocco) + var(--s3) + var(--filetto));
  }
}
.ponte {
  position: fixed;
  inset: 0 0 auto;
  /* Sopra banco e fiancata (2), sotto il salto al contenuto (100) e qualunque
     sovrapposto: il ponte deve restare disponibile, non diventare un coperchio. */
  z-index: 10;
  display: flex;
  align-items: center;
  gap: var(--s4);
  padding: 0 var(--s4);
  min-height: var(--ponte);
  border-bottom: var(--filetto) solid var(--contorno);
  background: var(--fondo-alto);
}
.ponte svg { width: 30px; height: 30px; flex: none; }
.ponte svg g { stroke: var(--carta); }
.ponte .nome {
  /* ⚠️ Il segno e la parola sono un collegamento solo (07.09.2026): un bersaglio
     invece di due mezzi, e sul telefono la parola si nasconde restando a casa. */
  display: inline-flex; align-items: center; gap: var(--s3);
  min-height: var(--tocco);
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-secondo); letter-spacing: .04em; line-height: 1;
  /* ⚠️ Il marchio e' un collegamento alla scrivania, e senza queste due righe il
     browser lo dipinge del suo viola sottolineato: il nome del prodotto, in
     cima a ogni pagina, con lo stile predefinito di un link visitato. Si vede
     in mezzo secondo guardando la pagina, e non si vede affatto leggendo l'HTML. */
  color: inherit;
  text-decoration: none;
}
.ponte .nome:focus-visible { outline: 2px solid var(--carta); outline-offset: 3px; }
.ponte .azienda {
  padding-left: var(--s4); margin-left: var(--s1);
  border-left: var(--filetto) solid var(--linea);
  font-size: var(--t-minuto); color: var(--tenue);
}
.ponte .spinta { margin-left: auto; }
/* ⚠️ **I tre comandi che ci sono sempre, in un gruppo solo.** Vanno a capo tutti
   e tre o nessuno: a 360 px «Esci» finiva da solo su una riga sua, e un a capo
   che sembra un guasto e' peggio di una riga in piu'. */
.ponte .comandi { display: flex; align-items: center; gap: var(--s4); }
/* ⚠️ La barra non deve MAI sbordare: e' l'unica cosa presente in ogni pagina, e
   se esce di 20 px esce di 20 px ovunque. Misurato il 28.08 aggiungendo il
   cambio lingua: tutte e 11 le pagine passate da 390 a 410 px, e il controllo
   `gesto-larghezza.py` l'ha presa prima che la vedesse una persona.
   Il nome dell'azienda e' la prima cosa che cede: e' identico in ogni pagina di
   una sessione e sta anche nel cartiglio in fondo, mentre «EN» ed «Esci» fanno
   qualcosa. Prima si accorcia, poi sparisce. */
.ponte .azienda { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.chiedi-al-volo {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex: 1 1 320px;
  min-width: 180px;
  max-width: 460px;
}
.chiedi-al-volo input {
  flex: 1 1 auto; min-width: 0;
  /* ⚠️ `--tocco` e non un numero mio: a bordo si tocca CON I GUANTI, e la misura
     sta in un posto solo. Li avevo fatti a 38 px e il guardiano dei bersagli me
     l'ha detto prima che li vedesse una persona. */
  min-height: var(--tocco);
  padding: 0 var(--s3);
  color: var(--carta);
  background: var(--fondo);
  border: var(--filetto) solid var(--contorno);
  border-radius: var(--raggio-1);
  font: inherit; font-size: var(--t-piccolo);
}
.chiedi-al-volo input:focus-visible {
  outline: 2px solid var(--ossido);
  outline-offset: 1px;
  border-color: var(--ossido);
}
.chiedi-al-volo button {
  min-height: var(--tocco); padding: 0 var(--s4);
  color: var(--carta);
  background: transparent;
  border: var(--filetto) solid var(--contorno);
  border-radius: var(--raggio-1);
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-piccolo); letter-spacing: .07em; text-transform: uppercase;
  cursor: pointer;
}
/* ⚠️ UX98: al passaggio cambia il CONTORNO, non la parola — l'ossido faceva 4,51:1
   contro i 14,48:1 della carta a riposo (vedi `.avviso a:hover`). */
.chiedi-al-volo button:hover { border-color: var(--ossido); color: var(--carta); }
.chiedi-al-volo button:focus-visible { outline: 2px solid var(--ossido); outline-offset: 2px; }

/* ⚠️ Sotto i 700 px il bottone sparisce e resta il campo: si manda con l'invio.
   Il campo NON sparisce — e' il cuore del programma, e su un telefono a bordo e'
   il modo piu' veloce di chiedere qualcosa senza cercare la pagina giusta.

   ⚠️ E il campo va A CAPO, su una riga tutta sua. Misurato l'01.09 a 360 px:
   il ponte non stringe sotto i 461 — il campo ha un minimo di 180 px e «EN»,
   «Esci» e il marchio non hanno niente da cedere — e OGNI pagina scorreva di
   lato di 101 px. Il difetto era intermittente solo perche' due lavoranti su
   tre servivano ancora il guscio vecchio, senza la barra: al primo riavvio
   sarebbe diventato fisso. Una riga intera e' anche piu' onesta col pollice:
   il bersaglio e' largo quanto lo schermo. */
@media (max-width: 759px) {
  .ponte { flex-wrap: wrap; row-gap: 0; padding-bottom: var(--s3); }
  .chiedi-al-volo { order: 10; flex-basis: 100%; min-width: 0; max-width: none; }
  .chiedi-al-volo button { display: none; }

  /* ⚠️ **A 360 px cede la PAROLA del marchio, non un comando.** Col pulsante
     delle impostazioni la riga vuole 411 px e ne ha 320: senza questa regola la
     barra diventava di TRE righe — 155 px su 780 di schermo, un quinto del
     telefono occupato prima di qualunque contenuto.
     Cosa cede, in ordine: il nome dell'azienda (sotto i 600, e sta anche nel
     cartiglio), poi la parola «Argo» — che ha accanto il suo segno, resta il
     collegamento a casa e vale ancora 48 px. I tre comandi FANNO qualcosa e
     non cedono mai: e' la stessa scala di priorita' gia' scritta per il nome
     dell'azienda, con un gradino in piu'.
     Misurato dopo: riga da 348 px su 328 disponibili — ci sta, e se un giorno
     non ci stesse piu' andrebbe a capo il gruppo intero, che e' l'a capo
     decente. */
  .ponte { gap: var(--s3); padding-left: var(--s4); padding-right: var(--s4); }
  .ponte .nome .parola { display: none; }
  .ponte .nome { min-width: var(--tocco); justify-content: center; }
  .ponte .spinta { display: none; }
  .ponte .comandi { margin-left: auto; gap: var(--s2); }
  /* ⚠️ **I TRE COMANDI PESAVANO PIU' DI QUELLO CHE VALGONO.** «Impostazioni»,
   * «EN» ed «Esci» erano disegnati come tre pulsanti col contorno, in cima a
   * ogni pagina: sul telefono, dove il contorno e' quasi tutto il segnale, la
   * cosa piu' in vista della schermata finiva per essere USCIRE dal programma.
   * Qui restano tutti e tre, restano larghi 48 px, e smettono di gridare: il
   * contorno se lo tiene chi ha qualcosa da difendere.
   * ⚠️ **E' un guadagno di GERARCHIA, non di spazio: il numero non cambia.**
   * Misurato sul servito a 360×780 l'08.09.2026, prima e dopo: la navigazione
   * arriva a 329 px contro 339, cioe' il 42-43% della prima schermata in tutti
   * e due i casi. E li' resta: sette porte, un campo di ricerca e tre comandi
   * su uno schermo largo 360 fanno tre righe qualunque cosa si faccia, e
   * l'unico modo di scendere sarebbe nascondere delle porte dietro un gesto —
   * che coi guanti e' una porta che non esiste. Meglio dirlo che spacciare per
   * risparmio quello che e' un ordine diverso. */
  .ponte .comandi .impostazioni,
  .ponte .comandi form button {
    background: none;
    border-color: transparent;
    padding-inline: var(--s2);
  }
  .ponte .comandi .impostazioni:hover,
  .ponte .comandi form button:hover { border-color: var(--contorno); }
}

/* Si legge con la voce, non con gli occhi: l'etichetta di un campo che sullo
   schermo e' gia' spiegata dal suo posto. */
.solo-lettori {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

@media (max-width: 600px) { .ponte .azienda { display: none; } }
.ponte form { margin: 0; }
.ponte .esci {
  /* ⚠️ `--tocco`, non 40px. La regola dei 48 px vale per OGNI bersaglio, e
     questo e' l'unico comando sempre presente in ogni pagina: uscire con i
     guanti da un bottone di 40 px vuol dire mancarlo. Le righe del registro
     erano gia' a 64 px, quindi la regola era nota e questo era un'eccezione
     senza motivo. Rilievo del revisore su A5b. */
  min-height: var(--tocco); padding: 0 var(--s4);
  background: none; border: var(--filetto) solid var(--contorno); border-radius: var(--raggio-0);
  color: var(--tenue); cursor: pointer;
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-piccolo); letter-spacing: .1em; text-transform: uppercase;
}
.ponte .esci:hover { border-color: var(--carta); color: var(--carta); }
.ponte .esci:focus-visible { outline: 2px solid var(--carta); outline-offset: 2px; }


.ponte .impostazioni {
  /* ⚠️ Su una riga sola con `display`, e non e' un capriccio di forma: la riga
     «min-height: var(--tocco); padding: 0 var(--s4);» e' l'ancora del canarino
     `bersaglio-sotto-i-48-px`, e un'ancora che compare due volte non pianta
     piu' niente — il guardiano l'ha detto prima che lo vedesse una persona. */
  display: inline-flex; align-items: center; min-height: var(--tocco);
  padding: 0 var(--s4);
  border: var(--filetto) solid var(--contorno); border-radius: var(--raggio-0);
  color: var(--tenue); text-decoration: none;
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-piccolo); letter-spacing: .1em; text-transform: uppercase;
  white-space: nowrap;
}
.ponte .impostazioni:hover { border-color: var(--carta); color: var(--carta); }
.ponte .impostazioni:focus-visible { outline: 2px solid var(--carta); outline-offset: 2px; }
/* ⚠️ «Ci sei»: il filetto si accende, come `aria-current` accende una voce del
   menu'. Non si toglie il collegamento — una pagina che si ricarica dal suo
   stesso pulsante e' un modo di tornare in cima, e chi ci arriva da una stanza
   del vocabolario ci torna davvero. */
.ponte .impostazioni[aria-current="page"] {
  border-color: var(--ossido); color: var(--carta);
}

/* ── Il cambio lingua: due lingue, un pulsante ──────────────────────────────
   ⚠️ Stessa altezza di «Esci» (`--tocco`), per la stessa ragione: e' un comando
   presente in ogni pagina e si preme coi guanti. Diceva «piu' stretto perche'
   dice due lettere, ma non piu' basso — l'altezza e' il bersaglio, la larghezza
   no»: ⚠️ misurato il 18.09.2026, non regge. Un bersaglio e' un'AREA, e 44×48
   e' l'area che il dito manca di lato invece che di sotto. Resta vero il resto:
   non si abbassa. */
.ponte .lingua button {
  /* ⚠️ UX98 giro 2 (18.09): misurato **44×48 px a 1440** sul servito — l'unico
   * `bersaglio` sotto misura di tutto il campione (13 vie). L'altezza era gia'
   * giusta; a mancare era la larghezza, e due lettere in una cassa di 48 px
   * restano due lettere. `min-width` e non `width`: «IT» e «EN» ci stanno
   * comodi, una lingua futura con una sigla piu' lunga allarga da se'. */
  min-height: var(--tocco); min-width: var(--tocco); padding: 0 var(--s3);
  background: none; border: var(--filetto) solid var(--contorno); border-radius: var(--raggio-0);
  color: var(--tenue); cursor: pointer;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: var(--t-nota); letter-spacing: .08em;
}
.ponte .lingua button:hover { border-color: var(--carta); color: var(--carta); }
/* ⚠️ UX98 giro 3 (18.09), criterio 5.1 · IL MARCHIO E' UN COLLEGAMENTO, e non
   lo diceva. «Argo» col segno porta alla scrivania da ogni pagina — sul
   telefono e' l'UNICO modo di tornare a casa dal ponte — e al passaggio e alla
   pressione non cambiava un pixel: misurato il 18.09 dall'inventario degli
   stati, a 360 e a 1440. Il segno resta com'e' (e' il marchio): cambia la
   parola, come per ogni altro legame del ponte, e la pressione porta l'anello
   interno di tutti i comandi.
   ⚠️ ⚠️ E il segno e' il FONDO, non il colore. Due tentativi sbagliati, tutti
   e due misurati nello stesso pomeriggio:
   · `color: var(--carta)` non cambiava un pixel — sul lavoro `--carta` e'
     #10202B, cioe' l'inchiostro, e il marchio ce l'ha gia';
   · `color: var(--ossido-vivo)` lo faceva leggere PEGGIO: 5,47:1 al passaggio
     contro 14,48:1 a riposo, preso da
     `test_il_PASSAGGIO_non_rende_meno_leggibile_un_TESTO`. E' la trappola
     scritta accanto a `--ossido-vivo` in `:root`, ripetuta: quel colore e'
     l'hover dei legami DENTRO il testo, dove a riposo il legame e' gia'
     ossido — non di una parola che a riposo e' inchiostro pieno.
   Il velo d'ossido al 6% e' lo stesso di `.registro a.riga:hover` e delle
   caselle della rotta: si vede, e non tocca il contrasto della parola. */
.ponte .nome:hover { background: color-mix(in srgb, var(--ossido) 6%, transparent); }
.ponte .nome:active { box-shadow: var(--ombra-premuto) currentColor; }
.ponte .lingua button:focus-visible { outline: 2px solid var(--carta); outline-offset: -2px; }
/* ⚠️ ⚠️ UX98 giro 3 (18.09), criterio 5.2 · DENTRO IL PONTE L'ANELLO STA
   DENTRO. Il ponte e' attaccato al bordo alto della finestra: con lo scarto
   positivo di 2 px il lato SOPRA dell'anello cade a quota negativa e non si
   disegna. Misurato col Tab a 360 — «Argo», «EN» ed «Esci»: «sopra: fuori».
   Non si puo' rimediare con l'imbottitura, perche' l'altezza del ponte e' il
   `--ponte-reso` su cui poggiano tutte le ancore del programma (criterio 1.1);
   si rimedia disegnando l'anello dentro il rettangolo del comando, dove i
   quattro lati ci stanno sempre. Il contrasto non cambia: il fondo dietro
   l'anello resta quello del ponte. */
.ponte :is(a, button, summary, [tabindex], [role="button"]):focus-visible {
  outline-offset: -2px;
}

/* ── «Salta al contenuto» ───────────────────────────────────────────────────
   ⚠️ Non `display: none` e nemmeno `visibility: hidden`: quelli lo tolgono
   ANCHE alla tastiera, ed e' l'unica cosa che questo collegamento serve a
   raggiungere. Sta fuori dallo schermo e rientra col fuoco addosso. */
.salta {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ossido-fondo); color: #fff;
  padding: var(--s3) var(--s4); text-decoration: none;
  font-family: "Barlow Condensed", sans-serif; font-size: var(--t-voce); letter-spacing: .04em;
}
/* ⚠️ **Il fuoco del salto si vede, e NON perche' ci sia una regola qui.** Il
 * 06.09.2026 questa era la prima fermata della tastiera su ogni pagina di Argo e
 * il suo anello faceva **1,15:1**: il salto sta scritto bianco sul suo fondo
 * rosso, e `a:focus-visible` disegnava il contorno in `currentColor` — cioe'
 * bianco — FUORI dall'elemento, sulla carta chiara.
 * ⚠️ La prima correzione e' stata una regola in piu' proprio qui. Sbagliata: la
 * causa non era il salto, era la regola generale, che legava una soglia di
 * NON-testo al colore di un testo misurato sul fondo sbagliato. Corretta quella
 * (riga 232), qui non serve niente, e una riga in meno e' un posto in meno dove
 * la stessa cosa puo' essere detta in due modi. */
.salta:focus { left: 0; }
/* ⚠️ UX98 giro 3 (18.09), criterio 5.2 · L'ANELLO DENTRO, E NON FUORI. Il salto
   sta nell'angolo in alto a sinistra (`top: 0`, e col fuoco `left: 0`): con il
   `outline-offset: 2px` della regola generale dei legami, due dei quattro lati
   dell'anello cadono FUORI dalla finestra — misurato col Tab a 360 e a 1440,
   «sopra: fuori, sinistra: fuori». Un anello di cui si vedono due lati su
   quattro dice meno di uno intero, e questa e' la PRIMA fermata della tastiera
   su ogni pagina di Argo. Con lo scarto negativo l'anello si disegna dentro il
   rettangolo, che qui e' alto 52 px: ci sta, e si vede tutto. */
.salta:focus-visible { outline: 2px solid var(--carta); outline-offset: -4px; }

/* ── Un COMANDO con la faccia di un legame ─────────────────────────────────
 * ⚠️ «Ferma l'aggiornamento» è un comando, quindi è un `<button>`: un legame che
 * non porta da nessuna parte mente alla sintesi vocale. Dentro una riga di testo
 * però deve avere la faccia di un legame — e fino al 06.09.2026 la classe che
 * glielo prometteva **non esisteva nel foglio**. Restava un bottone grigio di
 * sistema, col contorno nero del browser: **1,14:1** sulla tavolozza marina,
 * cioè un fuoco invisibile proprio sul comando che serve a fermare una pagina
 * che si ricarica da sola mentre la stai leggendo.
 * ⚠️ Niente 48 px qui: è un comando dentro una frase, e allargarlo a 48
 * spezzerebbe la riga che lo contiene. La soglia dei guanti vale per i bersagli
 * che stanno da soli; questo si prende come si prende un legame nel testo. */
.come-un-legame {
  background: none; border: 0; padding: 0;
  font: inherit; color: var(--ossido-testo);
  text-decoration: underline; text-underline-offset: 3px;
  cursor: pointer;
}
.come-un-legame:hover { color: var(--ossido-vivo); }
.come-un-legame:focus-visible {
  outline: 2px solid var(--carta); outline-offset: 3px;
}
/* ⚠️ `tabindex="-1"` sul banco lo rende raggiungibile dal salto senza metterlo
   nel giro della tastiera; il contorno che ne verrebbe non serve a nessuno.
   `scroll-margin-top` ferma il bersaglio sotto il ponte, non dietro: usa
   l'ingombro RESO, che sul telefono comprende anche la seconda riga. */
.banco { scroll-margin-top: var(--ponte-reso); }
.banco:focus { outline: none; }

/* ── Il banco: la colonna di lavoro sul reticolo ─────────────────────────── */
.banco {
  min-height: calc(100dvh - var(--ponte));
  padding: var(--s7) var(--s4) var(--s8);
  background-image:
    linear-gradient(var(--reticolo-fine) var(--filetto), transparent var(--filetto)),
    linear-gradient(90deg, var(--reticolo-fine) var(--filetto), transparent var(--filetto)),
    linear-gradient(var(--reticolo-marcato) var(--filetto), transparent var(--filetto)),
    linear-gradient(90deg, var(--reticolo-marcato) var(--filetto), transparent var(--filetto));
  background-size: 18px 18px, 18px 18px, 90px 90px, 90px 90px;
}
/* ⚠️ ⚠️ **LA COLONNA E' UNA, non un tetto ripetuto su ogni figlio.**
 * Qui c'era `.banco > * { max-width: 1080px; margin-inline: auto }`: ogni
 * blocco si centrava PER CONTO SUO dentro il banco. Finche' tutti i blocchi
 * sono larghi uguale non si vede la differenza — ma appena uno e' piu' stretto
 * degli altri, e la prosa con la misura di lettura lo e' per definizione, quel
 * blocco si centra rispetto agli altri invece di allinearsi con loro. Misurato
 * l'08.09.2026 su «La casa» a 1280 px: il paragrafo sotto il titolo cominciava
 * a 502 px mentre il titolo cominciava a 390 — staccato dalla pagina, come una
 * didascalia messa lì per sbaglio. L'ho introdotto io mettendo la misura di
 * lettura, ed e' la prova che il tetto stava sull'elemento sbagliato.
 * ⚠️ Con la griglia la colonna e' UNA: le tre tracce la tengono in mezzo (D30,
 * 07.09) e ogni figlio parte dal suo bordo sinistro. Chi e' piu' stretto resta
 * allineato con chi e' piu' largo, che e' l'unico modo in cui una colonna di
 * testo si legge come una colonna. */
.banco {
  display: grid;
  grid-template-columns: minmax(0, 1fr) min(1080px, 100%) minmax(0, 1fr);
  /* ⚠️ `start`: senza, le righe della griglia si spartiscono lo spazio che
     avanza e la pagina si allunga per aria — su una schermata corta i blocchi
     si allontanano fra loro senza che nessuno l'abbia chiesto. */
  align-content: start;
}
/* ⚠️ ⚠️ **E LA CONVERSAZIONE E' L'ECCEZIONE, per una ragione misurata.**
 * `align-content: start` fa dimensionare le righe sul CONTENUTO: un figlio con
 * `height: 100%` non ha piu' un'altezza definita a cui riferirsi, ci rinuncia,
 * e torna a crescere quanto il contenuto. Misurato l'08.09.2026 subito dopo
 * aver introdotto la griglia: `/chiedi/` e' tornata alta **11.626 px** a 1280,
 * cioe' il difetto «stretta e lunga» era rientrato dalla finestra mentre il
 * cancello restava verde — perche' il cancello l'altezza della pagina non la
 * guarda. Qui la sola pagina che ha bisogno di riempire lo schermo se lo
 * riprende, e le altre restano impacchettate in alto. */
@media (min-width: 760px) {
  /* ⚠️ `grid-template-rows: 100%` e non `align-content: stretch`: provato, e
     non basta. `stretch` distribuisce lo spazio che AVANZA, e qui non avanza
     niente — la riga e' dimensionata sul contenuto, il contenuto e' il dialogo,
     e il dialogo chiede il 100% della riga: un cerchio, che il browser rompe
     tornando all'altezza del contenuto. Misurato: banco alto 838 px, dialogo
     11.415. Con la riga dichiarata al 100% del banco l'altezza e' definita
     PRIMA, il cerchio non si forma, e le battute si stringono. */
  /* ⚠️ La riga del DIALOGO prende cio' che resta; quelle attorno stanno strette
     sul loro contenuto. `100%` sulla prima riga era sbagliato e l'ho misurato:
     i figli del banco su `/chiedi/` sono TRE — `.avvisi`, `.dialogo`,
     `.cartiglio` — e il 100% era finito sugli AVVISI (744 px di riquadro vuoto)
     mentre il dialogo restava nella sua riga a contenuto, alto 11.415 px. */
  /* ⚠️ ⚠️ **LA CONVERSAZIONE PRENDE LO SCHERMO, e il cartiglio scende sotto la
   * piega.** Misurato sul servito a 1280×900 prima di questa riga: la
   * conversazione aveva 376 px su 900, il **42%**, mentre il resto se lo
   * prendevano l'intestazione (61), il campo dove si scrive (173), il cartiglio
   * (61) e i margini. Il cartiglio dice azienda, utente, revisione e data: e'
   * riferimento, non lavoro, e su una pagina che serve a conversare non ha
   * motivo di rubare una riga di conversazione. Resta raggiungibile scorrendo.
   * ⚠️ Il conto usa `--ponte` e un gradino della scala, non due numeri scelti
   * qui: se domani la barra in cima cambia altezza, questa riga la segue. */
  .banco:has(> .dialogo) { grid-template-rows: auto minmax(0, 1fr); }
  .banco:has(> .dialogo) > .dialogo {
    height: 100%;
    min-height: 0;
  }
}
.banco > * { grid-column: 2; min-width: 0; }

/* La chat e' un ambiente di lettura, non una tavola: il reticolo si ferma alle
   altre pagine. L'avviso di sistema attraversa il banco, mentre il dialogo si
   centra nella propria misura e lascia al browser il conto dell'altezza. */
.banco:has(> .dialogo) {
  background-image: none;
  background-color: var(--fondo);
  padding-bottom: var(--s3);
}
.banco:has(> .dialogo) > .avvisi:has(.striscia-sistema) { grid-column: 1 / -1; }
.banco > .dialogo {
  width: 100%;
  max-width: 760px;
  min-height: 0;
  justify-self: center;
}

/* Sul telefono navigazione e chat si dividono lo spazio sotto il ponte. Il
   documento non scorre: scorre soltanto la storia, sopra al compositore. */
@media (max-width: 759.98px) {
  body.lavoro:has(> .banco > .dialogo) {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    /* ⚠️ GIRO 4 (rilievo 1 del giudizio 8,9): la riga del LAVORO e' la prima e
       prende lo spazio; la plancia e' la seconda, alta quanto le serve. Era il
       contrario, e su `/chiedi/` la collocazione esplicita batteva l'`order` del
       giro 3: misurato sul reso a 360×780, rotta a y=86 e chat a y=191 — il menu'
       in cima su una pagina di un mandato che si chiama «il disegno comune». */
    grid-template-rows: minmax(0, 1fr) auto;
    width: 100%;
    height: 100dvh;
    min-height: 0;
    overflow: hidden;
  }
  body.lavoro:has(> .banco > .dialogo) > .rotta {
    position: relative;
    top: auto;
    grid-row: 2;
    align-self: end;
    /* il distacco lo fa la riga della griglia: il margine della plancia comune
       qui mangerebbe lo schermo che serve alla conversazione */
    margin-top: 0;
  }
  /* ⚠️ ⚠️ 15.09.2026 (sera): i 52 px c'erano per «Committenti, cantieri e
     fornitori» su tre righe in un terzo di schermo. Adesso ogni nome sta su UNA
     riga (la plancia qui sotto dispone per nome), e la casella torna al
     bersaglio di tutte le altre: `--tocco`. */
  body.lavoro:has(> .banco > .dialogo) > .rotta a {
    min-height: var(--tocco);
    padding-inline: var(--s1);
    font-size: var(--t-nota);
  }
  /* ⚠️ Nella conversazione la plancia sta fino a TRE caselle per riga, anche
     sotto l'ingresso: e' la pagina che ha bisogno di schermo. Con i nomi interi
     chi amministra ha quattro righe e non tre — 208 px e non 169: e' il costo di
     un nome che non si spezza, detto. */
  body.lavoro:has(> .banco > .dialogo) > .rotta > .macro,
  body.lavoro:has(> .banco > .dialogo) > .rotta > a.sola {
    min-width: 25%;
  }
  /* Le porte della conversazione hanno la misura delle sue voci; aperta, una
     macro prende la riga intera (regola della plancia) — in una casella da un
     quarto le sue micro non si leggerebbero. */
  body.lavoro:has(> .banco > .dialogo) > .rotta :is(summary.macro-nome, a.testa, a.sola) {
    min-height: var(--tocco);
    padding-inline: var(--s1);
    font-size: var(--t-nota);
  }
  body.lavoro:has(> .banco > .dialogo) > .banco {
    grid-row: 1;
    height: 100%;
    min-height: 0;
    padding: var(--s3) var(--s4) var(--s2);
    overflow: hidden;
    grid-template-rows: auto minmax(0, 1fr);
    align-content: stretch;
  }
  body.lavoro:has(> .banco > .dialogo) > .banco > .dialogo {
    height: 100%;
    min-height: 0;
    max-height: none;
  }
  .banco > .dialogo > .intestazione {
    flex-wrap: nowrap;
    align-items: center;
    gap: var(--s2);
  }
  .banco > .dialogo > .intestazione h1 { font-size: var(--t-secondo); }
  .banco > .dialogo .nuova-conversazione {
    padding-inline: var(--s2);
    font-size: var(--t-nota);
    letter-spacing: .04em;
  }
  .banco > .dialogo > .scrivi {
    padding-block: var(--s2);
  }
  .banco > .dialogo > .scrivi > .campo-e-invio { gap: var(--s2); }
  .banco > .dialogo > .scrivi .allega-comando,
  .banco > .dialogo > .scrivi button.chiedi { padding-inline: var(--s3); }
}

.intestazione { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s4); margin-bottom: var(--s6); }
.intestazione h1 {
  margin: var(--s1) 0 0;
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-primo); letter-spacing: .03em; line-height: 1;
}
.intestazione .conto { margin-left: auto; }
.intestazione.staccata { margin-top: var(--s7); }
/* ⚠️ Un titolo di sezione e' un h2 (o un h3 sotto un h2), non un h1 piu'
   piccolo: cinque h1 in una pagina sono cinque pagine per chi si muove per
   titoli (S7 dell'audit UX del 15.09). La forma e' quella dell'h1 minore. */
/* ⚠️ Giro 3: la forma NON tocca l'intestazione di un `.dialogo` (il titolo della
   chat del preventivo, `_chat_preventivo.html`): quella pagina non e' di questo
   incremento e nessuno l'aveva misurata (rilievo del giudice del giro 2). Il
   `:where()` tiene la specificita' di prima, (0,2,1): il ritaglio non vince
   niente che prima perdesse. Misura in verifiche/ux-commessa/titolo-chat.py. */
.intestazione h1.minore, :where(:not(.dialogo)) > .intestazione h2.minore { font-size: var(--t-secondo); }
:where(:not(.dialogo)) > .intestazione :is(h2, h3).minore {
  margin: var(--s1) 0 0;
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; letter-spacing: .03em; line-height: 1;
}
:where(:not(.dialogo)) > .intestazione h3.minore { font-size: var(--t-terzo); }
.titolo-con-conto { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s3); }
.conto-vicino { color: var(--tenue); font-size: var(--t-voce); line-height: 1; }

/* ── Il registro: l'elenco si legge come l'indice di una tavola ─────────────
 * ⚠️ Non schede affiancate. Chi fa questo mestiere legge elenchi incolonnati
 * tutto il giorno: matricole, sigle, revisioni. Le colonne si confrontano a
 * colpo d'occhio, i riquadri no.                                            */
.registro { background: var(--fondo-alto); border: var(--filetto) solid var(--contorno); }
.registro .riga {
  /* ⚠️ FLEX, non griglia. Con `grid-auto-flow: column` le colonne si aprivano da
     sole e la loro larghezza andava INDOVINATA (`minmax(110px,168px)`): un numero
     che non puo' essere giusto per un nome di disegno, una data e tre pulsanti
     insieme. Misurato in produzione: la colonna del nome larga 48 px, la riga
     alta 462, e «Accetto» spezzato in AC/CE/TT/O.
     Qui ogni pezzo dichiara come si comporta invece di subire una traccia:
     il nome cresce, i dati stanno al loro minimo, i pulsanti restano interi. */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s3) var(--s4);
  min-height: 64px;                    /* piu' del bersaglio minimo: si tocca coi guanti */
  padding: var(--s3) var(--s4);
  border-top: var(--filetto) solid var(--linea);
  color: inherit; text-decoration: none;
}
/* Il numero d'ordine non cresce e non si stringe. */
.registro .riga > .indice { flex: 0 0 40px; }
/* ⚠️ UX98 (16.09), rilievo S5: le colonne erano a larghezza FISSA (140 px) e
   sotto i 700 px la riga andava a capo a metà: le frasi di stato partivano
   da x diverse e l'elenco zig-zagava. Colonne ELASTICHE: la riga continua a
   dichiararsi pezzo per pezzo, ma ogni pezzo si stringe invece di portare la
   pagina fuori schermo — e andando a capo, ogni pezzo riparte dallo stesso
   bordo. Un allineamento solo. */
.registro .riga > .colonna {
  flex: 1 1 auto;
  /* ⚠️ `min-width: 0`, altrimenti la larghezza non si stringe. Il minimo
     predefinito di un elemento flex e' `auto`, cioe' `min-content`: un valore
     senza spazi piu' largo della colonna — un indirizzo di posta come
     «info@riservati.de» — la apre e ruba lo spazio al nome. Misurato sul
     registro degli atti: 8 righe su 29 spostate di 52 px. */
  min-width: 0;
}
/* E il valore lungo si spezza dentro la sua colonna invece di allargarla. */
.registro .riga .valore { overflow-wrap: anywhere; }
/* ⚠️ L'impronta intera e' 64 caratteri esadecimali da quando si calcola in
   SHA-256 (era 32 in MD5, e le righe vecchie ce le hanno ancora): dentro 140 px
   va a capo, ed e' giusto cosi'. Piu' piccola e piu' fitta, perche' non si
   legge — si confronta e si copia. Che la colonna regga il doppio dei caratteri
   senza spostare le altre lo misura `strumenti/gesto-larghezza.py`, ed e' il
   motivo per cui `min-width: 0` qui sopra non e' un dettaglio. */
.registro .riga .valore.impronta { font-size: var(--t-nota); line-height: 1.35; letter-spacing: -.01em; }
/* ⚠️ L'impronta sta dietro il suo nome («Impronta · sha256»), chiusa: si apre
   per confrontarla o copiarla, non si legge. Il nome e' un bersaglio da tocco
   come ogni cosa che si preme, e dice che si apre col triangolo del sommario.
   Audit UX del 15.09.2026, Sol R31 e Opus P3. */
.registro details.impronta-del-file > summary {
  display: flex; align-items: center; gap: var(--s2);
  min-height: var(--tocco); cursor: pointer; list-style: none;
}
.registro details.impronta-del-file > summary::-webkit-details-marker { display: none; }
.registro details.impronta-del-file > summary::before {
  content: "▸"; color: var(--tenue); font-size: var(--t-minuto); line-height: 1;
}
.registro details.impronta-del-file[open] > summary::before { content: "▾"; }
.registro details.impronta-del-file > summary:focus-visible { outline: 2px solid var(--carta); outline-offset: 2px; }
.registro details.impronta-del-file > .valore { display: block; max-width: 34ch; }
/* ⚠️ Le colonne del registro attivita' hanno la stessa base in ogni riga, e
   ogni riga ha le stesse colonne (quella dell'impronta c'e' anche vuota): con
   `flex: 1 1 auto` la larghezza la decideva il contenuto, e la sola riga con
   l'impronta spostava QUANDO e CHI di 79 e 157 px. Stessa base, stessa
   crescita e `min-width: 0` danno la stessa larghezza a ogni riga. */
@media (min-width: 701px) {
  .registro-attivita .riga > .colonna:nth-child(2) { flex: 3 1 200px; }
  .registro-attivita .riga > .colonna:nth-child(n+3) { flex: 1 1 10rem; }
}
@media (max-width: 700px) {
  .registro-attivita .riga > .colonna.senza-impronta { display: none; }
}
/* ⚠️ La colonna del nome e' l'unica che deve crescere, e si scrive
   `nth-child(2)` — NON `nth-of-type(1)`, che era la mia prima stesura e non
   corrispondeva a niente: `nth-of-type` conta fra gli elementi dello STESSO
   TAG, e il primo `span` della riga e' l'indice, che `.colonna` non ce l'ha.
   Una regola che non corrisponde non da' errore: la pagina resta com'era e
   sembra che la modifica non serva. Misurato provando cinque larghezze diverse
   e vedendole rispondere tutte lo stesso numero.
   `min-width: 0` le permette di stringersi sotto il suo contenuto: senza, un
   nome lungo senza spazi tiene aperta la riga e la pagina scorre di lato.
   200px di base: misurato, con i dati a 140 porta le righe che vanno a capo
   sulla pagina della commessa da 69 a 0 fino a 1024 px. Sotto i 900 vanno a capo
   tutte, ed e' voluto: li' il menu diventa una barra e la riga si impila. */
.registro .riga > .colonna:nth-child(2) { flex: 1 1 200px; min-width: 0; }
/* I pulsanti in fondo, alla loro larghezza vera. */
.registro .riga > .azioni { flex: 0 0 auto; margin-left: auto; }
/* ⚠️ Sotto i 700 px ogni colonna prende la riga intera; sotto i 600 anche i
   pulsanti (regola più in basso) diventano una colonna: se restassero appesi
   a destra si stringerebbero. Vanno a capo, larghi tutto. */
@media (max-width: 700px) {
  /* ⚠️ UX98 (16.09), rilievo S5 e rilievo 7 del giudizio di giro 2: a 360 le
     colonne di una riga partivano da x diverse — due per riga finché ci
     stavano, la terza da sola — e l'elenco zig-zagava. Ogni colonna prende la
     riga intera: un allineamento solo.
     ⚠️ E fino a 700, non 600: fra 600 e 700 due colonne ci stanno ancora e la
     terza ricomincia da sinistra — lo zig-zag non è un difetto da 360 px, è
     un difetto di OGNI larghezza in cui le colonne non ci stanno tutte. */
  /* ⚠️ ⚠️ **E LA SECONDA VA NOMINATA, altrimenti questa regola non la tocca.**
     UX98, misurato il 19.09.2026 SUL SERVITO (rilievo 3 del revisore del giro
     3: «M3 non viene dalla pagina»). Sul conto di un preventivo vero, a 360:
     dieci righe del registro impilate a x 33 con scarto 0, e UNA — quella
     degli allegati, che ha l'indice — con le colonne a x 89 e 33, scarto 56.
     Cioe' proprio lo zig-zag che la nota qui sopra dichiara chiuso dal 16.09.
     La causa e' la SPECIFICITA': `.colonna:nth-child(2)` (piu' su) pesa una
     pseudo-classe in piu' di `.colonna`, e le media query non ne aggiungono —
     quindi il suo `flex: 1 1 200px` vinceva qui dentro e la colonna del nome
     restava accanto all'indice mentre la successiva andava a capo da sola.
     ⚠️ Nelle righe SENZA indice il difetto non si vede (li' `nth-child(2)` e'
     la seconda colonna, che a capo ci va lo stesso): si vede solo dove c'e' un
     indice — ed e' il motivo per cui nessuna prova su markup ricostruito
     poteva trovarlo. Il markup vero e' `modelli/dominio/_allegati.html`.
     ⚠️ Si nomina il selettore, non si alza a `!important`: la regola resta
     leggibile e una terza variante di colonna si vedra' allo stesso modo. */
  .registro .riga > .colonna,
  .registro .riga > .colonna:nth-child(2) { flex-basis: 100%; }
}
@media (max-width: 600px) {
  .registro .riga > .azioni { margin-left: 0; flex: 1 0 100%; }
}
.registro .riga:first-child { border-top: none; }
/* ⚠️ Solo le righe CLICCABILI si illuminano e prendono il fuoco: una riga che
   reagisce al passaggio del dito e poi non fa niente e' una promessa mancata.
   Le commesse, per ora, non si aprono. */
.registro a.riga:hover { background: color-mix(in srgb, var(--ossido) 6%, transparent); }
.registro a.riga:focus-visible { outline: 2px solid var(--carta); outline-offset: -2px; }
.registro .indice { font-size: var(--t-nota); color: var(--fioco); }
/* ⚠️ Il ritorno a capo dentro la parola sta SOLO qui: sono le due celle che
   portano testo del cantiere. I nomi arrivano come blocchi unici senza spazi
   («263.G.01.05.02.AA_WO0382571_Review…», 329 px in una casella da 260) e
   nessuna regola normale li spezza — ma `overflow-wrap` si EREDITA, e messo
   sulla riga lo prendevano anche i pulsanti. */
.registro .capo { overflow-wrap: anywhere; font-weight: 600; font-size: var(--t-voce); }
.registro .sotto {
  overflow-wrap: anywhere;
  /* Il motivo del rifiuto e' testo libero: senza un tetto una frase lunga
     allargherebbe la riga quanto vuole. 44 caratteri e' anche la misura giusta
     per leggerla. */
  max-width: 44ch;
  font-size: var(--t-minuto); color: var(--tenue);
}
/* ⚠️ `.colonna` sta al livello di TUTTI, non dentro `.registro`. Quando ci
   stava, spostando la targa fuori dal registro le voci hanno perso
   l'impaginazione e sono diventate «MATRICOLASC-2024-118»: etichetta e valore
   sulla stessa riga, senza nemmeno uno spazio. Una regola definita dentro un
   contenitore vale solo li' dentro, e la prima volta che il pezzo si sposta si
   scopre che non era un pezzo. */
.colonna { display: flex; flex-direction: column; gap: var(--s1); }
.colonna .valore { font-size: var(--t-minuto); }

/* ── Il filtro del registro: una tendina, coi conti dentro ─────────────────
   ⚠️ Il numero accanto a ogni tipo non e' decorazione: un filtro che si puo'
   scegliere e non da' niente fa credere che il registro sia vuoto. Col conto si
   sa PRIMA di scegliere, e i tipi mai successi si vedono per quello che sono.
   ⚠️ Erano pastiglie, una per tipo, pensate per «gli otto filtri»: i tipi sono
   diventati 89, e a 1440 facevano 29 righe (1672 px, la prima attivita' a
   y=1940), con la tastiera 105 fermate prima della prima riga, a 360 una
   striscia di lato lunga metri col filtro scelto fuori schermo. Audit UX del
   15.09.2026, P1 per tutti e tre i revisori. Ora e' UNA riga a ogni larghezza:
   l'etichetta, la tendina che porta ogni tipo col suo conto, «Mostra».
   ⚠️ La tendina si stringe con la pagina — `min-width: 0` e `max-width: 100%` —
   altrimenti il nome piu' lungo dei tipi la aprirebbe oltre i 360 px e
   porterebbe la pagina fuori schermo. E sta a 16 px: sotto, il telefono
   ingrandisce la pagina al tocco. */
.filtri {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s3);
  margin: 0 0 var(--s4);
}
.filtri > label { flex: 0 0 auto; }
.filtri .scelta-e-comando {
  display: flex; gap: var(--s3);
  flex: 1 1 420px; min-width: 0; max-width: 640px;
}
/* Il campo e' vestito dalla regola di ogni campo (`select` qui in alto): qui
   solo come sta nella fila. */
.filtri select { flex: 1 1 auto; min-width: 0; max-width: 100%; text-overflow: ellipsis; }
.filtri select:hover { border-color: var(--carta); }
/* ⚠️ `button[type="submit"]` e non la classe del bottone: `test_lingua.py`
   legge il PRIMO blocco del foglio che porta il nome di quella classe seguito
   dalla graffa, per sapere il fondo dei bottoni pieni — e una regola dei
   filtri scritta qui, prima del blocco vero, gli faceva leggere questa (rosso
   della suite, 18.09; vale anche per i commenti). La trappola e' scritta
   anche accanto al blocco vero, piu' in basso. */
.filtri button[type="submit"] { flex: 0 0 auto; }
/* A 360 la tendina prende lo spazio che «Mostra» non usa: con i rientri pieni
   del bottone il tipo scelto si leggeva «Disegno scaricato ·…». */
@media (max-width: 480px) {
  .filtri button[type="submit"] { padding: 0 var(--s4); }
  .filtri select { padding-inline: var(--s3); }
}
/* Il filtro scelto detto a parole, e il ritorno al tutto con un tocco solo.
   ⚠️ In fila, non in una riga di testo: la frase va a capo come un blocco e il
   collegamento (48 px, un bersaglio da dito) le sta accanto o tutto sotto. In
   coda alla frase, a 360 la spezzava e lasciava «71.» da solo sulla riga del
   collegamento (giudizio del giro 2, nota R3). `baseline`: quando stanno
   accanto, le due scritte poggiano sulla stessa linea.
   ⚠️ E la frase va a capo BILANCIATA: col collegamento gia' sotto, a 360
   «Solo «Modifica al quadro registrata»: 62 attività su» lasciava «71.» da
   solo sulla seconda riga (misurato sul servito, giro 3). */
.filtro-scelto {
  display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--s2);
  margin: 0 0 var(--s4); color: var(--tenue); font-size: var(--t-minuto);
}
.filtro-scelto > span { text-wrap: balance; }
.filtro-scelto a {
  display: inline-flex; align-items: center; min-height: var(--tocco);
  color: var(--ossido-testo);
}
.filtro-scelto a:hover { color: var(--ossido-vivo); }

/* La navigazione fra le pagine del registro. */
.pagine {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3) var(--s4);
  margin: var(--s6) 0 0;
}
.pagine .dove { color: var(--tenue); font-size: var(--t-minuto); }
/* ⚠️ Il bordo c'e' PRIMA della selezione: `body.lavoro a.pastiglia` da' gia'
   l'altezza del tocco (48 px) e il riempimento, ma non un contorno — e senza,
   «scelta» avrebbe cambiato il colore di un bordo che non esiste. Un chip senza
   contorno non si legge come una cosa da premere. */
.filtri .pastiglia {
  text-decoration: none;
  border: var(--filetto) solid var(--contorno);
  color: var(--tenue);
}
/* ⚠️ UX98: la parola va alla carta (l'ossido vivo, 5,47:1, era sotto il tenue del
   riposo, 5,80:1); il contorno resta ossido: e' lui a dire «passaggio». */
.filtri .pastiglia:hover { border-color: var(--ossido-vivo); color: var(--carta); }
/* Quella scelta si vede senza doverla confrontare con le altre — e non si affida
   al solo colore: il pieno la stacca anche a chi i colori non li distingue. */
.filtri .pastiglia.scelta {
  background: var(--ossido-fondo); color: #fff; border-color: var(--ossido-fondo);
}
.filtri .pastiglia.scelta::before { background: #fff; }
.filtri .pastiglia.scelta:hover { color: #fff; border-color: var(--ossido-fondo); }
.filtri .pastiglia:focus-visible { outline: 2px solid var(--ossido-vivo); outline-offset: 2px; }

/* La pastiglia del conteggio: rossa SOLO quando c'e' lavoro aperto. */
.pastiglia {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-family: "IBM Plex Mono", monospace; font-size: var(--t-nota);
}
.pastiglia::before {
  content: ""; width: 8px; height: 8px; flex: none;
  background: var(--ossido);
}
.pastiglia.ferma { color: var(--fioco); }
.pastiglia.ferma::before { background: var(--linea); }

/* ── La targa del bene: le voci che si leggono su una targa di macchina ────
 * ⚠️ Le colonne stavano in un `style=` dentro il modello, fisse a quattro. Su un
 * telefono da 390 px quattro colonne danno strisce da 90 px, e una matricola ci
 * va a capo in mezzo. Un attributo `style=` non ha media query: e' proprio il
 * genere di regola che non puo' adattarsi, ed e' per questo che qui i valori
 * stanno nel foglio di stile e non nella pagina.                            */
/* ⚠️ La targa NON sta dentro `.registro`, e non e' un dettaglio di markup.
   Quando ci stava, `.registro .riga` (specificita' 0,2,0) vinceva su `.targa`
   (0,1,0) e le imponeva le colonne del registro — 46 px alla prima, dove ci va
   la matricola: «SC-2024-118» andava a capo tre volte. Combattere a colpi di
   selettori sarebbe stato il rimedio sbagliato: la targa non e' una riga di
   elenco, e la cosa giusta era toglierla da li'. */
.targa {
  background: var(--fondo-alto);
  border: var(--filetto) solid var(--contorno);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--s4) var(--s4);
  padding: var(--s4);
}
.targa .luogo { grid-column: span 3; }

@media (max-width: 900px) { .targa { grid-template-columns: repeat(2, 1fr); }
                            .targa .luogo { grid-column: span 2; } }
@media (max-width: 480px) { .targa { grid-template-columns: 1fr; }
                            .targa .luogo { grid-column: auto; } }

/* ⚠️ Il conto dei rilievi sta SOTTO la targa e non deve aggiungere stacco.
   Lo stacco fra le sezioni della scheda lo da' la griglia della pagina — 32 px
   — e i margini di un `p` sono margini di un elemento di griglia: non si
   fondono, si SOMMANO al gap. Col margine di paragrafo «Commesse» stava a 48 px
   contro i 32 di «Allegati» e «Quadri e post-vendita»: misurato in chromium
   dalla corsa A del cancello del lotto C (21.09), non dedotto. */
.conto-rilievi-dell-ente { margin: 0; }
/* ⚠️ Il committente nella targa e' l'unico passaggio dalla nave a chi la
   commissiona, e col dito era un bersaglio di 192×18 px (audit UX del 15.09:
   Sol R14, Astra R003, Opus). `span.valore > a` sfugge alla regola dei
   bersagli sul tocco, che elenca h1–h4, td, th, li, dd: qui arriva ai 44 px di
   un legame dove si tocca — sotto i 700 px E con `pointer: coarse`, cioe'
   anche sul tablet largo. A sinistra, non centrato: e' un valore della targa. */
@media (max-width: 700px), (pointer: coarse) {
  .targa .valore > a {
    display: inline-flex; align-items: center; justify-content: flex-start;
    min-height: var(--tocco-legame); min-width: var(--tocco-legame);
  }
}
/* ⚠️ Le commesse della nave si confrontano fra loro: FASE e STATO stanno sulla
   stessa verticale in ogni riga. Con le colonne elastiche di UX98 ogni riga si
   misurava da sola — «chiusa il 10.06.2026» e' piu' largo di «aperta» — e a
   1440 FASE partiva a 822, 830 e 782 px, STATO a 1106, 1098 e 1034: un elenco
   da leggere come una tavola che zig-zagava (misurato il 18.09 in
   verifiche/ux-nave). Da 701 px in su i due dati hanno una larghezza sola; sotto
   ogni colonna prende la riga intera (regola dei 700 px, qui sopra), come prima. */
@media (min-width: 701px) {
  .registro.commesse-della-nave .riga > .colonna:nth-child(n+3) { flex: 0 0 12rem; }
}

/* ── Il vuoto: un invito, non un vicolo cieco ───────────────────────────────
 * ⚠️ Ogni schermata vuota di Argo deve finire con UN gesto possibile. Una
 * pagina che dice «non c'e' niente» e si ferma li' e' il 404 travestito.     */
.vuoto {
  background: var(--fondo-alto);
  border: var(--filetto) dashed var(--contorno);
  padding: var(--s7);
  text-align: center;
}
.vuoto p { max-width: 46ch; margin: 0 auto var(--s6); color: var(--tenue); }
.vuoto .etichetta { display: block; margin-bottom: var(--s3); }

/* ⚠️ U2 · Questo non e' il consueto messaggio vuoto: spiega come nasce il
   lavoro. Nella pagina servita il centrato generico lo stringeva su sei righe,
   colorava la spiegazione come il collegamento e lasciava quasi un terzo del
   riquadro vuoto sotto. La variante resta locale a Oggi: testo da leggere a
   sinistra, misura editoriale, gesti raccolti senza una coda di spazio. */
.vuoto-oggi { padding: var(--s6) var(--s7); text-align: left; }
/* ⚠️ ⚠️ **`ch` NON E' «un carattere», e qui la differenza vale otto righe di
 * troppo.** `1ch` e' la larghezza della cifra ZERO, che in IBM Plex Sans e' piu'
 * larga della media delle lettere: misurato il 06.09.2026 contando i caratteri
 * che cadono su ogni riga resa, `max-width: 65ch` dava righe da **83 caratteri**
 * — ben oltre la banda di lettura 45-75. Il foglio diceva 65 e lo schermo ne
 * faceva 83, e nessuno se n'era accorto perche' la prova leggeva il NUMERO nel
 * foglio invece di contare i caratteri sullo schermo.
 * ⚠️ 53ch dà [68, 63, 71, 58]: dentro la banda. Il numero non si deduce, si
 * misura — e la misura sta in `prove/test_stato_vuoto_oggi.py`.
 * ⚠️ Nel foglio ci sono altre 21 larghezze in `ch` con lo stesso equivoco
 * dentro: non le tocco alla cieca, si correggono dove si misurano. */
.vuoto-oggi > .spiega { max-width: var(--misura-di-lettura); margin: 0 0 var(--s4); color: var(--carta); }
.vuoto-oggi .azioni-vuoto { display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s4); }
.vuoto-oggi .filo { max-width: none; margin: 0; }
@media (max-width: 480px) { .vuoto-oggi { padding-inline: var(--s4); } }

/* ── L'azione ───────────────────────────────────────────────────────────── */
.azione {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tocco); padding: 0 var(--s6);
  /* ⚠️ Un pulsante non si spezza MAI a meta' parola. Sta QUI e non in una regola
     a parte per due ragioni: e' una proprieta' del pulsante, e un secondo blocco
     `.azione {` piu' in alto nel foglio faceva leggere a
     `test_le_etichette_si_leggono_su_tutte_e_due_le_superfici` il corpo del
     testo sbagliato — la prova cerca il PRIMO blocco, e diventava rossa. */
  white-space: nowrap;
  /* ⚠️ Bianco su `--ossido` da' 4,45:1. Il commento di prima si appoggiava
     all'esenzione «testo grande», ma WCAG chiama bold il peso >= 700 e qui e'
     600 — e `.azione.minore` sta a 14,4 px, dove non c'e' discussione.
     `--ossido-fondo` da' 6,58:1 e passa senza esenzioni. */
  background: var(--ossido-fondo); color: #fff;
  border: var(--filetto) solid transparent; border-radius: var(--raggio-0); cursor: pointer; text-decoration: none;
  font-family: "Barlow Condensed", sans-serif;
  /* 19 px e non 18: sopra i 18,66 px in grassetto l'AA chiede 3:1 invece di
     4,5:1, e il bianco sull'ossido sta a 4,45:1. Un pixel separa «passa» da
     «non passa», ed e' il genere di cosa che non si vede guardando. */
  font-weight: 600; font-size: var(--t-voce); letter-spacing: .1em; text-transform: uppercase;
}
.azione:hover { background: var(--ossido-cupo); }
.azione:focus-visible { outline: 2px solid var(--carta); outline-offset: 2px; }
.azione.quieta, .azione.fiacca, .azione.minore, .azione.minuta {
  background: none; color: var(--tenue); border: var(--filetto) solid currentColor;
}
.azione.quieta:hover:where(:not(:disabled):not([aria-disabled="true"])),
.azione.fiacca:hover:where(:not(:disabled):not([aria-disabled="true"])),
.azione.minore:hover:where(:not(:disabled):not([aria-disabled="true"])),
.azione.minuta:hover:where(:not(:disabled):not([aria-disabled="true"])) {
  color: var(--carta); border-color: var(--carta); background: none;
}

/* ⚠️ ⚠️ **`.azione.secondaria` SI USAVA IN QUATTRO MODELLI E NON ESISTEVA QUI.**
 * Misurato l'08.09.2026 sulla pagina servita di una commessa: «Confronta i
 * quadri» usciva a **1,01:1** — inchiostro grigio-ardesia su carta rosso ossido,
 * cioe' un bottone il cui testo non si vedeva affatto.
 * Due guasti che si sommavano, e nessuno dei due era visibile leggendo il codice:
 *   · la classe `secondaria` non aveva NESSUNA regola, quindi ogni azione
 *     «secondaria» usciva col pieno del primario — e la pagina finiva con sei
 *     bottoni pieni, che e' esattamente cio' che la D29 vieta;
 *   · dentro `p.filo` la regola `.filo a` (0,1,1) batte `.azione` (0,1,0) e ne
 *     cambiava l'INCHIOSTRO lasciandogli la CARTA. Un bottone e' una coppia:
 *     chi tocca il colore del testo deve toccare anche il fondo, o non toccare
 *     nessuno dei due.
 * Qui la secondaria e' quello che dice di essere: stessa forma e stesso
 * bersaglio del primario, senza il pieno. */
.azione.secondaria {
  background: none;
  color: var(--ossido-testo);
  border: var(--filetto) solid currentColor;
}
.azione.secondaria:hover:where(:not(:disabled):not([aria-disabled="true"])) { background: none; color: var(--ossido-vivo); }

/* I comandi di consultazione e quelli definitivi hanno ruoli riconoscibili.
   Il fuoco resta quello comune; la pressione si vede anche senza cambiare tinta. */
.azione.terziaria {
  background: none; color: var(--tenue);
  padding-inline: var(--s3);
  text-decoration: underline; text-underline-offset: .18em;
}
.azione.terziaria:hover:where(:not(:disabled):not([aria-disabled="true"])) { background: none; color: var(--carta); }
.azione.pericolo {
  background: none; color: var(--ossido-testo);
  border: 2px solid currentColor;
}
.azione.pericolo:hover:where(:not(:disabled):not([aria-disabled="true"])) { background: none; color: var(--ossido-vivo); }
.azione:active { box-shadow: var(--ombra-premuto) currentColor; }
.azione:disabled, .azione[aria-disabled="true"] {
  background: var(--fondo); color: var(--fioco);
  border: var(--filetto) solid currentColor;
  box-shadow: none; cursor: not-allowed;
}

/* ── Il modulo di inserimento, sul foglio ──────────────────────────────── */
.modulo {
  background: var(--fondo-alto);
  border: var(--filetto) solid var(--contorno);
  padding: var(--s6);
  max-width: 720px;   /* oltre, le righe diventano troppo lunghe da leggere */
}
/* ⚠️ ⚠️ **`.spiega` NON AVEVA NESSUNA MISURA DI LETTURA, ed e' la classe con cui
 * Argo spiega le cose: settantadue volte nei modelli.** Misurato sulla pagina del
 * preventivo SERVITA il 06.09.2026, col capitolato vero dentro: paragrafi da
 * **108 caratteri per riga**. La banda e' 45-75, e oltre l'occhio torna a capo e
 * ritrova la riga sbagliata — su una pagina che di quei paragrafi ne ha
 * cinquecento.
 * ⚠️ Non si era mai visto perche' le regole con una misura si guardavano una per
 * una, e questa una misura non ce l'aveva: cercare i numeri sbagliati non trova
 * il posto dove il numero manca. L'ha trovato il conto dei caratteri sulla
 * pagina servita, che guarda i paragrafi e non le regole. */
.spiega { max-width: var(--misura-di-lettura); }
/* ⚠️ ⚠️ **E DOVE LA PROSA STA DIRETTAMENTE NELLA COLONNA, QUESTA REGOLA PERDEVA.**
 * `.banco > *` (0,1,1) batte `.spiega` (0,1,0), e il tetto della colonna — 1080
 * px, che e' giusto per una TABELLA — vinceva sulla misura di lettura, che e'
 * giusta per un PARAGRAFO. Misurato sul servito l'08.09.2026 a 1280 px: «La
 * casa» e «Contabilita'» avevano paragrafi da **100 caratteri per riga**, e a
 * 1920 px da 108. La regola c'era, la misura era giusta, e non arrivava mai
 * dove serviva: nessuno se n'era accorto perche' il foglio dichiarava la cosa
 * giusta e la pagina ne faceva un'altra.
 * ⚠️ `:has()` esclude i paragrafi che portano comandi o pastiglie: quelli non
 * sono prosa, e stringerli a 51ch li manderebbe a capo senza motivo. */
.banco > .spiega, .banco > .aiuto, .banco > .tenue, .banco > .avviso,
.banco > p:not(:has(a, button, input, select, textarea)),
.a-che-punto {
  max-width: var(--misura-di-lettura);
}
/* ⚠️ E le altre due classi con cui Argo scrive prosa: `.aiuto` (la nota sotto un
 * campo) e `.tenue` (il testo secondario). Anche loro senza misura. Contato sul
 * SERVITO, sulla pagina del preventivo col capitolato dentro:
 *     senza misura su .spiega ............ 19 paragrafi oltre i 75 caratteri
 *     con .spiega ......................... 7
 *     con .spiega, .aiuto e .tenue ........ 3
 * ⚠️ Su un elemento in linea `max-width` non fa niente, e va bene cosi': queste
 * classi vestono sia paragrafi sia pezzi di riga, e la misura di lettura
 * riguarda i primi. */
.aiuto, .tenue, .avviso { max-width: var(--misura-di-lettura); }
/* ⚠️ E dentro una `.voce` l'aiuto e' uno `<span>` IN LINEA: `max-width` su un
 * elemento in linea non fa niente, quindi restava l'ultimo paragrafo lungo della
 * pagina — 83 caratteri. Diventa un blocco, e costa 51 px di altezza su una
 * pagina che ne fa 16.272: misurato sul servito prima di scriverlo. */
.voce > .aiuto { display: block; max-width: var(--misura-di-lettura); }
.modulo .spiega { margin: 0 0 var(--s6); color: var(--tenue); max-width: var(--misura-di-lettura); }
.modulo .campo textarea, .modulo .campo select, .modulo .campo input {
  min-height: var(--tocco); padding: var(--s2) var(--s4);
  background: var(--fondo); border: var(--filetto) solid var(--fioco);
  color: var(--carta); border-radius: var(--raggio-0);
  font: 16px/1.4 "IBM Plex Sans", sans-serif;
}
.modulo .campo textarea { min-height: 96px; resize: vertical; }
.modulo .campo .aiuto { font-size: var(--t-nota); color: var(--fioco); }
.modulo .campo .sbaglio { font-size: var(--t-minuto); color: var(--ossido-testo); }
/* ⚠️ La copia che stava qui — `.modulo .campo input`/`textarea` con le stesse
 * identiche dichiarazioni — è stata tolta il 06.09.2026: diceva la stessa cosa
 * della regola dei campi, e due posti che devono dire la stessa cosa prima o poi
 * non la dicono. Era anche il motivo per cui il `<select>` restava scoperto:
 * chi guardava qui vedeva due campi su tre e sembrava completo. */
.modulo .coppia { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--s4); }
/* Stesso gruppo per link, invii e filtri. I moduli non spezzano la fila.
 * ⚠️ ⚠️ **`.comandi` ERA GIA' PRESO, e non da un dettaglio: e' il gruppo dei tre
 * comandi fissi della barra in cima (`.ponte .comandi`, riga 731).** Scrivendo
 * qui `.comandi` senza ambito, il `flex-wrap: wrap` arrivava anche li' — la barra
 * poteva andare a capo e a 360 px passava da 121 a **233 px**. Essendo `fixed`,
 * copriva le prime tre voci del menu: «Oggi», «Parla con Argo», «Avvisi» non si
 * potevano piu' toccare. Misurato con `elementFromPoint` il 10.09.2026, e preso
 * da `test_a_360_tutte_le_voci_del_menu_sono_visibili_senza_scorrere`.
 * ⚠️ `.ponte .comandi` (0,2,0) vince su `.comandi` (0,1,0) per le proprieta' che
 * dichiara — display, align-items, gap — quindi il difetto NON si vedeva li':
 * passava solo `flex-wrap`, che la barra non dichiara. Una collisione di nome che
 * ne lascia fuori tre proprieta' su quattro e' peggio di una che le prende tutte:
 * sembra che non sia successo niente.
 * Il gruppo del banco si chiama `.comandi` **dentro il banco**, e basta. */
/* ⚠️ `.intestazione > .conto` sta in questo gruppo dal 10.09.2026 e solo quando
   contiene comandi (`:has`): su `/commesse/57/` teneva «Tranche» e «Nuovo
   documento», che a 360 px andavano a capo larghi 153 e 173 — una scaletta sul
   bordo destro. Senza `:has` la stessa regola prenderebbe i `div.conto` che
   portano il solo conteggio, che non sono un gruppo di comandi. */
.bottoni, .banco .comandi, .intestazione > .azioni, .banco p:has(> .azione),
.intestazione > .conto:has(> .azione) {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3);
}
.banco .comandi { align-items: flex-end; }
.banco .comandi > :is(form, .campo) { margin: 0; min-width: 0; }
.banco > .comandi { margin-bottom: var(--s6); }

/* La vicinanza identifica il gruppo: 16 dentro, 32 fra sezioni. */
:where(.banco) p { margin-block: 0 var(--s4); }
.banco > :is(section, h2, .modulo) { margin-top: var(--s7); }
/* ⚠️ Un titolo sta col modulo che INTRODUCE: la regola qui sopra dava lo stesso
   --s7 al titolo e al modulo che lo segue, e «Aggiungi destinatario» finiva piu'
   lontano dal suo modulo che dal blocco di sopra (32 px sopra, 44 sotto — rilievo
   del banco sulle impostazioni, 11.09.2026). */
.banco > h2 + .modulo { margin-top: var(--s3); }
.banco :where(section, article) > p:not(:has(.azione, input, select, textarea)) {
  max-width: var(--misura-di-lettura);
}
@media (max-width: 599px) {
  .comandi > *, .bottoni > *, .intestazione > .azioni,
  .intestazione > .azioni > *, .banco p:has(> .azione) > .azione,
  .intestazione > .conto:has(> .azione) > * {
    flex: 1 1 100%; width: 100%;
  }
  /* ⚠️ ⚠️ **ALLARGARE IL MODULO NON ALLARGA IL BOTTONE CHE C'E' DENTRO**, e
     questa e' la meta' che mancava. Su `/contabilita/` i comandi sono un
     collegamento nudo e un `<form>` (chiudere il periodo e' irreversibile,
     quindi POST): il modulo prendeva i 328 px, il suo bottone restava a 304, e
     il bordo destro faceva la scaletta lo stesso. Una regola che si ferma al
     contenitore ripara cio' che non si vede e lascia cio' che si vede. */
  .comandi > form > .azione, .bottoni > form > .azione,
  .intestazione > .azioni > form > .azione,
  .intestazione > .conto:has(> .azione) > form > .azione { width: 100%; }
}

/* ⚠️ ⚠️ **LA COLONNA SI DECIDE SULLA LARGHEZZA DEL BANCO, NON DELLO SCHERMO.**
   La regola qui sopra vale sotto i 599 px di SCHERMO, e non bastava: sopra i
   760 px compare la fiancata, il banco scende a ~530 px, e due comandi che non
   ci stanno affiancati vanno a capo ognuno con la sua larghezza. Misurato il
   10.09.2026 sul servito, a passi fitti:
     /contabilita/ «Registra…» 332 + «Chiudi e liquida» 304 — impilati a 600–680
       e di nuovo a 760–900 (il gruppo e' piu' stretto di 648 px);
     /commesse/57/ ricerca «Cerca» 99 + «139 aspettano» 170 — impilati a 760–820.
   Due scalette che il cancello a due larghezze non vedeva: le ha trovate il giro
   a cinque. Una soglia sullo schermo sarebbe fragile — basta un'etichetta piu'
   lunga su un'altra pagina per spostarla — mentre il difetto dipende da quanto
   e' largo il BANCO. Sotto i 700 px di banco i gruppi di comandi vanno in
   colonna, larghi uguali, come sul telefono. Scelta di disegno fatta con
   l'utente: il prezzo e' che in quella fascia anche le ricerche che oggi
   stanno in riga vanno in colonna.
   ⚠️ `container-type: inline-size` applica anche il contenimento di LAYOUT,
   che fa del contenitore il blocco di riferimento dei discendenti `fixed`.
   Dentro `.banco` non ce ne sono (i fissi sono `.ponte` e `.rotta`, fuori);
   gli `sticky` — `.scrivi` (la conferma della lista cavi non lo e' piu' dal 17.09) — non ne sono toccati.
   E la sua larghezza viene dalla griglia della pagina, non dal contenuto:
   il contenimento sull'asse in linea non lo fa collassare.
   ⚠️ La query colpisce solo i discendenti del banco: il `.comandi` della barra
   in cima (`.ponte .comandi`), nome gia' preso, resta fuori per costruzione. */
.banco { container: banco / inline-size; }
@container banco (max-width: 699px) {
  .comandi > *, .bottoni > *, .intestazione > .azioni, .intestazione > .azioni > *,
  .banco p:has(> .azione) > .azione, .intestazione > .conto:has(> .azione) > *,
  body.lavoro form.cerca > .azione, body.lavoro form.cerca > button,
  /* ⚠️ La chiave dei lettori stava sotto i 560 px di SCHERMO: a 768 il banco e'
     largo ~530 px, i due gesti andavano a capo larghi quanto le loro parole —
     una scaletta 234/211 (banco, 11.09.2026). E' la larghezza del banco che
     conta, e questa regola la misura gia'. */
  .azioni-chiave > * {
    flex: 1 1 100%; width: 100%;
  }
  .comandi > form > .azione, .bottoni > form > .azione,
  .intestazione > .azioni > form > .azione,
  .intestazione > .conto:has(> .azione) > form > .azione { width: 100%; }
}

/* Il filo di Arianna: da dove sei arrivato, e la via indietro. */
.filo { margin-bottom: var(--s4); font-size: var(--t-minuto); }
/* ⚠️ `:not(.azione)`: vedi la nota sulla secondaria. Un filo di briciole
   colora i suoi LEGAMI, non i comandi che qualcuno gli mette dentro. */
.filo a:not(.azione) { color: var(--tenue); }
/* UX98: dal tenue alla carta, come `.fasi a:hover` — l'ossido vivo leggeva meno del riposo. */
.filo a:not(.azione):hover { color: var(--carta); }

/* Il cartiglio in fondo alla pagina di lavoro: la stessa firma dell'ingresso. */
.banco .cartiglio {
  grid-template-columns: repeat(4, 1fr);
  margin-top: var(--s7); padding: var(--s4) 0 0;
}

@media (max-width: 720px) {
  /* ⚠️ Qui non c'e' piu' niente da correggere: la riga e' flex e va a capo da
     sola. Prima c'erano `grid-template-columns: 34px 1fr` e `grid-column: 2`
     sulle celle, e ognuna delle due si e' rotta una volta — la prima mandando
     l'ultima colonna a capo dentro i 46 px dell'indice, la seconda spingendo
     il contenuto della targa a destra con meta' scheda vuota. */
  .modulo .coppia { grid-template-columns: 1fr; }
  .banco .cartiglio { grid-template-columns: 1fr 1fr; }
}

/* ── Gli avvisi: il posto dove il programma parla, e c'e' sempre ────────────
 * ⚠️ L'ingresso aveva il suo avviso e le pagine di lavoro no. Un salvataggio
 * rifiutato, una sessione scaduta, una lavorazione finita non avevano nessun
 * posto dove farsi vedere: sarebbero finiti in silenzio, che e' il modo in cui
 * un programma perde la fiducia di chi lo usa. La zona sta SEMPRE nello stesso
 * punto, cosi' chi la cerca sa dove guardare.                                */
.avvisi { margin-bottom: var(--s4); }
.avvisi:not(:has(*)) { margin-bottom: 0; }
.avvisi .avviso { margin: 0 0 var(--s3); }
/* ⚠️ Una conferma col colore dell'errore (rilievo di sistema del giudizio sull'
   avanzamento cavi, 17.09.2026): «Spunta ricevuta dal server.» usciva col
   rosso-bruno di `--avviso-testo` su fondo verde, e coi guanti si legge
   «qualcosa non va». Testo e bordo prendono il tono del loro stato, coi toni DA
   TESTO gia' dichiarati per ogni tavolozza (`--verde-testo` #186043 sulla carta:
   5,85:1 sul fondo tinto; `--ambra-testo` #7A570F: 4,94:1 — misurati dalla prova
   sul fondo risolto, non stimati). `border-color` su tutti i lati: `body.lavoro
   .avviso` mette un filo `--ossido` sui quattro lati, e su una conferma restava
   rosso attorno a un bordo sinistro verde. */
.avviso.success { border-color: var(--verde); background: color-mix(in srgb, var(--verde) 12%, transparent); color: var(--verde-testo); }
.avviso.warning { border-color: var(--ambra); background: color-mix(in srgb, var(--ambra) 14%, transparent); color: var(--ambra-testo); }

/* Il bottone che sta lavorando: lo dice, e non si preme due volte. */
.azione[aria-disabled="true"], button.entra[aria-disabled="true"] {
  /* L'attesa resta leggibile: l'opacita' schiariva insieme testo e fondo.
     Il cursore e il messaggio di lavoro annunciano gia' lo stato. */
  opacity: 1;
  cursor: progress;
}

/* ── Cio' che non c'e' ancora, detto per nome ───────────────────────────────
 * ⚠️ Non un riquadro vuoto in attesa di riempirsi: un riquadro che c'e' e non
 * dice mai niente insegna a non guardarlo, e il giorno in cui dira' qualcosa
 * nessuno se ne accorgera'. Qui si dichiara cosa manca e da dove arrivera'.  */
.in-arrivo {
  margin-top: var(--s7);
  padding: var(--s4) var(--s4);
  border: var(--filetto) solid var(--contorno);
  color: var(--tenue);
  font-size: var(--t-piccolo);
}
.in-arrivo-elenco { margin: var(--s3) 0 0; max-width: 68ch; }
.in-arrivo-elenco > div {
  display: grid; grid-template-columns: 104px minmax(0, 1fr);
  gap: var(--s3); padding: var(--s2) 0;
  border-top: var(--filetto) solid var(--linea);
}
.in-arrivo-elenco dt { color: var(--carta); font-weight: 600; }
.in-arrivo-elenco dd { margin: 0; color: var(--tenue); }
.in-arrivo-nota { margin: var(--s2) 0 0; max-width: var(--misura-di-lettura); color: var(--tenue); }
@media (max-width: 480px) {
  .in-arrivo-elenco > div { grid-template-columns: 1fr; gap: var(--s1); }
}

/* La coda di un elenco tagliato: dice quanti non si vedono. */
.coda { margin: var(--s3) 0 0; font-size: var(--t-minuto); color: var(--tenue); }

/* Una revisione senza file: si dice, non si lascia vuoto. */
.senza-file { color: var(--fioco); font-style: italic; }

/* ── La rotta: il menù, sempre presente ─────────────────────────────────────
 * ⚠️ A sinistra sullo schermo grande, in fascia sul tablet e su due righe sul
 * telefono. Non un pannello che si apre: a bordo, coi guanti, un menù nascosto
 * dietro un gesto e' un menù che non si usa.                                 */
.rotta {
  position: sticky;
  /* Sul telefono resta sotto il ponte fisso; dai 760 px la fiancata ribadisce
     `--ponte`, che li' coincide con l'ingombro reso. */
  top: var(--ponte-reso);
  display: flex;
  gap: var(--s1);
  padding: var(--s3) var(--s4) 0;
  border-bottom: var(--filetto) solid var(--contorno);
  background: var(--fondo-alto);
  overflow-x: auto;                 /* la plancia mobile qui sotto lo disattiva */
  z-index: 2;
}

@media (max-width: 759px) {
  .rotta { position: static; }
}

@media (max-width: 759px) {
  /* ⚠️ ⚠️ ⚠️ `html, body { height: 100% }` (r.426) da' al corpo un'altezza
   * DEFINITA, e in una colonna flessibile un'altezza definita piu' corta del
   * contenuto fa STRINGERE i figli (`flex-shrink: 1` e' il valore di partenza).
   * Misurato il 18.09 su `/contabilita/` a 360×780, con la prima stesura di
   * questa regola: il banco alto 718 px con dentro 2.875 px di contenuto, che
   * gli traboccava fuori — e la plancia, disposta sotto la SCATOLA del banco,
   * finiva a 863 px A CAVALLO del lavoro che continuava sotto. Cioe' esattamente
   * il difetto che il criterio 1.4 vieta, rifatto dalla correzione del 1.3.
   * Otto prove delle ancore l'hanno preso (`elementFromPoint` rispondeva
   * «rotta»), e la mia non l'aveva preso perche' guardava il FONDO DELLA
   * SCATOLA del banco invece del fondo del suo contenuto: adesso guarda quello.
   * Il rimedio e' dire al corpo che l'altezza dello schermo e' un MINIMO, non
   * una misura, e ai due figli di non stringersi. */
  body.lavoro { display: flex; flex-direction: column; height: auto; min-height: 100%; }
  body.lavoro > .rotta, body.lavoro > .banco { flex: none; }
  /* ⚠️ ⚠️ ⚠️ GIRO 4: qui c'era `.rotta { order: 2 }`. Adesso il menu' sta DOPO il
   * banco nel guscio (`guscio.html`), quindi in questa colonna ci arriva da solo
   * — e l'ordine del FUOCO coincide con quello che si vede. Con `order` non
   * coincideva: il giudizio 8,9 (rilievo 2) ha misurato col Tab vero la pagina
   * che scendeva a 344 px, nove fermate nella plancia in fondo e poi la risalita.
   * `order` sposta i pixel e non sposta la tastiera: e' un difetto di accesso in
   * ogni caso in cui la tastiera c'e' — il reflow al 400 % di zoom su una
   * scrivania (1280/4 = 320 px) e' quello che la difesa del giro 3 non copriva.
   * ⚠️ Nessun `order` torni qui: se il menu' deve stare sotto, ci sta col DOM. */
  .rotta {
    margin-top: var(--s6);
    padding-block: var(--s3);
    border-top: var(--filetto) solid var(--contorno);
    border-bottom: 0;
  }
}

/* ⚠️ Un ELENCO di selettori e non `:is()`: `:is()` prende la specificita' piu'
   alta dei suoi argomenti, e `.rotta :is(a, summary.macro-nome)` batteva le
   regole della plancia e della fiancata scritte come `.rotta a` — misurato:
   dietro «Archivio» le due micro non stavano piu' su una riga. */
.rotta a, .rotta summary.macro-nome, .rotta p.macro-nome {
  display: flex; flex-wrap: wrap; align-items: center; align-content: center;
  column-gap: var(--s2); row-gap: 0;
  min-height: var(--tocco);
  margin: 0;
  padding: 0 var(--s4);
  color: var(--tenue);
  text-decoration: none;
  border-bottom: var(--segno) solid transparent;
  font-family: "IBM Plex Sans", sans-serif;
  /* ⚠️ 1,4 e non 1,25: la scatola del glifo di Plex Sans e' alta 1,3 em, e a
     14 px il browser la arrotonda a 18 px — con 17,5 px di riga sporgeva di un
     pixel sopra, e un nome che esce dalla sua riga e' un nome tagliato per chi
     lo misura (`test_menu_mobile.py`, «intero»). */
  font-weight: 500; font-size: var(--t-piccolo); line-height: 1.4;
}
.rotta .voce-nome { white-space: nowrap; }
.rotta a:hover, .rotta summary.macro-nome:hover { color: var(--carta); }
.rotta a[aria-current] {
  color: var(--carta);
  border-bottom-color: var(--ossido);
}
.rotta a:focus-visible, .rotta summary:focus-visible { outline: 2px solid var(--carta); outline-offset: -2px; }

/* ⚠️ **LA MACRO E' IL CARTIGLIO DEL GENERE**: la condensata maiuscola a 16 px
   (`--t-corpo`, il gradino delle sezioni di una commessa), .06em, il colore
   delle voci. Vale per il titolo che si apre (`summary`), per quello che non si
   apre (`p`, una macro con una micro sola) e per la testa («Oggi», che e' un
   collegamento). Non e' un colore da solo a dire che e' un titolo: e' la forma.
   ⚠️ E vale per la VOCE SOLA (`a.sola`, D88: «Parla con Argo»): e' una riga di
   primo livello come «Oggi», e ne porta il vestito. Cio' che la distingue da una
   macro non e' il carattere: e' che NON ha il segno di apertura (nessun `::after`,
   nessun comando accanto) — e da una micro, che NON rientra. */
.rotta :is(summary.macro-nome, p.macro-nome, a.testa, a.sola) {
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-corpo); letter-spacing: .06em; text-transform: uppercase;
}
/* La freccia che dice «si apre»: a destra da chiusa, in giu' da aperta. Sta in
   fondo alla riga, dopo il conto. Disegnata col colore della scritta. */
.rotta details.porta > summary::after {
  content: "";
  flex: none;
  margin-inline-start: auto;
  width: 7px; height: 7px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
}
.rotta details.porta[open] > summary::after { transform: rotate(45deg); }
.rotta details.porta[open] > summary.macro-nome { color: var(--carta); }
/* ⚠️ Il conto della macro sta sulla riga CHIUSA: aperta, lo dicono le micro. */
.rotta details.porta[open] > summary .quante { display: none; }
/* ⚠️ La testa porta il SUO conto e basta, aperta o chiusa: un numero che
   cambiasse sotto il dito che apre la porta direbbe due cose alla stessa
   persona. Il conto delle sue micro («Avvisi») si legge aprendola. */

/* ⚠️ ⚠️ **LA TESTA E IL SUO COMANDO SONO DUE BERSAGLI, NON UNO DENTRO L'ALTRO.**
   «Oggi» e' una pagina E una macro. Un collegamento dentro un `<summary>` e' un
   comando dentro un comando: lo sconsiglia chi legge con la voce e lo segnala
   axe (`nested-interactive`). Qui la riga e' il collegamento, largo tutto meno
   un tocco; il comando che apre le micro e' il `<summary>`, posato in assoluto
   sull'ultimo tocco della riga, 48 × 48, con la sola freccia e un nome per chi
   ascolta (`.solo-lettori`). Il tasto di tabulazione li prende in quest'ordine:
   prima il posto, poi il comando. Il `<details>` sta dopo il collegamento nel
   documento, e le micro scendono sotto la riga intera. */
.rotta .macro.con-testa { position: relative; }
.rotta .macro.con-testa > a.testa { margin-inline-end: var(--tocco); }
.rotta .macro.con-testa > details.porta > summary.apri {
  position: absolute; top: 0; right: 0;
  width: var(--tocco); height: var(--tocco); min-height: 0;
  justify-content: center;
  padding: 0;
  color: var(--tenue);
}
.rotta .macro.con-testa > details.porta > summary.apri::after { margin-inline-start: 0; }
.rotta .macro.con-testa > details.porta > summary.apri:hover,
.rotta .macro.con-testa > details.porta[open] > summary.apri { color: var(--carta); }



/* ⚠️ Sulla fascia intermedia il titolo di una macro senza porta (l'ospite del
   cantiere: «Il lavoro» sopra la sola «Commesse») diventa un FILETTO: il
   raggruppamento si legge lo stesso e non ruba larghezza. Sul telefono la
   plancia qui sotto lo nasconde visivamente. Il testo resta sempre nel
   documento per chi legge con la voce. */
@media (max-width: 759px) {
  p.macro-nome {
    width: 0; height: 22px; padding: 0; margin: 0 var(--s3);
    align-self: center; overflow: hidden;
    text-indent: -999em; white-space: nowrap;
    border-left: var(--filetto) solid var(--linea);
  }
}

/* ⚠️ ⚠️ **U1 · LA DISPOSIZIONE DEL MENU NON DEVE CONTARE LE VOCI.**
 * Fino all'08.09.2026 questo blocco disponeva le porte con dei selettori che
 * CONTANO i fratelli — `a:first-of-type:nth-last-of-type(5)`, poi un secondo
 * gruppo per il caso a sette. Funzionava per cinque voci; poi il loop ne ha
 * aggiunta una sesta e una settima («Avvisi»), e la plancia si e' rotta in tre
 * modi contemporaneamente: righe da 3-2-2, «Parla con Argo» che arrivava a
 * filo dello schermo, e le SEI prove che il menu lo fissano diventate rosse
 * senza che nessuno avesse toccato il menu.
 * ⚠️ Non e' stata una svista: e' il MECCANISMO. Una regola che sa quante porte
 * ci sono e' una regola che va riscritta ogni volta che se ne apre una — e
 * questo programma deve arrivare a gestire l'azienda intera, cioe' ad averne
 * venti. Il numero di voci non e' una cosa che il foglio di stile debba sapere.
 *
 * Qui non le conta piu'. Ogni casella e' larga almeno quanto la sua scritta
 * (`min-width: auto` di una casella flessibile, quindi non si tronca MAI) e
 * cresce a riempire la riga (`flex-grow`); le righe vanno a capo da sole. Due
 * caselle o venti, la disposizione e' la stessa e nessuna finisce fuori dallo
 * schermo.
 * ⚠️ E si perde il `overflow-x: auto`: una barra che scorre di lato nasconde
 * le porte senza dirlo, ed e' il difetto che da' il nome a U1. */
@media (max-width: 759px) {
  /* ⚠️ ⚠️ **15.09.2026 (sera): LE CASELLE SONO LE MACRO, e le micro stanno
   * dietro.** Chi amministra ha cinque caselle — tre righe: «Oggi» intera (la
   * regola del dispari), poi due a due — invece delle quattro righe di
   * quattordici voci. Al piu' DUE caselle per riga (`min-width: 33%`: tre non ci
   * stanno mai); l'andare a capo (`flex-wrap`), senza il quale le caselle escono
   * dallo schermo; e chi amministra resta con «Oggi» nel primo schermo.
   * ⚠️ Le caselle di una riga non sono larghe uguali: si allargano quanto il
   * loro nome. E' il prezzo, detto: una colonna allineata con un nome spezzato
   * in due si legge peggio di due caselle diverse con due nomi interi. */
  .rotta {
    display: flex;
    flex-wrap: wrap;
    column-gap: var(--s1); row-gap: 0;
    /* il margine sopra lo porta ogni casella */
    padding: 0 var(--s2);
    overflow-x: visible;
  }
  .rotta > .macro { flex: 1 1 auto; min-width: 33%; margin-top: var(--s1); }
  .rotta > .macro > p.macro-nome {
    position: absolute;
    width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
    clip-path: inset(50%); overflow: hidden; white-space: nowrap;
  }
  .rotta a {
    justify-content: center;
    padding: 0 var(--s2);
    font-size: var(--t-minuto);
  }
  /* ⚠️ ⚠️ **NESSUNA CASELLA RESTA SOLA SULLA SUA RIGA, e non contando le
   * caselle.** Col semplice `flex-wrap` le righe le decide la lunghezza delle
   * scritte, e una casella sola in fondo si legge come un a capo sbagliato, non
   * come una scelta. Due per riga: una riga puo' restare spaiata solo se il
   * totale e' dispari, e `:nth-child(1 of …):nth-last-child(odd of …)` prende la
   * PRIMA casella esattamente quando le caselle sono in numero dispari, dandole
   * la riga intera — ed e' la porta di casa. Da li' in giu' ne restano un
   * numero pari, e vanno a due a due fino in fondo.
   * ⚠️ ⚠️ **Con una macro APERTA le righe si contano attorno a lei** (15.09,
   * sera). La macro aperta prende la riga intera, con le sue micro sotto. Le
   * chiuse PRIMA di lei vanno a due a due, e se sono dispari quella subito prima
   * prende la riga intera; le chiuse DOPO di lei uguale, e se sono dispari la
   * prima di loro prende la riga intera. Cosi' nessuna resta sola e la plancia
   * non si allunga: sulla conversazione, con «Oggi» aperta, chi amministra ha
   * quattro righe (la testa, le due micro, due coppie), non sei. La regola non
   * sa quante macro ci sono: conta la parita', da qualunque parte stiano.
   * ⚠️ ⚠️ Qui c'erano `nth-last-of-type(5)` e `(7)`: regole che SANNO quante
   * porte ci sono e si rompono alla successiva — il difetto che ha fatto
   * diventare rosse sei prove quando e' arrivata «Avvisi». Erano state tolte, e
   * l'08.09.2026 sono RIENTRATE da una fusione risolta a macchina: il difetto
   * era invisibile a leggere il diff, e l'ha preso solo la prova che misura le
   * righe rese. Una risoluzione di conflitti scritta a macchina va guardata
   * come codice nuovo, non come una somma. */
  /* ⚠️ ⚠️ **LA VOCE SOLA E' UNA CASELLA COME LE ALTRE, e la parita' la conta**
   * (D88, 16.09.2026). `a.sola` sta fra i figli della rotta come i `.macro`:
   * le regole qui sotto contano `.macro` E `a.sola` insieme, se no la casella
   * di «Parla con Argo» sposterebbe le coppie di uno e una macro resterebbe
   * sola in fondo. Chi amministra su «Oggi» ha sei caselle: «Oggi» e «Parla
   * con Argo» sulla prima riga, poi due coppie — tre righe, come prima. */
  .rotta:not(:has(> .macro > details.porta[open]))
    > :is(.macro, a.sola):nth-child(1 of .macro, a.sola):nth-last-child(odd of .macro, a.sola) { flex-basis: 100%; }
  .rotta > .macro:has(> details.porta[open]) { flex-basis: 100%; }
  .rotta > :is(.macro, a.sola):nth-child(odd of .macro, a.sola):has(+ .macro > details.porta[open]) { flex-basis: 100%; }
  .rotta > .macro:has(> details.porta[open]) + :is(.macro, a.sola):nth-last-child(odd of .macro, a.sola) { flex-basis: 100%; }
}

/* ── LE PORTE DELLE MACRO ──────────────────────────────────────────────────
 * ⚠️ Le apre il browser (`<details>`), non un copione: senza JavaScript
 * funzionano uguale. Il bersaglio e' `--tocco` come ogni altra riga del menu'.
 * ⚠️ Nessun token nuovo: un token dichiarato in una tavolozza sola rende nulla
 * la dichiarazione nell'altra, in silenzio (la conversazione ha la scura).     */
/* ⚠️ Il bersaglio sta sulla PORTA, non sul posto dove si trova: dovunque un
   `details.porta` si apra, il suo titolo si prende coi guanti. Lo misura
   `test_pieghevoli.py`. */
details.porta > summary {
  display: flex; align-items: center;
  min-height: var(--tocco);
  list-style: none;
  cursor: pointer;
}
details.porta > summary::-webkit-details-marker { display: none; }
@media (max-width: 759px) {
  /* ⚠️ 15.09.2026: la casella e' il TITOLO della macro che si apre, e ne porta
     il vestito — il maiuscolo condensato, .06em — dentro il contorno e coi 48 px
     del bersaglio. Le micro dietro sono parole del testo: si vede cosa e' un
     genere e cosa e' un posto. Il contorno e' `--contorno`: e' cio' che
     distingue una casella che si APRE da una voce che PORTA, e un contorno che
     porta un'informazione regge 3:1 nelle due tavolozze. */
  .rotta :is(summary.macro-nome, a.testa, a.sola) {
    display: flex; align-items: center; justify-content: center; gap: var(--s2);
    min-height: var(--tocco);
    margin: 0; padding: 0 var(--s2);
    border: var(--filetto) solid var(--contorno);
    color: var(--tenue);
    font-size: var(--t-nota);
    text-align: center;
  }
  /* ⚠️ La voce sola e' un figlio DIRETTO della rotta, e la casella e' lei
     stessa: la disposizione della plancia (larghezza, spazio sopra) sta qui,
     DOPO la regola della casella, che azzera i margini. */
  .rotta > a.sola { flex: 1 1 auto; min-width: 33%; margin-top: var(--s1); }
  .rotta details.porta > summary.macro-nome::after { margin-inline-start: 0; }
  .rotta details.porta > summary.macro-nome:hover { color: var(--carta); }
  /* La testa sulla plancia: la casella e' il collegamento, e il comando che
     apre le micro sta sull'ultimo tocco, col suo contorno. */
  .rotta .macro.con-testa > a.testa { margin-inline-end: var(--tocco); }
  /* ⚠️ ⚠️ La testa sulla sua pagina si segna come ogni voce della plancia: la
     BARRA sotto, 3 px d'ossido, che sulle altre pagine NON c'e' — li' la
     casella ha il filetto da 1 px di tutte le caselle. Fino al 15.09 (sera) la
     barra era SEMPRE da 3 px e sulla propria pagina cambiava solo colore, cioe'
     il colore da solo, che al sole e a chi non distingue i rossi non dice
     niente (misurato dall'audit: contorno rgb(119,138,146) → ossido). Adesso
     cambia la FORMA: da filetto a barra. La barra corre sotto tutta la casella,
     comando compreso: la casella e' «Oggi», e si e' su «Oggi». */
  .rotta .macro.con-testa > a.testa[aria-current] { border-bottom: var(--segno) solid var(--ossido); }
  /* e la voce sola sulla SUA pagina (la conversazione): la stessa barra. */
  .rotta > a.sola[aria-current] { border-bottom: var(--segno) solid var(--ossido); }
  .rotta .macro.con-testa > details.porta > summary.apri {
    border: var(--filetto) solid var(--contorno); border-inline-start: 0;
  }
  .rotta .macro.con-testa:has(> a.testa[aria-current]) > details.porta > summary.apri {
    border-bottom: var(--segno) solid var(--ossido);
  }
  /* Dietro la porta, le stesse righe per nome: «Warehouse and delivery notes»
     e «Products» stanno insieme solo se nessuna casella ha un minimo da meta'
     riga. Il dispari da' ancora la riga intera alla prima. */
  .rotta .voci-della-porta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s1);
    padding-top: var(--s1);
  }
  .rotta .voci-della-porta > a { flex: 1 1 auto; }
  .rotta .voci-della-porta > a:nth-child(1 of a):nth-last-child(odd of a) { flex-basis: 100%; }
  /* ⚠️ Una porta CHIUSA non dispone le sue voci. Il browser non le dipinge, ma
     se qualcuno chiede il loro rettangolo le mette lo stesso in fila — dentro
     una porta larga meta' schermo, coi nomi che non vanno a capo: «Preventivato
     e consuntivo» finiva a 382 px su 360, e chi misura lo sbordo lo contava. */
  .rotta details.porta:not([open]) > .voci-della-porta { display: none; }
}

/* ⚠️ **LA FIANCATA, dai 1000 px in su.** La fascia orizzontale reggeva otto voci;
   questo programma deve arrivare a gestire l'azienda intera — cantiere, persone,
   fatture, contabilita' — e a venti voci in fila una barra orizzontale non ci
   sta: comincia a scorrere di lato, e un menu' che scorre e' un menu' in cui non
   si trova niente.
   ⚠️ Sotto i 1000 px NON cambia: resta la fascia, aperta e senza gesti da
   scoprire. Sta scritto nel guscio da luglio, ed e' una regola di bordo — coi
   guanti, un menu' che si apre con un gesto e' un menu' che non si usa. */
/* ⚠️ **LA FASCIA FRA 760 E 999 PX ERA LA PIU' ROTTA DI TUTTE, e non la
 * guardava nessuno.** Sotto i 760 c'e' la plancia, sopra i 1000 la fiancata; in
 * mezzo restava la barra orizzontale con `overflow-x: auto`, e a 768 px —
 * cioe' su un tablet tenuto in verticale, che e' il modo in cui questo
 * programma si usa in sala macchine — «La casa» cominciava a 769 px su uno
 * schermo largo 768: fuori, senza che niente dicesse che si poteva scorrere.
 * Misurato sul servito l'08.09.2026. La fiancata regge benissimo a 768 (236 px
 * di menu, 532 di lavoro): il rimedio e' cominciarla prima, non aggiustare una
 * barra che a quella larghezza non ci sta comunque. */
@media (min-width: 760px) {
  /* ⚠️ ⚠️ **280 px, e il numero sta in UN posto** (15.09.2026, sera). Era 272:
     con le micro rientrate sotto il filetto della macro la piu' lunga,
     «Committenti, cantieri e fornitori», chiede 216,4 px a 15 px e ne aveva
     212. Adesso ne ha 227: 280 − 16 di margini della rotta − 1 di filetto − 15
     del rientro (12 + 3 di barra della macro) − 2 di filetto − 3 di barra − 8 −
     8 = 227, cioe' 10 px di aria per un altro browser che arrotonda in un altro
     modo. 280 e' il tetto che il mandato del 15.09 aveva dato. La colonna del
     lavoro si stringe di altri 8 px.
     ⚠️ Non e' un colore, e sta sul corpo: vale uguale nelle due tavolozze. */
  body.lavoro {
    --fiancata: 280px;
    display: grid;
    grid-template-columns: var(--fiancata) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    min-height: 100dvh;
  }
  .ponte { grid-column: 1 / -1; }
  /* ⚠️ ⚠️ **LA FIANCATA SPARIVA SCORRENDO, e non da oggi.** Misurato sul
   * servito l'08.09.2026 a 1280×900: su `/preventivi/6/` a 1200 px di
   * scorrimento il menu stava da -1138 a -300, cioe' **fuori dallo schermo del
   * tutto**. Su una pagina alta ottomila pixel questo vuol dire che per
   * cambiare pagina bisogna prima risalire in cima.
   * La causa non e' `sticky`: e' il suo contenitore. `body.lavoro` e' una
   * griglia con `min-height: 100dvh` e la riga del banco a `minmax(0, 1fr)` —
   * quel minimo a ZERO permette alla riga di essere piu' bassa del contenuto,
   * quindi la griglia resta alta quanto lo schermo mentre il banco le esce
   * fuori. Un elemento appiccicato non puo' viaggiare oltre il proprio
   * contenitore: finito il contenitore, se ne va con la pagina.
   * ⚠️ Non si tocca `minmax(0, 1fr)`: e' quello che da' al banco un'altezza
   * definita, cioe' quello su cui la conversazione di `/chiedi/` calcola la
   * propria. Si toglie invece la fiancata dal flusso — la colonna della
   * griglia resta larga quanto la fiancata e continua a tenere il posto, quindi
   * non copre niente. */
  /* ⚠️ ⚠️ **GLI SPAZI DICONO I LIVELLI, e stanno nella scala** (15.09.2026,
   * sera). Fra due macro 4 px (`--s1`); fra la macro e le sue micro niente: le
   * micro pendono dalla macro, sotto il suo filetto; fra due micro 4 px.
   * ⚠️ Il conto dell'altezza: chi amministra su una pagina dei soldi ha 5 macro
   * e 3 micro da 48 px, cioe' 384 + 7 intervalli da 4 = 412 px, dentro gli 838
   * della fiancata a 900 px di schermo; con TUTTE le macro aperte col dito 16
   * righe, 828 px — ci stanno ancora. `test_menu_mobile.py` a 1280×900 e il
   * cancello a scorrimento pretendono ogni voce dentro lo schermo. */
  .rotta {
    position: fixed;
    top: var(--ponte);
    left: 0;
    width: var(--fiancata);
    height: calc(100dvh - var(--ponte));
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--s1) var(--s2) var(--s4);
    overflow-x: hidden;
    overflow-y: auto;
    border-bottom: none;
    border-right: var(--filetto) solid var(--contorno);
  }
  .rotta > .macro + .macro { margin-top: var(--s1); }
  /* la voce sola (D88) sta nella colonna con lo stesso passo delle macro */
  .rotta > .macro + a.sola, .rotta > a.sola + .macro { margin-top: var(--s1); }
  .rotta .voci-della-porta > a + a { margin-top: var(--s1); }
  /* la riga della macro comincia dopo lo spazio della barra: 3 px + 12, cosi'
     il suo nome e la barra della micro aperta stanno in colonna */
  .rotta :is(summary.macro-nome, p.macro-nome, a.testa, a.sola) {
    border-bottom: none;
    padding: 0 var(--s2) 0 calc(var(--s3) + var(--segno));
  }
  /* la voce corrente si segna a SINISTRA: sotto la voce, in colonna, il filetto
     inferiore diventerebbe una riga di separazione fra due voci — cioe' direbbe
     un'altra cosa. */
  .rotta a {
    border-bottom: none;
    border-left: var(--segno) solid transparent;
    padding: 0 var(--s2) 0 var(--s3);
  }
  /* ⚠️ ⚠️ **LE MICRO RIENTRANO, sotto un filetto che pende dalla macro**
     (15.09.2026, sera). Il filetto comincia dove comincia il nome della macro e
     scende lungo le sue micro: e' la forma che dice «queste stanno dentro
     quella», e la si vede anche senza leggere. E' `--contorno`, che porta
     un'informazione e regge 3:1 nelle due tavolozze — non `--linea`, che e' un
     righello. Il testo della micro comincia 13 px dopo quello della macro. */
  .rotta .voci-della-porta {
    display: flex; flex-direction: column; gap: 0;
    margin-inline-start: calc(var(--s3) + var(--segno));
    border-left: 2px solid var(--contorno);
  }
  .rotta .voci-della-porta > a { padding: 0 var(--s2) 0 var(--s2); }
  /* ⚠️ I DISTINTIVI STANNO A DESTRA, SULLA RIGA DEL NOME (15.09.2026): il conto
     «272». Il margine automatico lo spinge al bordo; il nome resta intero. */
  .rotta a > .voce-nome + .quante { margin-inline-start: auto; }
  .rotta a > .quante { flex: none; }
  /* ⚠️ ⚠️ **LA VOCE APERTA: LA BARRA, SUL FONDO DELLA PAGINA** (15.09.2026).
     Il segno che non e' un colore di testo e' la barra da 3 px, e deve reggere
     3:1 con i DUE colori che ha accanto: la rotta a sinistra, il fondo della voce
     a destra. Il fondo era un velo d'ossido all'8%: nella tavolozza scura della
     conversazione schiariva la voce, e la barra ci stava a 2,92:1. Adesso la voce
     aperta prende `--fondo`, il fondo del banco — piu' scuro della rotta nello
     scuro (barra 3,73:1) e nel chiaro (3,88:1) — cioe' la voce aperta sta allo
     stesso livello del lavoro che mostra. Nessun token nuovo: `--fondo` e'
     dichiarato nelle due tavolozze.
     ⚠️ Vale per la micro della pagina aperta E per la testa sulla sua pagina; e
     per la micro che CONTIENE la pagina aperta (`aria-current="true"`: dentro
     una commessa si e' dentro «Commesse»). */
  .rotta a[aria-current] {
    border-left-color: var(--ossido);
    background: var(--fondo);
  }
  .banco { grid-column: 2; grid-row: 2; min-height: 0; }
  
  /* ⚠️ Il tetto e la centratura stanno adesso nella GRIGLIA di `.banco`, una
     volta sola e per tutti: vedi la nota accanto a `.banco {`. Qui restava una
     seconda copia della stessa decisione — e due regole che devono dire la
     stessa cosa prima o poi non la dicono, come le due fiancate a 900 e 1000 px
     che questa casa ha gia' pagato. */
}

/* ⚠️ C'erano DUE fiancate: questa a 1000 px e una piu' vecchia a 900, scritte in
   due giorni diversi, e vinceva quasi sempre la seconda perche' stava dopo nel
   foglio — 210 px al posto dei 236 dichiarati, e fra 900 e 999 una colonna che
   il titolo di gruppo (fatto filetto sotto i 1000) rendeva illeggibile. Due
   regole che devono dire la stessa cosa prima o poi non la dicono: e' rimasta
   questa sola, con dentro cio' che dell'altra serviva. */

/* ⚠️ Lo stesso conto anche sulle schede di una micro (`nav.schede`): «Da
   fatturare» dietro «Fatturazione» dice quante tranche aspettano anche da li'. */
/* ⚠️ ⚠️ UX98 giro 3 (18.09), criterio 5.1 · LA TESTA E LA VOCE SOLA NON
   CAMBIAVANO AL PASSAGGIO, e la colpa era della specificita'. La regola della
   casella — `.rotta :is(summary.macro-nome, a.testa, a.sola)`, che le veste col
   contorno e le mette `color: var(--tenue)` — pesa quanto `.rotta a:hover`
   (0,2,1) e viene DOPO: vinceva lei, e passare il puntatore su «Oggi» o su
   «Parla con Argo» non faceva niente. Misurato il 18.09 dal nuovo inventario
   degli stati, a 360 e a 1440, con i gesti veri: le due caselle erano le sole
   due fermate del guscio ferme al passaggio. Non e' un dettaglio da scrivania:
   sul telefono il passaggio non c'e', ma la stessa regola dava anche la
   PRESSIONE, e quella col dito c'e' eccome.
   ⚠️ `:is()` per pesare quanto la regola che batteva, e non un `!important`. */
.rotta :is(a.testa, a.sola, summary.macro-nome):hover {
  color: var(--carta);
  /* ⚠️ E il FONDO, perche' il colore da solo non basta per chi e' gia' al
     massimo. Sulla fiancata la casella della pagina aperta (`aria-current`)
     porta gia' `--carta`: passarci sopra la portava a `--carta`, cioe' da
     nessuna parte — misurato il 18.09 a 1440, riposo e passaggio identici fino
     all'ultimo pixel. Il velo d'ossido al 6% e' lo stesso di
     `.registro a.riga:hover`: si vede su ogni casella, anche su quella che il
     colore non puo' piu' cambiare. */
  background: color-mix(in srgb, var(--ossido) 6%, transparent);
}
/* ⚠️ E la pressione: l'anello interno di `--ombra-premuto`, lo stesso di ogni
   `.azione` del programma — al clic non sposta niente, dove un bordo vero
   muoverebbe la riga. Il colore sta al punto d'uso (`currentColor`), come
   vuole il commento del token in `:root`. */
.rotta :is(a, summary.macro-nome):active { box-shadow: var(--ombra-premuto) currentColor; }

.rotta .quante, .fasi .quante {
  min-width: 22px; padding: 0 var(--s2);
  background: var(--fondo); color: var(--tenue);
  border: var(--filetto) solid var(--contorno);
  border-radius: var(--raggio-pieno);
  font-family: "IBM Plex Mono", monospace; font-size: var(--t-nota); line-height: 20px;
  text-align: center;
}

/* ── H1: la lettura di un disegno ─────────────────────────────────────────
   ⚠️ `.riga.segnata` non usa il colore da solo: porta anche una barra a
   sinistra. Chi non distingue i rossi — e su una barca al sole nessuno li
   distingue — vedrebbe righe identiche. */
body.lavoro .riga.segnata { border-left: 4px solid var(--ossido); padding-left: var(--s4); }
body.lavoro .riga.segnata .sotto { color: var(--ossido-testo); }
body.lavoro .avviso {
  border: 1px solid var(--ossido);
  border-left-width: 4px;
  padding: var(--s3) var(--s4);
  margin: var(--s2) 0;
  /* ⚠️ **IL COLORE NON SI RIDICE QUI, ed e' il difetto che questa riga ERA.**
     Piu' su, `.avviso` sceglie il tono con cura e lo spiega: «`--ossido-testo`
     ci da' 4,05:1 — sotto la norma — quindi qui si usa il tono piu' scuro».
     Poi questa regola, quattrocento righe dopo e piu' specifica, rimetteva
     `--ossido-testo`: la scelta ragionata la annullava una riga che nessuno
     rileggeva accanto al suo commento. Misurato dal browser il 06.09.2026:
     **3,43:1** sulla carta chiara, sotto la norma — mentre due commenti nel
     foglio dichiaravano 4,05 e 4,96. Due posti che devono dire la stessa cosa
     prima o poi non la dicono, e qui il posto che vinceva era quello muto.
     Il tono lo decide `--avviso-testo`, dichiarato una volta per tavolozza. */
  font-size: var(--t-piccolo);
}
/* ⚠️ E IL BORDO DI UNA CONFERMA QUI ERA ROSSO SU QUATTRO LATI, barra compresa.
   `body.lavoro .avviso` e' (0,2,1) — `body` conta — e batte `.avviso.success`
   (0,2,0): il `border` qui sopra vinceva sul colore del bordo di conferme e
   attenzioni, e «Spunta ricevuta dal server.» usciva con la barra e il filo
   dell'errore. Misurato sul reso il 17.09.2026 (i quattro lati a rgb 196,85,63
   con la regola generale gia' corretta). Lo stato ridice il suo colore CON la
   stessa specificita', subito sotto la regola che lo schiacciava. */
body.lavoro .avviso.success { border-color: var(--verde); }
body.lavoro .avviso.warning { border-color: var(--ambra); }
body.lavoro .fioco { color: var(--fioco); font-size: var(--t-piccolo); max-width: var(--misura-di-lettura); }

/* ── B4: la colonna «Fonte del dato» ──────────────────────────────────────
   ⚠️ Piu' larga delle altre, e il numero non e' un gusto: dentro ci va anche il
   dettaglio — «ricavata dall'intervallo «WY 37-38» in TIM020-N.pdf p.1» — che a
   140 px va a capo cinque volte e fa una riga alta il doppio delle vicine, cioe'
   un elenco che non si scorre piu' a colpo d'occhio. Cresce fino a 260 e sotto i
   600 px prende la riga intera come fanno gia' i pulsanti.
   ⚠️ Il valore NON e' colorato: e' una parola — PIANO, ETICHETTE ESISTENTI,
   IPOTESI. Un colore su una barca al sole non si distingue, e chi non lo
   distingue vedrebbe righe identiche: e' la stessa ragione per cui `.segnata`
   porta una barra e non solo il rosso. */
body.lavoro .registro .riga > .colonna.fonte { flex: 1 1 200px; max-width: 260px; }
@media (max-width: 599px) {
  body.lavoro .registro .riga > .colonna.fonte { flex: 1 0 100%; max-width: none; }
}
/* La legenda della colonna: stessa forma degli avvisi, ma non e' un avviso —
   niente ossido, perche' non c'e' niente che sia andato storto. */
body.lavoro .fonti {
  border: 1px solid var(--contorno);
  border-left-width: 4px;
  padding: var(--s3) var(--s4);
  margin: var(--s2) 0;
  font-size: var(--t-piccolo);
}
body.lavoro .fonti p { margin: var(--s2) 0 var(--s3); color: var(--tenue); }
body.lavoro .fonti dl { margin: 0; display: grid; gap: var(--s1) var(--s4); }
@media (min-width: 600px) {
  body.lavoro .fonti dl { grid-template-columns: max-content 1fr; align-items: baseline; }
}
body.lavoro .fonti dt { font-size: var(--t-minuto); }
body.lavoro .fonti dd { margin: 0 0 var(--s2); color: var(--tenue); }
body.lavoro .azione.minore { min-height: var(--tocco); padding-inline: var(--s3); font-size: var(--t-minuto); }

/* ── G1: i due gesti sulla riga di una revisione ──────────────────────────
   ⚠️ In colonna e non affiancati sotto i 600 px: due bersagli da 48 px uno
   accanto all'altro su un telefono si toccano, e chi ha i guanti preme quello
   sbagliato — che qui vuol dire accettare un disegno da rifare. */
body.lavoro .colonna.azioni { display: flex; flex-direction: column; gap: var(--s2); align-items: stretch; }
@media (min-width: 600px) { body.lavoro .colonna.azioni { flex-direction: row; align-items: center; } }
/* ⚠️ Sul telefono i pulsanti si impilano, e devono essere larghi UGUALI. Non lo
   erano: «Accetto» e «Lista cavi» stanno dentro un `<form>` e «Sbagliata» e' un
   collegamento nudo, quindi il flex allargava il modulo — non il bottone dentro —
   e il collegamento. Risultato: due pulsanti stretti e uno lungo tutta la riga.
   Si vede solo guardando il telefono: nessuna misura di larghezza se ne accorge. */
@media (max-width: 599px) {
  body.lavoro .colonna.azioni > form { display: flex; }
  body.lavoro .colonna.azioni .azione { flex: 1 1 auto; width: 100%; }
}
body.lavoro .azione.fioca:where(:not(:disabled):not([aria-disabled="true"])) { background: transparent; color: var(--fioco); border: 1px solid var(--fioco); }
body.lavoro .azione.fioca:hover:where(:not(:disabled):not([aria-disabled="true"])) { color: var(--ossido-vivo); border-color: var(--ossido-vivo); }

/* ── G1b: la parola detta una volta sola ──────────────────────────────────
   ⚠️ Grande e spaziata perche' si detta a voce: chi la legge la sta dicendo al
   telefono, e «l» e «1» al telefono sono la stessa cosa se il carattere non
   aiuta. Monospazio, e selezionabile tutta con un tocco. */
body.lavoro .parola-una-volta {
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--t-secondo); letter-spacing: .12em;
  padding: var(--s3) var(--s4); margin: var(--s3) 0;
  background: var(--fondo-alto); border: 1px solid var(--ossido-fondo);
  user-select: all; word-break: break-all;
}

/* ── Il segno che sta lavorando ───────────────────────────────────────────
   ⚠️ Ragionato come chi lo usa: il caso peggiore non e' la lettura di un
   disegno — quella ha una pagina che parla — e' il CARICAMENTO. Un DWG del
   cantiere pesa 27-29 MB: premi «Archivia» e il browser resta fermo per minuti
   senza dire niente. Chi guarda preme di nuovo, o chiude.

   ⚠️ Non e' un popup che blocca: la pagina della lettura dice «non serve
   restare qui», e un modale davanti direbbe il contrario. Il segno sta DOVE hai
   premuto. */
.barra-viva {
  display: block; margin-top: var(--s3);
  border: 1px solid var(--fioco); background: transparent;
  position: relative; overflow: hidden;
}
.barra-viva .riempimento {
  display: block; height: 6px; width: 0;
  background: var(--ossido-fondo);
  transition: width .25s ease-out;
}
.barra-viva .dice {
  display: block; padding: var(--s2) var(--s3);
  font-family: "IBM Plex Mono", monospace; font-size: var(--t-nota);
  color: var(--fioco);
}
/* Dove la percentuale NON si conosce: una barra che si muove e non promette
   niente. ⚠️ Mai una percentuale inventata — «una barra di avanzamento
   inventata e' peggio del silenzio, perche' il silenzio non promette niente». */
.barra-viva.indeterminata .riempimento {
  width: 34%;
  animation: barra-va 1.5s ease-in-out infinite;
}
.barra-viva.rotta { border-color: var(--ossido); }
.barra-viva.rotta .dice { color: var(--ossido-testo); }
@keyframes barra-va {
  0%   { margin-left: -34%; }
  100% { margin-left: 100%; }
}
/* ⚠️ Chi ha chiesto meno movimento non lo riceve: a bordo, su uno schermo
   piccolo e con la nausea, un'animazione che non si puo' spegnere e' un motivo
   per chiudere il programma. La barra resta, ferma e piena a meta': dice
   ugualmente «sto lavorando». */
@media (prefers-reduced-motion: reduce) {
  .barra-viva.indeterminata .riempimento { animation: none; width: 50%; margin-left: 0; }
  .barra-viva .riempimento { transition: none; }
}

/* ── Bersagli: cio' che si tocca sta a 48 px, anche quando e' un filo ──────
   ⚠️ Rilievo di un revisore, misurato: i «← indietro» stavano a 18 px e le
   pastiglie a 21. Sono i due gesti che si fanno di piu' su un telefono a bordo,
   ed erano i due piu' piccoli della pagina. */
body.lavoro .filo a,
body.lavoro .ponte .nome {
  display: inline-flex; align-items: center;
  min-height: var(--tocco); padding-right: var(--s2);
}
body.lavoro a.pastiglia {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tocco); padding: 0 var(--s4); text-decoration: none;
}
/* ⚠️ Su un dito il primo tocco non deve limitarsi a «illuminare»: le regole di
   hover valgono solo dove un puntatore c'e' davvero. */
@media (hover: none) {
  body.lavoro .registro .riga:hover { background: inherit; }
}

/* ── La ricerca in cima a un elenco lungo ─────────────────────────────────
   ⚠️ Sta in cima e non in un pannello: con 119 documenti e' il primo gesto, non
   uno di quelli che si cercano. */
body.lavoro form.cerca {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3);
  margin: 0 0 var(--s6);
}
body.lavoro form.cerca .etichetta { flex-basis: 100%; }
body.lavoro form.cerca input[type="search"] {
  flex: 1 1 260px; min-width: 0; min-height: var(--tocco);
  padding: 0 var(--s4); font-size: var(--t-corpo);   /* 16 px: sotto, il telefono ingrandisce da solo */
  background: var(--fondo-alto); color: var(--carta);
  border: 1px solid var(--fioco);
}
/* ⚠️ Il filtro acceso si riconosce dal BORDO, non dal fondo (D60): pieno, si
   sommava a «Nuovo documento» e la commessa filtrata aveva due primari. L'ombra
   interna fa il secondo pixel del bordo senza spostare niente al clic. */
body.lavoro .azione.fioca.accesa:where(:not(:disabled):not([aria-disabled="true"])) {
  background: transparent; color: var(--carta); font-weight: 600;
  border-color: var(--ossido-vivo); box-shadow: var(--ombra-acceso) var(--ossido-vivo);
}
body.lavoro p.zone { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* ── La conferma della lista cavi: in fondo, NEL FLUSSO ─────────────────
   ⚠️ Con 219 righe la pagina e' alta centomila pixel su un telefono: il bottone
   in cima e' irraggiungibile da chi ha appena finito di leggere, e risalire per
   premerlo e' il modo di non premerlo mai. Per questo sta in fondo alle righe.
   ⚠️ E NON e' piu' appiccicata (`position: sticky; bottom: 0`, fino al
   17.09.2026): una barra ferma in basso copre cio' che arriva in fondo allo
   schermo — misurato a 360 e a 1440 con `elementFromPoint`: 13 comandi su 16
   (spunte, motivi, «Evidenzia i mancanti», «Prepara il disegno annotato») al
   loro centro restituivano il bottone della barra, cioe' il tocco pensato per
   una spunta ARCHIVIAVA la lista. Tre revisori su tre (audit UX del 15.09).
   Nel flusso non copre niente; chi ha gia' guardato le righe ci arriva dal
   rimando in testa alla proposta (`.salto-alla-conferma`). */
body.lavoro .conferma-in-fondo {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s3);
  margin-top: var(--s7); padding: var(--s4);
  background: var(--fondo-alto);
  border: var(--filetto) solid var(--contorno);
  border-top: var(--segno) solid var(--ossido-fondo);
  max-width: 720px;
}
body.lavoro .conferma-in-fondo .riepilogo { margin: 0; font-size: var(--t-voce); }
/* ⚠️ I due rimandi della pagina atterravano SOTTO il ponte fisso (giudizio 9,1
   del 17.09): «La conferma e' in fondo alla lista» portava il modulo a 24 px
   dall'alto su un telefono da 640 (ponte 121: si leggeva «In quale zona
   vanno?» e non «Conferma»), e «N avvisi dalla lettura» portava l'elenco degli
   avvisi a 0 con il titolo a 12 px, cioe' dietro la barra, a 360 e a 1440.
   Lo stesso rimedio del salto alle commesse (`.commessa-nel-confronto`): il
   bersaglio si ferma sotto l'ingombro RESO del ponte, che sul telefono
   comprende la seconda riga, piu' un respiro. */
body.lavoro #avvisi-lettura,
body.lavoro #conferma-lista { scroll-margin-top: calc(var(--ponte-reso, var(--ponte)) + var(--gradino-dell-ancora)); }
/* E il campo della zona, bersaglio del rimando nell'avviso in testa. */
body.lavoro #campo-zona { scroll-margin-top: calc(var(--ponte-reso, var(--ponte)) + var(--gradino-dell-ancora)); }
/* ⚠️ E il rimando «WPn ↓» ai motivi delle righe (giro 3, giudizio 9,3 del
   17.09): il campo del motivo atterrava a top 0, dietro il ponte, con la
   sigla, l'etichetta e l'errore nascosti — sullo schermo si vedeva la riga
   DOPO. `scroll-margin` vale solo per l'elemento a cui si salta: sulla riga
   non farebbe niente, perche' il bersaglio e' il CAMPO, e resta il campo
   apposta, cosi' il salto gli porta anche il fuoco (lo fa il browser, non il
   copione). Sopra il campo la riga porta la sigla, il tipo, l'etichetta
   «Escludi» da un tocco e l'etichetta del motivo: 166 px misurati a 1440, di
   piu' sul telefono dove il numero di riga sta su una riga sua. Il margine li
   tiene in vista tutti, con la sigla come prima cosa che si legge. */
body.lavoro #righe-cavi .riga input[type="text"] {
  scroll-margin-top: calc(var(--ponte-reso, var(--ponte)) + var(--s4) + 13rem);
}
/* ⚠️ L'errore della zona sta ACCANTO al campo, non solo in testa (giro 2,
   giudizio 9,1): la stessa veste di `.modulo .campo .sbaglio`, ma leggibile a
   bordo (il corpo piccolo, non quello minuto) e col tono dell'avviso, che
   sulla superficie sollevata regge oltre 4,5:1. Il campo sbagliato porta un
   contorno: la parola dice cosa, il contorno dice DOVE, anche al sole.
   ⚠️ Vale anche per l'errore di una RIGA («Scrivi perche' escludi questo
   cavo.»): e' lo stesso modulo, e fino al giro 2 stava in corpo normale senza
   veste, accanto a un errore della zona vestito (rilievo 3 del giudizio 9,3). */
body.lavoro .conferma-in-fondo .sbaglio,
body.lavoro #righe-cavi .riga .sbaglio {
  display: block; font-size: var(--t-piccolo); font-weight: 600; color: var(--avviso-testo);
}
body.lavoro .conferma-in-fondo [aria-invalid="true"],
body.lavoro #righe-cavi .riga [aria-invalid="true"] {
  outline: 2px solid var(--ossido-fondo); outline-offset: 1px;
}
body.lavoro .conferma-in-fondo .campo { align-self: stretch; max-width: 480px; }
body.lavoro .conferma-in-fondo .campo select,
body.lavoro .conferma-in-fondo .campo input { width: 100%; }
/* Il rimando alla conferma, in testa: un bersaglio da guanti, non un bottone. */
body.lavoro .salto-alla-conferma { margin: 0; }
body.lavoro .salto-alla-conferma a {
  display: inline-flex; align-items: center; min-height: var(--tocco);
  padding-inline: var(--s2); font-size: var(--t-piccolo);
}
body.lavoro .proposta-dei-cavi h2 { margin: var(--s1) 0 0; line-height: 1.1; }
/* Il filtro delle righe segnate: una casella grande in una riga da un tocco. */
body.lavoro .filtro-righe {
  display: inline-flex; align-items: center; gap: var(--s3);
  min-height: var(--tocco); margin: 0 0 var(--s4); cursor: pointer;
  font-size: var(--t-piccolo);
}
body.lavoro .filtro-righe input { width: var(--casella-scelta); height: var(--casella-scelta); margin: 0; flex: none; accent-color: var(--ossido-vivo); }
body.lavoro .filtro-righe:focus-within { outline: 2px solid var(--carta); outline-offset: 2px; }
/* ⚠️ Le righe nascoste restano nel modulo: `display: none` non toglie una
   spunta dai dati inviati, e chi filtra non perde le esclusioni gia' fatte. */
body.lavoro:has(#solo-da-guardare:checked) #righe-cavi .riga:not(.segnata) { display: none; }
body.lavoro .spunta-grande { accent-color: var(--ossido-vivo); }
/* I pieghevoli degli attrezzi: un tocco alto quanto un tocco, col suo segno. */
body.lavoro #incrocio-cavi > details > summary,
body.lavoro details.cosa-cambia > summary {
  min-height: var(--tocco); padding: var(--s3) 0; box-sizing: border-box;
  cursor: pointer; font-weight: 600;
}
body.lavoro #incrocio-cavi > details > form { margin-top: var(--s3); }
body.lavoro .conti-del-confronto {
  display: grid; grid-template-columns: max-content 1fr; gap: var(--s1) var(--s4);
  margin: 0 0 var(--s4);
}
body.lavoro .conti-del-confronto dt, body.lavoro .conti-del-confronto dd { margin: 0; }
body.lavoro .chi-amministra { margin-top: var(--s7); }
body.lavoro details.avviso summary {
  cursor: pointer; min-height: var(--tocco);
  display: flex; align-items: center; font-weight: 600;
}
body.lavoro details.avviso ul { margin: var(--s2) 0 0 var(--s4); }
body.lavoro details.avviso li { margin-bottom: var(--s2); }

/* ── L1 + L0: chiedere ad Argo ──────────────────────────────────────────────
   ⚠️ La copertura sta ACCANTO al numero, non in fondo alla pagina: «17 elementi»
   e «12 dei 17 vengono da un disegno letto» sono due frasi che si leggono
   insieme o non si leggono. Un numero senza copertura e' un numero su cui
   qualcuno taglia il rame sbagliato. */
/* ⚠️ Rifatta dopo l'audit UX del 15.09.2026 (Opus, Sol, Astra: tre su tre).
   Le nove domande stanno DOPO la risposta, in una sezione secondaria: chi ha
   scelto una domanda vuole il numero, non il catalogo. Griglia a colonne
   uguali: con `flex: 1 1 260px` il nono riquadro si allargava a tutta la riga
   (1.080×86 px a 1.440) e sembrava un'altra cosa. */
/* --s4 sotto il filetto: il passo che gia' separa il titolo dalla griglia (.lenti); fra i gruppi ci pensa --s7 sopra. */
.altre-domande { margin-top: var(--s7); padding-top: var(--s4); border-top: var(--filetto) solid var(--linea); }
.altre-domande h2 { margin: 0; font-size: var(--t-voce); }
.lenti {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--s3); margin: var(--s4) 0 var(--s6);
}
.lenti .lente {
  flex: 1 1 260px; min-width: 0; display: flex; flex-direction: column; gap: var(--s1);
  padding: var(--s4) var(--s4); min-height: var(--tocco);
  background: var(--fondo-alto); border: var(--filetto) solid var(--contorno);
  border-radius: var(--raggio-2); text-decoration: none; color: inherit;
}
.lenti .lente:hover { border-color: var(--ossido); }
.lenti .lente:focus-visible { outline: 2px solid var(--carta); outline-offset: 2px; }
/* ⚠️ La lente scelta non si dice col solo COLORE: una barra spessa a sinistra
   — che e' FORMA — e una PAROLA («scelta»: «aperta», accanto a «Le commesse
   aperte», si leggeva come lo stato di una commessa). ⚠️ E NON e' piu' un
   riquadro pieno: era il quarto comando «pieno» della schermata, e nel tema
   scuro il suo rosso reggeva il bianco a 4,0:1. Testo e spiegazione restano
   quelli di tutte le altre, misurati nei due temi. */
.lenti .lente.scelta {
  border-color: var(--ossido); border-left: 4px solid var(--ossido);
}
.lenti .lente .aperta {
  align-self: flex-start; margin-top: var(--s1); padding: var(--s1) var(--s2);
  /* `--ossido-vivo`, non `--ossido-testo`: a 13 px sul sollevato scuro il
     secondo sta a 4,51:1, il primo a 6,0:1 (e 6,0:1 anche sulla carta). */
  color: var(--ossido-vivo);
  border: var(--filetto) solid currentColor; border-radius: var(--raggio-pieno);
  font-size: var(--t-nota); letter-spacing: .04em; text-transform: uppercase;
}
.lenti .lente .domanda { font-weight: 600; overflow-wrap: anywhere; }
.lenti .lente .spiega { color: var(--tenue); font-size: var(--t-minuto); overflow-wrap: anywhere; }

/* ⚠️ I comandi del modulo sono `.azione`: erano `<button>` nudi del browser —
   pieni, grigi, a 13,33 px in Arial, tre nella stessa schermata. Uno solo e'
   pieno («Aggiorna la risposta», e solo se ci sono filtri); grafico e PDF sono
   secondari. Il gruppo va a capo intero, sotto i campi. */
.filtri-lente {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s3); margin: 0 0 var(--s4);
}
.filtri-lente .comandi { display: flex; flex-wrap: wrap; gap: var(--s3); flex-basis: 100%; }
.filtri-lente .comandi .azione { flex: 0 1 auto; min-width: 0; white-space: normal; text-align: center; }
@media (max-width: 480px) {
  .filtri-lente label, .filtri-lente .comandi .azione { flex: 1 1 100%; }
  .filtri-lente label > select, .filtri-lente label > input { width: 100%; }
}
.filtri-lente label { display: flex; flex-direction: column; gap: var(--s1); min-width: 0; }
.filtri-lente label > span { color: var(--fioco); font-size: var(--t-nota); }
.filtri-lente select, .filtri-lente input {
  min-height: var(--tocco); max-width: 100%;
  padding: 0 var(--s3); color: var(--carta);
  background: var(--fondo-alto); border: var(--filetto) solid var(--contorno);
  border-radius: var(--raggio-2);
}
.filtri-lente select:focus-visible, .filtri-lente input:focus-visible {
  outline: 2px solid var(--carta); outline-offset: 2px;
}
.filtri-lente button { min-height: var(--tocco); }

.risposta { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s2) var(--s4); margin: 0 0 var(--s4); }
.risposta .conto-grosso { display: flex; align-items: baseline; gap: var(--s2); }
.risposta .numero { font-size: var(--t-cifra); font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; }
.risposta .cosa { color: var(--tenue); }
/* ⚠️ Coperta per intero: verde. Incompleta: ambra, che e' «da guardare», non
   rosso — non sapere tutto non e' un guasto, e' un fatto da dire. */
.risposta .copertura { margin: 0; color: var(--verde-testo); overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums; }
.risposta .copertura.incompleta { color: var(--ambra-testo); }
/* Il salto al primo «no» della colonna «Coperto»: un legame, con il bersaglio
   di un legame che sta da solo. */
.risposta .salto-ai-non-coperti {
  display: inline-flex; align-items: center; min-height: var(--tocco-legame);
  color: var(--ambra-testo); font-size: var(--t-minuto);
  text-decoration: underline; text-underline-offset: .18em;
}
.risposta .salto-ai-non-coperti:hover { color: var(--carta); }
.risposta .salto-ai-non-coperti:focus-visible { outline: 2px solid var(--carta); outline-offset: 2px; }

/* ── La tabella della risposta: colonne uguali, e sul telefono ogni valore
   con la sua etichetta ────────────────────────────────────────────────────
   ⚠️ Il registro comune da' 140 px fissi a ogni colonna e lascia crescere la
   seconda: a 1.440 il nome andava a capo in 140 px («Cantiere del / banco»)
   mentre «Tipo» prendeva lo spazio, e sotto i 700 px cinque valori nudi
   finivano a zig-zag, a x 110 e a x 33, senza dire quale fosse il telefono e
   quale il tipo. Qui ogni riga e' una griglia con `--colonne` colonne uguali
   (il numero lo scrive la pagina in `data-colonne`), e sotto i 700 px si
   impila: un valore per riga, l'etichetta sopra (`data-dice`, la forma di
   `.registro.persone`), tutti sullo stesso bordo.
   ⚠️ `data-colonne`, non `style="--colonne: N"`: niente misure dentro la
   pagina. Le lenti hanno da 1 a 5 colonne piu' «Coperto»: 6 e' il massimo, 8 e'
   il margine. */
.registro.lente .riga {
  display: grid;
  grid-template-columns: repeat(var(--colonne, 4), minmax(0, 1fr));
  gap: var(--s2) var(--s4);
  align-items: start;
}
.registro.lente[data-colonne="1"] { --colonne: 1; }
.registro.lente[data-colonne="2"] { --colonne: 2; }
.registro.lente[data-colonne="3"] { --colonne: 3; }
.registro.lente[data-colonne="4"] { --colonne: 4; }
.registro.lente[data-colonne="5"] { --colonne: 5; }
.registro.lente[data-colonne="6"] { --colonne: 6; }
.registro.lente[data-colonne="7"] { --colonne: 7; }
.registro.lente[data-colonne="8"] { --colonne: 8; }
.registro.lente .riga > .colonna { min-width: 0; }
.registro.lente .riga.capofila { align-items: end; }
/* «Coperto»: la parola, e per il no il colore dell'incompleto. Non da solo. */
.registro.lente .non-coperto { color: var(--ambra-testo); font-weight: 600; }
/* ⚠️ Sotto i 700 px: una cella per riga, etichetta e valore AFFIANCATI su una
   griglia a due colonne dentro la cella — l'etichetta in 7,5 rem a sinistra,
   il valore a destra. Con l'etichetta SOPRA il valore (la prima stesura) una
   riga di cinque celle faceva 250 px, e con le righe vere di una lista cavi la
   pagina non finiva piu'. Cosi' ogni cella sta su una riga di testo, tutte le
   celle partono dallo stesso bordo e ogni valore ha il suo nome accanto. */
@media (max-width: 700px) {
  .registro.lente .riga { grid-template-columns: minmax(0, 1fr); gap: var(--s1); }
  .registro.lente .riga.capofila { display: none; }
  .registro.lente .riga > .colonna[data-dice] {
    display: grid; grid-template-columns: minmax(6rem, 7.5rem) minmax(0, 1fr);
    gap: 0 var(--s3); align-items: baseline;
  }
  .registro.lente .riga > .colonna[data-dice]::before {
    content: attr(data-dice);
    color: var(--fioco); font-size: var(--t-nota);
  }
}

.scoperte { margin: var(--s4) 0; }
.scoperte > summary { min-height: var(--tocco); display: flex; align-items: center;
  color: var(--ambra-testo); cursor: pointer; }
.scoperte > summary:focus-visible { outline: 2px solid var(--carta); outline-offset: 2px; }
.registro .riga.capofila { min-height: 0; padding-top: var(--s1); padding-bottom: var(--s1);
  color: var(--fioco); font-size: var(--t-nota); }

/* ── Persone: sette colonne, una riga di dati e una piega per i gesti ───── */
.registro.persone .riga {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) 5.5rem 5rem 6rem 6rem 6rem;
  gap: var(--s2) var(--s3);
  padding-block: var(--s2);
}
.registro.persone .riga > .azioni { margin: 0; }
.registro.persone .riga.spenta .valore { color: var(--fioco); }
.registro.persone .riga.spenta .valore.capo { text-decoration: line-through; }
.gesti-persona[open] { grid-column: 1 / -1; }
.gesti-persona > summary { width: 100%; }
.gesti-persona[open] > summary { width: fit-content; }

/* Nomi e permessi restano associati anche quando la tabella diventa stretta. */
@media (max-width: 1100px) {
  .registro.persone .riga { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s3); }
  .registro.persone .riga.capofila { display: none; }
  .registro.persone .riga > :is(.colonna:first-child, .gesti-persona) { grid-column: 1 / -1; }
  .registro.persone .riga > .colonna[data-dice]::before {
    content: attr(data-dice);
    color: var(--fioco); font-size: var(--t-nota);
  }
}

.ruoli-assegnati { margin: 0; background: var(--fondo-alto); }
.ruoli-assegnati > div {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--s4); padding: var(--s4);
  border-bottom: var(--filetto) solid var(--linea);
}
.ruoli-assegnati dt { font-weight: 600; overflow-wrap: anywhere; }
.ruoli-assegnati dd { margin: 0; display: flex; flex-direction: column; gap: var(--s1); }
@media (max-width: 599px) {
  .ruoli-assegnati > div { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ruoli-assegnati dt { grid-column: 1 / -1; }
}



.dialogo {
  display: flex;
  flex-direction: column;
  max-width: 820px;
}

.dialogo .intestazione { margin-bottom: var(--s3); }
/* il comando di ricominciare sta in fondo alla riga del titolo */
.dialogo .intestazione .azzera-la-chat { margin-left: auto; }
.dialogo .nuova-conversazione {
  color: var(--tenue);
  background: transparent;
  border-color: transparent;
}
.dialogo .nuova-conversazione:hover {
  color: var(--carta);
  background: var(--fondo-alto);
  border-color: var(--contorno);
}

.battute {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--s4);
  padding-bottom: var(--s4);
  /* ⚠️ `dvh` e non `vh`: sul telefono la barra del browser entra ed esce, e con
     `vh` il campo dove si scrive finisce sotto di essa proprio mentre si scrive.
     ⚠️ Il tetto e' un MASSIMO, non un'altezza: una conversazione di due battute
     non deve lasciare mezzo schermo vuoto sopra il campo. */
  /* ⚠️ Rete, non regola: il tetto vero lo da' `.dialogo` qui sotto. Questo
     serve solo se un giorno il pannello si ritrova senza limite. */
  max-height: 100dvh;
  min-height: 0;
  overflow-y: auto;
  scrollbar-gutter: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--contorno) transparent;
}
.battute::-webkit-scrollbar { width: 6px; }
.battute::-webkit-scrollbar-track { background: transparent; }
.battute::-webkit-scrollbar-thumb {
  background: var(--contorno);
  border-radius: var(--raggio-pieno);
}
/* ⚠️ **Il numero magico non regge, e il browser sa fare il conto da solo.**
 * `100dvh - 330px` e' una stima dell'ingombro di intestazione + campo: misurata
 * a 1280×900 lasciava il campo dove si scrive a cavallo del bordo inferiore,
 * cioe' proprio la cosa che questo riquadro esiste per tenere in vista. Da 760
 * px in su il pannello prende l'altezza dello schermo e le battute si prendono
 * CIO' CHE AVANZA: se domani l'intestazione cresce di una riga, il conto si
 * rifa' da solo. ⚠️ `min-height: 0` non e' decorativo — senza, un figlio in
 * colonna flex non si lascia stringere sotto il proprio contenuto e il tetto
 * non ha effetto. */
/* ⚠️ ⚠️ **SOTTO I 760 IL PANNELLO SI LIMITA DA SE', e questo sostituisce un
 * numero indovinato.** Il tetto stava su `.battute` come `100dvh - 330px`: una
 * stima dell'ingombro di intestazione piu' campo, che non sa niente di quanto
 * sia alto davvero il resto del pannello. Misurato l'08.09.2026 col cancello:
 * dialogo alto **799 px su uno schermo di 780** a 360, e **863 su 844** a 390 —
 * diciannove pixel di troppo in tutti e due i casi, cioe' un ingombro fisso che
 * quella stima non contava. Un pannello piu' alto dello schermo obbliga il campo
 * a scavalcare le battute per restare in vista, ed e' il difetto di cui parla la
 * nota su `.scrivi`.
 * ⚠️ Qui il limite si mette al PANNELLO e si esprime in cio' che si sa davvero —
 * l'altezza dello schermo meno il ponte — e le battute si prendono l'avanzo con
 * `flex`. Nessun numero da azzeccare: se domani l'intestazione cresce di una
 * riga, il conto si rifa' da solo, esattamente come dai 760 in su. */
@media (max-width: 759.98px) {
  .dialogo { max-height: calc(100dvh - var(--ponte)); }
  .battute { flex: 1 1 auto; max-height: none; }
}

@media (min-width: 760px) {
  /* ⚠️ `100%`, non un `calc` su `100dvh`: dai 760 px in su `body.lavoro` e' una
     griglia con la riga del banco a `minmax(0, 1fr)`, quindi il banco ha GIA'
     l'altezza esatta di cio' che resta sotto il ponte. Sottrarla a mano voleva
     dire indovinare l'ingombro del ponte e i margini del banco: a 1280×900 il
     conto sbagliava di otto pixel e il campo dove si scrive finiva mezzo sotto
     il bordo — cioe' l'unica cosa che questo riquadro esiste per tenere in
     vista. Il numero giusto ce l'ha il browser. */
  /* ⚠️ ⚠️ **`.banco >` E NON `.dialogo` NUDO, e il giorno che manca quella
     freccia la conversazione si srotola di nuovo.** `height: 100%` vale se il
     padre un'altezza ce l'ha: qui il `.banco` e' una griglia con la riga a
     `minmax(0, 1fr)`, quindi ce l'ha. Sotto il preventivo lo stesso dialogo sta
     dentro un `aside` dentro un blocco alto quanto il suo contenuto: li' `100%`
     si risolve in `auto` e, insieme al `max-height: none` della riga dopo,
     `.battute` resta SENZA TETTO — cioe' il difetto per cui questo riquadro
     esiste (76 battute = 11.968 px di pagina) rientrato dalla porta di
     servizio, senza che nessuno tocchi una riga di `.battute`.
     ⚠️ Misurato l'08.09.2026 sul servito, il giorno stesso in cui la chat del
     preventivo ha preso queste classi: dialogo 820×401 con la conversazione
     VUOTA, cioe' altezza del contenuto e nessun limite.
     ⚠️ L'altezza di quell'altro dialogo la dichiara la pagina che lo ospita —
     `_stile_chat_preventivo.html` — perche' li' e' una scelta di dove sta nella
     pagina. Qui resta la regola di CHI ha gia' l'altezza dal reticolo. */
  .banco > .dialogo { height: 100%; }
  .battute { flex: 1 1 auto; max-height: none; }
}
/* ⚠️ La RIGA si ferma in banda, il pannello no: e' la distinzione che mancava. */
.battuta .detto { max-width: var(--misura-di-lettura); }
.battuta.persona .detto { max-width: none; }

/* ⚠️ Chi parla si dice con una PAROLA, non con l'allineamento o col colore: sui
   monitor da cantiere, lavati dal sole, «a destra vuol dire io» non si legge.
   La forma aiuta — la domanda è un riquadro stretto, la risposta è a piena
   larghezza — ma la parola è quella che regge da sola. */
.battuta .chi {
  display: block;
  font-family: "Barlow Condensed", sans-serif;
  font-size: var(--t-nota);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--tenue);
  margin-bottom: var(--s2);
}
.battuta.argo .chi { color: var(--tenue); }

.battuta.persona {
  align-self: flex-end;
  max-width: min(86%, 36rem);
  padding: var(--s4) var(--s4);
  background: var(--fondo-alto);
  border: 1px solid var(--contorno);
  border-radius: var(--raggio-2) var(--raggio-2) var(--raggio-1) var(--raggio-2);
}
.battuta.persona .chi { text-align: right; }
.battuta.persona .detto p { margin: 0; }

.battuta.argo { max-width: 100%; }
/* ⚠️ Un numero che non viene da un conto si dice con una PAROLA
   («Attenzione») e con una riga spessa, non col solo colore: sui monitor da
   cantiere lavati dal sole il colore è la prima cosa che si perde. */
/* ⚠️ Più tenue di «non calcolati», e non per estetica: sono due gradi diversi di
   dubbio, e mostrarli uguali li farebbe leggere come la stessa cosa. */
.ripresi {
  margin: 0 0 var(--s3);
  padding: var(--s2) 0;
  color: var(--tenue);
  font-size: var(--t-minuto);
  line-height: 1.5;
}

/* La fonte si legge PRIMA del contenuto. Parole, peso e posizione tengono
   distinta la prosa dai risultati anche senza colore, in cantiere al sole.
   Gli stessi token seguono il tema della pagina, anche sulla carta. */
.dialogo .battute { --copertura-provenienza: 0px; }
.battuta .provenienza {
  position: sticky;
  top: var(--copertura-provenienza);
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s1) var(--s3);
  margin: 0 0 var(--s3);
  padding: var(--s2) 0;
  border-bottom: 1px solid var(--contorno);
  background: var(--fondo);
  color: var(--carta);
  font-size: var(--t-piccolo);
  line-height: 1.5;
}
.battuta .provenienza strong { font-weight: 600; }
.battuta .provenienza span { color: var(--tenue); font-size: var(--t-minuto); }
.battuta .commento { max-width: var(--misura-di-lettura); }
.battuta .fonte-argo { margin-top: var(--s6); }
.battuta .fonte-dati {
  margin-bottom: 0;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--contorno);
  border-radius: var(--raggio-2) var(--raggio-2) var(--raggio-0) var(--raggio-0);
  background: var(--fondo-alto);
}
.battuta .fonte-argo .allegato { margin-top: 0; border-top: 0; border-radius: var(--raggio-0) var(--raggio-0) var(--raggio-2) var(--raggio-2); }
.battuta .fonte-argo a {
  display: inline-flex;
  align-items: center;
  min-width: var(--tocco);
  min-height: var(--tocco);
}
.battuta .senza-dati.provenienza-assente {
  margin: 0 0 var(--s3);
  padding: 0;
  border: 0;
  background: none;
  color: var(--tenue);
  font-size: var(--t-minuto);
}
/* I fatti TOLTI dal codice (16.09.2026): una riga ambra, non un riquadro rosso —
   il dato inventato non c'e' piu', e' stato tolto; qui si dice che e' successo e
   che cosa vuol dire il segnaposto nella frase. `role=status`, come `.ripresi`. */
.battuta .fatti-tolti {
  margin: 0 0 var(--s3);
  padding: var(--s2) var(--s3);
  border-left: var(--segno) solid var(--ambra-testo);
  color: inherit;
  font-size: var(--t-minuto);
  line-height: 1.5;
}

/* Una risposta porta al massimo un riquadro, e solo per il pericolo vero: un
   numero non calcolato. «Nessun dato consultato» non e' un avviso ma la riga
   tenue della provenienza qui sopra (`.provenienza-assente`), fuori dal riquadro. */
.avviso-risposta {
  margin: 0 0 var(--s3);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--avviso-testo);
  border-radius: var(--raggio-2);
  background: color-mix(in srgb, var(--avviso-testo) 8%, transparent);
  color: var(--carta);
  font-size: var(--t-piccolo);
  line-height: 1.5;
}
.avviso-risposta .non-calcolati { margin: 0; padding: 0; }

/* ══ I SEGNI DELLA PROVENIENZA (13.09.2026) ═══════════════════════════════════
 * ⚠️ Il modello adesso risponde anche fuori dall'archivio, e una stessa
 * risposta puo' mescolare un dato di Argo e una frase sua: si leggevano uguali.
 * I segni li mette il CODICE (`dominio.argo.segna`); qui si disegnano.
 * ⚠️ Ognuno si distingue per FORMA oltre che per colore — riga piena,
 * tratteggiata, puntinata — perche' sui monitor da cantiere lavati dal sole il
 * colore e' la prima cosa che si perde (WCAG 1.4.1). E il testo dentro il segno
 * resta del colore del testo: il segno e' il fondo e la riga sotto, non una
 * scritta colorata che scende di contrasto. */
mark.da-argo,
mark.non-verificato,
mark.dalla-domanda,
mark.tolto {
  color: inherit;
  background: none;
  padding: 0 .12em;
  border-radius: var(--raggio-1);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
/* Il dato di Argo: fondo verde tenue e riga PIENA — l'ha contato il codice. */
mark.da-argo {
  background: color-mix(in srgb, var(--verde-testo) 13%, transparent);
  border-bottom: 2px solid var(--verde-testo);
}
/* Il fatto che nessun dato conferma: niente fondo, riga TRATTEGGIATA. */
mark.non-verificato { border-bottom: 2px dashed var(--ambra-testo); }
/* Ripreso dalla domanda: PUNTINATA e tenue, come `.ripresi` — un altro grado. */
mark.dalla-domanda { border-bottom: 2px dotted var(--tenue); }
/* Il segnaposto messo dal codice al posto di un fatto scritto senza strumenti:
 * corsivo e fondo ambra tenue, riga tratteggiata come il non verificato — e' il
 * grado piu' alto dello stesso dubbio: qui il dato non c'e' proprio. */
mark.tolto {
  font-style: italic;
  background: color-mix(in srgb, var(--ambra-testo) 12%, transparent);
  border-bottom: 2px dashed var(--ambra-testo);
}

/* La legenda sta SOPRA la risposta, e mostra solo i segni che la risposta porta.
 * ⚠️ Non si chiama `.provenienza`: quel nome e' della riga appiccicosa in cima
 * alla battuta («Testo del modello»), e `.battuta .provenienza` la fa sticky con
 * bordo e fondo. Con lo stesso nome la legenda diventava una seconda riga
 * appiccicosa che scorrendo copriva la prima. */
.legenda-dei-segni {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s4);
  margin: 0 0 var(--s2);
  font-size: var(--t-nota);
  color: var(--tenue);
  line-height: 1.6;
}

.detto p { margin: 0 0 var(--s3); line-height: 1.6; font-size: var(--t-corpo); }
.detto p:last-child { margin-bottom: 0; }

/* Da dove escono i numeri: chiuso, ma sempre a un dito di distanza. */
.passi { margin-top: var(--s4); }
.passi summary {
  cursor: pointer;
  font-size: var(--t-nota);
  color: var(--fioco);
  /* ⚠️ `--tocco` pieno: è la misura dichiarata di questa casa, e qui il dito ha
     il guanto. Avevo scritto 32px perché «è solo un dettaglio da aprire» — ma un
     bersaglio piccolo è piccolo lo stesso, e chi lo manca due volte smette di
     provare a sapere da dove escono i numeri. */
  display: flex;
  align-items: center;
  min-height: var(--tocco);
}
.passi summary:hover { color: var(--tenue); }
.passi summary:focus-visible { outline: 2px solid var(--ossido-testo); outline-offset: 2px; }
.passi ul { margin: var(--s1) 0 0; padding-left: var(--s4); }
.passi li { font-size: var(--t-nota); color: var(--tenue); margin: var(--s2) 0; }
.passi code {
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--t-nota);
  color: var(--carta);
}
.passi .arg {
  display: inline-block;
  margin-left: var(--s2);
  padding: var(--s1) var(--s2);
  border: 1px solid var(--contorno);
  border-radius: var(--raggio-1);
  font-size: var(--t-nota);
  color: var(--fioco);
}
.passi .guasto { color: var(--ossido-testo); margin-left: var(--s2); }

/* ⚠️ Il vuoto insegna con TRE RIGHE. Uno schermo bianco lascia chi arriva a
   indovinare; venti riquadri gli dicono che deve scegliere invece di scrivere. */
.primo-giorno { padding: var(--s2) 0 0; }
.primo-giorno .apertura {
  margin: 0 0 var(--s3);
  font-family: "Barlow Condensed", sans-serif;
  font-size: var(--t-secondo);
  color: var(--carta);
}
.primo-giorno .esempi {
  margin: 0 0 var(--s4);
  color: var(--tenue);
  line-height: 1.7;
  max-width: 62ch;
}
.primo-giorno .minuta { margin: 0; font-size: var(--t-minuto); color: var(--fioco); }

/* ── dove si scrive ──────────────────────────────────────────────────────── */
/* NOTA STORICA SUPERATA dalla regola locale della chat qui sotto.
   `sticky` non serviva nella vecchia struttura: con la conversazione che scorre
   dentro il suo riquadro, il campo e' gia' sempre in vista, e un elemento
   appiccicato sopra la sezione delle lenti le copriva la prima riga. */

/* ⚠️ ⚠️ **L'AGGANCIO VALE SOLO DOVE IL PANNELLO CI STA NELLO SCHERMO, e la
   ragione e' che `sticky` NON INVENTA SPAZIO: tiene il campo in vista tirandolo
   SU, e cio' che stava in quel punto finisce sotto.**
   Dai 760 px in su il dialogo e' alto quanto lo schermo — gliela da' il reticolo
   di `body.lavoro` — quindi il campo e' gia' in fondo e l'aggancio non deve
   spostare niente: e' una rete che non morde mai. Sotto i 760 il dialogo e' piu'
   alto di cio' che si vede, e li' l'aggancio lavora davvero: sale, e si mette
   sopra le battute.
   ⚠️ Misurato DUE VOLTE l'08.09.2026 sul servito, `/chiedi/` a 360×780, e la
   seconda vale piu' della prima. Prima: il collegamento «10263» in una cella
   della risposta, 44×44 px a y=725, con sopra `span.aiuto` — «Invio va a capo».
   Ho dato al pannello un'altezza vera a ogni larghezza credendo di aver capito,
   e il difetto **si e' spostato invece di sparire**: «ZZ-IV-053733-COMP»,
   134×44 px a y=551, con sopra `form.scrivi` intero. Due righe della risposta di
   Argo che sul telefono NON SI POTEVANO TOCCARE. Un rimedio che sposta un
   difetto di 174 pixel non e' un rimedio: e' la stessa causa vista da un'altra
   distanza.
   ⚠️ **Un campo che si raggiunge scorrendo e' peggio di un campo agganciato; un
   campo agganciato che copre la risposta e' peggio di tutti e due.** Sul telefono
   il campo sta in fondo alla conversazione e ci si arriva scorrendo — che poi e'
   il gesto che si fa comunque dopo aver letto. L'aggancio resta dove serve e dove
   non nasconde niente.
   ⚠️ Chi lo rimette a `sticky` qui sotto deve prima far fallire
   `strumenti/cancello.py` su `/chiedi/` a 360×780: il difetto lo vede
   `interazioni`, non le regole del cancello, e si presenta come «il puntatore
   non attiva :hover». */
.scrivi {
  /* ⚠️ Niente `bottom` ne' `z-index`: su `position: static` non fanno NIENTE, e
     una riga che non cambia niente resta li' a far credere che serva — il
     prossimo che legge pensa che il campo si sovrapponga a qualcosa. Erano
     avanzate togliendo l'aggancio; rilievo di un revisore, 09.09.2026. */
  position: static;
  padding: var(--s3) 0 var(--s3);
  background: var(--fondo);
  border-top: 1px solid var(--linea);
}
/* Nella pagina chat storia e compositore sono fratelli dentro un dialogo ad
   altezza definita: scorre solo la storia e il compositore resta sul suo fondo.
   La specificita' protegge gli altri form `.scrivi`, che restano statici. */
.banco > .dialogo > .scrivi {
  position: sticky;
  bottom: 0;
  z-index: 2;
  flex: none;
}
/* NOTA STORICA SUPERATA dalla struttura a scorrimento interno della chat.
   **NEL VECCHIO ASSETTO L'AGGANCIO NON C'ERA PIU'**, per una
   ragione misurata tre volte e non per rinuncia.**
   `position: sticky` non inventa spazio: tiene il campo in vista TIRANDOLO SU,
   e cio' che stava in quel punto finisce sotto. Serve solo se il campo, da
   fermo, cadrebbe fuori dallo schermo — cioe' solo se il pannello NON ci sta.
   Ma un pannello che non ci sta e' il difetto vero, e l'aggancio lo nasconde
   scambiandolo per una soluzione.
   Le tre misure, tutte sul servito dell'08.09.2026:
   · `/chiedi/` 360×780 — «10263» in una cella, 44×44 a y=725, con sopra
     `span.aiuto`. Corretto dando al pannello un'altezza vera? No: il difetto si
     e' SPOSTATO — «ZZ-IV-053733-COMP» a y=551, con sopra `form.scrivi` intero.
   · tolto l'aggancio sotto i 760: a 360, 390 e 768 nessun comando piu' coperto.
   · restava la regola per i 760 in su, che un revisore indipendente ha scoperto
     INERTE (stava sopra la base, e `@media` non aggiunge specificita'). Rimessa
     al posto giusto, ha subito coperto «ZZ-SCATTO-030723» a 1280×900:
     `pila: form.scrivi > a > td > table`. **La regola sbagliata era protetta
     dall'essere inefficace.**
   Il campo sta in fondo a `.dialogo`, che dai 760 in su e' alto quanto lo
   schermo (`.banco > .dialogo { height: 100% }`) e sotto ha il suo tetto: li'
   e' gia' l'ultima cosa in basso e non deve scavalcare niente per restare in
   vista. ⚠️ Chi lo rimette deve prima far fallire `strumenti/cancello.py` su
   `/chiedi/` a 1280×900: il difetto lo vede `interazioni` — «il puntatore non
   attiva :hover» — non le regole del cancello. */
.scrivi > label {
  display: block;
  font-family: "Barlow Condensed", sans-serif;
  font-size: var(--t-nota);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--tenue);
  margin-bottom: var(--s2);
}
.campo-e-invio {
  display: flex;
  gap: var(--s3);
  align-items: stretch;
}
.banco > .dialogo > .scrivi > .campo-e-invio {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
}
.scrivi textarea {
  flex: 1;
  min-width: 0;
  min-height: var(--tocco);
  padding: var(--s3) var(--s4);
  font-family: inherit;
  font-size: var(--t-corpo);              /* 16px pieni: sotto, iOS ingrandisce la pagina */
  line-height: 1.5;
  color: var(--carta);
  background: var(--fondo-alto);
  border: 1px solid var(--contorno);
  border-radius: var(--raggio-2);
  resize: none;
}
.scrivi textarea:focus-visible {
  outline: 2px solid var(--ossido-testo);
  outline-offset: 1px;
  border-color: var(--ossido-testo);
}
.scrivi button.chiedi {
  /* ⚠️ 19px come `button.entra`: bianco su ossido fa 4,45:1, sotto il 4,5 che
     l'AA chiede al testo piccolo. A 19px grassetto la soglia è 3:1 e basta. */
  min-height: var(--tocco);
  padding: 0 var(--s6);
  color: #FFFFFF;
  /* ⚠️ `--ossido-fondo`, come `.azione`: il bianco sull'ossido pieno da' 4,45:1
     — misurato sul servito, e sotto il 4,5 dell'AA. Reggeva solo appoggiandosi
     all'esenzione del «testo grande», che a 18 px con peso 600 non vale (WCAG
     chiama grassetto il peso >= 700). Qui sono 6,58:1 e non serve esenzione. */
  background: var(--ossido-fondo);
  border: 1px solid var(--ossido-fondo);
  border-radius: var(--raggio-2);
  font-family: "Barlow Condensed", sans-serif;
  font-size: var(--t-voce);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
}
.scrivi button.chiedi:hover { background: var(--ossido-cupo); border-color: var(--ossido-cupo); }
/* ⚠️ **La variante QUIETA dello stesso bottone.** Serve dove la chat e' un
 * PANNELLO e non la pagina: sotto il preventivo il gesto primario e' il passo
 * del preventivo, e due pieni sulla stessa schermata non guidano piu' nessuno
 * (decisione del 07.09.2026, rimisurata l'08). Stessa forma, stesso bersaglio,
 * stesso posto: cambia solo il peso. */
.scrivi button.chiedi.quieta {
  background: none;
  color: var(--ossido-testo);
  border: var(--filetto) solid currentColor;
}
.scrivi button.chiedi.quieta:hover { background: none; color: var(--ossido-vivo); }
.scrivi button.chiedi:focus-visible { outline: 2px solid var(--carta); outline-offset: 2px; }
/* ⚠️ `aria-disabled`, non `disabled`: un `disabled` toglie il campo dai dati
   inviati in alcuni browser, e se l'invio fallisce la persona resta con un
   bottone morto. È scritto in argo.js e vale anche qui. */
.scrivi button.chiedi[aria-disabled="true"] { opacity: 1; cursor: progress; }

.scrivi .sotto {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-top: var(--s1);
}
.scrivi .aiuto { font-size: var(--t-nota); color: var(--fioco); }

/* ── i file della domanda (13.09.2026) ──────────────────────────────────────
 * ⚠️ Il campo e' quello del browser, con la sua etichetta: si raggiunge con la
 * tastiera, dal telefono apre fotocamera e galleria, e senza JavaScript funziona
 * uguale. Il bottone che il browser disegna prende la faccia della variante
 * QUIETA di «Chiedi»: e' un gesto secondario accanto al primario, e due pieni
 * sulla stessa riga non guidano piu' nessuno.
 * ⚠️ I quattro stati sul CAMPO, non solo sul bottone disegnato dentro: chi
 * misura l'hover guarda l'elemento, e un campo che cambia solo dentro uno
 * pseudo-elemento sembra un comando morto. */
.scrivi .allega-comando {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tocco);
  padding: 0 var(--s4);
  color: var(--tenue);
  background: transparent;
  border: var(--filetto) solid var(--contorno);
  border-radius: var(--raggio-2);
  cursor: pointer;
  overflow: hidden;
}
.scrivi .allega-comando > label {
  font-family: "Barlow Condensed", sans-serif;
  font-size: var(--t-voce);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: inherit;
  pointer-events: none;
}
.scrivi input[type="file"] {
  position: absolute;
  inset: 0;
  width: 100%;
  min-height: var(--tocco);
  opacity: 0;
  cursor: pointer;
}
.scrivi input[type="file"]:hover { color: var(--carta); }
.scrivi .allega-comando:has(input:hover) { color: var(--carta); background: var(--fondo-alto); }
.scrivi input[type="file"]:active { color: var(--carta); }
.scrivi .allega-comando:has(input:active) { color: var(--carta); background: var(--linea); }
.scrivi input[type="file"]:focus-visible { outline: 2px solid var(--ossido-testo); outline-offset: 2px; }
.scrivi .allega-comando:has(input:focus-visible) {
  outline: 2px solid var(--ossido-testo);
  outline-offset: 2px;
}
.scrivi .limiti-file { flex: 1 1 100%; }
.scrivi .scelti {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--t-nota);
  color: var(--tenue);
  overflow-wrap: anywhere;
}
.scrivi .scelti:empty { display: none; }
.scrivi .scelti li {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: var(--tocco);
  max-width: 100%;
  padding: var(--s1) var(--s2);
  background: var(--fondo-alto);
  border: var(--filetto) solid var(--contorno);
  border-radius: var(--raggio-2);
}
.scrivi .scelti img {
  width: var(--tocco);
  height: var(--tocco);
  object-fit: cover;
  border-radius: var(--raggio-1);
}
.scrivi .scelti .nome { min-width: 0; overflow-wrap: anywhere; }
.scrivi .scelti .errore { flex-basis: 100%; color: var(--avviso-testo); font-weight: 600; }
.scrivi .scelti.fuori-misura { color: var(--ossido-testo); font-weight: 600; }

/* Il rifiuto dei file: lo stesso peso di «non calcolati», perche' la domanda NON
   e' partita — e dice cosa fare, riga per riga. */
.file-rifiutati {
  margin: 0 0 var(--s3);
  padding: var(--s3) var(--s4);
  border-left: 4px solid var(--ossido);
  background: var(--fondo-alto);
  color: var(--carta);
  font-size: var(--t-piccolo);
  line-height: 1.5;
}
.file-rifiutati p { margin: 0 0 var(--s2); font-weight: 600; }
.file-rifiutati ul { margin: 0; padding-left: var(--s4); }
.file-rifiutati li { margin: var(--s1) 0; }

/* I file sulla battuta della domanda: ognuno un collegamento intero, alto un
   dito col guanto, con la miniatura e cio' che ne ha avuto il modello. */
.file-della-battuta {
  list-style: none;
  margin: var(--s3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}
.file-della-battuta a {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: var(--tocco);
  padding: var(--s2) var(--s3);
  color: var(--carta);
  text-decoration: none;
  background: var(--fondo);
  border: 1px solid var(--contorno);
  border-radius: var(--raggio-2);
}
.file-della-battuta a:hover { border-color: var(--ossido-testo); background: var(--fondo-alto); }
.file-della-battuta a:hover .nome { color: var(--ossido-vivo); text-decoration: underline; }
.file-della-battuta a:focus-visible { outline: 2px solid var(--ossido-testo); outline-offset: 2px; }
.file-della-battuta a:active {
  border-color: var(--ossido-cupo);
  background: color-mix(in srgb, var(--ossido) 10%, var(--fondo-alto));
}
.file-della-battuta img {
  flex: none;
  width: 72px;
  height: 72px;
  object-fit: cover;
  border-radius: var(--raggio-2);
  background: var(--fondo-alto);
}
.file-della-battuta .testi { display: flex; flex-direction: column; min-width: 0; }
.file-della-battuta .nome { font-weight: 600; overflow-wrap: anywhere; }
.file-della-battuta .come { font-size: var(--t-nota); color: var(--tenue); }
/* ⚠️ `.ricomincia` e' stato tolto: il gesto e' salito nell'intestazione della
   conversazione, dove non lo blocca il `required` del campo della domanda. Lo
   stesso gesto in due posti e' il difetto che U3 ha gia' chiuso una volta. */

/* ⚠️ Fuori dallo schermo, non `display: none`: quello la toglie anche al lettore
   di schermo, ed è l'unica cosa che questa etichetta serve a raggiungere. */
.nascosto {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ── ciò che una risposta porta oltre al testo ─────────────────────────── */
.allegato {
  margin: var(--s4) 0 0;
  padding: var(--s4) var(--s4);
  background: var(--fondo-alto);
  border: 1px solid var(--contorno);
  border-radius: var(--raggio-2);
}
.allegato h3 {
  margin: 0 0 var(--s3);
  font-family: "Barlow Condensed", sans-serif;
  font-size: var(--t-voce);
  letter-spacing: .02em;
}
/* ⚠️ La tabella scorre DENTRO il suo riquadro: una tabella larga che fa scorrere
   di lato la pagina intera rende illeggibile anche il testo accanto. */
.allegato .scorre { overflow-x: auto; }
.allegato table { width: 100%; border-collapse: collapse; font-size: var(--t-minuto); }
.allegato th, .allegato td {
  padding: var(--s2) var(--s3) var(--s2) 0;
  text-align: left;
  border-bottom: 1px solid var(--linea);
  white-space: nowrap;
}
.allegato td { font-variant-numeric: tabular-nums; }
.allegato th {
  color: var(--fioco);
  font-family: "Barlow Condensed", sans-serif;
  font-size: var(--t-nota);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 600;
}
.allegato tr:last-child td { border-bottom: 0; }

/* ⚠️ La copertura sta ATTACCATA al numero, non in fondo alla pagina: «17
   elementi» e «12 dei 17 vengono da un disegno letto» si leggono insieme o non
   si leggono. */
.allegato .copertura {
  margin: var(--s3) 0 0;
  font-size: var(--t-nota);
  color: var(--fioco);
  line-height: 1.5;
}
.allegato .copertura a { color: var(--ossido-testo); }

.allegato.collegamenti ul { margin: 0; padding: 0; list-style: none; }
.allegato.collegamenti li { padding: var(--s3) 0; border-bottom: 1px solid var(--linea); }
.allegato.collegamenti li:last-child { border-bottom: 0; }
.allegato.collegamenti a { font-size: var(--t-piccolo); }
.allegato.collegamenti .dove {
  display: block;
  font-size: var(--t-nota);
  color: var(--fioco);
  margin-top: var(--s1);
}
.allegato.collegamenti .niente { color: var(--fioco); }

/* ⚠️ Barre in HTML con `<meter>`: si leggono con lo zoom, le legge un lettore di
   schermo («12 su 40»), e ogni barra porta il suo NUMERO SCRITTO accanto. Un
   grafico si guarda e non si conta — se la barra sbaglia e il numero no, si vede. */
.allegato.grafico .barre { margin: 0; padding: 0; list-style: none; }
.allegato.grafico .barre li {
  display: grid;
  grid-template-columns: minmax(10ch, 24ch) 1fr auto;
  gap: var(--s4);
  align-items: center;
  padding: var(--s2) 0;
}
.allegato.grafico .nome {
  font-size: var(--t-minuto);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* ⚠️ `<meter>` va vestito su pseudo-elementi diversi, uno per motore. Se un
   motore nuovo non li conoscesse resta una barra leggibile: si perde il colore,
   non l'informazione. */
.allegato.grafico meter.barra {
  display: block;
  width: 100%;
  height: 16px;
  border: 1px solid var(--contorno);
  border-radius: var(--raggio-1);
  background: var(--reticolo-marcato);
}
.allegato.grafico meter.barra::-webkit-meter-bar {
  background: var(--reticolo-marcato);
  border: 0;
  border-radius: var(--raggio-1);
}
.allegato.grafico meter.barra::-webkit-meter-optimum-value { background: var(--ossido); }
.allegato.grafico meter.barra::-moz-meter-bar { background: var(--ossido); }
.allegato.grafico .valore {
  font-variant-numeric: tabular-nums;
  font-size: var(--t-minuto);
  font-weight: 600;
}

@media (max-width: 599px) {
  .dialogo { min-height: calc(100vh - 160px); }
  .battuta.persona { max-width: 100%; }
  /* Il nome sta sopra la sua barra: 24ch di nome più una barra su uno schermo da
     360px lasciano alla barra due centimetri, e due centimetri non sono un grafico. */
  .allegato.grafico .barre li { grid-template-columns: 1fr auto; gap: var(--s2); }
  .allegato.grafico .nome { grid-column: 1 / -1; }
  .campo-e-invio { flex-direction: column; }
  .scrivi button.chiedi { width: 100%; }
  .banco > .dialogo > .scrivi button.chiedi { width: auto; }
  .banco > .dialogo > .scrivi .sotto > .aiuto:last-child { display: none; }
}

/* ⚠️ Le QUOTE, che sono un disegno diverso dalle barre e devono sembrarlo: il
   riferimento è cento, non la barra più lunga, e la percentuale sta scritta
   accanto al valore assoluto. Una proporzione che si può solo guardare è una
   proporzione che nessuno può controllare. */
.allegato.grafico .quote { margin: 0; padding: 0; list-style: none; }
.allegato.grafico .quote li {
  display: grid;
  grid-template-columns: minmax(10ch, 22ch) 1fr auto auto;
  gap: var(--s3);
  align-items: center;
  padding: var(--s2) 0;
}
.allegato.grafico meter.quota {
  display: block;
  width: 100%;
  height: 16px;
  border: 1px solid var(--contorno);
  border-radius: var(--raggio-2);                /* tondo: si distingue dalle barre a colpo d'occhio */
  background: var(--reticolo-marcato);
}
.allegato.grafico meter.quota::-webkit-meter-bar {
  background: var(--reticolo-marcato); border: 0; border-radius: var(--raggio-2);
}
.allegato.grafico meter.quota::-webkit-meter-optimum-value { background: var(--ossido); border-radius: var(--raggio-2); }
.allegato.grafico meter.quota::-moz-meter-bar { background: var(--ossido); }
.allegato.grafico .quote .valore { font-variant-numeric: tabular-nums; font-weight: 600; font-size: var(--t-minuto); }
.allegato.grafico .quote .assoluto {
  font-variant-numeric: tabular-nums;
  font-size: var(--t-nota);
  color: var(--fioco);
}

@media (max-width: 599px) {
  .allegato.grafico .quote li { grid-template-columns: 1fr auto auto; gap: var(--s2); }
  .allegato.grafico .quote .nome { grid-column: 1 / -1; }
}

/* ── E1: il ciclo di vita, e i tratti che Argo non sa ancora fare ──────────────
   ⚠️ La regola che questa striscia rende visibile: un tratto NON COSTRUITO si
   dichiara. Non si nasconde, e soprattutto **non si colora come un guasto**: non
   è rotto, è non ancora fatto, e la differenza si vede — filetto tratteggiato e
   tinta spenta, non l'ossido degli errori.
   ⚠️ E lo stato è scritto a parole dentro ogni tratto: il colore da solo non lo
   vede chi non distingue il rosso dal verde. */
.ciclo-guscio { margin: var(--s6) 0 var(--s7); }
.ciclo-guscio > h2 { margin: 0 0 var(--s3); }

.ciclo {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--s2);
}
.tratto { margin: 0; }
.tratto-porta {
  display: flex; flex-direction: column; gap: var(--s1);
  /* ⚠️ 44px non è un numero tondo: è il dito di chi lavora coi guanti. */
  min-height: 88px;
  padding: var(--s3);
  border: 1px solid var(--contorno);
  border-radius: var(--raggio-2);
  background: var(--fondo-alto);
  color: inherit; text-decoration: none;
  height: 100%;
}
/* ⚠️ Il passaggio non puo' INDEBOLIRE il bordo: `--ossido-alto` sulla carta fa
   2,86:1, meno del contorno a riposo (3,14:1). Cambiava tinta e perdeva forma,
   il tranello gia' pagato due volte nel CRM. `--ossido` fa 3,88:1 qui e 3,73:1
   sul marino. */
a.tratto-porta:hover { border-color: var(--ossido); }
a.tratto-porta:focus-visible { outline: 2px solid var(--ossido-vivo); outline-offset: 2px; }

.tratto-passo {
  font-variant-numeric: tabular-nums;
  font-size: var(--t-nota); color: var(--fioco);
}
.tratto-nome { font-weight: 600; font-size: var(--t-piccolo); line-height: 1.25; }
.tratto-stato { font-size: var(--t-nota); }
/* La misura sta DENTRO la riga dello stato («avviato · 4 disegni»): stessa
   riga, tinta tenue, cifre incolonnabili. */
.tratto-misura { color: var(--tenue); font-variant-numeric: tabular-nums; }
/* ⚠️ ⚠️ **La porta di un tratto e' una SCHEDA, non un legame in una frase.**
   Misurato dall'audit UX del 15.09 a 360 px: la regola dei bersagli sul tocco
   (`:is(h1, …, li, …) > a { display: inline-flex; justify-content: center }`,
   piu' avanti nel foglio, (0,1,1)) vinceva su `.tratto-porta` ((0,1,0)): le
   schede che erano collegamenti si stringevano sul testo e lo centravano
   — larghe 273, 197, 242, 180, 206 px fra sorelle da 328 — e «A che punto e'»
   sembrava una pagina rotta. Qui si ridice la scheda con una specificita'
   che quella regola non raggiunge, e vale su ogni schermo che si tocca. */
.ciclo .tratto-porta {
  display: flex; flex-direction: column;
  justify-content: flex-start; align-items: stretch;
  width: 100%;
}

.tratto--fatto .tratto-stato { color: var(--verde-testo); }
/* ⚠️ Il bordo di stato E' il contorno della porta, e ne eredita la soglia. Con
   la tinta piena `--verde`/`--ambra` la miscela sulla carta scendeva a 3,08:1 e
   **2,75:1**: la porta «in corso» si apriva sul fondo. Le voci `-testo` sono
   tarate per tavolozza — scure sulla carta, chiare sul marino — e tengono la
   stessa tinta: 4,39 e 4,17:1 sulla carta, 5,50 e 4,73:1 sul marino. */
.tratto--fatto .tratto-porta { border-color: color-mix(in srgb, var(--verde-testo) 45%, var(--contorno)); }
.tratto--in-corso .tratto-stato { color: var(--ambra-testo); }
.tratto--in-corso .tratto-porta { border-color: color-mix(in srgb, var(--ambra-testo) 45%, var(--contorno)); }
.tratto--da-fare .tratto-stato { color: var(--tenue); }
.tratto--non-costruito .tratto-porta {
  border-style: dashed;
  background: transparent;
}
.tratto--non-costruito .tratto-nome,
.tratto--non-costruito .tratto-stato { color: var(--fioco); }

.commessa-riga {
  padding: var(--s4) 0;
  border-top: 1px solid var(--linea);
}
.commessa-riga h2 { margin: 0 0 var(--s1); font-size: var(--t-terzo); }
/* ⚠️ UX98 giro 2 (18.09) · Il codice e' il collegamento alla commessa, e a 1440
 * era **44×25 px**: largo abbastanza, alto la meta'. Stessa cura del titolo di
 * `/preventivi/` e stessa forma di `.commessa-nel-confronto h3 a`. Il titolo che
 * segue resta un `.tenue` che NON si preme: si allarga il bersaglio, non la
 * superficie che porta altrove. */
.commessa-riga h2 > a {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  min-height: var(--tocco-legame);
}
.commessa-riga .a-che-punto { margin: var(--s1) 0 var(--s3); font-size: var(--t-minuto); color: var(--tenue); }
.commessa-riga .ciclo { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.commessa-riga .tratto-porta { min-height: 64px; padding: var(--s2) var(--s3); }

@media (max-width: 599px) {
  /* ⚠️ Sul telefono i tratti si impilano: una griglia a due colonne su 360px
     darebbe caselle da 160px con dentro tre righe di testo, e il nome del tratto
     andrebbe a capo in mezzo a una parola. */
  .ciclo, .commessa-riga .ciclo { grid-template-columns: 1fr; }
  /* ⚠️ E sulla pagina della commessa ogni tratto e' una RIGA da due righe di
     testo, non una scheda da 88 px: il numero a sinistra, il nome accanto, lo
     stato con la misura sotto il nome. Nove schede da 88-110 px facevano
     1.180 px di stato prima del lavoro (audit UX del 15.09: la ricerca dei
     disegni a 2.384 px, oltre tre schermi); nove righe da 48-56 ne fanno
     ~500, e i disegni entrano nel secondo schermo. Il bersaglio resta
     `--tocco`: si tocca coi guanti anche cosi'. */
  .ciclo-guscio .ciclo .tratto-porta {
    display: grid;
    grid-template-columns: 1.25rem minmax(0, 1fr);
    grid-template-areas: "passo nome" "passo stato";
    column-gap: var(--s2); row-gap: var(--s1);
    align-items: baseline;
    min-height: var(--tocco);
    padding: var(--s2) var(--s3);
  }
  .ciclo-guscio .ciclo .tratto-passo { grid-area: passo; }
  .ciclo-guscio .ciclo .tratto-nome { grid-area: nome; }
  .ciclo-guscio .ciclo .tratto-stato { grid-area: stato; line-height: 1.35; }
}

/* ── G2: il protocollo di campo, e si tocca coi guanti ────────────────────────
   ⚠️ Il vincolo non è estetico ed è scritto nel verbale: «noi lo facciamo per
   cretini, devono soltanto pigiare». Chi usa questa pagina ha i guanti, è in
   piedi in un corridoio d'acciaio, e spesso ha una mano sola libera. */
/* ⚠️ Sotto niente margine: `.banco` e' una griglia, i margini non si fondono, e
   i 24 di qui piu' i 32 della sezione dei cavi facevano un buco da 56 px fra
   il perche' e il primo cavo. */
.quanto-siamo { margin: var(--s4) 0 0; }
.quanto-siamo .grande {
  margin: 0 0 var(--s3);
  font-size: var(--t-cifra); font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.quanto-siamo .grande .tenue {
  display: block; margin-top: var(--s2);
  font-size: var(--t-piccolo); font-weight: 400; color: var(--tenue);
}
/* ⚠️ Il titolo sta col blocco che INTRODUCE: prima aveva 15 px sopra e 30 sotto
   (audit UX 15.09.2026, due revisori), e sembrava la didascalia del numero. Sopra
   almeno il doppio di sotto, sulla scala 4/8/12/16/24/32/48. */
.quanto-siamo h2.etichetta { margin: var(--s6) 0 0; }
.perche { list-style: none; margin: var(--s1) 0 0; padding: 0; }
.perche li {
  display: flex; gap: var(--s3); align-items: baseline;
  padding: var(--s2) 0; border-top: 1px solid var(--linea);
}
/* Il titolo dell'esito della ricerca: la frase e il ritorno a tutti i cavi.
   ⚠️ L'àncora `#cavi` atterra SOTTO il ponte, che sul telefono e' alto 121 px:
   con 5rem (80) la riga «111 cavi con «WY5»» finiva dietro al ponte, misurato
   con elementFromPoint (giro 2, 17.09.2026). Stesso conto delle altre àncore,
   ma con 24 di respiro e non 16: `--ponte-reso` fa 109 sul telefono e il ponte
   RESO ne misura 121 — la seconda riga e' piu' alta di `--tocco` — e con 16 la
   riga atterrava a 125, quattro pixel sotto il ponte, cioe' attaccata. */
/* ⚠️ ⚠️ E sul telefono SOTTO LA ROTTA, non solo sotto il ponte (giro 3, 17.09.2026):
   la rotta e' appiccicata sotto il ponte per la prima schermata di scorrimento
   (`body.lavoro` e' alto una schermata), e queste due ancore atterrano proprio
   li' — `#ricerca` a 133 px con la rotta fino a 253: campo coperto per intero,
   `elementFromPoint` = rotta. Il foglio non sa quanto e' alta la rotta (le righe
   dipendono dal ruolo e dalla macro aperta): `--rotta-resa` la misura il copione
   (argo.js, «le ancore che atterrano nella prima schermata»); senza copione resta
   il margine del ponte. Dal tablet in su la rotta e' di lato e la variabile non c'e'. */
/* ⚠️ Il token si DICHIARA anche qui, al valore «non c'e'»: `initial` su una
   proprieta' personalizzata e' il valore garantito non valido, e `var(--rotta-resa,
   riserva)` usa la riserva — cioe' il margine del ponte, finche' il copione non
   la scrive sull'elemento radice (lo stile in linea vince su questa riga). Un
   `var()` di un token mai dichiarato lo segnala `test_contrasto` come refuso, e
   questo dal giro 3 lo era: rosso latente del ramo, visto dalla suite intera. */
html { --rotta-resa: initial; }
.i-cavi { scroll-margin-top: calc(var(--rotta-resa, var(--ponte-reso, var(--ponte))) + var(--s6)); }
/* ⚠️ Dopo una ricerca si atterra sul CAMPO (`#ricerca`), non sull'elenco: con
   «WY5» (111 righe) il campo restava 660 px sopra l'esito, e per correggere la
   sigla si tornava su a cercarlo (giudizio del giro 2, rilievo 3). Cercando, i
   conti della commessa lasciano il posto ai cavi, quindi campo, frase dell'esito
   e prime righe stanno nello stesso schermo. Stesso conto di `.i-cavi`, che resta
   il bersaglio di «Mostra tutti i cavi». */
form.cerca-cavo { scroll-margin-top: calc(var(--rotta-resa, var(--ponte-reso, var(--ponte))) + var(--s6)); }
/* ⚠️ Sul telefono campo e bottone della ricerca dei cavi stanno sulla stessa
   riga: la regola generale del banco stretto allarga ogni bottone di `form.cerca`
   a tutta la riga, e qui impilati facevano 141 px, col bottone fuori dal primo
   schermo. Il campo si stringe (217 px a 360): una sigla ci sta. */
@container banco (max-width: 699px) {
  body.lavoro form.cerca.cerca-cavo > button { flex: 0 0 auto; width: auto; }
  /* ⚠️ La base di 260 px del campo piu' il bottone non entrano in una riga da
     328, e con `flex-wrap` il bottone andava a capo lo stesso: la base scende a
     10em e il campo si allarga fino a cio' che resta (217 px a 360). */
  body.lavoro form.cerca.cerca-cavo > input[type="search"] { flex-basis: 10em; }
}
.i-cavi > h2.esito-ricerca {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s4);
  margin: 0 0 var(--s2); min-height: var(--tocco-legame);
}
.i-cavi > h2.esito-ricerca a {
  display: inline-flex; align-items: center; min-height: var(--tocco-legame);
  color: var(--ossido-testo); text-decoration: underline; text-underline-offset: .18em;
}
.perche .quanti {
  min-width: 2.5em; text-align: right;
  font-variant-numeric: tabular-nums; font-weight: 600;
}
/* ⚠️ I cavi fermi su cui NESSUNO ha detto niente non si nascondono: sono quelli
   da andare a chiedere, ed è l'unica riga di questo elenco che è un compito. */
.perche .senza-motivo .motivo { color: var(--ambra-testo); }

.cavi { list-style: none; margin: 0; padding: 0; }
.cavo {
  display: grid;
  grid-template-columns: minmax(9em, 14em) minmax(10em, 1fr);
  gap: var(--s1) var(--s4);
  padding: var(--s4) 0;
  border-top: 1px solid var(--linea);
}
.cavo .sigla { font-weight: 600; font-size: var(--t-corpo); }
.cavo-chi { display: flex; flex-direction: column; gap: var(--s1); }
.cavo-stato { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3); align-items: baseline; }
.cavo-stato .stato-nome { font-size: var(--t-piccolo); }
/* ⚠️ Il SEGNO di questa azienda, riprodotto accanto alla parola: chi lavora da
   vent'anni riconosce «spunta nera» prima di leggere «passato». */
.cavo-stato .stato-segno {
  font-size: var(--t-nota); color: var(--fioco);
  padding: var(--s1) var(--s2); border: 1px solid var(--contorno); border-radius: var(--raggio-pieno);
}
.cavo-stato .in-piu-mani { font-size: var(--t-nota); color: var(--ambra-testo); }
.cavo-stato .cavo-motivo { font-size: var(--t-nota); color: var(--tenue); flex-basis: 100%; }
.cavo--finito .sigla { color: var(--verde-testo); }
/* ⚠️ La risposta alla spunta (`?cavo=N`): nella riga del cavo, fra lo stato e i
   passi, larga tutta la riga. In cima alla pagina stava a −520 px dal punto in
   cui la pagina atterra (giudizio del giro 2, rilievo 4). Stesso `.avviso` di
   ogni altra pagina: chi lo ha imparato altrove lo riconosce qui. */
.cavo > .risposta-sul-cavo { grid-column: 1 / -1; }
.cavo > .risposta-sul-cavo > .avviso { margin: var(--s1) 0 0; }

/* ⚠️ Un cavo, un'azione (audit UX 15.09.2026, tre revisori su tre: sei bottoni
   uguali per cavo, 18 comandi per tre cavi, 4.800 per ottocento). In vista resta
   il PROSSIMO passo; tutto il resto — i passi indietro, quelli avanti, le
   dichiarazioni, il taglio, il motivo — sta dietro una piega che ha la forma di
   un passo. Sul telefono i due si impilano larghi tutta la riga; dal tablet in su
   stanno affiancati e la piega, aperta, si allarga a destra del prossimo. */
.spunte { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--s2); margin-top: var(--s2); }
.spunte .passo {
  /* ⚠️ 48px, non 44: 44 è il minimo per un dito nudo, e qui i diti hanno i guanti.
     La larghezza minima serve perché due bottoni vicini non si tocchino. */
  box-sizing: border-box;
  min-height: 48px; min-width: 7em;
  padding: var(--s2) var(--s4);
  font-size: var(--t-corpo); font-family: inherit; line-height: 1.25;
  
  color: var(--carta); background: none;
  border: 1px solid var(--contorno); border-radius: var(--raggio-2);
  cursor: pointer; text-decoration: none; text-align: center;
}
/* Il testo sta al centro anche in verticale: a 1440 le etichette di una riga
   stavano in alto nei bottoni da 69 px, quelle di due righe al centro. */
.spunte .passo { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s1); }
/* Il segno di casa, sotto la parola: piu' piccolo, e non grida. */
.spunte .passo-segno { font-size: var(--t-nota); opacity: .8; font-weight: 400; }
/* ⚠️ Stesso tranello di `a.tratto-porta:hover`: `--ossido-alto` sulla carta
   (2,86:1) e' piu' debole del contorno a riposo. */
.spunte .passo:hover { border-color: var(--ossido); }
.spunte .passo:focus-visible { outline: 2px solid var(--ossido-vivo); outline-offset: 2px; }
/* Il passo che viene DOPO quello di adesso: è quello che si preme nove volte su
   dieci, e si vede senza cercarlo — dal BORDO spesso e dal peso, non dal fondo
   (D60). Il testo resta del colore di sempre: il contrasto non cambia. */
.spunte .passo--prossimo { border: var(--segno) solid var(--ossido); font-weight: 600; }
.spunte .passo--prossimo:hover { background: none; border-color: var(--ossido-cupo); }
.spunte .passo--prossimo .passo-segno { opacity: 1; }
/* ⚠️ Una dichiarazione non è un passo avanti — «lo fa un'altra ditta» — e non
   deve sembrarlo: filetto tratteggiato, mai il colore dell'azione principale. */
.spunte .passo--dichiarazione { border-style: dashed; color: var(--tenue); }
/* Tornare indietro si legge a parole («Torna a …») e si vede quieto. */
.spunte .passo--indietro { color: var(--tenue); }
/* Il passo di adesso: c'è, si legge, non si ripreme. */
.spunte .passo[aria-current="true"] { border-color: var(--carta); cursor: default; }
/* ⚠️ Dal tablet in su il prossimo e la piega stanno sulla stessa riga; la piega
   prende lo spazio che resta, così aperta si allarga senza spostare il prossimo. */
/* ⚠️ E il prossimo e' largo ALMENO quanto la piega: a 1440 misurava 112 px contro
   i 204 di «Altri passi e il motivo», e la gerarchia la reggeva il solo bordo
   (giudizio del giro 2, rilievo 5). 16em = 256 px: piu' della piega in italiano
   (204) e in inglese («Other steps and the reason», ~224), e a 600 ci sta ancora
   accanto alla piega chiusa. Sul telefono i due sono gia' larghi tutta la riga. */
.spunte > .passo--prossimo { flex: 0 1 auto; min-width: 16em; }
.spunte > .altri-passi { flex: 1 1 14em; min-width: 0; }
.altri-passi > summary.passo {
  display: inline-flex; flex-direction: row; align-items: center; justify-content: center; gap: var(--s2);
  list-style: none; color: var(--tenue); font-weight: 400;
  /* ⚠️ I 48 px dei guanti li dice ANCHE il pieghevole, non solo `.spunte .passo`
     che lo contiene: `test_pieghevoli` misura ogni `<details>` dei modelli come
     e' scritto, fuori dal suo modulo, e qui trovava 25,6 px (rosso latente del
     ramo dal giro 1, visto dalla suite intera il 17.09.2026). */
  box-sizing: border-box; min-height: 48px;
}
.altri-passi > summary::-webkit-details-marker { display: none; }
.altri-passi > summary::marker { content: ""; }
.altri-passi > summary::after {
  content: "+";
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--t-voce); line-height: 1;
  transition: transform .18s ease;
}
.altri-passi[open] > summary::after { transform: rotate(45deg); }
@media (prefers-reduced-motion: reduce) { .altri-passi > summary::after { transition: none; } }
/* Gli altri passi: una griglia di bersagli uguali, due colonne sul telefono,
   quante ne entrano dal tablet in su. Il motivo sotto, largo quanto la griglia. */
.passi-tutti {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(9em, 1fr));
  gap: var(--s2); margin-top: var(--s2);
}
.passi-tutti .col-perche { grid-column: 1 / -1; }

.col-perche { display: block; margin-top: var(--s2); }
.col-perche > .etichetta { display: block; margin-bottom: var(--s1); }
.col-perche textarea {
  box-sizing: border-box;
  width: 100%; max-width: 32em; min-height: 48px; display: block;
  padding: var(--s2) var(--s3); font-size: var(--t-corpo); font-family: inherit;
  color: var(--carta); background: var(--fondo);
  border: 1px solid var(--contorno); border-radius: var(--raggio-2);
}
.col-perche textarea:focus-visible { outline: 2px solid var(--ossido-vivo); outline-offset: 2px; }

.da-dichiarare { max-width: 42em; }
.da-dichiarare p { font-size: var(--t-corpo); line-height: 1.5; }

@media (max-width: 599px) {
  /* Sul telefono: una colonna, e i bottoni larghi tutta la riga — è la mano sola. */
  .cavo { grid-template-columns: 1fr; }
  .spunte > .passo--prossimo, .spunte > .altri-passi { flex: 1 1 100%; }
  .altri-passi > summary.passo { width: 100%; }
}

/* ⚠️ La parola ritirata si legge lo stesso, e si vede che è ritirata: il lavoro
   fatto con una parola che l'azienda non usa più non diventa invisibile. */
.cavo-stato .stato-ritirata {
  font-size: var(--t-nota); color: var(--fioco);
  padding: var(--s1) var(--s2); border: 1px dashed var(--contorno); border-radius: var(--raggio-pieno);
}

/* ⚠️ L'avviso che la percentuale è più bassa del vero: sta accanto al numero,
   perché è quel numero che finisce in una riunione. */
.avviso-sparite {
  margin: 0 0 var(--s3); padding: var(--s2) var(--s3);
  border-left: var(--segno) solid var(--ambra);
  color: var(--ambra-testo); font-size: var(--t-minuto);
}

/* ── G3 · i collaudi ─────────────────────────────────────────────────────
   ⚠️ Il bottone della controfirma si preme in piedi, col tablet in mano e
   spesso coi guanti. 44px è il minimo che un dito guantato prende al primo
   colpo: qui è 56, e occupa la riga intera, perché sbagliare bersaglio in
   sala macchine vuol dire riprendere il tablet e ricominciare. */
/* ⚠️ ⚠️ **QUATTRO TOKEN INVENTATI, e per mesi NON HANNO TINTO NIENTE.** Trovati
   il 06.09.2026: `--bordo`, `--superficie`, `--testo-fioco` e `--inchiostro`
   erano usati in sei punti e dichiarati in nessuno. Un `var()` che non trova il
   suo token rende la dichiarazione INVALIDA, e la proprieta' torna al suo valore
   iniziale: `border: 1px solid var(--bordo)` non e' un bordo grigio chiaro, e'
   NESSUN BORDO. Le schede dei collaudi erano senza contorno e senza fondo, e la
   tabella della relazione senza le righe di separazione.
   ⚠️ Il difetto e' silenzioso per costruzione: nessun errore, nessun avviso,
   solo una regola che non c'e'. I nomi giusti erano li' accanto — `--linea`,
   `--fondo-alto`, `--fioco`, `--carta` — e nessuno li ha confrontati.
   ⚠️ Adesso li confronta una prova: `test_contrasto.py`. */
.collaudi { list-style: none; margin: 0; padding: 0; }
.collaudo {
  border: 1px solid var(--contorno); border-radius: var(--raggio-2);
  padding: var(--s4); margin-bottom: var(--s3); background: var(--fondo-alto);
}
.collaudo--firmato { border-left: var(--segno) solid var(--verde); }
.collaudo-testa {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--s3); margin-bottom: var(--s2);
}
.collaudo .posizione { font-weight: 600; font-size: var(--t-voce); }
.collaudo .quando { color: var(--fioco); font-variant-numeric: tabular-nums; }
.collaudo .ripete, .collaudo .esito, .collaudo .note { margin: var(--s1) 0; }
.collaudo .ripete { color: var(--fioco); font-size: var(--t-minuto); }
/* ⚠️ La firma non è verde e basta: porta la spunta, perché il colore da solo
   non si legge in controluce sul ponte, e non lo legge chi non lo distingue. */
.collaudo .firma { color: var(--verde-testo); font-weight: 600; margin: var(--s2) 0 0; }
.azione.grande {
  display: block; width: 100%; min-height: 56px; margin-top: var(--s3);
  font-size: var(--t-voce);
}
.relazione { width: 100%; border-collapse: collapse; }
.relazione th, .relazione td {
  text-align: left; padding: var(--s3) var(--s3); border-bottom: 1px solid var(--linea);
}
.relazione .numero { font-variant-numeric: tabular-nums; }

/* ── Le aree dichiarate, e il contesto della commessa (01.09) ──────────────
 * ⚠️ La parola dello stato («non ancora», «in parte», «fuori perimetro») sta
 * ACCANTO alla voce del menu': il collegamento non finge di essere una
 * funzione, e la parola la legge anche chi non distingue i colori. Il token e'
 * `--fioco`, che ha il contrasto misurato in testa al foglio.                */
/* ⚠️ 15.09.2026 (sera): la parola dello stato NON sta piu' accanto alla voce del
   menu' — e' gergo interno, e se una cosa e' a meta' lo dice la sua pagina
   (`.stato-area`, qui sotto), non la porta. La regola `.rotta .voce-stato` che
   stava qui e' andata via con il distintivo. */

/* La pagina della dichiarazione. */
.stato-area {
  display: inline-block;
  padding: var(--s2) var(--s3);
  border: var(--filetto) solid var(--contorno);
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-piccolo); letter-spacing: .08em; text-transform: uppercase;
  color: var(--tenue);
}
.stato-area--in-parte { border-color: var(--ambra); color: var(--ambra-testo); }
.area-dichiarata { margin: var(--s6) 0; max-width: var(--misura-di-lettura); }
.area-dichiarata .etichetta { display: block; margin-bottom: var(--s2); }
.righe-oneste { margin: 0; padding-left: var(--s4); }
.righe-oneste li { margin: var(--s2) 0; line-height: 1.5; }

/* Il contesto della commessa: il codice e il bene, sempre in cima. */
/* ⚠️ Il codice della commessa e' un collegamento e si tocca col telefono: era
   alto 18 px (audit UX 15.09.2026, due revisori). La riga si alza a 44 e il
   collegamento la riempie; il margine sotto sparisce perche' la riga e' gia'
   alta quanto basta a staccarsi dalle porte. */
.contesto-commessa {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s2);
  min-height: var(--tocco-legame);
  margin: 0;
  font-size: var(--t-minuto);
}
.contesto-commessa .etichetta { margin-right: 0; }
.contesto-commessa a {
  display: inline-flex; align-items: center; align-self: stretch;
  min-height: var(--tocco-legame);
  font-weight: 600;
}
.contesto-commessa .bene-del-contesto { color: var(--tenue); }

/* ⚠️ Le porte della commessa: bersagli da --tocco anche qui — il campo e i
 * collaudi si aprono col telefono, in nave, coi guanti. Sotto i 400 px la fila
 * scorre di lato come la rotta, non si accavalla e non sborda.               */
.fasi {
  display: flex;
  gap: var(--s1);
  margin: 0 0 var(--s4);
  border-bottom: var(--filetto) solid var(--linea);
  overflow-x: auto;
  /* ⚠️ ⚠️ **SENZA QUESTA RIGA LA NAVIGAZIONE E' ALTA UN PIXEL, e il pixel e' il
     filetto qui sopra.** Un elemento con `overflow` diverso da `visible` perde
     la propria ALTEZZA MINIMA AUTOMATICA quando diventa figlio di una griglia o
     di un flex: `min-height: auto` vale `0` per un contenitore che scorre.
     Quindi non apre la riga, si schiaccia, e i suoi collegamenti — alti 48 —
     restano ritagliati fuori: ci sono, hanno un rettangolo valido, e non si
     vedono ne' si possono toccare.
     ⚠️ **L'ho introdotto io** l'08.09.2026 alle 11:48 con `ad4857a`, facendo di
     `.banco` una griglia: fino a quel momento `nav.fasi` non era figlio di una
     griglia e il difetto non poteva esistere. E' rimasto in produzione un
     giorno intero, su OGNI pagina di commessa.
     ⚠️ **E il cancello me l'aveva detto**: «il puntatore non attiva :hover» su
     `/commesse/57/` a 768. Ho passato un giorno a spiegarmelo come un artefatto
     del misuratore, scartando sette ipotesi — pieghe chiuse, pointer-events,
     content-visibility, elementi sopra, `contain: paint`, deriva della
     viewport, scroll in vista — mentre lo strumento aveva ragione dal primo
     minuto. **Quando una misura e' scomoda, la prima ipotesi da scartare non e'
     la misura.** L'ho vista solo chiedendo i rettangoli degli antenati invece
     di chiedere un giudizio: `nav.fasi rect=492x1 clientH=0 scrollH=48`. */
  min-height: var(--tocco);
}
.fasi a {
  display: flex; align-items: center;
  min-height: var(--tocco);
  padding: 0 var(--s4);
  color: var(--tenue);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: var(--segno) solid transparent;
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-corpo); letter-spacing: .06em; text-transform: uppercase;
}
.fasi a:hover { color: var(--carta); }
/* ⚠️ A 360 le quattro porte del dossier («Il quadro · A bordo · Collaudi · Soldi»)
   misuravano 354 px in 328: «Soldi» usciva dallo schermo tagliata a «Sold», e
   niente diceva che la fila scorre (audit UX 15.09.2026, sulla pagina delle
   tranche; si vede su ogni pagina della commessa). Con 12 px di imbottitura
   fanno 322 e stanno tutte; con piu' porte la fila scorre come prima. */
@media (max-width: 399px) {
  .fasi a { padding: 0 var(--s3); }
}
.fasi a[aria-current="page"] { color: var(--carta); border-bottom-color: var(--ossido); }
.fasi a:focus-visible { outline: 2px solid var(--carta); outline-offset: -2px; }

/* ── E7 · i preventivi ──────────────────────────────────────────────────────
 * ⚠️ Nessun valore a caso: colori dai token misurati in testa al foglio,
 * bersagli da --tocco, spaziature della scala già in uso (4·8·12·16·24).
 * La pagina vive dentro `body.lavoro` (superficie chiara), come le commesse. */

.preventivo-riga {
  border: var(--filetto) solid var(--contorno); border-radius: var(--raggio-2);
  border-left-width: 3px;
  padding: var(--s4); margin-bottom: var(--s3); background: var(--fondo-alto);
}
.preventivo-riga h2 { margin: 0; font-size: var(--t-terzo); }
/* ⚠️ UX98 giro 2 (18.09) · **IL TITOLO E' L'UNICO MODO DI APRIRE IL PREVENTIVO**,
 * e misurato sul servito a 1440 era alto **25 px**: 221×25 e 441×25 il 18.09.2026
 * (l'audit ne aveva trovati altri due, 225×25 e 324×25). Un collegamento che sta
 * su una riga sua e' un bersaglio, e un bersaglio vale `--tocco-legame` (44): un
 * titolo non si ingrossa fino a 48, ma nemmeno resta l'altezza di una riga di
 * testo per chi lo cerca col dito guantato in banchina.
 * ⚠️ `flex-wrap: wrap` perche' il titolo e' una FRASE: a 360 px «2026/0001 ·
 * Illuminazione di coperta» deve poter andare a capo. Senza, l'`inline-flex`
 * terrebbe il numero e la frase su una riga sola e sborderebbe. */
.preventivo-testa h2 a {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  min-height: var(--tocco-legame);
}
.preventivo-riga .etichetta { display: block; margin-top: var(--s1); }
.preventivo-testa {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--s3); flex-wrap: wrap;
}
.preventivo-riga .nato-in { margin: var(--s2) 0 0; font-size: var(--t-minuto); }

/* ⚠️ Lo stato porta SEMPRE la parola: il bordo colorato è un rinforzo, mai il
 * messaggio. I toni sono i `-testo`, che hanno il contrasto misurato. */
.stato-parola {
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-minuto); letter-spacing: .06em; text-transform: uppercase;
  color: var(--tenue); white-space: nowrap;
}
.stato--aperto { border-left-color: var(--contorno); }
.stato--in-attesa { border-left-color: var(--ambra); }
.stato--in-attesa .stato-parola, .stato-parola.stato--in-attesa { color: var(--ambra-testo); }
.stato--accettato { border-left-color: var(--verde); }
.stato--accettato .stato-parola, .stato-parola.stato--accettato { color: var(--verde-testo); }
.stato--rifiutato { border-left-color: var(--fioco); }
.stato--scaduto { border-left-color: var(--ossido); }
.stato--scaduto .stato-parola, .stato-parola.stato--scaduto { color: var(--ossido-testo); }

.preventivo-fatti { margin-bottom: var(--s4); }
.preventivo-testo .testo-libero {
  max-width: var(--misura-di-lettura); white-space: normal; line-height: 1.6;
}
.preventivo-voci, .preventivo-chiusura, .preventivo-risposta, .preventivo-esito,
.preventivo-testo { margin: var(--s6) 0; }
/* I titoli di sezione della scheda: sotto l'h1, sopra il corpo.
 * ⚠️ UX98 (16.09): erano a `--t-voce` (18 px) mentre gli h2 di sezione fuori
 *   dalla scheda — «Il prezzo consigliato» in testa al conto — uscivano a 25:
 *   due corpi per lo stesso livello nella stessa pagina. Un corpo per livello. */
.preventivo-voci h2.minore, .preventivo-chiusura h2.minore,
.preventivo-risposta h2.minore, .preventivo-testo h2.minore {
  font-size: var(--t-secondo); margin: 0 0 var(--s3);
}
/* ⚠️ UX98 (17.09), rilievo 3 del giudizio 4 · IL TITOLO DI SEZIONE RESPIRA
 * SOPRA. Misurato dopo il giro 4 sulla pagina servita: gli h2 della scheda
 * uscivano con `margin-top: 0` — «La distinta» attaccata al blocco che sta
 * sopra, e ogni sezione partiva dove l'altra finiva, senza il passo che dice
 * «cambia il discorso» (prossimità, d2). Un gradino sopra il titolo, uguale
 * per tutte le sezioni della pagina del preventivo: il margine del primo
 * titolo collassa con quello che già separa le sezioni (nessun raddoppio),
 * gli altri se lo guadagnano. */
.pagina-preventivo h2.minore { margin-top: var(--s6); }
.preventivo-voci .relazione tfoot .totale th,
.preventivo-voci .relazione tfoot .totale td {
  border-top: 2px solid var(--linea); border-bottom: 0;
  font-weight: 600;
}
.preventivo-voci .relazione .etichetta { margin-left: var(--s2); }
/* ── D53 · il preventivo si compila nella riga ─────────────────────────────
 * ⚠️ Il campo e' largo quanto un numero, non quanto una descrizione: su 792
 * righe ogni centimetro inutile moltiplica lo scorrimento orizzontale e
 * allontana l'importo dai suoi fattori. Il fuoco evidenzia l'intera riga,
 * perche' dopo molti Invii e' facile perdere quale riga si sta scrivendo. */
.preventivo-voci .numeri-della-voce { display: inline; margin: 0; }
.preventivo-voci .numero-della-riga,
.preventivo-voci .prezzo-della-riga { min-width: 12ch; vertical-align: top; }
.preventivo-voci input[data-campo-riga] {
  box-sizing: border-box; width: 10ch; min-height: var(--tocco);
  padding: var(--s2); text-align: right; font: inherit;
  font-variant-numeric: tabular-nums;
  color: var(--carta); background: var(--fondo);
  border: var(--filetto) solid var(--contorno); border-radius: var(--raggio-0);
}
.preventivo-voci input[data-campo-riga]:focus-visible {
  outline: 2px solid var(--ossido-vivo); outline-offset: 2px;
}
.preventivo-voci .relazione tr:focus-within { background: var(--fondo-alto); }
/* ⚠️ UX98 (17.09), rilievo 2 del giudizio 4 · I COMANDI IMPILATI DELLA RIGA
 * HANNO LA LARGHEZZA DELLA COLONNA. Misurato dopo il giro 4 sulla pagina
 * servita: 262/181/71 a 1440 e 181/181/71 a 360 (il giudizio lesse
 * 198/136/58) — tre comandi sovrapposti che finiscono ognuno dove il suo
 * testo la smette, e la colonna perde il filo (d2/d1). Stessi comandi,
 * stessa larghezza: è il trattamento che i gesti del conto hanno già sotto
 * i 700 px (`.documento-gesti .azione`), qui a ogni larghezza perché la
 * colonna dei gesti esiste a ogni larghezza. Vale per la tavola delle voci
 * e per quella delle opzioni: stesso piede, stessa colonna.
 * ⚠️ `width: 100%` e non il solo `display: flex`: misurato, il box esterno
 * di un `<button>` non si allarga con la blockification (l'ancora sì, i due
 * bottoni no: 272/181/71), e il comando pieno quanto la colonna lo rende
 * il `width`. */
.preventivo-voci .relazione tbody td:last-child .azione { display: flex; width: 100%; }
.preventivo-voci .unita-della-riga { display: inline-block; }
/* ⚠️ UX98 (16.09), rilievo R07 · UN AZIONE PIENA PER SCHERMATA. La difesa del
 * conto vissuto sta in `test_azioni_primarie.py`; questa e' una GUARDIA per il
 * giorno che un «salva-voce» compare su ogni riga della tavola: pieno solo
 * sulla riga in modifica, mai sulle righe ferme.
 * ⚠️ Rilievo 2 del giudizio di giro 2: la guardia diceva `.riga:not(.in-modifica)`
 *    ma nel template né `.riga` né `.in-modifica` esistono — la tavola delle
 *    voci è fatta di `<tr>` con un modulo per riga, e una guardia che non lega
 *    il markup reale non difende niente (misurato: una sonda contava 800
 *    comandi «Salva quantità e prezzo» pieni nella stessa schermata, perché il
 *    riquadro del bottone — nascosto a forbice — porta il FONDO del browser:
 *    rgb(239,239,239), e `checkVisibility` la forbice non la vede).
 *    La riga in modifica qui è la riga il cui modulo HA IL FUOCO: si batte un
 *    numero, quella riga — e solo quella — espone il suo salva. Senza
 *    JavaScript il fuoco arriva battendo sul campo, e Invio invia comunque:
 *    l'invio implicito del modulo non ha bisogno del bottone visibile. */
.numeri-della-voce:not(:focus-within) .salva-voce { display: none; }
.preventivo-voci .origine-del-prezzo,
.preventivo-voci .stato-dei-numeri {
  display: block; margin-top: var(--s1); max-width: 18ch;
  white-space: normal; text-align: right;
  font-size: var(--t-nota); line-height: 1.25; color: var(--fioco);
}
.preventivo-voci .origine-del-prezzo[title] {
  text-decoration: underline dotted; text-underline-offset: .18em;
  cursor: help;
}
.preventivo-voci .stato-dei-numeri[data-stato="salvo"] { color: var(--tenue); }
.preventivo-voci .stato-dei-numeri[data-stato="salvato"] { color: var(--verde-testo); }
.preventivo-voci .stato-dei-numeri[data-stato="errore"] { color: var(--ossido-testo); }
.preventivo-voci .battitura-in-riga { max-width: var(--misura-di-lettura); }

/* Numero permanente e ritorno alla voce, anche nella tabella larga sul telefono. */
.riferimento-voce {
  display: inline-flex; align-items: center; min-height: var(--tocco);
  padding-inline: var(--s2); font-variant-numeric: tabular-nums;
  font-weight: 600; white-space: nowrap;
}
.riferimento-voce:focus {
  outline: 2px solid var(--ossido-vivo); outline-offset: -2px;
}
.gesti-del-dettaglio h3:focus {
  outline: 2px solid var(--ossido-vivo); outline-offset: 2px;
}
.descrizione-voce, .esito-ritorno-voce { display: block; }
.esito-ritorno-voce { margin-top: var(--s2); font-size: var(--t-nota); }
[id^="voce-"], [id^="gruppo-"], .riferimento-voce, #aggiungi-voce, #numero-riga {
  scroll-margin-top: calc(var(--ponte-reso, var(--ponte)) + var(--gradino-dell-ancora));
}
[id^="voce-"]:target { background: var(--fondo-alto); }
.vai-alla-voce {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2);
  margin-block: var(--s4);
}
.vai-alla-voce label { font-weight: 600; }
.vai-alla-voce input[type="text"] {
  box-sizing: border-box; width: 12ch; min-height: var(--tocco);
  padding: var(--s2); font: inherit; font-variant-numeric: tabular-nums;
  color: var(--carta); background: var(--fondo); border: var(--filetto) solid var(--contorno);
}
.vai-alla-voce input:focus-visible { outline: 2px solid var(--ossido-vivo); }
.vai-alla-voce > p { flex-basis: 100%; margin-block: 0; }
/* ⚠️ La tabella scorre DENTRO il suo contenitore sul telefono: la pagina non
 * deve mai scorrere di lato (regola di gesto-larghezza.py). */
.preventivo-voci { overflow-x: auto; }

/* U4 · La controprova e' una parte del lavoro, non un allarme laterale. Sta fra
 * la lettura e la distinta, usa lo stesso registro e tiene il gesto sulla riga
 * che puo' risolvere. Sul telefono `.azioni` va gia' a capo a tutta larghezza. */
.controprova { margin: var(--s6) 0; }
/* ⚠️ UX98 (16.09), rilievo 8: era a `--t-voce` (18 px) ed era l'ULTIMO h2
 * della pagina del preventivo con un corpo suo — la sonda sul reso vero
 * contava due corpi per lo stesso livello (25 e 18). Un corpo per livello. */
/* ⚠️ Il margine sopra lo dichiara la regola della pagina (`.pagina-preventivo
 *   h2.minore`): qui si ridice perché questa regola è PIÙ AVANTI nel foglio
 *   e la sua shorthand `margin: 0 …` glielo toglierebbe — rilievo 3 del
 *   giudizio 4, misurato: era l'unico titolo rimasto attaccato al blocco
 *   che sta sopra. */
.controprova h2.minore { font-size: var(--t-secondo); margin: var(--s6) 0 var(--s3); }
.controprova-intro { max-width: var(--misura-di-lettura); }
.controprova .riga > .colonna:first-child { flex: 1 1 320px; }
.controprova-esito {
  margin: var(--s3) 0 0; padding: var(--s3) var(--s4);
  border: var(--filetto) solid var(--contorno);
  color: var(--tenue);
}

/* I moduli «aggiungi» chiudono l'elenco come la sua ultima riga. Non aprono un
 * pannello nuovo con un altro titolo: il gesto resta attaccato ai dati su cui
 * agisce e sul telefono i campi si impilano. */
.voce-nuova,
.riga-aggiunta {
  margin: 0; padding: var(--s4);
  max-width: none;
  border: var(--filetto) solid var(--contorno); border-top: 0;
  background: var(--fondo-alto);
}
.riga-aggiunta .aggiunta-titolo { margin: 0 0 var(--s1); font-size: var(--t-voce); }
.riga-aggiunta .aiuto { max-width: var(--misura-di-lettura); }
.voce-nuova .voce-campi {
  display: grid; gap: var(--s3);
  grid-template-columns: minmax(16ch, 2fr) repeat(3, minmax(9ch, 1fr));
  align-items: start;
}
/* ⚠️ **`1fr` NON e' «una parte dello spazio»: e' `minmax(auto, 1fr)`**, e quel
 * minimo automatico e' il min-content della colonna — che qui e' un `<input>`,
 * cioe' circa 220 px che non scendono. Misurato sul servito il 06.09.2026 a
 * 360 px: le due colonne restavano `220px 220px` dentro un contenitore largo
 * 320, e il campo «Prezzo unitario» finiva a 491 px, raggiungibile solo
 * scorrendo di lato DENTRO la sezione. Un campo che si compila solo dopo aver
 * trovato una barra di scorrimento nascosta e' un campo che non si compila. */
@media (max-width: 700px) {
  .voce-nuova .voce-campi { grid-template-columns: 1fr 1fr; }
}
/* ⚠️ E sotto i 480 px UNA COLONNA SOLA. Non e' gusto: a 360 px le due colonne
 * restavano larghe `220px 220px` dentro un contenitore da 320, e il campo
 * «Prezzo unitario» finiva a 491 px — raggiungibile solo scorrendo di lato
 * DENTRO la sezione, che vuol dire non raggiungibile. Misurato sul servito.
 * ⚠️ La causa e' che `1fr` NON e' «una parte dello spazio»: e' `minmax(auto,
 * 1fr)`, e quel minimo automatico e' il min-content della colonna — qui un
 * `<input>`, cioe' 220 px che non scendono. Sopra i 480 px il contenitore e'
 * abbastanza largo perche' le due colonne ci stiano lo stesso: li' non c'e'
 * niente da correggere, e infatti spegnere la correzione a 560 px non cambia
 * nulla. Si corregge dove il difetto si vede. */
@media (max-width: 480px) {
  .voce-nuova .voce-campi { grid-template-columns: minmax(0, 1fr); }
}
.voce-nuova .campo { margin-bottom: 0; }
.voce-nuova .aiuto { font-size: var(--t-nota); color: var(--fioco); }
.voce-nuova .sbaglio, .piega .sbaglio { font-size: var(--t-minuto); color: var(--ossido-testo); }
.piega .aiuto { font-size: var(--t-nota); color: var(--fioco); }
.voce-nuova > .azione { margin-top: var(--s3); }

/* ⚠️ <details>: la risposta si apre senza JavaScript. Il summary è un bersaglio
 * vero (--tocco) e tiene il focus visibile — è un elemento interattivo come
 * gli altri, con tutti i suoi stati. */
.piega { margin: var(--s3) 0; }
.piega > summary {
  display: inline-flex; align-items: center; gap: var(--s2);
  /* ⚠️ `--tocco` su una riga sua: il canarino dei 48 px si ancora alla riga
     di «Esci», e una copia identica gli uccide l'ancora (2 punti = morto). */
  min-height: var(--tocco);
  padding: 0 var(--s4);
  cursor: pointer; list-style: none; user-select: none;
}
.piega > summary::-webkit-details-marker { display: none; }
.piega > summary::before { content: "▸"; font-size: var(--t-nota); }
.piega[open] > summary::before { content: "▾"; }
.piega > summary:focus-visible { outline: 2px solid var(--ossido); outline-offset: 2px; }
.piega > form {
  margin: var(--s3) 0 var(--s1); padding: var(--s4);
  border: var(--filetto) solid var(--contorno); border-radius: var(--raggio-2);
  background: var(--fondo-alto); max-width: 46rem;
}

.preventivo-esito .firma { color: var(--verde-testo); font-weight: 600; }
.preventivo-esito .manca { color: var(--ambra-testo); }

/* ── U3 · una pagina diversa per il lavoro possibile in questo stato ───────
 * Le parti ormai congelate sono righe, non pannelli accartocciati: si leggono
 * senza un gesto e portano direttamente al file che le conserva. Le parti su
 * cui si puo' agire restano intere. */
.indice-capitoli {
  margin: var(--s4) 0 var(--s4);
  border: var(--filetto) solid var(--contorno);
  background: var(--fondo-alto);
}
.indice-capitoli > summary {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3) var(--s6);
  min-height: var(--tocco); padding: var(--s3) var(--s4);
  cursor: pointer; list-style: none; user-select: none;
}
.indice-capitoli > summary::-webkit-details-marker { display: none; }
.indice-capitoli > summary::before {
  content: "▸"; flex: 0 0 auto; color: var(--ossido-testo); font-size: var(--t-minuto);
}
.indice-capitoli[open] > summary::before { content: "▾"; }
.indice-capitoli > summary:hover { background: color-mix(in srgb, var(--ossido) 6%, transparent); }
.indice-capitoli > summary:focus-visible {
  outline: 2px solid var(--ossido-testo); outline-offset: -2px;
}
.indice-capitoli-identita,
.indice-capitoli-misura { display: flex; flex-direction: column; gap: var(--s1); }
.indice-capitoli-identita { flex: 1 1 180px; }
.indice-capitoli-misura { flex: 0 1 auto; }
.indice-capitoli-gesto {
  margin-left: auto; color: var(--ossido-testo);
  font-family: "Barlow Condensed", sans-serif;
  font-size: var(--t-piccolo); font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; white-space: nowrap;
}
.indice-capitoli-chiudi { display: none; }
.indice-capitoli[open] .indice-capitoli-apri { display: none; }
.indice-capitoli[open] .indice-capitoli-chiudi { display: inline; }
.indice-capitoli-avviso { margin: 0; padding: var(--s3) var(--s4); border-top: var(--filetto) solid var(--linea); }
.indice-capitoli .capitoli { border: 0; border-top: var(--filetto) solid var(--linea); }
.indice-capitoli .capitoli .riga > .colonna { flex: 1 1 320px; }
.indice-capitoli .capitolo-misura {
  flex: 0 0 auto; margin-left: auto; max-width: none; white-space: nowrap;
}

.preventivo-momento {
  display: flex; align-items: baseline; gap: var(--s3);
  margin: var(--s6) 0 var(--s4); max-width: var(--misura-di-lettura);
  font-size: var(--t-voce);
}
.preventivo-momento .etichetta { flex: none; color: var(--ossido-testo); }
.preventivo-sintesi { margin: 0 0 var(--s7); }
.preventivo-sintesi .riga > .colonna { flex: 1 1 260px; }
.preventivo-sintesi .riga-vai {
  margin-left: auto; color: var(--ossido-testo);
  font-family: "Barlow Condensed", sans-serif;
  font-size: var(--t-piccolo); font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; white-space: nowrap;
}
.preventivo-carta { margin: var(--s7) 0; scroll-margin-top: var(--s4); }
.preventivo-carta h2,
.preventivo-risposta h2 { margin: var(--s1) 0 var(--s3); font-size: var(--t-terzo); }

/* Accettare e rifiutare sono le due risposte possibili, entrambe visibili.
 * Non sono due schede: una sola superficie, divisa come una distinta. */
.preventivo-risposte {
  display: grid; grid-template-columns: 1fr 1fr;
  margin-top: var(--s4);
  border-block: var(--filetto) solid var(--linea);
}
.preventivo-risposte .modulo {
  max-width: none; padding: var(--s6) var(--s6) var(--s6) 0;
  background: transparent; border: 0;
}
.preventivo-risposte .modulo + .modulo {
  padding-inline: var(--s6) 0;
  border-left: var(--filetto) solid var(--linea);
}
.preventivo-risposte h3 { margin: 0 0 var(--s2); font-size: var(--t-voce); }
.preventivo-risposte .azione { margin-top: var(--s2); }

.preventivo-esito--grande {
  margin: var(--s7) 0; padding: var(--s7) 0;
  border-block: var(--filetto) solid var(--linea);
}
.preventivo-esito--grande h2 {
  margin: var(--s1) 0 var(--s2); font-size: var(--t-secondo); line-height: 1.2;
}
.preventivo-esito--grande p { max-width: var(--misura-di-lettura); }
.preventivo-esito--grande .motivo-rifiuto {
  color: var(--ambra-testo); font-size: var(--t-voce);
}

@media (max-width: 700px) {
  .indice-capitoli > summary { gap: var(--s2) var(--s4); }
  .indice-capitoli-identita { flex-basis: calc(100% - 30px); }
  .indice-capitoli-misura { margin-left: var(--s7); }
  .indice-capitoli-gesto { flex: 1 0 calc(100% - 30px); margin-left: var(--s7); }
  .indice-capitoli .capitoli .riga > .colonna { flex-basis: calc(100% - var(--colonna-misura)); }
  .indice-capitoli .capitolo-misura { margin-left: var(--colonna-misura); }
  .preventivo-momento { align-items: flex-start; flex-direction: column; gap: var(--s1); }
  .preventivo-sintesi .riga-vai { width: 100%; margin-left: 0; }
  .preventivo-risposte { grid-template-columns: 1fr; }
  .preventivo-risposte .modulo { padding: var(--s6) 0; }
  .preventivo-risposte .modulo + .modulo {
    padding: var(--s6) 0; border-left: 0; border-top: var(--filetto) solid var(--linea);
  }
}

/* Solo per la sintesi vocale: l'intestazione della colonna dei gesti. */
.visivamente-nascosto {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  /* ⚠️ UX98 (16.09): i bottoni non ereditano il corpo del genitore e restano
     ai 13,3333 px del predefinito del browser — fuori scala, e una sonda li
     contava a decine su questa pagina sola. */
  font-size: inherit;
}

/* Gli interruttori delle aree (02.09): una riga per area, un bersaglio alto
   almeno 56 px, la spunta grande. La usa chi amministra, ma la regola dei
   guanti vale lo stesso: lo stato si legge a parole accanto al nome, non dal
   solo colore della spunta. */
.interruttori { list-style: none; margin: 0 0 var(--s4); padding: 0; max-width: 56ch; }
.interruttori li { border-top: var(--filetto) solid var(--linea); }
.interruttori li:last-child { border-bottom: var(--filetto) solid var(--linea); }
.interruttori label {
  display: flex; align-items: center; gap: var(--s4);
  min-height: 56px; padding: var(--s2) var(--s1); cursor: pointer;
}
.interruttori input[type="checkbox"] {
  width: var(--casella-scelta); height: var(--casella-scelta); flex: none; margin: 0;
  accent-color: var(--ossido-vivo);
}
.interruttori .voce-nome { flex: 1; font-size: var(--t-voce); }
.interruttori .voce-stato { font-size: var(--t-minuto); color: var(--tenue); white-space: nowrap; }  /* 02.09: 14px e il secondario, non il fioco — si legge anche con la luce addosso */
.interruttori label:focus-within { outline: 2px solid var(--carta); outline-offset: 2px; }


/* ⚠️ L'ancora della spunta (audit dell'interfaccia, rilievo 1). Senza questo, il
   browser porta il cavo appena spuntato ESATTAMENTE sul bordo alto — sotto la
   barra — e chi guarda crede di essere finito da un'altra parte. Il margine di
   scorrimento e' la differenza fra un salto che funziona e uno che sembra
   rotto. */
/* ⚠️ E il margine e' quello del PONTE RESO piu' un respiro, non un numero: sul
   telefono il ponte e' alto 121 px e con 5rem (80) il cavo appena spuntato
   atterrava dietro al ponte, sigla e zona coperte — misurato sulla commessa da
   ottocento cavi, dove la pagina scorre davvero (giro 2, 17.09.2026). I 24 di
   respiro, non 16, per lo stesso conto di `.i-cavi` qui sopra. */
.cavo { scroll-margin-top: calc(var(--ponte-reso, var(--ponte)) + var(--s6)); }

/* ⚠️ E il cavo su cui si e' appena tornati si fa riconoscere per un istante:
   in un elenco di duecento righe uguali, «dove ero?» e' la domanda che costa.
   `:target` e' del browser, non serve JS. */
@media (prefers-reduced-motion: no-preference) {
  .cavo:target { animation: eccoti 1.6s ease-out; }
  @keyframes eccoti {
    from { background: var(--ambra, #f6e3c0); }
    to   { background: transparent; }
  }
}
/* ⚠️ Chi ha chiesto meno movimento riceve lo stesso il segnale, fermo: togliere
   l'animazione non deve voler dire togliere l'informazione. */
@media (prefers-reduced-motion: reduce) {
  .cavo:target { outline: 2px solid var(--ambra, #f6e3c0); outline-offset: 2px; }
}


.rotta .versione { display: none; }
@media (min-width: 1000px) {
  .rotta .versione {
    display: block;
    margin: auto 0 0;           /* auto in alto: va in fondo alla colonna */
    /* a sinistra dove cominciano i nomi delle voci: 3 px di barra + 12 */
    padding: var(--s4) var(--s2) 0 calc(var(--s3) + var(--segno));
    border-top: var(--filetto) solid var(--linea);
    color: var(--fioco);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: var(--t-nota);
    letter-spacing: .02em;
    line-height: 1.5;
  }
  /* Il numero: quello che si dice al telefono. Legge come una parola, non come
     un codice — quindi NON monospazio, e con il colore del testo, non del fioco. */
  .rotta .versione .versione-numero {
    display: block;
    font-family: "Barlow Condensed", sans-serif;
    font-size: var(--t-piccolo); font-weight: 600; letter-spacing: .06em;
    color: var(--tenue);
  }
  /* L'OTA: il numero che si chiede al telefono. Si muove da sola, quindi e'
     quella che dice la verita' su cosa sta girando. Monospazio perche' e' un
     conto, non una parola. */
  .rotta .versione .ota {
    display: block;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: var(--t-nota);
    user-select: all;
  }
  
  .rotta .versione .impronta {
    display: block;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: var(--t-nota);
    user-select: all;
    visibility: hidden;
    transition: visibility 0s .12s;
  }
  .rotta .versione:hover .impronta,
  .rotta .versione:focus-within .impronta { visibility: visible; }
  @media (prefers-reduced-motion: reduce) {
    .rotta .versione .impronta { transition: none; }
  }
}

/* ── E9j · Dall'account alla chiave provata ─────────────────────────────── */
.chiave-costo {
  margin: 0 0 var(--s4);
  padding: var(--s4) var(--s4);
  max-width: 72ch;
  border: 2px solid var(--carta);
  background: var(--fondo-alto);
}
.chiave-costo p { margin: var(--s1) 0 0; line-height: 1.5; }
.chiave-costo .costo-detto { font-size: var(--t-voce); }
.chiave-costo .costo-detto strong {
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--t-secondo);
}
.scelta-lettori {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
  max-width: 760px;
  margin: 0 0 var(--s6);
}
.scelta-lettori > a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  min-height: var(--tocco);
  padding: var(--s3) var(--s3);
  border: var(--filetto) solid var(--contorno);
  color: var(--carta);
  text-decoration: none;
}
.scelta-lettori > a[aria-current="page"] { border-color: var(--ossido-fondo); }
.fornitore-chiave {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3) var(--s7);
  max-width: 72ch;
  margin-bottom: var(--s6);
  padding-bottom: var(--s4);
  border-bottom: var(--filetto) solid var(--linea);
}
.fornitore-chiave p { margin: 0; max-width: 52ch; line-height: 1.5; }
.fornitore-chiave code { font-size: var(--t-corpo); color: var(--carta); }
.stato-chiave {
  display: inline-flex;
  align-items: center;
  /* ⚠️ 48, non 44: e' il bersaglio minimo dichiarato per un dito, e la prova
     test_ogni_bersaglio_da_toccare_arriva_alla_misura_dichiarata lo tiene fermo.
     Una targhetta di stato si tocca come tutto il resto. */
  min-height: 48px;
  padding: var(--s2) var(--s3);
  border: 2px solid var(--contorno);
  font-family: "Barlow Condensed", sans-serif;
  font-size: var(--t-corpo);
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.stato-chiave--funzionante { border-color: var(--verde); color: var(--verde-testo); }
.stato-chiave--mai-provata { border-color: var(--ambra); color: var(--ambra-testo); }
.stato-chiave--rifiutata { border-color: var(--ossido); color: var(--ossido-fondo); }
/* ⚠️ ⚠️ **`min-height: min-content` PER LA STESSA RAGIONE DI `.fasi`, e questa
   e' la seconda volta: e' una CLASSE di difetto, non un caso.** Un elemento con
   `overflow` diverso da `visible` perde l'altezza minima automatica quando
   diventa figlio di una griglia — `min-height: auto` vale `0` per un contenitore
   che scorre. Collassa a zero, e cio' che viene dopo gli finisce SOPRA: nel
   campionario il pieghevole «Apri il modulo» copriva «Collega il lettore», che
   ha un rettangolo valido e non si puo' toccare.
   ⚠️ Da quando `.banco` e' una griglia (08.09), ogni suo figlio che scorre e'
   esposto. Qui sono due — `.fasi` e questo — e la regola per il prossimo e'
   scritta: **un contenitore che scorre, dentro una griglia, dichiara la propria
   altezza minima, o sparisce senza dirlo.** */
.percorso-chiave { max-width: 760px; margin: 0 0 var(--s6); overflow-x: auto; min-height: var(--tocco); }
/* ⚠️ Un VALORE, non `min-content`: per un contenitore che scorre anche
   `min-content` vale ZERO — e' la stessa ragione per cui `auto` collassava, e
   ci sono cascato scrivendo la correzione. Il numero e' l'altezza dei suoi
   collegamenti, che e' quello che deve restare visibile. */
.percorso-chiave ol {
  display: grid;
  grid-template-columns: repeat(4, minmax(126px, 1fr));
  gap: var(--s1);
  margin: 0;
  padding: 0;
  list-style: none;
}
.percorso-chiave a {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: var(--tocco);
  padding: var(--s2) var(--s3);
  border: var(--filetto) solid var(--contorno);
  color: var(--tenue);
  text-decoration: none;
  white-space: nowrap;
}
.percorso-chiave a span { font-family: "IBM Plex Mono", monospace; }
.percorso-chiave a:hover { color: var(--carta); border-color: var(--carta); }
.percorso-chiave a:focus-visible { outline: 2px solid var(--carta); outline-offset: -3px; }
.percorso-chiave a[aria-current="step"] {
  border-color: var(--ossido-fondo);
  color: var(--carta);
  font-weight: 600;
}
.passo-chiave {
  max-width: 760px;
  padding: var(--s6);
  border: var(--filetto) solid var(--contorno);
  background: var(--fondo-alto);
}
.passo-chiave h2 { margin: var(--s2) 0 var(--s3); font-size: var(--t-secondo); }
.passo-chiave > p { max-width: 64ch; line-height: 1.6; }
.azioni-chiave { display: flex; flex-wrap: wrap; gap: var(--s3); margin-top: var(--s4); }
.azioni-chiave > .azione { justify-content: center; text-align: center; }
.modulo-chiave { padding: var(--s4) 0 0; border: 0; max-width: 620px; }
.modulo-chiave .campo input { font-family: "IBM Plex Mono", monospace; }

@media (max-width: 560px) {
  .chiave-costo, .passo-chiave { padding: var(--s4); }
  .scelta-lettori { grid-template-columns: minmax(0, 1fr); }
  .percorso-chiave { overflow-x: visible; }
  .percorso-chiave ol { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .percorso-chiave a { white-space: normal; }
  /* `.azioni-chiave` a colonna: ora la decide la larghezza del BANCO, nel
     container query di `.comandi` — questa guardava lo schermo. */
}

/* ── U3 · Il modulo di una sezione vuota sta dietro una riga che lo apre ──────
 * ⚠️ Misurato il 05.09.2026 sulla pagina servita a 1280 px: la pagina del
 * preventivo mostrava QUATTRO moduli interi sotto altrettante sezioni vuote
 * («Nessuna riga: la distinta non esiste ancora» sopra sei campi aperti), e SEI
 * bottoni primari dello stesso rosso. Se sei cose gridano, nessuna guida.
 * ⚠️ Il riassunto e' un comando VERO: `<summary>` prende il fuoco da tastiera,
 * si apre con Invio e con la barra, e la sintesi vocale dice «espandibile».
 * Qui si toglie solo il triangolino del browser, che su Argo stonerebbe: il
 * segno lo da' il piu'/meno disegnato accanto, che ruota di 45 gradi. */
.apri-modulo { margin: 0 0 var(--s6); }

/* ⚠️ **UNA FORMA SOLA, QUATTRO USI.** Fino al 06.09.2026 questa regola stava
 * scritta TRE volte — `.apri-modulo`, `.altre-righe`, `.dettaglio-capitolo` —
 * copiata a mano a ogni pieghevole nuovo, e la terza copia aveva gia' perso il
 * margine da aperta. Due posti che devono dire la stessa cosa prima o poi non
 * la dicono: il comportamento sta qui una volta, e attorno cambiano solo i
 * margini. Il quarto pieghevole nasce percio' gia' giusto invece di nascere
 * quasi giusto. */
.apri-modulo > summary,
.altre-righe > summary,
.correzioni > summary,
.tutte-le-voci > summary,
.storia-della-regola > summary,
.da-dove-viene > summary,
.come-ci-e-arrivato > summary,
.dettaglio-capitolo > summary,
.dettaglio-tecnico > summary,
.disaccordi-delle-letture > summary,
.righe-in-piu > summary,
.fonti-del-capitolo > summary {
  display: inline-flex; align-items: center; gap: var(--s3);
  cursor: pointer; list-style: none;
  /* ⚠️ 48 px pieni: e' la stessa soglia dei bersagli del menu, e vale qui per la
   * stessa ragione — si lavora coi guanti addosso. */
  min-height: 48px;
  /* ⚠️ **E il riassunto VA A CAPO.** Questi `<summary>` portano `.azione
   * quieta`, e `.azione` dichiara `white-space: nowrap` apposta — un PULSANTE
   * non si spezza a meta' parola. Ma qui l'etichetta e' una frase intera («Che
   * cosa hanno letto i lettori: 54 righe»), e a 360 px una frase che non va a
   * capo e' larga 443 px: misurato sulla pagina servita il 06.09.2026, con la
   * pagina che di conseguenza era larga 465 px invece di 360. Un comando che
   * porta una frase non e' un pulsante, e si comporta come un testo. */
  white-space: normal;
  justify-content: flex-start;
  text-align: left;
}
.apri-modulo > summary::-webkit-details-marker,
.altre-righe > summary::-webkit-details-marker,
.correzioni > summary::-webkit-details-marker,
.tutte-le-voci > summary::-webkit-details-marker,
.storia-della-regola > summary::-webkit-details-marker,
.da-dove-viene > summary::-webkit-details-marker,
.come-ci-e-arrivato > summary::-webkit-details-marker,
.dettaglio-capitolo > summary::-webkit-details-marker,
.dettaglio-tecnico > summary::-webkit-details-marker,
.disaccordi-delle-letture > summary::-webkit-details-marker,
.righe-in-piu > summary::-webkit-details-marker,
.fonti-del-capitolo > summary::-webkit-details-marker { display: none; }
.apri-modulo > summary::before,
.altre-righe > summary::before,
.correzioni > summary::before,
.tutte-le-voci > summary::before,
.storia-della-regola > summary::before,
.da-dove-viene > summary::before,
.come-ci-e-arrivato > summary::before,
.dettaglio-capitolo > summary::before,
.dettaglio-tecnico > summary::before,
.disaccordi-delle-letture > summary::before,
.righe-in-piu > summary::before,
.fonti-del-capitolo > summary::before {
  content: "+";
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--t-voce); line-height: 1;
  transition: transform .18s ease;
}
.apri-modulo[open] > summary::before,
.altre-righe[open] > summary::before,
.correzioni[open] > summary::before,
.tutte-le-voci[open] > summary::before,
.da-dove-viene[open] > summary::before,
.come-ci-e-arrivato[open] > summary::before,
.dettaglio-capitolo[open] > summary::before,
.dettaglio-tecnico[open] > summary::before,
.disaccordi-delle-letture[open] > summary::before,
.righe-in-piu[open] > summary::before,
.fonti-del-capitolo[open] > summary::before { transform: rotate(45deg); }
/* ⚠️ Il fuoco da tastiera si VEDE: senza, chi non usa il mouse non sa dove sta.
 * `:focus-visible` e non `:focus`, cosi' il clic col mouse non lascia l'anello. */
.apri-modulo > summary:focus-visible,
.altre-righe > summary:focus-visible,
.correzioni > summary:focus-visible,
.tutte-le-voci > summary:focus-visible,
.storia-della-regola > summary:focus-visible,
.da-dove-viene > summary:focus-visible,
.come-ci-e-arrivato > summary:focus-visible,
.dettaglio-capitolo > summary:focus-visible,
.dettaglio-tecnico > summary:focus-visible,
.disaccordi-delle-letture > summary:focus-visible,
.righe-in-piu > summary:focus-visible,
.fonti-del-capitolo > summary:focus-visible {
  outline: 2px solid var(--tenue); outline-offset: 3px; border-radius: var(--raggio-1);
}
.apri-modulo[open] > summary,
.altre-righe[open] > summary,
.correzioni[open] > summary,
.tutte-le-voci[open] > summary,
.da-dove-viene[open] > summary,
.come-ci-e-arrivato[open] > summary,
.dettaglio-capitolo[open] > summary,
.dettaglio-tecnico[open] > summary,
.fonti-del-capitolo[open] > summary { margin-bottom: var(--s3); }

/* ── UX98 giro 2 (18.09) · LA SCALETTA: pieghevoli IMPILATI, un bordo destro solo ──
 * ⚠️ Misurato il 18.09.2026 sul servito, `/economico/`,
 * `section.altri-dati-del-confronto`: quattro riassunti uno sotto l'altro larghi
 * **295, 421, 448 e 333 px a 1440** (scarto 154), 241, 336, 355, 262 a 390
 * (scarto 114), 241, 328, 328, 262 a 360 (scarto 87). La regola `scaletta` del
 * banco (`strumenti/GRAFICA.md`) ammette **8 px**: «o stanno in fila, o hanno lo
 * stesso bordo». Un riassunto largo quanto la sua frase e' giusto quando sta da
 * SOLO; in colonna diventa una scaletta, e l'occhio la legge come quattro cose
 * di quattro generi diversi invece che come quattro moduli da aprire.
 * ⚠️ Solo quando sono IMPILATI. `:has(+ …)` prende il primo di una fila, `… + …`
 * i successivi: un pieghevole che sta da solo resta largo quanto dice, perche'
 * una barra a tutta larghezza per una cosa sola e' rumore al contrario.
 * ⚠️ `width: 100%` e NON `display: flex`: il riassunto resta `inline-flex`, e
 * cosi' conserva il `+` davanti, `align-items: center` e la frase che va a capo
 * a 360 px (la ragione sta nel commento di `white-space: normal` qui sopra).
 * ⚠️ La famiglia e' la stessa delle nove regole di sopra — «una forma sola,
 * quattro usi»: se si aggiunge un pieghevole li', va aggiunto anche qui, o la
 * decima piega nasce con la scaletta che le altre nove non hanno piu'. */
:is(.apri-modulo, .altre-righe, .correzioni, .tutte-le-voci, .da-dove-viene,
    .come-ci-e-arrivato, .dettaglio-capitolo, .dettaglio-tecnico,
    .fonti-del-capitolo):has(+ :is(.apri-modulo, .altre-righe, .correzioni,
    .tutte-le-voci, .da-dove-viene, .come-ci-e-arrivato, .dettaglio-capitolo,
    .dettaglio-tecnico, .fonti-del-capitolo)) > summary,
:is(.apri-modulo, .altre-righe, .correzioni, .tutte-le-voci, .da-dove-viene,
    .come-ci-e-arrivato, .dettaglio-capitolo, .dettaglio-tecnico,
    .fonti-del-capitolo) + :is(.apri-modulo, .altre-righe, .correzioni,
    .tutte-le-voci, .da-dove-viene, .come-ci-e-arrivato, .dettaglio-capitolo,
    .dettaglio-tecnico, .fonti-del-capitolo) > summary {
  width: 100%;
}

/* -- UX98 chiusura (18.09) . LA PIEGA CHE APRE UN COMANDO SOLO ---------------
 * `voto-1800.md` rilievo 2, e la trappola gia' pagata di `voto-1237.md`
 * rilievo 2. La tabella del giro 4 diceva «scaletta a zero violazioni» perche'
 * nessuno APRIVA questa piega: chiusa, e' un riassunto solo, e non c'e' niente
 * con cui essere in scaletta. Misurato dal giudice sul servito di un preventivo
 * vero con le pieghe APERTE: il riassunto «Carica» e' largo **129 px** e il
 * comando che apre -- «Dichiara un'aliquota» -- **328 a 360** e **227 a 1440**:
 * scarto **199** e **98**, contro gli 8 px che la regola `scaletta` del banco
 * ammette. Chiuso e aperto sono lo stesso gesto in due momenti: se cambiano
 * bordo, l'occhio legge due cose diverse invece di una cosa che si apre.
 * ⚠️ Vale SOLO per la piega che apre UN COMANDO SOLO -- un `p` o un `div` che
 * non e' un modulo. Una piega che apre un MODULO (`.voce-nuova`, `.modulo`) non
 * e' questo caso: li' il riassunto apre un foglio da compilare, e il bottone
 * d'invio sta in fondo al foglio, non sotto il riassunto. Su questa pagina le
 * altre TRE pieghe (a 360: 307/270, 328/294 e 306/294) sono di quel genere, e
 * restano come sono: allinearle vorrebbe dire far finta che un modulo sia un
 * comando.
 * ⚠️ 19.09 (giudizio 9,6, `voto-0116.md` rilievo 1): qui c'era scritto «due».
 * Le `apri-modulo` di un preventivo sono QUATTRO, e la quarta -- «Aggiungi una
 * riga misurata», 306 contro 294 a 360, 324 a 390 e 269 a 1440 -- non l'aveva
 * misurata nessuno: la sonda del giudice ne restituiva tre. Un conto scritto
 * in un commento e' una misura come le altre, e invecchia come le altre.
 * ⚠️ **`width: max-content` sulla piega, e NON `width: 100%` sul riassunto.**
 * Una colonna sola larga quanto il piu' largo dei due mette d'accordo riassunto
 * e comando SENZA fare una barra a tutta pagina -- che e' esattamente cio' che
 * il commento della scaletta qui sopra chiama «rumore al contrario». A 1440 la
 * coppia resta larga quanto la frase piu' lunga, non quanto il banco.
 * ⚠️ `max-width: 100%` accanto: senza, a 360 px una frase lunga porterebbe la
 * piega oltre lo schermo e la pagina si scorrerebbe di lato.
 * ⚠️ **E si esclude la piega IMPILATA.** Se una piega di questo genere nascesse
 * in una fila, le due regole si contraddirebbero: la scaletta qui sopra vuole
 * il riassunto largo quanto il contenitore, questa lo vuole largo quanto la
 * frase. Vince la scaletta -- una fila di riassunti con un bordo destro solo
 * conta piu' dell'allineamento interno di una sola di esse -- e percio' la
 * piega in fila e' esclusa qui, non lassu'. Una difesa che ne rompe un'altra
 * non e' una difesa.
 * ⚠️ Il contenitore non puo' portare `summary:has(+ ...)` nel suo selettore:
 * `:has()` dentro `:has()` non e' CSS valido. La coppia e' percio' scritta in
 * due regole, e chi la spegne per misurarla deve spegnerle tutte e due. */
details.apri-modulo:has(> summary + :is(p, div):not(.modulo)):not(details + details):not(:has(+ details)) {
  width: max-content;
  max-width: 100%;
}
details.apri-modulo > summary:has(+ :is(p, div):not(.modulo)) { width: 100%; }
details.apri-modulo > summary:has(+ :is(p, div):not(.modulo)) + :is(p, div):not(.modulo) :is(.azione, button) {
  width: 100%;
}
/* ⚠️ ⚠️ **E LA PIEGA CHIUSA E' GIA' LARGA QUANTO QUELLA APERTA** (19.09.2026,
 * giudizio 9,6, `voto-0116.md` rilievo 2). Le tre regole qui sopra allineavano
 * riassunto e comando a piega APERTA, e basta: da chiusa la piega contiene il
 * solo riassunto, `max-content` e' la sua frase, e «Carica» era largo **129,5
 * px chiuso e 227 aperto**, a 360, a 390 e a 1440, nei due temi (misurato sul
 * reso, `verifiche/ux98-disegno-comune/sonda_pieghe.py`). Il comando premuto
 * cresceva di 98 px verso destra sotto il dito -- proprio cio' che il commento
 * qui sopra vieta: chiuso e aperto sono lo stesso gesto in due momenti.
 * Il rimedio tiene il contenuto della piega chiusa NEL CALCOLO DELLA LARGHEZZA
 * e fuori da tutto il resto: il browser chiude una piega con
 * `content-visibility: hidden` su `::details-content`, che toglie il contenuto
 * anche dal conto di `max-content`; qui torna `visible` per il conto, e
 * `visibility: hidden` lo tiene invisibile, fuori dal fuoco da tastiera e fuori
 * dall'albero dell'accessibilita', con altezza zero.
 * ⚠️ `overflow: hidden` e non `clip`: `hidden` fa da contenitore ai margini del
 * `p` dentro, che con `clip` attraversano l'altezza zero e allungano la piega
 * chiusa di 18 px (misurato in Chromium 151 su una pagina di prova).
 * ⚠️ Due prezzi, dichiarati. La ricerca nella pagina (Ctrl+F) non trova piu'
 * «Dichiara un'aliquota» a piega chiusa, e quindi non la apre da sola: col
 * contenuto `visibility: hidden` non c'e' testo da trovare. E un browser che
 * non conosce `::details-content` scarta questa regola intera e resta con lo
 * scatto di prima -- mai con qualcosa di peggio. Misurato solo in Chromium. */
details.apri-modulo:has(> summary + :is(p, div):not(.modulo)):not(details + details):not(:has(+ details)):not([open])::details-content {
  content-visibility: visible;
  visibility: hidden;
  block-size: 0;
  overflow: hidden;
}

/* ── UX98 (16.09) · UN CAPITOLO, UNA PIEGA ──────────────────────────────────
 * La riga del capitolo e la piega delle fonti sono diventate una cosa sola:
 * il summary porta il nome del capitolo, il verdetto e quante righe sono state
 * lette; tutto il resto apre da lì. Il filetto della riga se lo prende la
 * piega, e il titolo del capitolo si impila su due righe accanto al segno. */
.registro.capitoli-letti > details.capitolo { border-top: var(--filetto) solid var(--linea); }
.registro.capitoli-letti > details.capitolo:first-child { border-top: none; }
.registro.capitoli-letti > details.capitolo > summary {
  align-items: flex-start; padding: var(--s3) var(--s4);
}
.registro.capitoli-letti > details.capitolo > summary .titolo-del-capitolo {
  display: flex; flex-direction: column; gap: var(--s1); min-width: 0;
}
.registro.capitoli-letti > details.capitolo > summary .sotto { max-width: none; }
.registro.capitoli-letti > details.capitolo[open] > summary { margin-bottom: var(--s3); }
/* ⚠️ Chi ha chiesto meno movimento non lo riceve. */
@media (prefers-reduced-motion: reduce) {
  .apri-modulo > summary::before,
  .altre-righe > summary::before,
  .correzioni > summary::before,
  .tutte-le-voci > summary::before,
  .storia-della-regola > summary::before,
  .da-dove-viene > summary::before,
  .come-ci-e-arrivato > summary::before,
  .dettaglio-capitolo > summary::before,
  .dettaglio-tecnico > summary::before,
  .disaccordi-delle-letture > summary::before,
  .righe-in-piu > summary::before,
  .fonti-del-capitolo > summary::before { transition: none; }
}

/* ── U4 · Lo stato vuoto della controprova si LEGGE ─────────────────────────
 * ⚠️ `.vuoto` e' centrato e in `--tenue`, e va bene per un elenco che aspetta
 * una riga. Qui non aspetta una riga: SPIEGA che cos'e' il conto di cio' che
 * manca, ed e' un testo da leggere. Centrato su 46 caratteri lo si legge male,
 * ed e' lo stesso rilievo che U2 aveva chiuso su «Oggi» — li' pero' la
 * correzione era stata tenuta locale, quindi qui il difetto era ancora intero.
 * ⚠️ Locale anche questa: `.vuoto` la usano molte schermate che non ho
 * guardato, e cambiarla a tutte vorrebbe dire correggere alla cieca. */
.controprova .vuoto { text-align: left; padding: var(--s6) var(--s7); }
.controprova .vuoto p { max-width: var(--misura-di-lettura); margin: 0 0 var(--s4); color: var(--carta); }
.controprova .vuoto .aiuto { display: block; max-width: var(--misura-di-lettura); }

/* ── «Non e' ancora acceso» non e' «non potrai chiudere» ────────────────────
 * ⚠️ Sulla pagina del preventivo convivevano DUE riquadri rossi identici: la
 * chat che dice «qui non c'e' ancora un modo di parlare» e l'intestazione
 * mancante che dice «la chiusura si fermera' qui». Il primo e' un'attesa, il
 * secondo ferma il lavoro — e avevano lo stesso peso, cioe' o si impara a
 * ignorarli tutt'e due o ci si allarma per niente. Gravita' diverse, aspetto
 * diverso: l'attesa perde il fondo tinto e il filetto colorato, e resta una
 * nota. Il colore non e' l'unico segno: cambiano anche il bordo e il peso. */

.esito-lettura {
  border-left: var(--segno) solid var(--linea);
  padding: var(--s3) var(--s4);
  margin: 0 0 var(--s4);
  font-size: var(--t-voce);
}

/* ⚠️ E le faccende che si rifanno con un comando NON sono allarmi: nota, non
 * riquadro. Il rosso resta a cio' che chiede un giudizio o ferma il lavoro. */
.da-rifare {
  border-left: var(--segno) solid var(--linea);
  padding: var(--s2) var(--s4);
  margin: 0 0 var(--s3);
  color: var(--fioco);
}

.avviso.in-attesa {
  border-left-color: var(--contorno);
  background: transparent;
  color: var(--fioco);
}


.sta-leggendo {
  border-left: var(--segno) solid var(--ossido);
  padding: var(--s3) var(--s4);
  margin: 0 0 var(--s2);
  background: var(--fondo-alto);
}
.sta-leggendo strong { font-size: var(--t-voce); }
/* ⚠️ L'avvertenza sui numeri parziali sta ATTACCATA sotto, senza filetto: e' la
 * seconda meta' della stessa frase, non un secondo avviso da leggere a parte. */
.sta-leggendo-avvertenza {
  margin: 0 0 var(--s4);
  padding: 0 var(--s4) 0 calc(var(--segno) + var(--s4));
  color: var(--fioco);
  font-size: var(--t-minuto);
}

/* ── U3/U4 · Un elenco lungo si RIASSUME, non si srotola ───────────────────
 * ⚠️ Misurato il 06.09.2026 sulla lettura vera del capitolato: la sola
 * controprova era alta **47.015 px** a 1280 (244 righe scoperte srotolate una
 * per una), e la pagina intera 139.428 — cento schermate. Il difetto non si
 * vede sul banco, dove le righe scoperte sono due o tre: si vede solo col
 * documento vero, ed e' li' che il preventivo si usa. */
.altre-righe { margin: 0 0 var(--s6); }

/* ⚠️ Il dettaglio di un capitolo, e le fonti che i due lettori hanno prodotto,
 * stanno dietro una riga che li apre: srotolarli tutti faceva 87.845 px di
 * registro su una lettura vera, e 41.525 le sole fonti. La forma del comando e'
 * quella comune, scritta una volta sopra. */
/* ⚠️ **E6c la voleva «sotto e in piccolo», e piccola resta — ma il
 * BERSAGLIO no.** Misurato il 06.09.2026: la fila delle correzioni in
 * `bozza.html` apriva su un `<summary>` nudo, che nessuna regola nominava, alto
 * **25,6 px** — poco piu' della meta' della soglia dei guanti. Stava li' dal
 * 02.09 e nessuna prova lo diceva, perche' le prove guardavano il foglio e non
 * il rendering. Peso visivo piccolo e area da toccare piccola sono due cose
 * diverse: la prima e' gerarchia, la seconda e' un comando che non si prende. */
.correzioni { margin: 0 0 var(--s3); }
.correzioni > summary { font-size: var(--t-minuto); color: var(--fioco); }

/* ── «Com'è messo Argo, adesso» ────────────────────────────────────────────
 * ⚠️ Quello che MANCA si vede: un vocabolario vuoto non rifiuta niente e non si
 * lamenta — le pagine funzionano e il difetto si scopre da un dato sbagliato sei
 * mesi dopo. Qui «non dichiarato» porta il tono dell'ossido, e sotto sta scritto
 * che cosa costa: e' la conseguenza che fa decidere, non il nome dell'ambito. */
.come-e-messo { margin: 0 0 var(--s6); }
.come-e-messo .da-dichiarare { color: var(--ossido-testo); font-weight: 600; }
/* ⚠️ **Il rimando «si dichiara in…» e' QUIETO, e non e' gusto.** Guardando la
 * pagina servita: i cinque rimandi uscivano rossi e sottolineati come i due
 * «non dichiarato», e in un elenco dove il rosso vuol dire «questo ti costa»,
 * cinque rossi che non costano niente se lo mangiano. Il rosso resta a cio' che
 * manca; il rimando e' una nota, e si vede lo stesso perche' e' un collegamento. */
.come-e-messo .aiuto a { color: var(--fioco); text-decoration-color: var(--contorno); }
.come-e-messo .aiuto a:hover,
.come-e-messo .aiuto a:focus-visible { color: var(--carta); }

/* ── Le voci del preventivo: il fatto, poi l'elenco ────────────────────────
 * ⚠️ Misurato sulla pagina servita il 07.09.2026, col primo preventivo vero
 * nato dal capitolato: **1059 voci**, e la sola sezione delle voci alta
 * **298.405 px** — circa trecentoquaranta schermate. Il difetto non si vedeva
 * perche' U3 e U4 erano stati misurati su un preventivo VUOTO: la pagina stava
 * in 6.940 px perche' non c'era dentro niente.
 * ⚠️ La riga d'esito dice il fatto — quante voci ci sono — e l'elenco sta
 * dietro una riga che lo apre, come il registro dei capitoli. */
.esito-voci { font-size: var(--t-voce); margin: 0 0 var(--s3); }
.tutte-le-voci { margin: 0 0 var(--s4); }
/* ⚠️ **La citazione di una voce sta dietro una piega**: srotolata faceva ~280 px
 * a riga, cioe' i 298.405 px di sopra. E' materiale di consultazione — serve
 * quando si controlla QUELLA riga, non mentre si scorre l'elenco. */
.da-dove-viene { margin: var(--s2) 0 0; }
.storia-della-regola > summary,
.da-dove-viene > summary { font-size: var(--t-nota); color: var(--fioco); }
.da-dove-viene blockquote { margin: var(--s2) 0; font-size: var(--t-nota); }

/* ⚠️ ⚠️ **IL CONTENUTO LARGO SCORRE DENTRO IL SUO RIQUADRO, NON PORTA FUORI LA
 * PAGINA.** Misurato a 360 px lo stesso giorno: `table.relazione` e' larga
 * 720 px e la pagina intera diventava **597 px** — il telefono scorreva di
 * lato, che e' esattamente il difetto per cui U1 esiste. Una tabella con cinque
 * colonne di numeri non si puo' impilare senza perdere il confronto fra le
 * righe: si lascia larga e si lascia scorrere DA SOLA.
 * ⚠️ `overscroll-behavior-x: contain` perche' arrivando in fondo alla tabella
 * il gesto non si porti via anche la pagina. */
.tabella-che-scorre {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  max-width: 100%;
  /* ⚠️ ⚠️ **E ALTO QUANTO LA SUA TABELLA, non zero — E LO E' ANCHE LA SUA RIGA.**
   * Dai 760 px il banco e' una riga di griglia ad altezza FISSA, e le sue righe
   * si dimensionano sul contenuto — ma un riquadro che scorre ha per minimo
   * zero, e quando la pagina e' piu' lunga del banco il browser lo schiaccia fin
   * li'. Misurato l'11.09.2026 su «Le parole e i numeri»: alto 0 px con 2507 px
   * di righe a 768, 0 con 1739 a 1280, e `contain: paint` qui sotto le tagliava
   * tutte — la tabella non si vedeva e non si toccava. A 360 no: li' il banco
   * non e' una riga fissa. Rilievo del revisore, che l'aveva visto a 768.
   * ⚠️ ⚠️ Qui c'era `min-height: min-content`, e curava META' del difetto:
   * il RIQUADRO tornava alto quanto la tabella, ma la RIGA della griglia restava
   * a zero, e tutto cio' che veniva dopo partiva dalla cima della tabella. Su
   * «Le parole e i numeri» non si vedeva perche' la tabella e' l'ultimo blocco;
   * sulla pagina di un vocabolario il modulo «Dichiarane una» cominciava a 446
   * px con la tabella che finiva a 690, e il clic nei campi lo prendeva la
   * tabella (audit UX del 15.09.2026, P0 per due revisori su tre). Riprodotto in
   * una pagina sintetica con `html, body { height: 100% }`: con `min-height:
   * min-content` la riga resta a 40 px su 554 di riquadro; con `height:
   * max-content` la riga e' 554. Un riquadro che scorre di lato non ha mai
   * bisogno di essere piu' basso del suo contenuto, quindi l'altezza si puo'
   * DICHIARARE, e dichiarata la griglia la rispetta. */
  height: max-content;
  /* ⚠️ ⚠️ **`overflow-x: auto` DA SOLO NON BASTA, ed e' misurato.** Col riquadro
   * largo 320 px e la tabella 632, la pagina restava larga **509 px** e
   * scorreva davvero di lato — `scrollingElement.scrollLeft` arrivava a 149 —
   * mentre a quell'altezza non c'era dipinto NIENTE: si scorreva nel vuoto, che
   * e' il modo peggiore, perche' chi scorre crede di aver perso del contenuto.
   * ⚠️ Provate sulla pagina servita, una per una: `overflow-x: clip` sul
   * riquadro NON la chiude, e nemmeno sulla sezione; `display: flow-root` non
   * la chiude. La chiudono `contain: paint` e `table-layout: fixed`. Si sceglie
   * il primo: dice al browser una cosa VERA — questo riquadro non dipinge fuori
   * di se' — e non tocca il modo in cui la tabella distribuisce le colonne,
   * che con `fixed` schiaccerebbe la descrizione. */
  contain: paint;
}

/* ⚠️ Il verbale di cinquantaquattro capitoli sta dietro una riga: a chi lavora
 * al preventivo serve cosa manca, non rileggere trentamila pixel di lettura. */
.come-ci-e-arrivato { margin: var(--s6) 0; }
/* ⚠️ E il gesto che genera il preventivo sta dove finisce il lavoro di chi
 * legge, non ventimila pixel piu' in basso in un'altra sezione. */
.genera-tutto { margin: var(--s4) 0 var(--s2); }
.genera-tutto .aiuto { display: block; margin-top: var(--s2); }

.dettaglio-capitolo { margin: 0 0 var(--s3); }
.fonti-del-capitolo { margin: 0 0 var(--s4); }
/* ⚠️ I numeri da officina — quale modello ha letto, quanti token — stanno
 * dietro questa riga: al cliente non interessano, a noi si'. */
.dettaglio-tecnico { margin: 0 0 var(--s4); }

.cose-da-sistemare {
  list-style: none;
  margin: 0 0 var(--s6);
  padding: 0;
  border-left: var(--segno) solid var(--ossido);
}
.cose-da-sistemare .cosa {
  margin: 0;
  padding: var(--s2) var(--s4);
  font-size: var(--t-piccolo);
}
/* ⚠️ Un capello fra una voce e l'altra, non un bordo per ciascuna: sono voci di
 * una lista sola, e il primo non ha niente sopra da separare. */
.cose-da-sistemare .cosa + .cosa { border-top: var(--filetto) solid var(--linea); }

/* ── U1 · A 360 px NIENTE esce dallo schermo ───────────────────────────────
 * ⚠️ Misurato il 06.09.2026 sulla pagina del preventivo SERVITA a 360 px, col
 * capitolato vero dentro: la pagina era larga **660 px**. Cioe' per leggerla si
 * scorreva in orizzontale — e un menu' che sta nei 360 px dentro una pagina
 * larga 660 non ha risolto niente. Tre cause, tutte e tre invisibili sul banco,
 * perche' sul banco non c'e' ne' un'impronta di quaranta caratteri ne' i titoli
 * di un capitolato vero:
 *   · `span.valore.impronta`, 640 px — quaranta caratteri esadecimali sono UNA
 *     parola, e una parola non si spezza da sola;
 *   · il `<select>` della specifica, 562 px — prende la larghezza dell'opzione
 *     piu' lunga, e l'opzione e' il titolo del capitolato;
 * ⚠️ **E i `<fieldset>` del travaso NON erano una terza causa.** Li avevo
 * misurati a 508 px e ci avevo messo sopra `min-inline-size: 0` — la trappola
 * classica dei fieldset, che pero' qui non c'entrava: erano larghi cosi' perche'
 * il `<select>` accanto allargava il contenitore. Tolto il tetto al select,
 * stanno. La regola e' stata rimossa dopo averla spenta sul SERVITO e aver visto
 * che non cambiava niente: una regola che si puo' togliere senza che nulla si
 * muova non sta difendendo nulla, e il suo canarino non poteva cadere.
 * ⚠️ Sono due regole larghe apposta: il difetto non e' di una schermata, e' della
 * forma di quei due elementi ovunque compaiano. L'impronta sta nel piede di OGNI
 * pagina. */
.impronta { overflow-wrap: anywhere; }
select { max-width: 100%; }

/* ⚠️ **E sul telefono un pulsante va a capo invece di allargare la pagina.**
 * `white-space: nowrap` su `.azione` e' giusto sul foglio largo — un pulsante
 * non si spezza a meta' parola — ma a 360 px «Porta le righe scelte nel
 * preventivo» e' largo 390 px, e la pagina intera diventa larga 439. Fra un
 * pulsante su due righe e una pagina che si scorre in orizzontale per leggerla,
 * si sceglie il pulsante su due righe: misurato sul servito il 06.09.2026. */
@media (max-width: 560px) {
  .azione { white-space: normal; max-width: 100%; }
}

/* ── Il passo di adesso: quanto fa, e cosa aspetta te ────────────────────────
 * ⚠️ **Perche' esiste.** Misurato il 07.09.2026 sulla pagina servita del primo
 * preventivo vero (1059 voci, 7.515 px): la prima schermata era il nome di un
 * file PDF, un'impronta SHA-256 su due righe e una casella di chat — e l'unico
 * bottone pieno visibile era «Invia la domanda». Sulla pagina ce n'erano SEI, e
 * il passo vero — mettere i prezzi che mancano — non era detto da nessuna parte.
 * Questa fascia dice le due cose che una persona chiede aprendo: quanto fa, e
 * cosa tocca a me. Il filetto d'ossido a sinistra e' l'unico accento: il gesto
 * pieno sta piu' sotto, dove si preme.                                        */
.passo-di-adesso {
  display: grid;
  grid-template-columns: minmax(200px, 1fr) 1.6fr;
  gap: var(--s3) var(--s7);
  margin: var(--s6) 0 var(--s7);
  padding: var(--s4) var(--s6);
  background: var(--fondo-alto);
  border: var(--filetto) solid var(--contorno);
  border-left: var(--segno) solid var(--ossido);
}
.passo-di-adesso .etichetta { display: block; margin-bottom: var(--s2); }
.passo-di-adesso .numero {
  display: block;
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-primo); line-height: 1.1;
  /* ⚠️ Le cifre in colonna: senza, il totale balla fra una revisione e l'altra. */
  font-variant-numeric: tabular-nums;
  color: var(--carta);
}
/* ⚠️ «ancora nessun prezzo» NON e' un numero e non ne prende il peso: scritto
   grande come un totale, a mezzo secondo di distanza sembra un totale. */
.passo-di-adesso .numero.niente {
  font-size: var(--t-voce); font-weight: 500; color: var(--tenue);
}
.passo-di-adesso .aiuto { display: block; margin-top: var(--s2); }
/* ⚠️ Un collegamento, non un bottone: il bottone vero sta dove si fa la cosa, e
   due comandi che dicono la stessa parola sono due comandi da spiegare. Il
   bersaglio resta di 48 px perche' a bordo si tocca coi guanti. */
.passo-di-adesso .passo-parola {
  display: inline-flex; align-items: center;
  min-height: var(--tocco);
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-terzo); line-height: 1.15;
  color: var(--carta); text-decoration: none;
  border-bottom: 2px solid var(--ossido);
}
.passo-di-adesso .passo-parola:hover { border-bottom-color: var(--carta); }
.passo-di-adesso .passo-parola:focus-visible {
  outline: 2px solid var(--ossido); outline-offset: 3px;
}
@media (prefers-reduced-motion: no-preference) {
  /* ⚠️ 120 ms sul solo colore del filetto: il movimento qui serve a dire «questo
     si puo' premere», non a farsi notare. Niente trasformazioni, niente rimbalzi:
     una pagina di lavoro che rimbalza si legge peggio. */
  .passo-di-adesso .passo-parola { transition: border-bottom-color .12s ease-out; }
}
@media (max-width: 700px) {
  .passo-di-adesso {
    grid-template-columns: 1fr;
    gap: var(--s4);
    padding: var(--s4) var(--s4);
  }
}

/* ── Il pannello di controllo (07.09.2026) ───────────────────────────────────
 * ⚠️ Una riga che NON si apre non deve avere l'aria di una che si apre: niente
 * cursore, niente sottolineatura al passaggio. E' una dichiarazione — «questo
 * non c'e' ancora, ecco cosa si fa oggi» — e un finto collegamento che non
 * risponde insegna a non fidarsi di quelli veri.                              */
.registro .riga.non-si-apre {
  cursor: default;
  align-items: flex-start;
}
.registro .riga.non-si-apre .capo { color: var(--tenue); }
.registro .riga.non-si-apre .sotto { display: block; margin-top: var(--s1); }

/* ⚠️ **I bersagli del pannello arrivano ai 48 px.** Misurato il 07.09.2026 sulla
 * pagina servita: ventuno collegamenti alti VENTI pixel — «Si dichiara in
 * «valuta»», i nomi dei vocabolari nella tabella. A bordo si tocca coi guanti, e
 * un bersaglio di 20 px si manca. L'altezza e' il bersaglio: la larghezza resta
 * quella del testo, perche' un collegamento in mezzo a una frase non diventa un
 * bottone.                                                                    */
.come-e-messo .aiuto a,
.vocabolari td a,
.vocabolari th a {
  display: inline-flex; align-items: center;
  min-height: var(--tocco);
}

/* ── L'indice dei vocabolari, «Tutti i vocabolari» (giro 3, 16.09.2026) ─────
 * ⚠️ La tabella era senza nessuna regola: celle a un pixel, nessuna riga di
 * separazione, «aperto» schiacciato contro il perche', e la riga «Ogni voce
 * dice anche: …» in linea col nome. A 360 scorreva di lato nel riquadro con la
 * terza colonna tagliata; senza le chiavi del codice entrava in 360 stretta in
 * tre colonne, alta 7.790 px. Stessa veste delle voci di un vocabolario, e
 * sotto i 1000 px (la soglia della fiancata) ogni vocabolario e' una scheda. */
table.vocabolari { width: 100%; border-collapse: collapse; }
table.vocabolari th, table.vocabolari td {
  text-align: left; vertical-align: top;
  padding: var(--s2) var(--s3) var(--s2) 0;
  border-bottom: var(--filetto) solid var(--linea);
}
table.vocabolari thead th {
  font-family: "IBM Plex Sans", sans-serif;
  font-size: var(--t-minuto); font-weight: 600; color: var(--tenue);
  border-bottom-color: var(--contorno);
}
table.vocabolari td.nome { font-weight: 600; }
table.vocabolari td.nome .tenue { display: block; font-weight: 400; font-size: var(--t-piccolo); }
table.vocabolari td.numero { white-space: nowrap; }
table.vocabolari td.conto::before { display: none; content: attr(data-colonna) ": "; color: var(--fioco); }
@media (max-width: 999px) {
  .elenco-dei-vocabolari.tabella-che-scorre { overflow: visible; contain: none; height: auto; }
  table.vocabolari, table.vocabolari tbody { display: block; }
  table.vocabolari thead { display: none; }
  table.vocabolari tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--s1) var(--s3);
    align-items: start;
    padding: var(--s3) 0;
    border-top: var(--filetto) solid var(--linea);
  }
  table.vocabolari tr:last-child { border-bottom: var(--filetto) solid var(--linea); }
  table.vocabolari th, table.vocabolari td { display: block; padding: 0; border: 0; min-width: 0; }
  table.vocabolari td.nome { grid-column: 1; grid-row: 1; font-size: var(--t-voce); overflow-wrap: anywhere; }
  table.vocabolari td.numero { grid-column: 2; grid-row: 1; align-self: center; text-align: right; }
  table.vocabolari td.conto::before { display: inline; }
  table.vocabolari td.perche { grid-column: 1 / -1; font-size: var(--t-piccolo); }
}

/* ── Le voci di UN vocabolario (audit UX, 15.09.2026) ───────────────────────
 * ⚠️ La tabella era senza nessuna regola: celle a un pixel di respiro, nessuna
 * riga di separazione, e a 360 px meta' colonne e i sei «Ritira» oltre lo
 * schermo, dentro un riquadro che scorreva di lato. Dai 1000 px in su e' una
 * tabella; sotto, ogni voce e' una SCHEDA: nome e gesto sulla prima riga, e i
 * dati sotto, ognuno col nome della sua colonna davanti (`data-colonna`).
 * Sotto i 1000 px `.tabella-che-scorre` non ha piu' niente da far scorrere.
 * ⚠️ ⚠️ **1000, NON 700 — e' la soglia della fiancata, non del telefono.** Il
 * primo giro metteva le schede sotto i 700 e la tabella sopra: ma dai 760 la
 * fiancata prende 280 px, e a 768 (tablet in verticale, il modo in cui questo
 * programma si usa in sala macchine) la colonna del lavoro e' larga ~450 px:
 * la tabella da sette colonne scorreva di lato nel riquadro e i sei «Ritira»
 * stavano a x 868-989 su 768 di schermo, cioe' fuori, senza che niente lo
 * dicesse (audit del primo giro, P2). Misurato il 16.09.2026: la tabella con
 * le sei voci d'esempio chiede 609 px (min-content), e la colonna del lavoro
 * ne ha 688 da 1000 px in su (1000 − 280 di fiancata − 32 di margini del
 * banco): 79 px d'aria. Fra 760 e 999 la fascia era gia' «la piu' rotta di
 * tutte» per il menu' (vedi la fiancata): le schede sono la forma giusta
 * anche qui.                                                                 */
.voci-dichiarate > h2.minore { font-size: var(--t-voce); margin: 0 0 var(--s3); }
.voci-di-vocabolario { width: 100%; border-collapse: collapse; }
.voci-di-vocabolario th, .voci-di-vocabolario td {
  text-align: left; vertical-align: middle;
  /* ⚠️ A destra soltanto, come `.allegato`: la prima colonna comincia sul filo
     della sezione, e la tabella chiede 84 px in meno — con 12 px per lato le
     sette colonne volevano 705 px, e a 1000 px la colonna del lavoro ne ha 688:
     la tabella scorreva di 17 px nel riquadro proprio sulla soglia in cui
     smette di essere schede. Misurato il 16.09.2026.
     ⚠️ E a destra 8, non 12 (UX 9,8, 19.09.2026): la tabella mostra adesso
     tutto cio' che il modulo chiede, «Ordine» e «Note» comprese (voto-0450,
     rilievo 3), e con 12 px chiedeva 709 px nei 688 della colonna a 1000:
     «Ritira» a x 884-1005 su uno schermo da 1000. Con 8 px ne chiede 677. */
  padding: var(--s2) var(--s2) var(--s2) 0;
  border-bottom: var(--filetto) solid var(--linea);
}
.voci-di-vocabolario thead th {
  font-family: "IBM Plex Sans", sans-serif;
  font-size: var(--t-minuto); font-weight: 600; color: var(--tenue);
  border-bottom-color: var(--contorno);
}
.voci-di-vocabolario th.valore { font-weight: 400; }
.voci-di-vocabolario td.nome { font-weight: 600; }
.voci-di-vocabolario td.dato { color: var(--tenue); }
.voci-di-vocabolario td.gesto { text-align: right; white-space: nowrap; padding-right: 0; }
.voci-di-vocabolario td.gesto form { margin: 0; }
/* Una voce ritirata resta in elenco, in tono minore, con la parola accanto:
   lo stato lo legge anche chi non distingue i colori. */
.voci-di-vocabolario tr.ritirata :is(th, td.nome, td.dato) { color: var(--fioco); }
.voci-di-vocabolario .voce-stato {
  margin-left: var(--s2);
  font-size: var(--t-nota); font-weight: 400; color: var(--fioco);
  white-space: nowrap;
}
.voci-di-vocabolario td.dato::before { display: none; content: attr(data-colonna) ": "; }
@media (max-width: 999px) {
  .voci-dichiarate .tabella-che-scorre { overflow: visible; contain: none; height: auto; }
  .voci-di-vocabolario, .voci-di-vocabolario tbody { display: block; }
  .voci-di-vocabolario thead { display: none; }
  /* ⚠️ Una griglia e non un flusso a capo: con «Lo collega un'altra ditta» il
     gesto andava a capo da solo e i dati gli si mettevano accanto. Qui il nome
     e il valore stanno a sinistra, il gesto a destra su tutt'e due, e ogni dato
     ha la sua riga intera sotto. */
  .voci-di-vocabolario tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--s1) var(--s3);
    align-items: start;
    padding: var(--s3) 0;
    border-top: var(--filetto) solid var(--linea);
  }
  .voci-di-vocabolario tr:last-child { border-bottom: var(--filetto) solid var(--linea); }
  .voci-di-vocabolario th, .voci-di-vocabolario td { display: block; padding: 0; border: 0; min-width: 0; }
  .voci-di-vocabolario td.nome { grid-column: 1; grid-row: 1; font-size: var(--t-voce); overflow-wrap: anywhere; }
  .voci-di-vocabolario th.valore { grid-column: 1; grid-row: 2; overflow-wrap: anywhere; }
  .voci-di-vocabolario td.gesto { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
  /* poi i dati, uno per riga, col nome della colonna davanti */
  .voci-di-vocabolario td.dato { grid-column: 1 / -1; font-size: var(--t-piccolo); }
  .voci-di-vocabolario td.dato::before { display: inline; color: var(--fioco); }
}
/* ⚠️ UX 9,8 (voto-0500, rilievo 3) · «Note» e' TESTO LIBERO, l'unica colonna che
 * non ha una lunghezza. Con una nota vera (230 caratteri) la tabella le dava la
 * larghezza delle altre: a 1440 sui passi le intestazioni su 3 righe e «non
 * collego» a capo; a 1000, su Classi di stima, un'intestazione su 5 righe e la
 * nota a ~15 caratteri per riga. Misurato nel giudizio del 19.09.2026; le prove
 * e `misura.py` avevano solo note vuote.
 * ⚠️ Una colonna da 45ch (la misura di lettura della skill, §3) accanto alle
 * altre NON ci sta nemmeno a 1440: provata, la tabella dei passi chiedeva 1096 px
 * nei 1080 della colonna del lavoro, con «Fa avanzare il lavoro» su tre righe.
 * Quindi: se almeno una voce ha una nota (`con-note`, dalla vista) la tabella e'
 * fatta a schede a ogni larghezza, come sotto i 1000, e la nota prende la sua
 * riga intera, al massimo 52ch (~70 caratteri: il `ch` e' la cifra, piu' larga
 * della lettera media). Senza note la tabella resta com'era.
 * ⚠️ La misura sta su `.nota-testo`, un blocco DENTRO la cella, non sulla cella:
 * `prove/test_misura_di_lettura.py` misura ogni `max-width` in `ch` del foglio
 * costruendo il selettore in una pagina, e una `td` fuori da una tabella il
 * parser la butta via (la prova cadeva su «firstChild» di null). E nelle schede
 * «Note:» sta sulla sua riga e la nota sotto, intera.
 * E nelle schede una nota vuota non si scrive: «Note: —» su ogni voce era una
 * riga che non dice niente. */
.voci-di-vocabolario .nota-testo { display: block; max-width: 52ch; }
@media (max-width: 999px) {
  .voci-di-vocabolario td.nota.vuota { display: none; }
}
@media (min-width: 1000px) {
  .voci-dichiarate .tabella-che-scorre:has(> .con-note) { overflow: visible; contain: none; height: auto; }
  .voci-di-vocabolario.con-note, .voci-di-vocabolario.con-note tbody { display: block; }
  .voci-di-vocabolario.con-note thead { display: none; }
  .voci-di-vocabolario.con-note tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--s1) var(--s3);
    align-items: start;
    padding: var(--s3) 0;
    border-top: var(--filetto) solid var(--linea);
  }
  .voci-di-vocabolario.con-note tr:last-child { border-bottom: var(--filetto) solid var(--linea); }
  .voci-di-vocabolario.con-note :is(th, td) { display: block; padding: 0; border: 0; min-width: 0; }
  .voci-di-vocabolario.con-note td.nome { grid-column: 1; grid-row: 1; font-size: var(--t-voce); overflow-wrap: anywhere; }
  .voci-di-vocabolario.con-note th.valore { grid-column: 1; grid-row: 2; overflow-wrap: anywhere; }
  .voci-di-vocabolario.con-note td.gesto { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
  .voci-di-vocabolario.con-note td.dato { grid-column: 1 / -1; font-size: var(--t-piccolo); }
  .voci-di-vocabolario.con-note td.dato::before { display: inline; color: var(--fioco); }
  .voci-di-vocabolario.con-note td.nota.vuota { display: none; }
}

/* ⚠️ Una casella di scelta dentro un modulo: la RIGA e' il bersaglio. Prima
 * (audit UX, 15.09.2026) il modulo era `as_p`: casella da 13 px, etichetta
 * alta 20 e staccata, e col `color-scheme: dark` della pagina la casella vuota
 * era un quadratino pieno scuro — coi guanti «pieno» si legge «scelto». Stessa
 * forma degli interruttori delle aree: casella grande, riga alta almeno un
 * tocco, la spunta color ossido, e la casella disegnata CHIARA sulla carta. */
.campo.scelta > label {
  display: flex; align-items: center; gap: var(--s3);
  min-height: var(--tocco); padding: var(--s1) 0;
  cursor: pointer;
}
.campo.scelta > label .voce-nome { font-size: var(--t-voce); }
.modulo .campo.scelta input[type="checkbox"] {
  width: var(--casella-scelta); height: var(--casella-scelta); flex: none; margin: 0;
  accent-color: var(--ossido-vivo);
  color-scheme: light;
}
.campo.scelta > label:focus-within { outline: 2px solid var(--carta); outline-offset: 2px; }
.campo.scelta .aiuto { margin-left: calc(var(--casella-scelta) + var(--s3)); }
/* ⚠️ La stessa forma dove la casella sta FUORI dall'etichetta (bozza.html, «La
 * strada non la sa nessuno»): misurato il 16.09.2026, con le regole qui sopra
 * l'etichetta scendeva sotto la casella su una riga propria — non era rotto, ma
 * era un'altra forma per la stessa cosa. Qui casella ed etichetta stanno sulla
 * stessa riga e la nota va a capo intera. Il sabotaggio e' nel canarino.
 * ⚠️ UX 9,8 (voto-2020, rilievo 7: «probabilmente innocuo», mai misurato).
 * Misurato il 19.09.2026 sul reso, a 360 e 1440 nei due temi: NON lo era. Il
 * `gap` di 12 px fra casella ed etichetta era una striscia che non prende il
 * tocco — 36 punti su 444 della fascia da 48 px attorno alla casella — e a 360,
 * con l'etichetta su due righe, la casella stava fra le due, a 13,6 px dal
 * centro della prima. Adesso il respiro sta DENTRO l'etichetta, e toccarlo
 * spunta la casella; la prima riga del testo e' centrata sui 48 px della
 * casella (`(tocco - 1lh) / 2` sopra; sotto il `--s1` di prima): con una riga
 * sola resta alta 48, come prima. */
.campo.scelta:has(> input[type="checkbox"] + label) {
  display: flex; flex-direction: row; flex-wrap: wrap; align-items: flex-start; gap: 0;
}
.campo.scelta:has(> input[type="checkbox"] + label) > label {
  flex: 1 1 0; min-width: 0;
  align-items: flex-start;
  padding: calc((var(--tocco) - 1lh) / 2) 0 var(--s1) var(--s3);
}
.campo.scelta:has(> input[type="checkbox"] + label) > :is(.nota, .aiuto, .sbaglio) { flex-basis: 100%; margin-left: 0; }
/* ⚠️ UX 9,8 · Il vocabolario VUOTO porta «Dichiara la prima voce» subito dopo la
 * frase che dice che cosa ci va dentro, PRIMA dell'avvertenza «aperto» (dopo,
 * con le spiegazioni lunghe, finiva a 783-808 px su 780: misurato su tutti gli
 * ambiti vuoti), e il comando salta al titolo del modulo. Sul telefono il menu' e'
 * appiccicato sotto il ponte per la prima schermata, ed e' proprio li' che il
 * titolo atterra: stesso conto delle altre ancore che possono finirci
 * (`.i-cavi`, `form.cerca-cavo`), col bordo basso della rotta misurato da argo.js. */
#dichiarane-una { scroll-margin-top: calc(var(--rotta-resa, var(--ponte-reso, var(--ponte))) + var(--s6)); }

/* ⚠️ ⚠️ **UNA riga con UNA colonna sola: quella colonna e' il nome, e cresce.**
 * Misurato il 07.09.2026 sul pannello di controllo servito a 1280 px: i nomi
 * delle porte incolonnati in 140 px — «Le parole e i / numeri», «Chi riceve gli
 * / avvisi» — con seicento pixel vuoti a destra. La regola generale mette le
 * colonne a `0 0 140px` perche' nel registro degli atti sono DATI incolonnati,
 * e quella che cresce e' la seconda (`nth-child(2)`). Dove la colonna e' una
 * sola non c'e' niente da incolonnare: e' il nome, e la larghezza fissa lo
 * spezza per niente.
 * ⚠️ `:first-child:last-child` e non una classe nuova: la stessa riga serve «La
 * casa», il pannello e ogni elenco futuro fatto cosi', e una classe da
 * ricordarsi di mettere e' una classe che il prossimo dimentica.             */
.registro .riga > .colonna:first-child:last-child { flex: 1 1 auto; min-width: 0; }

/* ⚠️ La parola dello stato non e' parte del nome. Senza questa regola «Chi
 * riceve gli avvisi» e «non ancora» si leggono come una frase sola, e sembra
 * che la voce si chiami cosi'. E' la stessa parola, con lo stesso token, che il
 * menu' usa accanto alle aree dichiarate.                                     */
.registro .riga .capo .voce-stato {
  margin-left: var(--s3);
  font-family: "Barlow Condensed", sans-serif;
  font-weight: 600; font-size: var(--t-nota); letter-spacing: .12em;
  text-transform: uppercase; color: var(--fioco);
  white-space: nowrap;
}

/* ⚠️ **Anche il collegamento dentro un avviso e' un bersaglio.** Misurato il
 * 07.09.2026 sulla pagina servita del preventivo: «Scrivila adesso» — la via per
 * dichiarare l'intestazione che manca, cioe' l'unica cosa che sblocca la
 * chiusura — alto VENTI pixel dentro la sua frase. E' l'ultimo rimasto sotto i
 * 48 su tutte e tre le pagine che una persona apre davvero.                   */
.avviso a, .spiega a { display: inline-flex; align-items: center; min-height: var(--tocco); }


.azione.minuta {
  padding: 0 var(--s3);
  font-size: var(--t-nota);
  letter-spacing: .06em;
  /* ⚠️ **`nowrap`, e la CELLA che cresce.** La prima stesura lasciava andare a
     capo il testo dentro il bottone: l'urto spariva e ne nasceva un altro —
     misurato subito dopo sulla pagina servita del preventivo, **108 pulsanti
     spezzati a meta' parola a 360 px**. La regola di casa e' scritta da luglio e
     vale anche per i minuti: un pulsante non si spezza MAI a meta' parola.
     Quindi il bottone resta intero e a crescere e' la sua colonna. */
  white-space: nowrap;
  text-align: center;
}
/* ⚠️ **Una colonna che contiene un comando si misura sul comando.** Le colonne
 * del registro sono larghe 140 px fisse perche' portano DATI incolonnati — e un
 * dato si spezza, un bottone no. Dove c'e' un bottone la cella smette di essere
 * una colonna di dati e prende la sua misura: senza, il bottone sfonda in quella
 * accanto e ci finisce SOPRA (misurato su «Persone e accessi» a 1280 px, tre
 * coppie sovrapposte per 11×48 px).
 * ⚠️ `:has()` regge da Chrome 105, Safari 15.4 e Firefox 121. Dove non c'e', il
 * `.minuta` piu' stretto qui sopra basta da solo per le etichette di oggi: la
 * regola e' un rinforzo, non l'unica difesa. */
 * ⚠️ E si scrive `.azione.minuta`, non `.azione`: col selettore largo anche le
 * celle del registro dei capitoli — che portano una PIEGA larga quanto la sua
 * frase — smettevano di essere incolonnate, e le colonne ballavano di 8 px fra
 * una riga e l'altra. Misurato sul preventivo servito a 1440 px subito dopo
 * averlo scritto: una difesa che ne rompe un'altra non e' una difesa. */
.registro .riga > .colonna:has(.azione.minuta) { flex: 0 0 auto; }

/* -- UX98 chiusura (18.09) . LA CELLA DEI GESTI: UN CORPO SOLO, E SI ALZA ----
 * `voto-1800.md` rilievo 3. La cella dei gesti di una voce porta tre comandi --
 * «Completa la voce» (un'ancora), «Rendila un'opzione» e «Togli» (due bottoni
 * minuti) -- e li portava a **18 / 13 / 13 px**, misurato 815 volte sulla
 * pagina servita di un preventivo vero: 815 celle su 815 con i corpi misti.
 * Tre corpi in tre centimetri: l'occhio legge tre generi di cosa dove ce n'e'
 * uno solo.
 * ⚠️ ⚠️ **E SI ALZA, NON SI ABBASSA.** La correzione rimasta solo su disco al
 * giro 5 pareggiava la cella portando tutti e tre a `--t-nota`. Tre danni,
 * misurati: «Completa la voce» finiva sul token che `:root` dichiara «mai
 * un'informazione da sola»; a 360 px passava da 60 a **44 px d'altezza**, 815
 * volte, sotto il `--tocco` di 48; e le tre etichette diventavano identiche
 * per corpo, peso, colore e bordo -- l'azione della riga smetteva di essere
 * l'azione della riga. Pareggiare verso il basso non e' pareggiare: e'
 * togliere. Il corpo comune di una cella di comandi non scende mai sotto
 * `--t-minuto`, e qui e' quello dell'azione della riga.
 * ⚠️ **`--tocco` e non `--tocco-legame`, ANCHE per l'ancora.** Il bersaglio da
 * 44 px vale per un titolo o per una cella che si apre. Qui «Completa la voce»
 * sta in fila con due bottoni e fa il loro stesso mestiere: in questa cella e'
 * un COMANDO, non un legame, e si preme col guanto come gli altri due. Il
 * banco lo conta ancora come legame (44): la prova di questa cella lo misura
 * a 48, ed e' la prova ad avere ragione.
 * ⚠️ **Il peso resta la gerarchia.** Stesso corpo per tutti (2.3 del mandato) e
 * l'azione della riga pesa di piu': i minuti scendono a 500, l'ancora resta a
 * 600. Nessuno dei tre diventa pieno -- la regola dei pieni a riposo non si
 * tocca, e «Togli» resta nel colore del pericolo.
 * ⚠️ **`white-space: normal` e il respiro stretto, QUI DENTRO.** `.azione.minuta`
 * porta `nowrap` per non spezzare un bottone a meta' parola, e a 13 px in una
 * colonna da 136 px bastava. A 18 px «Rendila un'opzione» non ci sta piu':
 * senza queste due righe il testo sborda dalla colonna e a 360 px la pagina si
 * scorre di lato. Va a capo FRA le due parole -- la regola di casa, un pulsante
 * non si spezza mai dentro una parola, regge: non c'e' `anywhere` qui.
 * ⚠️ ⚠️ **E UN ALLINEAMENTO SOLO: `text-align: center`, scritto QUI.** (18.09
 * sera, rilievo 1 del giudizio 9,3.) Col corpo comune le etichette vanno a
 * capo -- anche a 1440, dove la colonna e' larga ~101 px. Su una riga sola il
 * flex centra tutto e la differenza non si vede; su due righe decide
 * `text-align`, che l'ancora EREDITA dalla cella (`start`) mentre il browser
 * da' `center` ai bottoni. Misurato sulla pagina servita: «COMPLETA LA / VOCE»
 * con le righe a -4,6 e -36,4 px dal centro, «RENDILA / UN'OPZIONE» e «TOGLI»
 * a 0 -- tre comandi pareggiati per corpo, larghezza e peso, e storti a occhio.
 * Si scrive per TUTTI e tre, non per la sola ancora: la cella ha un
 * allineamento, non tre eccezioni. La prova misura ogni riga di testo contro
 * il centro del suo comando (`prove/test_ux98_cella_dei_gesti.py`).
 * ⚠️ **E UN'INTERLINEA SOLA, per la stessa ragione.** Guardata la schermata a
 * 360 dopo il centro: «COMPLETA / LA VOCE» aveva le righe lontane, «RENDILA /
 * UN'OPZIONE» vicine. L'ancora eredita il `16px/1.6` del corpo del testo --
 * righe da 28,8 px, comando alto 59,6 -- e il bottone tiene la `normal` del
 * browser, circa 21,6 px, alto 48. Due interlinee nella stessa colonna si
 * leggono come due generi di cosa. 1.2 e' l'interlinea di un'etichetta di
 * comando su due righe: 2 x 21,6 + il filetto sta sotto il `--tocco`, e i tre
 * comandi escono tutti alti 48. La prova confronta l'interlinea calcolata. */
.preventivo-voci .relazione tbody td:has(> form) :is(.azione, button) {
  font-size: var(--t-voce);
  min-height: var(--tocco);
  white-space: normal;
  padding-inline: var(--s2);
  text-align: center;
  line-height: 1.2;
}
.preventivo-voci .relazione tbody td:has(> form) :is(.azione, button).minuta {
  font-weight: 500;
}

/* ⚠️ **Un campo di testo largo quanto il suo modulo, non quanto i suoi `cols`.**
 * Misurato il 07.09.2026 a 360 px sulla pagina servita di un vocabolario: la
 * `<textarea>` era larga 343 px e finiva a 392 — la pagina scorreva di lato di
 * 32 px. La larghezza di una textarea la decide l'attributo `cols` del browser,
 * che non sa niente della colonna in cui sta.
 * ⚠️ E il selettore NON è `.modulo .campo textarea`: dove il modulo si rende con
 * `as_p` la textarea sta dentro un `<p>`, non dentro un `.campo`, e quella
 * regola non corrispondeva a niente. Una regola che non corrisponde non dà
 * nessun errore: la pagina resta com'era, e sembra che la modifica non serva.
 * ⚠️ E un commento CHIUSO DUE VOLTE fa cadere in silenzio la regola che segue:
 * la prima stesura di questo blocco chiudeva a meta', e il foglio servito
 * conteneva la riga mentre il browser la ignorava — `max-width` restava «none».
 * Poi ci sono ricascato scrivendolo: la sequenza di chiusura, CITATA dentro un
 * commento, lo chiude davvero. Qui non si cita: si racconta.
 * Si vede solo chiedendo al browser lo stile CALCOLATO, non leggendo il file. */
.modulo textarea { width: 100%; max-width: 100%; box-sizing: border-box; }


.pannello-carte {
  display: grid;
  /* ⚠️ `min(380px, 100%)` e non `380px`: con la misura nuda la colonna resta
     larga 380 anche dentro uno schermo da 360, e la pagina scorre di lato —
     misurato subito dopo averlo scritto, pagina larga 400 px su 360. E' la
     trappola classica di `auto-fit`, e si vede solo a 360. */
  grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr));
  gap: var(--s6) var(--s6);
  align-items: start;
}
.pannello-carte .casa-gruppo { margin: 0; }
/* ⚠️ Il titolo del gruppo sta con le SUE porte: era a 12 px dal blocco di sopra e
   a 12 px dall'elenco sotto — equidistante, non diceva a chi apparteneva (banco
   sulle impostazioni, 11.09.2026). */
.pannello-carte .casa-gruppo h3.minore { margin: 0 0 var(--s2); }
/* ⚠️ Lo stato si legge, l'aiuto si spiega: due pesi diversi, o si leggono come
   una frase sola. Lo stato prende il colore del testo, l'aiuto resta tenue. */
.registro .riga .sotto.dice {
  display: block;
  margin-top: var(--s1);
  color: var(--carta);
  font-size: var(--t-minuto);
}
.registro .riga .sotto.dice + .sotto.tenue { margin-top: var(--s2); }


.intestazione .chi-e-quando {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s1) var(--s4);
  margin: var(--s3) 0 0;
}
.intestazione .chi-e-quando .etichetta { margin-right: -var(--s3); }
/* ⚠️ Cio' che manca si nomina e si vede: «da dichiarare» in ossido, come sul
   pannello di controllo. Un trattino non si cerca e non si legge come un
   compito. */
.intestazione .chi-e-quando .da-dichiarare { color: var(--ossido-testo); }
/* Il comando che corregge sta accanto a cio' che corregge, e resta quieto: non
   e' il gesto della schermata. Il bersaglio arriva a 48 px come ogni altro. */
.intestazione .chi-e-quando .corregge {
  display: inline-flex; align-items: center;
  min-height: var(--tocco);
  color: var(--tenue);
}
/* Lo stato accanto al numero, nell'occhiello: due parole sulla stessa cosa. */
.intestazione .etichetta .stato-parola { margin-left: var(--s3); }

/* ⚠️ L'impronta si apre: 64 caratteri esadecimali occupavano due righe piene
 * della prima schermata per una cosa che non si legge mai — si confronta. */
.impronta-del-documento { margin-top: var(--s3); }
.impronta-del-documento > summary {
  display: inline-flex; align-items: center;
  min-height: var(--tocco);
  color: var(--tenue);
  cursor: pointer;
}
.impronta-del-documento > summary:hover { color: var(--carta); }
.impronta-del-documento .impronta {
  display: block;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: var(--t-nota); letter-spacing: -.01em;
  overflow-wrap: anywhere;
}

/* ── Le ore da ripartire (E3) ────────────────────────────────────────────────
 * ⚠️ Queste misure stavano scritte DENTRO la pagina, in due `style=`. La regola
 * di casa e' una sola — nessuna misura dentro l'HTML — e la ragione e' che una
 * misura nel modello non si trova cercando nel foglio, non si cambia in un posto
 * solo e non partecipa alle regole di larghezza. Le ha prese
 * `test_nessuna_misura_sta_scritta_dentro_la_pagina`.                          */
.modulo#quote-ore {
  position: static;
  box-sizing: border-box;
  width: 100%;
  max-width: 42rem;
  max-height: 90dvh;
  overflow: auto;
  color: inherit;
  background: inherit;
  border: var(--filetto) solid var(--contorno);
  margin: 0 auto;
  padding: var(--s4);
}
.modulo#quote-ore fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }


.passo-di-adesso .passo-gesto { margin-top: var(--s1); }


.documento-preventivo .documento-gruppi th[scope="row"] {
  font-weight: 500; line-height: 1.35;
}
.documento-preventivo .documento-gruppi .numero {
  text-align: right; white-space: nowrap;
}
.documento-preventivo .documento-gruppi .denaro { font-weight: 600; }
/* ⚠️ La nota sotto il nome del gruppo — «194 non riconosciute» — e' un secondo
 * livello: piu' piccola e piu' fioca, cosi' la riga si legge lo stesso da
 * lontano e il dettaglio resta li' per chi lo cerca. */
.documento-preventivo .documento-gruppi .sotto {
  display: block; font-size: var(--t-nota); line-height: 1.3;
  color: var(--fioco); font-weight: 400;
}
/* ⚠️ `--ossido-testo`, non `--ossido`: il pieno come testo da' 3,88:1 a 13 px
   sulla carta chiara — misurato sul servito l'08.09.2026 su «81 senza
   quantita'». E' lo stesso scambio gia' pagato su `.avviso` il 06.09: un token
   che si chiama come una SUPERFICIE usato per l'INCHIOSTRO. */
.documento-preventivo .documento-gruppi .sotto.manca { color: var(--ossido-testo); }
/* ⚠️ ⚠️ **LA BASE STA NEL `tfoot`, E IL PRIMO POSTO CHE AVEVO SCELTO ERA
 * SBAGLIATO.** Rilievo D del giudice del giro 4: «sul conto la base si vede
 * solo aprendo una piega». L'avevo messa sotto «Importo», nel `thead` — e a
 * 360 px il `thead` di questa tavola e' `display: none` (la riga diventa una
 * scheda a due colonne, sei regole piu' su). Cioe' l'avevo resa invisibile
 * PROPRIO alla larghezza del metro: l'elettricista coi guanti, su 360 px, a
 * bordo. Se ne e' accorta la prova, dicendo `visibile: false` — ed e' la
 * ragione per cui una misura vale piu' di una scelta ragionata.
 * Nel `tfoot` si legge a tutte e due le larghezze, e sta attaccata al numero
 * che qualifica: «Totale di quello che si sa», nella base che ha. */
.documento-preventivo .documento-gruppi tfoot th .base-del-conto {
  white-space: normal; font-weight: 400;
}

/* ⚠️ **IL PIEGHEVOLE «dai il numero» ERA NUDO: 25,6 px di bersaglio.**
 * Gli altri pieghevoli dei modelli passano perche' il loro `summary` porta
 * `.azione.quieta`, che ha `min-height: var(--tocco)` senza condizioni; questo
 * non porta niente e restava alto quanto la sua riga di testo.
 * ⚠️ La regola generale sui bersagli vale sotto i 700 px o su uno schermo che
 * si tocca — e `test_pieghevoli` misura a 1280 con un mouse, perche' un
 * pieghevole si apre coi guanti a QUALUNQUE larghezza: sul tablet in sala
 * macchine la finestra e' larga, il dito no. Qui il bersaglio non dipende dalla
 * larghezza.
 * ⚠️ ⚠️ **E LA CONVENZIONE NON E' «ogni cosa cliccabile e' `.azione`»: E'
 * «ogni COMANDO e' `.azione`».** Sembra la stessa frase e non lo e'. Questo
 * `summary` e' una riga di testo che si apre, non un comando: mettendogli
 * `.azione.quieta` prenderebbe contorno e imbottitura di un bottone, e da li'
 * in poi il rilevatore delle azioni della schermata **lo conterebbe fra i
 * comandi** — cioe' il difetto si sposterebbe dentro il misuratore, dove non
 * lo vede nessuno.
 * ⚠️ Non e' teoria: l'08.09.2026 `test_azioni_primarie` guardava
 * `.azione:not(.quieta):not(.minuta)` ed era CIECO a `button.chiedi`, che e'
 * pieno. Passava per la ragione sbagliata, e corretto il selettore ha subito
 * detto «2 azioni piene sulla stessa schermata» — la decisione del 07.09 era
 * violata da giorni e nessuno lo vedeva.
 * Quindi qui il bersaglio si da' con questa regola, e la classe no. */
.dai-il-numero > summary {
  display: flex;
  align-items: center;
  min-height: var(--tocco);
}
/* ⚠️ **Il modulo sta in RIGA**: etichetta, campo e comando sono una frase sola
 * — «stessa quantita' per 79 voci [__] Dai la quantita'» — e a blocco diventano
 * tre righe che si leggono come tre cose.
 * ⚠️ Queste righe erano in `principale` (D45) e la fusione del ramo grafica le
 * ha scartate: il bersaglio del `summary` qui sopra e' stato risolto, il layout
 * del modulo no. Misurato dopo la fusione: `display: block`, il comando finito
 * SOPRA la sua etichetta. Rimesse, senza toccare la regola del bersaglio. */
.documento-preventivo .dai-il-numero { margin: var(--s2) 0 0; }
.documento-preventivo .dai-il-numero form {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); margin: var(--s2) 0;
}
.documento-preventivo .dai-il-numero label { font-size: 13px; color: var(--tenue); }
/* ⚠️ Nove caratteri: ci si scrive «3» o «1200», non una frase. Un campo largo
 * quanto la riga promette un testo lungo e fa esitare chi deve battere una
 * cifra. */
.documento-preventivo .dai-il-numero input[type="text"] { max-width: 9ch; }

/* ⚠️ D48 — che cosa c'e' dentro il gruppo, prima di dargli un numero. In corpo
 * minore e rientrato: e' materiale per DECIDERE, non il contenuto del
 * preventivo — se pesasse come le righe vere si leggerebbe come un secondo
 * elenco, e sarebbe di nuovo il muro che il gesto toglie. */
.documento-preventivo .cosa-c-e-dentro { margin: var(--s1) 0 var(--s2); }
.documento-preventivo .voci-del-gruppo {
  margin: var(--s1) 0 var(--s2); padding-left: var(--s4); font-size: 13px; color: var(--tenue);
}
.documento-preventivo .voci-del-gruppo li { margin: var(--s1) 0; }
/* ⚠️ Non e' un divieto: e' la conseguenza del gesto, accanto al campo PRIMA
 * che venga premuto. Il filetto resta un secondo segno oltre al colore. */
.documento-preventivo .avviso-del-gesto {
  max-width: var(--misura-di-lettura); margin: var(--s2) 0;
  padding-left: var(--s3); border-left: var(--segno) solid var(--ambra);
  color: var(--ambra-testo); font-size: var(--t-minuto); line-height: 1.4;
}
.documento-preventivo .origine-dei-prezzi {
  max-width: var(--misura-di-lettura); margin: var(--s2) 0 var(--s4);
  color: var(--carta);
}
.documento-preventivo .totale-consigliato { margin: 0; }
.documento-preventivo .totale-consigliato strong {
  display: block;
  font-family: "Barlow Condensed", sans-serif;
  /* ⚠️ UX98 (16.09): era `clamp(2.5rem, 7vw, 4.5rem)` — 72 px a 1440 e 40 a
   * 360, entrambi fuori scala. Resta il testo più grande della pagina (l'h1
   * ferma a 25): la gerarchia non cambia, il corpo entra nel gradino. */
  font-size: var(--t-cifra);
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  color: var(--carta);
}
.documento-preventivo .riferimento-consuntivo {
  max-width: var(--misura-di-lettura);
  margin: calc(-1 * var(--s2)) 0 var(--s4);
  color: var(--tenue);
}
.documento-preventivo .riferimento-consuntivo.manca {
  padding-left: var(--s3);
  border-left: var(--segno) solid var(--ambra);
  color: var(--ambra-testo);
}
.documento-preventivo .nome-del-sistema { display: block; }
.documento-preventivo .origine-del-sistema { color: var(--tenue); }
/* ⚠️ 54ch, non 62: misurato dal browser (test_misura_di_lettura), a 62ch questa
 * riga portava 85 caratteri — il corpo minore ha caratteri piu' stretti dello
 * zero con cui `ch` si misura, e la riga si allungava oltre la misura di
 * lettura senza che il numero lo dicesse. */
.documento-preventivo .perche-del-sistema { max-width: 54ch; }
.documento-preventivo .correggi-prezzo-sistema { margin-top: var(--s2); }
.documento-preventivo .correggi-prezzo-sistema > summary { width: fit-content; }
.documento-preventivo form.prezzo-del-sistema {
  display: grid;
  grid-template-columns: minmax(9ch, 12ch) minmax(16ch, 1fr) auto;
  gap: var(--s1) var(--s2);
  align-items: end;
  margin: var(--s2) 0;
}
.documento-preventivo form.prezzo-del-sistema label {
  color: var(--tenue);
  font-size: var(--t-minuto);
}
.documento-preventivo form.prezzo-del-sistema label:first-of-type { grid-column: 1; }
.documento-preventivo form.prezzo-del-sistema label:last-of-type { grid-column: 2; }
.documento-preventivo form.prezzo-del-sistema input[name="importo"] { grid-column: 1; }
.documento-preventivo form.prezzo-del-sistema input[name="perche"] { grid-column: 2; }
.documento-preventivo form.prezzo-del-sistema button { grid-column: 3; grid-row: 2; }

/* D54: i vecchi gesti di massa sono strumenti del dettaglio. */
.gesti-del-dettaglio {
  margin: var(--s4) 0;
  padding: var(--s3);
  border: var(--filetto) solid var(--contorno);
}
.gesti-del-dettaglio h3 { margin: 0 0 var(--s2); }
.gesti-del-dettaglio .dai-il-numero form {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2);
  margin: var(--s2) 0;
}
.gesti-del-dettaglio .dai-il-numero input[type="text"] { max-width: 9ch; }
.gesti-del-dettaglio .voci-del-gruppo {
  margin: var(--s1) 0 var(--s2); padding-left: var(--s4);
  color: var(--tenue); font-size: var(--t-nota);
}
/* ⚠️ Il gesto che torna indietro sta FUORI dal pieghevole, accanto al conto
 * delle voci che ha riempito: dentro sparirebbe proprio quando il gesto e'
 * riuscito — e un annullamento raggiungibile solo finche' non serve non e' un
 * annullamento. */
.documento-preventivo .documento-gruppi form.disfa { margin: var(--s1) 0 0; }

/* ⚠️ D55 — le proposte della chat si leggono PRIMA di applicarle. Un blocco per
 * proposta, con un filo a sinistra: «12 righe: quantità 1 → 60» si scorre in un
 * colpo. Il filo cambia colore per il tipo — lo sconto, la riga tolta — perche'
 * togliere e' un gesto diverso dal correggere e si deve vedere senza leggere;
 * il colore rinforza, il testo dice. */
.chat-del-documento .cambio-proposto {
  margin: var(--s2) 0; padding: var(--s1) 0 var(--s1) var(--s3);
  border-left: var(--segno) solid var(--linea);
  font-size: 13px;
}
.chat-del-documento .cambio-proposto p { margin: var(--s1) 0; color: var(--tenue); }
.chat-del-documento .cambio-sconto { border-left-color: var(--ossido-testo); }
.chat-del-documento .cambio-togli { border-left-color: var(--ossido-vivo); }
.chat-del-documento .cambio-riga { border-left-color: var(--carta); }

/* ⚠️ D72 — le righe che pesano, e l'oggetto dell'appalto.
 * Il riquadro delle righe grosse sta APERTO: e' il gesto di chi fa preventivi
 * da trent'anni — si guardano le righe che pesano PRIMA di mandare — e un
 * pieghevole chiuso lo si apre solo quando si sa gia' che c'e' qualcosa dentro.
 * ⚠️ Un filo d'ambra, non un rosso: non e' un guasto, e' una cosa da guardare.
 * Il colore rinforza, la percentuale in grassetto dice. */
.documento-preventivo .righe-che-pesano {
  margin: var(--s3) 0; padding: var(--s2) 0 var(--s2) var(--s3);
  border-left: var(--segno) solid var(--ambra);
    /* ⚠️ Il fondo tenue non e' decorazione: in un elenco di 792 voci un filo di
       1px non si trova, un'area colorata si'. E' l'idioma che `.avviso.warning`
       usa gia' in questo foglio per dire «guarda qui» — non se ne inventa uno
       nuovo. Il filo su questo fondo fa 3,10:1: il riquadro si distingue anche
       dall'interno, senza dipendere dal confronto col bordo vicino. */
    background: color-mix(in srgb, var(--ambra) 12%, transparent);
}
/* ⚠️ `--tocco` sul summary: un pieghevole si apre coi guanti, in sala macchine.
 * La regola vale per i summary di tutta la casa, e questi due non fanno
 * eccezione — `test_pieghevoli` li misura a 1280 px col mouse, perche' un
 * pieghevole si apre coi guanti a QUALUNQUE larghezza. */
.righe-che-pesano > summary,
.comprende-l-appalto > summary,
.imposta-del-preventivo > summary,
.validita-del-preventivo > summary {
  display: flex; align-items: center; min-height: var(--tocco);
}
.documento-preventivo .righe-che-pesano > summary { font-weight: 600; }
.documento-preventivo .righe-che-pesano ul { margin: var(--s2) 0 0; padding-left: var(--s4); }
/* ⚠️ UX98 (16.09), rilievo 10 del giudizio di giro 2: misurata una riga di
 * 131 caratteri a 1440 — una riga di lettura oltre ogni limite, l'occhio
 * perde il rigo al primo a capo. La misura di lettura di questo corpo. */
.documento-preventivo .righe-che-pesano li { margin: var(--s1) 0; font-size: 13px; max-width: 60ch; }
/* L'oggetto dell'appalto: chiuso, perche' si legge una volta e poi si sa. */
.documento-preventivo .comprende-l-appalto { margin: var(--s2) 0; }
/* ⚠️ D73 · l'imposta e la validità stanno SOTTO il conto, dove si vedono i
 * numeri che riguardano: «con IVA o senza» e «fino a quando vale» sono
 * domande sul documento, non impostazioni dell'azienda. In riga, come gli
 * altri gesti del documento. */
.documento-preventivo .imposta-del-preventivo,
.documento-preventivo .validita-del-preventivo { margin: var(--s2) 0; }
/* ⚠️ UX98 (16.09), sonda a 360: le risposte dell'imposta erano etichette di
 * blocco da 4 px con dentro un pallino da 13×13 — sotto il tocco coi guanti.
 * La risposta è il bersaglio: tutta la riga, 48 px.
 * ⚠️ Rilievo 1 del giudizio di giro 3 (16.09): la sonda dopo-3 misurava
 * l'input «senza» a 24×24 e chiedeva 48. Il pallino È il bersaglio che la
 * sonda misura, non un ornamento dentro la riga: `--tocco`, come i radio
 * di `.livelli-persona` — il minimo che si tocca con i guanti. */
.documento-preventivo .scegli-imposta label {
  display: flex; align-items: center; gap: var(--s2);
  min-height: var(--tocco); padding: 0 var(--s2);
  font-size: var(--t-nota);
}
.documento-preventivo .scegli-imposta input[type="radio"],
.documento-preventivo .scegli-imposta input[type="checkbox"] {
  width: var(--tocco); height: var(--tocco); flex: 0 0 auto; margin: 0;
}
.documento-preventivo .scegli-validita {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); margin: var(--s2) 0;
}
.documento-preventivo .scegli-validita label { font-size: 13px; color: var(--tenue); }
.documento-preventivo .comprende-l-appalto ul { margin: var(--s1) 0 0; padding-left: var(--s4); }
.documento-preventivo .comprende-l-appalto li { margin: var(--s1) 0; font-size: 13px; color: var(--tenue); }

/* ⚠️ D52 — lo sconto e la maggiorazione sul totale. Il gesto sta SOTTO il
 * conto, dove si vede l'effetto: uno sconto si decide guardando il totale, non
 * in una pagina di impostazioni.
 * ⚠️ Il `summary` prende il bersaglio come quello del gruppo — è una riga di
 * testo che si apre, non un comando, quindi il bersaglio si dà con la regola e
 * non con la classe `.azione` (che lo farebbe contare fra i comandi della
 * schermata, dove il difetto non lo vedrebbe piu' nessuno). */
.ritocco-del-totale > summary {
  display: flex;
  align-items: center;
  min-height: var(--tocco);
}
.documento-preventivo .ritocco-del-totale { margin: var(--s3) 0 0; }
/* ⚠️ In RIGA, come il gesto del gruppo: «Sconto [5] per cento — perché [__]» è
 * una frase sola, e a blocco diventa cinque righe che si leggono come cinque
 * cose da decidere. */
.documento-preventivo .ritocco-del-totale form.ritocca {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); margin: var(--s2) 0;
}
.documento-preventivo .ritocco-del-totale label { font-size: 13px; color: var(--tenue); }
/* Nove caratteri: ci si scrive «5» o «1200», non una frase. */
.documento-preventivo .ritocco-del-totale input#ritocco-quanto { max-width: 9ch; }
/* Il perché invece è una frase, e deve avere lo spazio di esserlo: un campo
 * stretto fa scrivere «anticipo» dove serviva «per pagamento anticipato». */
.documento-preventivo .ritocco-del-totale input#ritocco-motivo { min-width: 24ch; flex: 1 1 24ch; }
/* ⚠️ Il netto in evidenza, il ritocco no: la riga che conta è quella che il
 * committente paga. */
.documento-preventivo .documento-gruppi tfoot tr.netto th,
.documento-preventivo .documento-gruppi tfoot tr.netto td { font-weight: 600; }

/* ⚠️ D47 — le cinque condizioni. Ognuna col SUO perche' sopra il campo, non in
 * fondo alla pagina: chi compila deve sapere cosa succede se lascia vuoto
 * mentre ha il cursore li', non dopo. */
.le-condizioni .una-condizione { margin: 0 0 var(--s4); }
.le-condizioni .una-condizione > label { display: block; font-weight: 600; }
.le-condizioni .una-condizione .aiuto { margin: var(--s1) 0 var(--s2); }
.le-condizioni .una-condizione textarea { width: 100%; }
/* ⚠️ Un filo sul fianco di quelle che mancano: si vede scorrendo, senza
 * leggere. Colore e non solo posizione sarebbe un segno che chi non distingue
 * i colori non riceve — qui il segno e' la RIGA, il colore la rinforza. */
.le-condizioni .una-condizione.manca { border-left: var(--segno) solid var(--ossido-testo); padding-left: var(--s3); }
@media (max-width: 480px) {
  /* Sotto i 480 la riga non ci sta: va a blocco, e il campo prende tutto. */
  .documento-preventivo .dai-il-numero form { display: block; }
  .documento-preventivo .dai-il-numero input[type="text"] { max-width: 100%; }
  .documento-preventivo .ritocco-del-totale form.ritocca { display: block; }
  .documento-preventivo .ritocco-del-totale input[type="text"] { max-width: 100%; }
  .documento-preventivo form.prezzo-del-sistema { display: block; }
  .documento-preventivo form.prezzo-del-sistema label,
  .documento-preventivo form.prezzo-del-sistema input,
  .documento-preventivo form.prezzo-del-sistema button { display: block; width: 100%; margin-top: var(--s1); }
  .gesti-del-dettaglio .dai-il-numero form { display: block; }
  .gesti-del-dettaglio .dai-il-numero input[type="text"] { max-width: 100%; }
}
/* ⚠️ Il totale non e' una riga come le altre: filetto pieno sopra, e nessuna
 * riga sotto. E' la fine del documento, non l'inizio di altro. */
.documento-preventivo .documento-gruppi tfoot th,
.documento-preventivo .documento-gruppi tfoot td {
  border-top: 2px solid var(--linea); border-bottom: 0;
  font-weight: 700; padding-top: var(--s3);
}

/* ── UX98 (16.09), rilievo P1: il conto si legge a 360 ──────────────────────
 * ⚠️ La tabella del conto era larga 437 px dentro uno schermo da 328: «Imposta
 *   22%» e «Totale» restavano senza le cifre e «Nel conto» arrivava mozzato.
 *   Sotto i 480 px ogni riga diventa una GRIGLIA a due colonne — che cosa è a
 *   sinistra, quanto costa a destra — e le intestazioni di colonna lasciano il
 *   posto al contenuto: a 328 px non c'e' spazio per dirle entrambe. Le celle
 *   vuote delle righe di ritocco e imposta spariscono, se no portano righe
 *   bianche dentro la griglia. */
@media (max-width: 480px) {
  .documento-preventivo .tabella-che-scorre:has(> .documento-gruppi) {
    overflow-x: visible; contain: none; height: auto;
  }
  .documento-preventivo .documento-gruppi { display: block; }
  .documento-preventivo .documento-gruppi thead { display: none; }
  /* ⚠️ UX98 (16.09), rilievo 1 del giudizio di giro 2: le celle della griglia
   *   restavano al minimo predefinito (`min-width: auto`, cioè il contenuto), e
   *   il contenuto è la piega che corregge il prezzo: un bottone che sotto i
   *   700 px non scende da 48 px. La colonna `1fr` non poteva stringersi, il
   *   conto finiva a 371 px con scrollWidth 372: fuori schermo, di nuovo. Il
   *   minimo a 0 lo diceva il progetto; senza, la riga della griglia decide la
   *   larghezza col contenuto, che è esattamente il difetto della tabella. */
  .documento-preventivo .documento-gruppi tr > th,
  .documento-preventivo .documento-gruppi tr > td { min-width: 0; }
  .documento-preventivo .documento-gruppi tr {
    display: grid; grid-template-columns: 1fr auto; column-gap: var(--s3);
    align-items: start;
    padding: var(--s3) 0; border-bottom: var(--filetto) solid var(--linea);
  }
  .documento-preventivo .documento-gruppi tr > :empty { display: none; }
  .documento-preventivo .documento-gruppi tr > :nth-child(1) {
    grid-column: 1; grid-row: 1; font-size: var(--t-corpo);
  }
  .documento-preventivo .documento-gruppi tr > :nth-child(2) {
    grid-column: 1; grid-row: 2; font-size: var(--t-minuto); color: var(--tenue);
  }
  .documento-preventivo .documento-gruppi tr > :nth-child(3) {
    grid-column: 1; grid-row: 3; font-size: var(--t-minuto); color: var(--tenue);
  }
  .documento-preventivo .documento-gruppi tr > :nth-child(4) {
    grid-column: 2; grid-row: 1 / 4; justify-self: end; align-self: center;
    font-size: var(--t-corpo); font-variant-numeric: tabular-nums;
  }
  .documento-preventivo .documento-gruppi tfoot tr { border-bottom: 0; }
  .documento-preventivo .documento-gruppi tfoot tr > :nth-child(1),
  .documento-preventivo .documento-gruppi tfoot tr > :nth-child(4) {
    font-size: var(--t-voce); font-weight: 600;
  }
}
.documento-preventivo .manca-per-chiudere { margin-top: var(--s3); }
/* ⚠️ I due gesti stanno in fila e respirano: 12px fra loro, 16px dal conto.
 * Su un telefono si impilano — due bottoni affiancati a 360 px diventano due
 * bersagli stretti, e uno dei due si preme per sbaglio. */
.documento-preventivo .documento-gesti {
  display: flex; flex-wrap: wrap; gap: var(--s3); margin-top: var(--s4);
  align-items: center;
}
@media (max-width: 480px) {
  .documento-preventivo .documento-gesti { flex-direction: column; align-items: stretch; }
  .documento-preventivo .documento-gesti > * { width: 100%; }
  .documento-preventivo .documento-gesti .azione { display: block; text-align: center; }
}

/* ══ LA RIGA A UNA COLONNA: il titolo e la sua spiegazione stanno AFFIANCATI ═══
 * ⚠️ **Misurato l'08.09.2026 su «La casa» servita.** La riga e' larga 1.046 px
 * e la spiegazione dentro va a capo a 510 — giustamente, perche' quella e' la
 * misura di lettura — lasciando **piu' di mezza riga vuota**, sempre, su ognuna
 * delle nove voci. Non e' un difetto della misura: e' che il titolo e la sua
 * spiegazione erano incolonnati uno SOTTO l'altro dentro un mobile largo il
 * doppio di quello che serve a tutt'e due.
 * Affiancandoli, la riga usa la larghezza che ha e ogni blocco resta in banda.
 * ⚠️ E l'elenco torna a leggersi come l'indice di una tavola — i titoli tutti
 * incolonnati sullo stesso bordo — che e' esattamente cio' che `.registro`
 * dichiara di essere qualche riga piu' su.
 * ⚠️ `:only-child` e `:has(> .sotto)`: vale SOLO dove la riga ha una colonna
 * sola E una spiegazione. Le righe a piu' colonne (i beni, le commesse) la
 * larghezza la usano gia' — misurato: quattro colonne su 1.002 px — e
 * affiancare li' vorrebbe dire spostare dei dati incolonnati, che e' un'altra
 * cosa e non la si fa da un foglio di stile.
 * ⚠️ Sotto i 760 px NON si affianca: su un telefono due colonne di testo da
 * 170 px sono due colonne di parole spezzate. */
@media (min-width: 760px) {
  .registro .riga > .colonna:only-child:has(> .sotto) {
    display: grid;
    grid-template-columns: minmax(11rem, 19rem) minmax(0, 1fr);
    align-items: baseline;
    gap: var(--s1) var(--s6);
  }
}

/* ══ I BERSAGLI SUL TOCCO ═══════════════════════════════════════════════════
 * ⚠️ **`--tocco` era dichiarato dal 26.08 e non era imposto a nessuno.** Un
 * token che nessuno applica e' una promessa scritta: misurato sul servito a 360
 * px l'08.09.2026, i campi della data di «Contabilita'» erano alti **21 px**, i
 * legami dentro i titoli e le celle **18-25 px**, e il bottone della lingua
 * largo 44. Il commento accanto al token dice «a bordo si tocca CON I GUANTI»,
 * ed era vero solo per i pulsanti che se lo scrivevano da soli.
 *
 * Due misure e non una, perche' le cose non sono la stessa cosa:
 *   · un COMANDO (campo, scelta, bottone, pieghevole) arriva a `--tocco`, 48;
 *   · un LEGAME che sta da solo — il titolo di una riga, il codice in una cella
 *     — arriva a 44, che e' il minimo del WCAG 2.2. Portarlo a 48 gonfierebbe
 *     ogni riga di una tabella da ottocento voci senza che nessuno lo chieda.
 * ⚠️ I legami DENTRO UNA FRASE restano come sono: ingrossarli spezzerebbe
 * l'interlinea del paragrafo, e il WCAG li esclude apposta.
 * ⚠️ Vale sotto i 700 px E su ogni schermo che si tocca (`pointer: coarse`):
 * il tablet in sala macchine e' largo 900 px e si usa con i guanti lo stesso. */
@media (max-width: 700px), (pointer: coarse) {
  input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]),
  select, textarea, button, summary { min-height: var(--tocco); }
  /* i bottoni stretti: «EN» stava a 44 di larghezza */
  button, .azione, a.azione { min-width: var(--tocco); }

  :is(h1, h2, h3, h4, td, th, li, dd, .nome, .titolo) > a,
  .registro a.riga {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* ⚠️ Anche in LARGO, non solo in alto: un codice corto come «10263» in una
       cella faceva 40 px, e un bersaglio che manca per quattro pixel si manca
       lo stesso. Misurato sul servito a 360 px. */
    min-height: var(--tocco-legame);
    min-width: var(--tocco-legame);
  }
  /* ⚠️ `inline-flex` su un legame che avvolge piu' righe di testo le
     affiancherebbe: qui resta un blocco che si comporta da blocco. */
  .registro a.riga { display: flex; }
  /* ⚠️ E LA STESSA TRAPPOLA per ogni componente marcato `li > a`: il selettore
     qui sopra ha specificita' (0,1,1) e batte QUALUNQUE classe (0,1,0), quindi
     si porta via il `display` che il componente si e' dato — anche a 1440 px,
     perche' `pointer: coarse` non parla di larghezza ma di dita. Misurato il
     17.09.2026 su `/contabilita/`: `.liquidazione-chiusa` calcolava
     `inline-flex` a 360 E a 1440 col dito; i suoi `grid-column`/`grid-row`
     restavano inerti, il periodo andava a capo quattro volte e il dettaglio
     finiva in una terza colonna che nessuno aveva dichiarato.
     Si rialza la specificita' a (0,2,3) e si rimette cio' che la regola aveva
     preso: il `display`, il `justify-content` (che in un flex centrava la riga
     dentro il suo riquadro) e il `min-height` PROPRIO del componente, che e'
     un tocco pieno e non il minimo di un legame.
     ⚠️ `grep "li > a"` non trova ne' questa riga ne' quella sopra: il selettore
     vive dentro un `:is()`. Chi aggiunge un componente dentro un `<li>` se ne
     accorge solo MISURANDO `getComputedStyle(el).display` con `has_touch`. */
  ul.liquidazioni-chiuse > li > a.liquidazione-chiusa {
    display: grid;
    justify-content: normal;
    min-height: var(--tocco);
  }
}
/* ── Le regole che riconoscono le voci (08.09.2026) ────────────────────────
 * ⚠️ Il gesto e' UNA FRASE — «quando una riga dice ___ allora e' ___» — e si
 * legge come una frase: i campi stanno in linea col testo, non incolonnati
 * sotto due etichette. Un modulo con due righe e due label sopra direbbe la
 * stessa cosa e si leggerebbe come un modulo, cioe' come qualcosa da compilare
 * invece che da dire. */
.le-regole-del-preventivo .regola-a-parole {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2);
  margin: 0 0 var(--s2); max-width: none;
}
.le-regole-del-preventivo .regola-a-parole label {
  margin: 0; font-weight: 400; color: var(--tenue);
}
.le-regole-del-preventivo .regola-a-parole input[type="text"] { width: 14ch; }
.le-regole-del-preventivo .regola-a-parole select { max-width: 26ch; }
/* ⚠️ A 480 px la frase si spezza comunque: allora ogni pezzo prende la riga
 * intera, se no i campi diventano due fessure da sei caratteri. */
@media (max-width: 480px) {
  .le-regole-del-preventivo .regola-a-parole { display: block; }
  .le-regole-del-preventivo .regola-a-parole > * { display: block; width: 100%; margin-bottom: var(--s2); }
}
.le-regole-del-preventivo .regole-dichiarate .sotto.proposte { color: var(--fioco); }
.le-regole-del-preventivo .togli-regola { display: inline-block; margin: 0 var(--s1) var(--s1) 0; }

/* ── Le misure che stavano DENTRO le pagine ────────────────────────────────
   ⚠️ Diciassette attributi `style=` in sei modelli, spostati qui l'08.09.2026.
   Non e' pulizia: un attributo `style=` non puo' avere una media query e non si
   puo' provare — e' il posto dove una misura smette di potersi adattare. La
   scheda del bene aveva `grid-template-columns:repeat(4,1fr)` scritto cosi', e
   su un telefono da 390 px dava strisce da 90 px con la matricola a capo.
   ⚠️ Uno dei diciassette nascondeva un secondo difetto: `min-height:44px` su
   due campi di `estrazione.html`. Sotto i 48 px del bersaglio minimo — a bordo
   si tocca CON I GUANTI — e dentro un attributo nessun controllo lo vedeva.
   Qui usa `var(--tocco)` come tutti gli altri, cioe' 48. */
/* ⚠️ 56ch, non i 65 dell'attributo da cui viene: `ch` e' la larghezza
   dello ZERO, non del carattere medio, e 65ch resi fanno 85 caratteri per
   riga — dieci oltre il tetto. Lo dice `test_misura_di_lettura`, che il
   foglio lo rende davvero con Chromium e conta. Dentro un attributo
   `style=` quella prova non lo vedeva: e' il terzo difetto che questi
   diciassette spostamenti tirano fuori. */
.foglio-stretto { max-width: 56ch; margin: 2rem auto; padding: 1rem; }
.tabella-piena { width: 100%; text-align: left; }
/* Lo sforamento: il testo, non il fondo. `--ossido-testo` e' il tono misurato
   per il testo (4,96:1 sul chiaro); l'ossido pieno come testo si ferma a 3,88. */
.sfora { color: var(--ossido-testo); }
.commessa-nel-confronto { margin-block: 2rem; }
.bersaglio-tocco { min-height: var(--tocco); }
.campo-tocco { min-height: var(--tocco); max-width: 100%; }
.spunta-grande { width: 1.5rem; height: 1.5rem; }

/* Promemoria della parola: una fascia neutra, distinta dagli errori. */
body.lavoro .promemoria-parola .avviso {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s3);
  max-width: none; margin: 0; padding: 0; border: 0;
  background: none; color: var(--tenue); font-size: var(--t-minuto);
}
.striscia-sistema {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: var(--tocco);
  padding: 0 var(--s3);
  color: var(--tenue);
  background: var(--fondo-alto);
  border: var(--filetto) solid var(--contorno);
  border-radius: var(--raggio-2);
}
.striscia-sistema > .avviso { flex: 1 1 auto; min-width: 0; }
.striscia-sistema .chiudi-striscia {
  flex: none;
  width: var(--tocco);
  height: var(--tocco);
  padding: 0;
  color: var(--tenue);
  background: transparent;
  border: 0;
  border-radius: var(--raggio-2);
  font: inherit;
  font-size: var(--t-terzo);
  cursor: pointer;
}
.striscia-sistema .chiudi-striscia:hover { color: var(--carta); background: var(--fondo); }
/* Col guanto non c'e' passaggio: la pressione e' l'unico segno che il dito e'
   arrivato sulla croce (prove/test_oggi_coi_guanti.py). */
.striscia-sistema .chiudi-striscia:active { color: var(--carta); background: var(--linea); }
.striscia-sistema .chiudi-striscia:focus-visible {
  outline: 2px solid var(--ossido-testo);
  outline-offset: -2px;
}
.promemoria-parola a {
  display: inline-flex; align-items: center; min-height: var(--tocco);
}

/* E14a: la ricerca precede l'elenco; i comandi sono figli dello stesso gruppo.
   Le regole restano locali all'anagrafica, sulla scala e sui ruoli della casa. */
.anagrafica-articoli > * + * { margin-block-start: var(--s7); }
.anagrafica-articoli > nav { margin-block: 0 var(--s3); }
.anagrafica-articoli > header { margin-block-start: 0; }
.anagrafica-articoli .intestazione { margin-bottom: var(--s3); }
.anagrafica-articoli h2 { margin: 0 0 var(--s3); }
.anagrafica-articoli .comandi { justify-content: flex-end; }
.anagrafica-articoli .azione { max-width: 100%; white-space: normal; text-align: center; }
.anagrafica-articoli .vuoto { padding: var(--s6); text-align: left; }
.anagrafica-articoli .vuoto p { max-width: var(--misura-di-lettura); margin: 0 0 var(--s4); }
.anagrafica-articoli .righe-articoli { list-style: none; padding: 0; margin: 0; }
.anagrafica-articoli .righe-articoli > li + li { border-top: var(--filetto) solid var(--linea); }
.anagrafica-articoli .colonna { min-width: 0; gap: var(--s1); }
.anagrafica-articoli .valore { overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
.anagrafica-articoli .riga[aria-current] { outline: var(--filetto) solid var(--ossido-testo); }
.anagrafica-articoli .spiega, .anagrafica-articoli .righe-oneste { overflow-wrap: anywhere; }
.anagrafica-articoli .campo { display: grid; gap: var(--s2); margin-bottom: var(--s4); min-width: 0; }
.anagrafica-articoli .campo :is(input, select, textarea) { width: 100%; min-width: 0; }
.anagrafica-articoli .campo input[type="checkbox"] { width: var(--tocco); height: var(--tocco); }
/* ⚠️ Le caselle di spunta di OGNI modulo, non solo dell'anagrafica: sulla pagina
   degli avvisi erano 13×48 con l'etichetta alta 19 px, e nessuno dei due dava un
   bersaglio da un dito (rilievo del revisore, 11.09.2026).
   ⚠️ UX98 (16.09), rilievo 4 del giudizio di giro 2: dentro un'etichetta flex
   («azione quieta» del travaso: l'unica casella della pagina del preventivo)
   la casella è un elemento flex e SI STRINGE — misurato 19×48, con il quadrato
   più piccolo di quello che la regola dichiara. `flex: none` tiene la misura. */
.modulo .campo input[type="checkbox"] { width: var(--tocco); height: var(--tocco); flex: none; }
/* ⚠️ UX98 giro 3: qui c'era `--ponte` (62 px) e non il ponte RESO — sotto i
   760 px il ponte e' alto 121, quindi il campo col fuoco dopo un errore atterrava
   43 px SOTTO la barra. Stesso conto di tutte le altre àncore. */
.anagrafica-articoli :is(input, select, textarea, [tabindex="-1"]) { scroll-margin-top: calc(var(--ponte-reso, var(--ponte)) + var(--gradino-dell-ancora)); }
.anagrafica-articoli .nomi-fornitore { margin-top: var(--s6); }
.anagrafica-articoli .pagine-articoli { margin-top: var(--s4); }
@media (max-width: 37.5em) {
  .anagrafica-articoli .registro .riga > .colonna { flex: 1 1 100%; }
  .anagrafica-articoli .comandi { width: 100%; flex-direction: column; align-items: flex-end; }
  .anagrafica-articoli .comandi > .azione { width: 100%; }
  .anagrafica-articoli .modulo, .anagrafica-articoli .vuoto { padding: var(--s4); }
}

/* 10.09 · l'anteprima della carta intestata nelle impostazioni: la prima
   pagina di un documento d'esempio, come immagine. Le proporzioni sono quelle
   di un A4, cosi' la pagina non salta quando l'immagine arriva; non piu'
   larga della colonna, perche' su un telefono una carta intera non ci sta. */
.carta-in-anteprima {
  display: block;
  width: 100%;
  max-width: 40rem;
  height: auto;
  aspect-ratio: 210 / 297;
  border: var(--filetto) solid var(--contorno);
}

/* I fattori si correggono accanto alla descrizione della stessa voce. */
.dettaglio-costi-voce { margin-block: var(--s2); text-align: left; }
.dettaglio-costi-voce > summary { min-height: 3rem; }
/* ⚠️ UX98 (17.09), rilievo 4 del giudizio 4 · LA PIEGA DEI COSTI E IL COMANDO
 * CHE LI APRE, LARGHI UGUALI. Misurato dopo il giro 4: summary e collegamento
 * impilati uscivano 347/325 a 1440 (258/246 nella misura del giudizio,
 * scarto 11): la stessa famiglia del rilievo 2, in piccolo. Il comando che
 * apre i costi è il proseguimento della piega: ne prende la larghezza, e il
 * «Salva i costi» fa uguale, così la colonna si legge come una colonna.
 * ⚠️ Anche qui `width: 100%`: il box di un `<button>` non si allarga con la
 * sola blockification (misurato sul rilievo 2). */
.dettaglio-costi-voce > summary.azione,
.dettaglio-costi-voce > a[data-carica-costi],
.dettaglio-costi-voce form.costi-della-voce > button.azione {
  display: flex; width: 100%;
}
.costi-della-voce { display: flex; flex-wrap: wrap; gap: var(--s3); max-width: 42rem; }
.campo-costo-voce { flex: 1 1 8rem; min-width: 0; }
.campo-costo-voce label { display: block; font-size: .85rem; }
.campo-costo-voce input { width: 100%; min-height: 3rem; box-sizing: border-box; }
.costi-della-voce > .aiuto { flex-basis: 100%; }
@media (max-width: 600px) {
  .dettaglio-costi-voce { min-width: calc(100vw - 4rem); }
}
/* ⚠️ ⚠️ UX98 giro 3 (18.09), rilievo 2 del giudizio 7,5 · I DUE COMANDI DELLA
 * CELLA DELLA VOCE: un bordo destro e un corpo.
 * Misurato dal giudice sul servito, `/preventivi/6/`, con la piega «Vedi le 815
 * voci» APERTA: in ognuna delle 815 righe «Manodopera e materiale» e «Da dove
 * viene» stanno uno sotto l'altro larghi **296 e 161 px a 360** (scarto 135) e
 * **479 e 161 a 1440** (scarto 318), con corpo **18 contro 13 px**. La regola
 * `scaletta` del banco ammette 8 px, e il mandato (2.3) chiede per i comandi di
 * riga lo stesso bordo e lo stesso corpo.
 * ⚠️ Perche' nessuno l'aveva visto: le righe stanno dentro `details.tutte-le-voci`
 * CHIUSO, e una misura dello stato di partenza trova zero righe — la sonda del
 * giro 2 diceva «0 scalette» su uno stato vuoto. Ora la sonda apre la piega
 * (`sonda_comandi.py`, fase «aperta»), e la prova la apre col clic.
 * ⚠️ `.dettaglio-costi-voce` NON sta nella famiglia dei nove pieghevoli di sopra
 * (il suo riassunto e' un `.azione` pieno di larghezza, non una frase), quindi la
 * regola della scaletta non la vedeva: la coppia si dice qui, per nome.
 * ⚠️ Il corpo e' quello di `--t-minuto`, lo stesso di `.correzioni` e dei minori
 * del lavoro: sono comandi di CONSULTAZIONE della riga, non la sua azione (che e'
 * scrivere quantita' e prezzo). 18 px su 815 righe gridavano; 13 px, come stava
 * «Da dove viene», e' il corpo delle note, non dei comandi. L'altezza resta
 * `--tocco`: si toglie peso, non bersaglio. */
.dettaglio-costi-voce > summary.azione,
.dettaglio-costi-voce + .da-dove-viene > summary {
  width: 100%; font-size: var(--t-minuto); letter-spacing: .06em;
}
.dettaglio-costi-voce + .da-dove-viene > summary { color: var(--tenue); }

/* ── D78b · Come è nato il prezzo, capitolo per capitolo ───────────────────
 * ⚠️ L'installatore: «ogni capitolo devi dare la spiegazione come ci sei
 * arrivato». Un <details> per capitolo — si apre SENZA JavaScript, il summary
 * e' un bersaglio da guanti (--tocco) e tiene il fuoco visibile — e dentro le
 * sette parti, numerate, nello stesso ordine della relazione approvata.
 * ⚠️ La tabella del materiale a 360 px NON scorre di lato: sotto i 760 px ogni
 * riga diventa una scheda con l'etichetta della colonna davanti al valore
 * (`data-etichetta`). Scorrere una tabella a sei colonne in cantiere, con i
 * guanti, e' il modo di non leggere il materiale. */
.spiegazione-capitoli { margin: var(--s6) 0; }
/* 21.09 · LE TRE LETTURE (dominio/tre_letture.py): i disaccordi fra i tre lettori,
 * con le tre citazioni una sotto l'altra sul telefono e affiancate sullo schermo
 * largo. Solo gradini della scala: nessuna ricetta nuova. */
.tre-letture { margin: var(--s6) 0; }
.tre-letture h2.minore { font-size: var(--t-voce); margin: var(--s6) 0 var(--s3); }
.tre-letture .riepilogo-tre-letture { margin: var(--s2) 0; }
.tre-letture .da-guardare { margin: var(--s3) 0; padding: 0; list-style: none; display: grid; gap: var(--s4); }
.tre-letture .le-tre { margin: var(--s2) 0; padding: 0; list-style: none; display: grid; gap: var(--s2);
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
.tre-letture .le-tre blockquote { margin: var(--s1) 0 0; font-size: var(--t-nota); overflow-wrap: anywhere; }
.tre-letture .gesto-delle-letture { display: inline-block; margin: var(--s1) var(--s2) 0 0; }
/* ⚠️ Il margine sopra lo dichiara la regola della pagina (`.pagina-preventivo
 *   h2.minore`): qui si ridice perché questa regola è PIÙ AVANTI nel foglio
 *   e la sua shorthand `margin: 0 …` glielo toglierebbe — la spiegazione è
 *   un ospite della pagina ripensata da UX98 e ne prende la geometria, il
 *   gradino sopra il titolo incluso (stessa ragione di `.controprova`). */
.spiegazione-capitoli h2.minore { font-size: var(--t-voce); margin: var(--s6) 0 var(--s3); }
.spiegazione-capitoli .riepilogo-materiale {
  max-width: var(--misura-di-lettura); font-variant-numeric: tabular-nums;
}
.spiegazione-capitoli .forfait-spiegati { margin: var(--s3) 0; }
.spiegazione-capitoli .elenco-forfait { margin: var(--s2) 0 0; padding-left: 1.2em; display: grid; gap: var(--s1); }
.capitoli-spiegati { list-style: none; margin: var(--s4) 0 0; padding: 0; display: grid; gap: var(--s3); }
.capitolo-spiegato {
  border: var(--filetto) solid var(--contorno); background: var(--fondo-alto);
  border-radius: var(--raggio-2);
}
.capitolo-spiegato > summary {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s1) var(--s3);
  min-height: var(--tocco); padding: var(--s3) var(--s4);
  cursor: pointer; list-style: none; user-select: none;
}
.capitolo-spiegato > summary::-webkit-details-marker { display: none; }
.capitolo-spiegato > summary::before {
  content: "▸"; flex: 0 0 auto; color: var(--ossido-testo); font-size: var(--t-minuto);
}
.capitolo-spiegato[open] > summary::before { content: "▾"; }
.capitolo-spiegato > summary:hover { background: color-mix(in srgb, var(--ossido) 6%, transparent); }
.capitolo-spiegato > summary:focus-visible { outline: 2px solid var(--ossido-testo); outline-offset: -2px; }
.capitolo-spiegato > summary .capo {
  margin: 0; flex: 1 1 260px; font-size: var(--t-voce); font-weight: 600;
  overflow-wrap: anywhere;
}
.capitolo-spiegato > summary .sotto {
  flex: 1 1 100%; margin-left: calc(var(--s3) + 1ch);
  color: var(--tenue); font-size: var(--t-nota); font-variant-numeric: tabular-nums;
}
.capitolo-spiegato .parti { border-top: var(--filetto) solid var(--linea); padding: 0 var(--s4) var(--s3); }
.capitolo-spiegato .parte { padding: var(--s4) 0; border-top: var(--filetto) solid var(--linea); }
.capitolo-spiegato .parte:first-child { border-top: 0; }
.capitolo-spiegato .parte h4 {
  display: flex; align-items: baseline; gap: var(--s2);
  margin: 0 0 var(--s2); font-size: var(--t-voce);
}
.capitolo-spiegato .numero-parte {
  font-family: "Barlow Condensed", sans-serif; font-weight: 600; letter-spacing: .04em;
  color: var(--ossido-testo); min-width: 2ch; white-space: nowrap;
  /* ⚠️ Non si stringe: a 360 px «3 ter» e «4 bis» venivano schiacciati a
   * `min-width` e il titolo ci si scriveva sopra («4 biQuanto ci costa»).
   * Misurato sulla schermata del gesto, 17.09. */
  flex: 0 0 auto;
}
/* ⚠️ ⚠️ **QUI `max-width: none` TOGLIEVA LA MISURA DI LETTURA A TUTTA LA
 * PROSA DELLA SPIEGAZIONE** (D78b, 16.09), e con lei la difesa che `.aiuto`
 * porta dal 06.09: una riga di regola generale annullata da una di dettaglio,
 * senza che nessuno l'avesse deciso — la riga non ha nemmeno un ⚠️ accanto.
 * Misurato il 19.09.2026 sul reso a 1440: DODICI righe fra 99 e 126ch, cioe'
 * fino a ~163 caratteri, contro la banda 45-75 della skill (`ui-ux-pro-max`
 * §3). «Per ogni voce: quante unità, il prezzo unitario…» ne faceva 126.
 * A riga lunga l'occhio, tornando a capo, sbaglia riga: e' la prima cosa che
 * si smette di leggere in una spiegazione che serve a giustificare un prezzo.
 * ⚠️ Vale per i paragrafi E per le liste di prosa, comprese quelle annidate
 * dentro `.famiglie-spiegate`: il difetto non guarda il nome del tag. Restano
 * fuori le liste che NON sono prosa — `.conteggi-origini` e' una griglia di
 * numeri, e stringerla la spezzerebbe. */
.capitolo-spiegato .parte > p { margin: 0 0 var(--s2); max-width: var(--misura-di-lettura); }
.capitolo-spiegato .voci-principali li,
.capitolo-spiegato .famiglie-spiegate li,
.capitolo-spiegato .motivazioni-integrali li,
.capitolo-spiegato .punti-deboli li,
.capitolo-spiegato .progettazione-voci li { max-width: var(--misura-di-lettura); }
.capitolo-spiegato .parte > p.aiuto { color: var(--fioco); font-size: var(--t-nota); }
.capitolo-spiegato .parte .sotto {
  display: block; color: var(--tenue); font-size: var(--t-nota); line-height: 1.4;
  overflow-wrap: anywhere;
}
.capitolo-spiegato .voci-principali, .capitolo-spiegato .famiglie-spiegate,
.capitolo-spiegato .motivazioni-integrali, .capitolo-spiegato .punti-deboli {
  margin: 0; padding-left: 1.2em; display: grid; gap: var(--s2);
}
.capitolo-spiegato .famiglie-spiegate ul { margin: var(--s1) 0 0; padding-left: 1.2em; }
.capitolo-spiegato .conteggi-origini {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--s2);
}
.capitolo-spiegato .conteggi-origini .numero {
  font-size: var(--t-terzo); font-weight: 600; font-variant-numeric: tabular-nums;
  margin-right: var(--s2);
}
.capitolo-spiegato .motivazioni-integrali .motivo { display: block; white-space: pre-wrap; overflow-wrap: anywhere; }
.capitolo-spiegato .errore-dimostrato { color: var(--tenue); font-size: var(--t-nota); }
/* ── PV3a in pagina · la progettazione: i tre anelli ETICHETTATI ────────────
 * Il titolare: «non dà nessuna spiegazione sulla progettazione nei vari
 * capitoli». Per ogni quantità stimata una scheda con tre righe etichettate —
 * dato di partenza, regola applicata, risultato — e non una frase. La <dl> e'
 * una griglia a due colonne dove c'e' spazio, e si impila sotto i 760 px: in
 * cantiere, coi guanti, un'etichetta sopra il valore si legge; una tabella no.
 * Lo stato si legge dalla parola (stato-progetto), non solo dal colore. */
.spiegazione-capitoli .riepilogo-progettazione {
  max-width: var(--misura-di-lettura); font-variant-numeric: tabular-nums;
}
.capitolo-spiegato .progettazione-voci {
  margin: 0; padding-left: 1.2em; display: grid; gap: var(--s3);
}
.capitolo-spiegato .progettazione-voci > li { overflow-wrap: anywhere; }
.capitolo-spiegato .progettazione-voci .stato-progetto { color: var(--fioco); }
.capitolo-spiegato .progettazione-voci .avviso-progetto {
  display: block; color: var(--ambra-testo); font-size: var(--t-piccolo); margin-top: var(--s1);
}
.capitolo-spiegato .tre-anelli {
  margin: var(--s2) 0 0; display: grid; grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--s1) var(--s3); font-size: var(--t-piccolo);
}
.capitolo-spiegato .tre-anelli dt {
  color: var(--fioco); font-size: var(--t-nota); letter-spacing: .05em; text-transform: uppercase;
  padding-top: var(--s1);
}
.capitolo-spiegato .tre-anelli dd { margin: 0; }
.capitolo-spiegato .tre-anelli .regola { display: block; }
.capitolo-spiegato .tre-anelli .regola .sotto { display: inline; }
.capitolo-spiegato .tre-anelli .conto { font-weight: 600; }
.capitolo-spiegato .tre-anelli .senza-regola { color: var(--ambra-testo); font-style: italic; }
.capitolo-spiegato .tre-anelli [data-ipotesi] > .numero { color: var(--ambra-testo); }

/* ⚠️ LA CASCATA DELLE FONTI accanto al numero (17.09.2026). La fonte scelta si
   legge come le altre righe dei tre anelli; il DISACCORDO no — deve farsi
   guardare, perche' e' l'unica cosa che chi prepara il preventivo non puo'
   scoprire da solo. Sul preventivo vero sono 25 voci su 37. */
.capitolo-spiegato .tre-anelli [data-anello="cascata"] .fonte-scelta { display: block; }
.capitolo-spiegato .fonti-in-disaccordo {
  margin: var(--s1) 0 0; padding: var(--s1) var(--s2); list-style: none;
  border-inline-start: 3px solid var(--ambra-testo);
}
.capitolo-spiegato .fonti-in-disaccordo li { margin: 0; overflow-wrap: anywhere; }
.capitolo-spiegato .fonti-concordi,
.capitolo-spiegato .fonti-altro-perimetro { display: block; }
.capitolo-spiegato [data-anello="cascata"][data-forza="8"] .fonte-scelta { color: var(--ambra-testo); }
.capitolo-spiegato .progettazione-voci [data-progetto="incoerente"] .conto { text-decoration: line-through; }
/* La vendita del capitolo (4 bis) usa la stessa scheda a due colonne: costo,
 * ricarico, vendita, margine — e «non calcolabile» resta una parola, non un
 * numero, dove il ricarico non e' dichiarato. */
.spiegazione-capitoli .riepilogo-vendita {
  max-width: var(--misura-di-lettura); font-variant-numeric: tabular-nums;
}
.capitolo-spiegato .stato-vendita { margin: 0 0 var(--s2); }
.capitolo-spiegato [data-vendita-capitolo][data-completa="no"] { color: var(--ambra-testo); }
.capitolo-spiegato .vendita-del-capitolo .manca { display: block; color: var(--ambra-testo); }
@media (max-width: 759px) {
  .capitolo-spiegato .tre-anelli { grid-template-columns: minmax(0, 1fr); gap: var(--s1); }
  .capitolo-spiegato .tre-anelli dd { margin-bottom: var(--s2); }
}
.voci-del-capitolo { font-size: var(--t-piccolo); }
.voci-del-capitolo th, .voci-del-capitolo td { vertical-align: top; }
.voci-del-capitolo tbody th { font-weight: 600; overflow-wrap: anywhere; }
.voci-del-capitolo .numero { font-variant-numeric: tabular-nums; }
/* ⚠️ Il «non spezzare» vale per la CIFRA, non per la cella: misurato a 1280 con
 * `nowrap` sul td, il motivo del materiale (una frase) allargava la tabella a
 * 1951 px e la pagina scorreva di lato. */
.voci-del-capitolo span.numero { white-space: nowrap; }
.voci-del-capitolo tr.fuori-dal-conto { color: var(--tenue); }
.voci-del-capitolo tr.fuori-dal-conto td .numero { text-decoration: line-through; }
/* Il materiale non noto si distingue anche senza colore: la parola lo dice. */
.voci-del-capitolo [data-materiale="ignoto"] [data-materiale-voce] { color: var(--ambra-testo); font-style: italic; }
.voci-del-capitolo [data-materiale="zero"] [data-materiale-voce] { color: var(--tenue); }
.voci-del-capitolo tfoot .totale th, .voci-del-capitolo tfoot .totale td {
  border-top: 2px solid var(--contorno); border-bottom: 0; font-weight: 600;
}
@media (max-width: 759px) {
  .capitolo-spiegato .parti { padding-inline: var(--s3); }
  .voci-del-capitolo thead { display: none; }
  .voci-del-capitolo tbody tr, .voci-del-capitolo tfoot tr {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s2) var(--s3);
    padding: var(--s3) 0; border-top: var(--filetto) solid var(--linea);
  }
  .voci-del-capitolo th, .voci-del-capitolo td { display: block; padding: 0; border: 0; text-align: left; }
  .voci-del-capitolo tbody tr > :nth-child(-n + 3), .voci-del-capitolo tfoot th { grid-column: 1 / -1; }
  .voci-del-capitolo td::before {
    content: attr(data-etichetta); display: block;
    color: var(--fioco); font-size: var(--t-nota); letter-spacing: .05em; text-transform: uppercase;
  }
  .voci-del-capitolo span.numero { white-space: normal; }
  .voci-del-capitolo tfoot .totale th, .voci-del-capitolo tfoot .totale td { border-top: 0; }
  .voci-del-capitolo tfoot tr { border-top: 2px solid var(--contorno); }
}

/* ── La liquidazione: il periodo chiuso, letto riga per riga ───────────────
 * Audit UX del 15.09.2026, tre revisori: /contabilita/liquidazioni/<id>/ fra le
 * peggiori per due su tre. Rimisurato sul reso il 16.09 prima di scrivere
 * (verifiche/ux-liquidazioni/prima):
 *   · a 360 px la pagina era larga 569: la tabella a sette colonne, 553 px,
 *     non aveva un riquadro che scorre e allargava tutto, ponte compreso —
 *     ESCI fuori dallo schermo, 32 elementi oltre il bordo;
 *   · il saldo stava in una frase a 16 px, senza moneta, sotto un titolo a 31
 *     fatto di due date AAAA-MM-GG;
 *   · 0 colonne numeriche su 3 a destra e tabulari, intestazioni centrate;
 *   · l'unico ritorno nel contenuto era un collegamento di 97×16 px.
 * ⚠️ Le regole stanno su classi DI QUESTA PAGINA (`.saldo-della-liquidazione`,
 * `.dettaglio-della-liquidazione`, `table.dettaglio-liquidazione`): un incarico
 * e' una pagina, e cio' che qui si e' misurato non si replica altrove per
 * supposizione. Il riquadro che scorre e' `.tabella-che-scorre`, gia' in casa. */

/* Il saldo: la cifra per cui si apre la pagina, sul gradino alto della scala e
 * con la moneta, prima della frase che dice come esce. */
.saldo-della-liquidazione {
  display: grid; gap: var(--s1);
  margin: 0 0 var(--s6);
  max-width: var(--misura-di-lettura);
}
.saldo-della-liquidazione .cifra {
  font-size: var(--t-cifra); font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.saldo-della-liquidazione .come { color: var(--tenue); font-size: var(--t-piccolo); }

/* Il titolo della tabella sta col SUO blocco: 32 sopra, 12 sotto. */
h2.documenti-contati { margin: var(--s7) 0 var(--s3); }

/* ⚠️ Il riquadro si raggiunge col tasto Tab (`tabindex="0"`), quindi il fuoco
 * deve vedersi su tutti e quattro i lati, e sta DENTRO. Fuori non puo' stare:
 * a 1440 il banco e' una riga di griglia ad altezza fissa e la pagina finisce
 * dove finisce il riquadro — misurato, Tab dal filo del ritorno porta il fondo
 * del riquadro a 899,5 px su 900, e un contorno 2 px fuori non ha dove stare
 * (`scroll-margin` non aiuta: lo scorrimento e' gia' al massimo). Dentro,
 * pero', le celle FERME — la colonna del numero, la sua testata e le cifre dei
 * totali, che nei banchi stretti hanno un fondo pieno e sono posizionate — si
 * dipingono sopra il contorno del riquadro e lo coprivano a sinistra, in alto e
 * a destra (misurato sui pixel il 16.09). Quando il riquadro ha il fuoco, quelle
 * celle si RITAGLIANO di 2 px sul lato del contorno (`clip-path`, piu' sotto):
 * il contorno, dipinto sopra il contenuto in flusso, torna a vedersi; senza
 * fuoco le celle coprono tutto come prima. */
.dettaglio-della-liquidazione { margin: 0 0 var(--s6); }
.dettaglio-della-liquidazione:focus-visible { outline: 2px solid var(--carta); outline-offset: -2px; }

/* Sette colonne che si confrontano riga per riga: la stessa veste delle voci di
 * un vocabolario. Le cifre a destra e tabulari; date, numeri e importi che non
 * vanno a capo; la controparte che invece puo' andarci, entro una misura. */
table.dettaglio-liquidazione {
  width: 100%; border-collapse: collapse;
  /* La dissolvenza della colonna ferma (sotto): una testa opaca di 16 px e
   * una rampa lunga SETTE GLIFI tabulari. La coda «0,00 €» di un importo — la
   * cosa piu' corta che passa sotto con la faccia di un numero — e' lunga sei;
   * una rampa lunga quanto la coda finisce SUL suo ultimo glifo, che esce
   * pieno (giro 5, misurato sui pixel col carattere di riserva: «€» al 100%
   * a 76-80 px dal bordo con 6ch). Con sette la rampa finisce dopo la coda. In
   * `ch`, cosi' segue il carattere davvero caricato: ~79 px col carattere del
   * programma, ~89 con quello di riserva. */
  --dissolvenza: calc(var(--s4) + 7ch);
}
table.dettaglio-liquidazione th, table.dettaglio-liquidazione td {
  text-align: left; vertical-align: top;
  padding: var(--s2) var(--s3) var(--s2) 0;
  border-bottom: var(--filetto) solid var(--linea);
  font-size: var(--t-piccolo);
}
/* ⚠️ La prima colonna comincia 8 px dopo il bordo del riquadro: il contorno del
 * fuoco sta DENTRO (`outline-offset: -2px`, sotto) e con `padding-left: 0`
 * toccava «Numero», il numero di ogni documento e le parole dei totali
 * (rilievo del 16.09). Le parole dei totali, che restano ferme scorrendo, si
 * fermano allo stesso punto (`left: var(--s2)` su `.fermo`, sotto). */
table.dettaglio-liquidazione tr > :first-child { padding-left: var(--s2); }
table.dettaglio-liquidazione thead th {
  font-family: "IBM Plex Sans", sans-serif;
  font-size: var(--t-minuto); font-weight: 600; color: var(--tenue);
  border-bottom-color: var(--contorno);
  white-space: nowrap;
}
table.dettaglio-liquidazione .numero { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
table.dettaglio-liquidazione .quando, table.dettaglio-liquidazione .codice {
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
/* ⚠️ Non `.registro`: quella classe e' l'ELENCO che si legge come l'indice di
 * una tavola, con fondo e righe sue, e vestiva la cella. */
table.dettaglio-liquidazione td.da-quale-registro { white-space: nowrap; }
table.dettaglio-liquidazione td.chi { min-width: 12rem; }
/* ⚠️ Nel banco stretto la controparte NON va a capo: a 360 px, in una colonna
 * che sta fuori dallo schermo, un nome di 53 caratteri andava su tre righe e
 * la riga del documento era alta 89 px — sotto il numero, che e' l'unica cosa
 * ferma, restava un vuoto senza motivo (rilievo del revisore del 16.09). Con
 * `nowrap` ogni riga e' una riga (41 px): la tabella scorre comunque, e una
 * colonna piu' larga costa meno di un vuoto che sembra una riga mancante. Il
 * tetto (28rem, ~60 caratteri) prende solo i nomi fuori misura — il campo ne
 * tiene 200 — e l'ellissi dice che c'e' dell'altro; il testo intero resta
 * nella cella (e nel suo `title`) per chi legge con lo screen reader. */
@container banco (max-width: 799px) {
  table.dettaglio-liquidazione td.chi {
    white-space: nowrap; max-width: 28rem; overflow: hidden; text-overflow: ellipsis;
  }
}
/* ⚠️ Dove la tabella ha spazio (dagli 800 px del banco) il nome va a capo — ma
 * non oltre DUE righe. Le altre sei colonne non si stringono (date, numeri e
 * importi non vanno a capo), quindi fra 1150 e 1440 la controparte resta una
 * colonna da 190-370 px, e un nome di 200 caratteri faceva una riga alta
 * 137-233 px (rilievo del revisore del 16.09, giro 3). Due righe portano ~90
 * caratteri, cioe' ogni nome che un cantiere scrive davvero; oltre, l'ellissi
 * dice che c'e' dell'altro, e il nome intero sta nel `title` della cella e nel
 * testo per chi legge con lo screen reader. Il tetto sta sullo `<span>` dentro
 * la cella: una cella non puo' diventare `-webkit-box` senza smettere di essere
 * una cella. Il conto delle colonne non cambia: il tetto taglia in altezza, non
 * in larghezza. */
@container banco (min-width: 800px) {
  table.dettaglio-liquidazione td.chi .nome {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  }
}
/* ⚠️ Il numero del documento resta FERMO scorrendo di lato (la «prima colonna
 * identificativa persistente» del revisore), e con lui la sua testata «Numero»:
 * senza, scorrendo di 40 px la testata mostrava «ero» a sinistra della colonna
 * ferma. Con un fondo pieno, se no le celle che passano sotto si leggono
 * attraverso. `sticky` dentro un riquadro con `overflow-x: auto` vale anche con
 * `contain: paint`: misurato. */
table.dettaglio-liquidazione tbody th[scope="row"],
table.dettaglio-liquidazione thead th:first-child {
  position: sticky; left: 0; z-index: 1;
  padding-right: var(--s4);
  font-weight: 600;
}
/* ⚠️ ⚠️ LA VESTE DELLA COLONNA FERMA SEGUE LO SCORRIMENTO, NON LA LARGHEZZA —
 * un predicato solo, per il foglio e per il copione. Fino al giro 3 fondo,
 * filetto, dissolvenza e totali fermi stavano in `@container banco (max-width:
 * 799px)`, mentre il copione (argo.js) decideva la fermata del Tab
 * sull'overflow VERO del riquadro: «la tabella vuole 745 px a contenuto minimo»
 * era vero coi dati del banco e falso con quelli di un cantiere — con un numero
 * di 20 caratteri e importi a sette cifre vuole 905, e fra 800 e 905 px di banco
 * (una finestra da 1080-1200, un iPad da 11" di traverso) scorreva con la
 * colonna ferma TRASPARENTE: «FATT-2026-000123-BIS» sopra «Documenti emessi»
 * (rilievo del revisore del 16.09, giro 3). Il contenuto minimo di una tabella
 * dipende dai dati, non dal foglio: il foglio non puo' sapere se scorre.
 * Lo sa il riquadro: il copione mette `data-scorre` quando `scrollWidth`
 * supera `clientWidth` e lo toglie quando la tabella sta tutta — la stessa
 * condizione della fermata del Tab, nello stesso punto. Il modello lo porta gia'
 * scritto: senza copione la colonna e' vestita dovunque, e a riposo la veste non
 * si vede (il fondo e' quello della pagina, la dissolvenza ha opacita' zero) —
 * resta un filetto a destra della prima colonna dove non serve, che e' il lato
 * giusto su cui sbagliare: una colonna nuda su una tabella che scorre e' un
 * difetto, un filetto di troppo no. */
.dettaglio-della-liquidazione[data-scorre] tbody th[scope="row"],
.dettaglio-della-liquidazione[data-scorre] thead th:first-child {
  background: var(--fondo);
  /* ⚠️ Un'ombra interna e non `border-right`: con `border-collapse: collapse`
   * i bordi li dipinge la TABELLA, e non seguono la cella appiccicata —
   * misurato, il filetto non compariva. L'ombra e' della cella e la segue. */
  box-shadow: var(--filetto-della-colonna-ferma) var(--contorno);
}
/* ⚠️ E il filetto da solo NON basta, misurato dal revisore del 16.09: scorsa
 * in fondo, «12.500,00 €» che passa sotto la colonna ferma si legge «00,00 €»,
 * «3.420,00 €» si legge «20,00 €» — cifre tagliate con la faccia di cifre vere.
 * Il taglio si scioglie: una dissolvenza dal fondo della colonna ferma verso
 * cio' che le passa sotto, con un'ombra leggera al bordo, cosi' le prime cifre
 * svaniscono invece di cominciare nette. ⚠️ Una TESTA OPACA di 16 px e una
 * rampa lunga sette glifi tabulari (`--dissolvenza`, sopra): a 24 px (giro 2)
 * sfumava un glifo e «12.500,00 €» si leggeva «0,00 €» col primo zero grigio;
 * a 32 lineari (giro 3) lo stesso, misurato a scala 3 dal revisore; a 48 con
 * la testa (primo tentativo del giro 4) il secondo zero era ancora al 77% e
 * «€» pieno; a 16 + 6ch (giro 4) il glifo fra 48 e 64 px stava al 74% —
 * misurato sui pixel, colonna per colonna di 4 px. La testa nasconde DEL
 * TUTTO il glifo tagliato dal bordo: senza, il «€» tagliato resta un fantasma
 * al 15%, che si riconosce. La rampa, con sette glifi, fa che cio' che passa
 * fra 24 e 48 px stia sotto la meta' e fra 48 e 64 sotto il 70% — niente che
 * abbia la faccia di una cifra vera (`test_scorsa_in_fondo_nessuna_cifra_
 * piena_accanto_alla_colonna_ferma`). Non di piu': la dissolvenza copre la
 * colonna accanto a ogni fermata dello scorrimento — in fondo a 360, col
 * carattere di riserva, sotto la rampa passa «22,00%» dell'aliquota, che e'
 * un valore vero, e a 360 restano ~120 px puliti oltre la colonna ferma.
 * Si accende nei primi 24 px di SCORRIMENTO (`animation-range`, sotto): quello
 * e' un altro numero, e resta. Compare SOLO scorrendo (`scroll()` come linea
 * del tempo dell'animazione): a riposo niente passa sotto, e una dissolvenza
 * dipinta sulla colonna accanto coprirebbe le prime lettere di «Documenti
 * emessi». Dove il browser non sa legare un'animazione allo scorrimento resta
 * il filetto di prima, che non copre niente. */
@supports (animation-timeline: scroll()) {
  .dettaglio-della-liquidazione[data-scorre] tbody th[scope="row"]::after,
  .dettaglio-della-liquidazione[data-scorre] thead th:first-child::after {
    content: ""; position: absolute; top: var(--filetto); bottom: var(--filetto); left: 100%;
    width: var(--dissolvenza); pointer-events: none;
    background:
      linear-gradient(to right, rgb(16 32 43 / 0.12), transparent var(--s2)),
      linear-gradient(to right, var(--fondo) var(--s4), transparent);
    opacity: 0;
    animation: liquidazione-colonna-scorsa linear both;
    animation-timeline: scroll(inline nearest);
    animation-range: 0 var(--s6);
  }
}
@keyframes liquidazione-colonna-scorsa { from { opacity: 0; } to { opacity: 1; } }
/* ⚠️ UX98 (18.09.2026): era l'UNICO movimento del foglio senza guardia. Con
   `prefers-reduced-motion: reduce` la dissolvenza non si accende: resta cio' che
   gia' vedono i browser che non legano un'animazione allo scorrimento — il
   filetto, che non copre niente. Lo stato finale e' uno dei due gia' previsti,
   non una dissolvenza ferma a meta'. */
@media (prefers-reduced-motion: reduce) {
  .dettaglio-della-liquidazione[data-scorre] tbody th[scope="row"]::after,
  .dettaglio-della-liquidazione[data-scorre] thead th:first-child::after { animation: none; content: none; }
}
/* ⚠️ E le TRE CIFRE dei totali restano al bordo destro del riquadro, con un fondo
 * pieno: a 360 px, a riposo, le righe dei totali mostravano la parola e poi il
 * vuoto — la cifra stava 400 px piu' a destra, e per leggere «Da versare» si
 * doveva scorrere. La riga di un totale e' una parola a sinistra e una cifra a
 * destra: tutte e due si vedono sempre. Nella stessa condizione della colonna
 * ferma, cioe' dove la tabella scorre: dove sta tutta non serve. */
.dettaglio-della-liquidazione[data-scorre] tfoot td { position: sticky; right: 0; background: var(--fondo); }
/* Col fuoco sul riquadro, le celle ferme lasciano vedere il contorno (2 px)
 * sul lato che coprirebbero: la colonna del numero a sinistra, la sua testata
 * anche in alto, le cifre dei totali a destra, l'ultima anche in basso. Il
 * ritaglio si allarga quanto la dissolvenza a destra della colonna ferma per
 * non tagliarla: e' un suo figlio dipinto fuori dalla sua scatola. */
.dettaglio-della-liquidazione[data-scorre]:focus-visible tbody th[scope="row"] { clip-path: inset(0 calc(-1 * var(--dissolvenza)) 0 2px); }
.dettaglio-della-liquidazione[data-scorre]:focus-visible thead th:first-child { clip-path: inset(2px calc(-1 * var(--dissolvenza)) 0 2px); }
.dettaglio-della-liquidazione[data-scorre]:focus-visible tfoot td { clip-path: inset(0 2px 0 0); }
.dettaglio-della-liquidazione[data-scorre]:focus-visible tfoot tr.saldo td { clip-path: inset(0 2px 2px 0); }
/* I totali in fondo: le tre cifre della testata congelata, e l'ultima e' il
 * saldo, che si vede anche in cima. La parola del totale sta in uno `<span>`
 * appiccicato a sinistra del riquadro: a 360 px le tre righe si vedevano VUOTE
 * finche' non si scorreva all'ultima colonna, e li' la parola era gia' uscita.
 * Uno span e non la cella: una cella `sticky` larga sei colonne si muove di
 * quanto le resta a destra, cioe' quasi niente. */
table.dettaglio-liquidazione tfoot th { font-weight: 400; color: var(--tenue); }
table.dettaglio-liquidazione tfoot .fermo { position: sticky; left: var(--s2); display: inline-block; }
table.dettaglio-liquidazione tfoot tr.saldo th,
table.dettaglio-liquidazione tfoot tr.saldo td { font-weight: 700; color: var(--carta); border-bottom: 0; }

/* ── Preventivato e consuntivo: il confronto si legge in una passata ────────
 * Audit UX del 15.09.2026, tre revisori: /economico/ fra le peggiori per due su
 * tre. Rimisurato sul reso il 17.09 prima di scrivere (verifiche/ux-economico/
 * prima): a 360 px otto-dodici tabelle scorrevano in riquadri da 312 px con
 * 40-53 parole tagliate dal bordo, i codici commessa a capo dentro il loro
 * bottone («C-» / «2026-» / «01», 85 px), la riga piu' alta 242-290 px per il
 * testo di una colonna che non si vedeva; le cifre senza migliaia e a
 * sinistra; ogni riga che sfora tutta rossa, preventivato compreso.
 * ⚠️ Le regole stanno su classi DI QUESTA PAGINA (`table.confronto-economico`,
 * `.confronti-ricorrenti`, `.commessa-nel-confronto`, `.vuoto-economico`): un
 * incarico e' una pagina, e cio' che qui si e' misurato non si replica altrove
 * per supposizione. La forma delle schede sotto i 1000 px e' quella delle voci
 * di un vocabolario (sopra), per la stessa ragione: 1000 e' la soglia della
 * fiancata, e fra 760 e 999 la colonna del lavoro e' larga ~450 px. */

/* Lo stato vuoto: senza un preventivato la pagina E' il gesto. Il modulo del
 * preventivato sta subito sotto il titolo, con la frase che dice perche'; negli
 * altri due casi (nessuna commessa, nessuna valuta) un riquadro che spiega e un
 * solo comando. Testo a sinistra e misura di lettura, come `.vuoto-oggi`: e' una
 * spiegazione, non un cartello. */
.vuoto-economico { margin: var(--s6) 0 var(--s7); }
.vuoto.vuoto-economico { text-align: left; padding: var(--s6) var(--s7); }
.vuoto.vuoto-economico > h2 { margin: 0 0 var(--s3); }
.vuoto.vuoto-economico > .spiega { max-width: var(--misura-di-lettura); margin: 0 0 var(--s6); color: var(--carta); }
@media (max-width: 480px) { .vuoto.vuoto-economico { padding-inline: var(--s4); } }

/* Le voci che sforano di nuovo: un elenco senza pallini, una riga per voce, il
 * nome sul gradino delle voci e la frase dei conti sotto, entro la misura di
 * lettura. La piega sta col suo blocco. */
.confronti-ricorrenti { list-style: none; padding: 0; margin: 0; }
.confronti-ricorrenti > li { margin: 0; padding: var(--s4) 0; border-top: var(--filetto) solid var(--linea); }
.confronti-ricorrenti > li:last-child { border-bottom: var(--filetto) solid var(--linea); }
.confronti-ricorrenti p { margin: 0 0 var(--s1); max-width: var(--misura-di-lettura); }
.confronti-ricorrenti .voce-del-confronto { font-size: var(--t-voce); }
.confronti-ricorrenti .voce-del-confronto .sfora { margin-left: var(--s2); font-size: var(--t-piccolo); }
.confronti-ricorrenti .come-ci-e-arrivato { margin: var(--s3) 0 0; }
/* Il riassunto di una piega e' UNA frase: `.azione` e' un flex, e un testo in due
 * pezzi (la frase e il nome della voce) diventava due colonne affiancate con
 * la frase a capo in mezzo. Il modello lo porta in un solo `<span>`; qui lo
 * span puo' andare a capo come un testo. */
.confronti-ricorrenti .come-ci-e-arrivato > summary > span,
.voci-senza-sforamenti > summary > span { white-space: normal; min-width: 0; }
/* Le voci che non sforano: dietro una piega, dopo quelle che sforano. */
.voci-senza-sforamenti { margin: var(--s4) 0 0; }
.voci-senza-sforamenti[open] > summary { margin-bottom: var(--s4); }
/* I quattro moduli secondari: una riga che li apre, il riquadro sotto. */
.altri-dati-del-confronto { margin-top: var(--s7); }
.altri-dati-del-confronto > .spiega { color: var(--tenue); margin: 0 0 var(--s4); }
.altri-dati-del-confronto .apri-modulo { margin: 0 0 var(--s3); }
.altri-dati-del-confronto .apri-modulo > summary > span { white-space: normal; min-width: 0; }
.altri-dati-del-confronto .apri-modulo[open] > summary { margin-bottom: var(--s3); }
.altri-dati-del-confronto .apri-modulo > .modulo { margin: 0 0 var(--s6); }

/* Ogni commessa: un blocco col suo filetto, il collegamento alla commessa alto
 * un tocco di legame (44 px: era 28, rilievo P3 dell'audit), lo stato sotto. */
.commessa-nel-confronto { margin: 0; padding: var(--s4) 0 var(--s6); border-top: var(--filetto) solid var(--linea); }
.commessa-nel-confronto:first-of-type { border-top: 0; padding-top: 0; }
.commessa-nel-confronto h3 { margin: 0; }
.commessa-nel-confronto h3 a { display: inline-flex; align-items: center; min-height: var(--tocco-legame); }
.commessa-nel-confronto .stato-della-commessa { margin: 0 0 var(--s3); color: var(--tenue); font-size: var(--t-piccolo); }
.commessa-nel-confronto h4 { margin: var(--s6) 0 var(--s2); }
.commessa-nel-confronto .riferimenti-delle-categorie { margin: var(--s3) 0 0; padding-left: var(--s4); font-size: var(--t-nota); }

/* La tabella del confronto: la stessa veste delle voci di un vocabolario. Le
 * cifre a destra, tabulari, con le migliaia (`dominio.presentazione_economico`),
 * e non vanno a capo; il rosso dello sforamento sta SULLO SCOSTAMENTO e sulla
 * parola «Sfora», non su tutta la riga — «4.200,00» di preventivato in rosso
 * diceva che il numero era sbagliato. Cio' che manca e' in tono minore, e ha
 * un nome solo: «Da registrare». */
table.confronto-economico { width: 100%; border-collapse: collapse; }
table.confronto-economico th, table.confronto-economico td {
  text-align: left; vertical-align: top;
  padding: var(--s2) var(--s3) var(--s2) 0;
  border-bottom: var(--filetto) solid var(--linea);
  font-size: var(--t-piccolo);
}
table.confronto-economico thead th {
  font-family: "IBM Plex Sans", sans-serif;
  font-size: var(--t-minuto); font-weight: 600; color: var(--tenue);
  border-bottom-color: var(--contorno);
  white-space: nowrap;
}
table.confronto-economico tbody th { font-weight: 600; }
table.confronto-economico .numero { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
table.confronto-economico .manca { color: var(--tenue); font-weight: 400; }
/* Le due tabelle di una commessa hanno quattro colonne: su 1080 px di banco i
 * numeri finivano a 800 px dal nome della voce. Un tetto di 46rem li tiene a
 * portata d'occhio; quella tra commesse ha il motivo dell'esclusione e resta
 * larga tutta. */
table.confronto-economico:not(.tra-commesse) { max-width: 46rem; }
/* Tra commesse la prima cella e' un collegamento alto un tocco di legame: le
 * cifre si allineano al suo centro, non alla riga sopra. */
table.confronto-economico.tra-commesse th, table.confronto-economico.tra-commesse td { vertical-align: middle; }
table.confronto-economico tr.sfora { color: inherit; }
table.confronto-economico tr.sfora td.scostamento { color: var(--ossido-testo); }
/* ⚠️ Il codice della commessa e' un collegamento al suo blocco piu' in basso, non
 * un pulsante: come pulsante (`.azione.quieta`) a 360 px andava a capo ai
 * trattini dentro il suo bordo, perche' sotto i 560 px `.azione` torna a
 * `white-space: normal` (regola del 06.09) — e un codice spezzato non e' piu' un
 * codice. Alto un tocco di legame, su UNA riga, con le cifre tabulari. */
table.confronto-economico .codice-commessa {
  display: inline-flex; align-items: center; min-height: var(--tocco-legame);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
table.confronto-economico td.nel-confronto { min-width: 14rem; }
table.confronto-economico td::before { display: none; content: attr(data-colonna); }
/* ⚠️ Sotto i 1000 px ogni riga e' una SCHEDA: il nome della voce (o il codice
 * della commessa) su tutta la larghezza, poi i tre numeri UNO ACCANTO ALL'ALTRO
 * — il confronto e' fra loro, e impilarli lo scioglierebbe — ognuno con
 * l'etichetta della sua colonna davanti (`data-colonna`): niente scorre, niente
 * e' tagliato, e ogni riga e' alta quanto il suo testo, tutto visibile. Il
 * motivo dell'esclusione, che e' una frase, prende una riga intera sotto. Il
 * riquadro che scorre non ha piu' niente da far scorrere.
 * ⚠️ `minmax(0, 1fr)`: senza lo zero una cella con «Non confrontabile» allarga
 * la sua colonna oltre un terzo e stringe le altre due. */
@media (max-width: 999px) {
  .tabella-che-scorre:has(> table.confronto-economico) { overflow: visible; contain: none; height: auto; }
  table.confronto-economico, table.confronto-economico tbody { display: block; }
  table.confronto-economico thead { display: none; }
  table.confronto-economico tr {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--s1) var(--s3);
    align-items: start;
    padding: var(--s3) 0;
    border-top: var(--filetto) solid var(--linea);
  }
  table.confronto-economico tr:last-child { border-bottom: var(--filetto) solid var(--linea); }
  table.confronto-economico th, table.confronto-economico td { display: block; padding: 0; border: 0; min-width: 0; }
  table.confronto-economico th[scope="row"] { grid-column: 1 / -1; font-size: var(--t-corpo); overflow-wrap: anywhere; }
  table.confronto-economico td.numero { text-align: left; white-space: normal; }
  table.confronto-economico td.scostamento strong { white-space: nowrap; }
  table.confronto-economico td::before {
    display: block; margin-bottom: var(--s1);
    font-size: var(--t-nota); font-weight: 400; color: var(--fioco);
    font-variant-numeric: normal;
  }
  table.confronto-economico td.nel-confronto { grid-column: 1 / -1; min-width: 0; font-size: var(--t-piccolo); }
}
/* Il riassunto di una piega a 360: «COMMESSE CONSIDERATE ED ESCLUSE: MATERIALI ·
 * CORPI ILLUMINANTI» in maiuscolo condensato a 18 px con spaziatura .1em stava
 * su tre righe (83 px, rilievo P3 del revisore del 17.09). Sotto i 560 px — la
 * soglia in cui `.azione` torna a capo — il riassunto scende al corpo piccolo
 * con la spaziatura delle intestazioni: due righe al piu', senza cambiare la
 * veste dei pieghevoli del programma. */
@media (max-width: 560px) {
  .confronti-ricorrenti .come-ci-e-arrivato > summary,
  .voci-senza-sforamenti > summary,
  .altri-dati-del-confronto .apri-modulo > summary { font-size: var(--t-piccolo); letter-spacing: .04em; }
}
/* La commessa senza nessun dato porta al modulo del preventivato dalla sua riga:
 * un collegamento alto un tocco di legame, sulla sua riga, non un pulsante. */
.commessa-nel-confronto .registra-da-qui { display: inline-flex; align-items: center; min-height: var(--tocco-legame); }
/* ⚠️ Il salto alle ancore atterrava SOTTO il ponte fisso. `#budget` (dal rimando
 * «Registra il preventivato» della commessa senza dati) e il blocco di una
 * commessa (dai codici della tabella tra commesse) finivano a top 0, coperti
 * dal ponte — 121 px a 360, 62 a 1440: si vedeva un modulo senza titolo con la
 * spiegazione mozzata a «registrato non si riscrive.», o tre numeri senza sapere
 * di quale commessa (giudizio del 17.09, rilievo 1). `scroll-margin-top` stava
 * sul banco e sulle voci del preventivo, non qui. L'ingombro RESO del ponte piu'
 * un gradino; per il titolo del modulo anche la cornice del riquadro
 * (imbottitura e filetto): il bersaglio e' l'h2 DENTRO `.modulo`, e il riquadro
 * deve entrare in vista con lui, non restare tagliato sotto la barra.
 * ⚠️ GIRO 5 (rilievo 4 del giudizio 9,4) · Qui c'era `--s4 + --s6 + --filetto`
 * = 41, e il filetto se lo mangiava la CORNICE del riquadro (`--s6` + un
 * filetto = 25): il riquadro atterrava a 16,4 px a 360 e a **15,6 a 1440**,
 * mezzo pixel sotto il gradino di tutte le altre ancore (16,3-17,4) — l'unico
 * fuori passo, e per la stessa ragione gia' pagata al giro 3: il pixel che lo
 * scorrimento si mangia lo paga il FOGLIO, non la prova. Adesso il conto e'
 * esplicito — il gradino delle altre PIU' la cornice — e non c'e' un `--s4`
 * che finge di essere un gradino. */
.commessa-nel-confronto { scroll-margin-top: calc(var(--ponte-reso, var(--ponte)) + var(--gradino-dell-ancora)); }
.modulo > #budget { scroll-margin-top: calc(var(--ponte-reso, var(--ponte)) + var(--gradino-dell-ancora) + var(--s6) + var(--filetto)); }

/* ── Il gemello-inventario: la frase della provenienza accanto al numero ─────
 * ⚠️ La frase NON è una nota a margine e non si rimpicciolisce: è la cosa che
 * distingue «13,6 m letti» da «13,6 m ipotizzati», e una quantità del gemello
 * senza la sua frase non va mostrata affatto. Corpo del testo, larghezza di
 * lettura, e l'accento solo dove il numero non esiste. */
.gemello-fonte { color: var(--tenue); }
.gemello-quantita {
  background: var(--fondo-alto); border: var(--filetto) solid var(--linea);
  border-radius: var(--s2); padding: var(--s4) var(--s6); margin-bottom: var(--s6);
}
.gemello-frase {
  font-size: var(--t-corpo); line-height: 1.5; max-width: var(--misura-di-lettura);
  margin: 0 0 var(--s3);
}
.gemello-frase.minore { font-size: var(--t-piccolo); color: var(--tenue); }
/* Il conto che non torna sui suoi addendi: è un guasto, e si vede come tale. */
.gemello-allarme { color: var(--avviso-testo); font-size: var(--t-piccolo); margin: 0 0 var(--s3); }
.gemello-scarto { color: var(--ossido-testo); font-size: var(--t-voce); margin: var(--s4) 0 0; }

/* ── Il gesto sul locale proposto: «c'è» e «non c'è» ────────────────────────
 * ⚠️ **Due comandi OPPOSTI non si toccano.** Senza questa regola il modulo e'
 * un blocco e i due bersagli restano a **6 px** l'uno dall'altro: misurato in
 * un browser, 169x48 a x313 e 137x48 a x488. Su questa pagina il bersaglio da
 * 48 px esiste perche' a bordo si tocca CON I GUANTI (`--tocco`), e due
 * bersagli da guanto separati da 6 px sono un bersaglio solo. Lo sbaglio qui
 * non e' innocuo: scrive una decisione sul locale col nome di chi l'ha fatta.
 * ⚠️ E il modulo in blocco faceva **scorrere la frase INTORNO al bottone**: il
 * «conferma tutti» e' largo 740 px e la spiegazione ripartiva sotto, a
 * sinistra, fuori dal comando che spiega. Con le due cose come righe di un
 * flex la frase resta un blocco suo e va a capo dentro di se'. */
.riga-gesto { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); }
.riga-gesto > .sotto { flex: 1 1 18rem; margin: 0; }
/* ⚠️ Gli addendi si aprono con un tocco, e il tocco vale 48 px anche coi guanti:
 * `summary` è un bersaglio come un bottone, e qui sotto ci sta la catena intera. */
.gemello-quantita > details > summary {
  display: flex; align-items: center; min-height: var(--tocco);
  cursor: pointer; color: var(--tenue); font-size: var(--t-piccolo);
}
.gemello-quantita > details > summary:focus-visible { outline: 2px solid var(--contorno); outline-offset: 2px; }

/* ── La contabilità: registri e liquidazioni (audit UX del 15.09.2026) ─────
 * Tre revisori indipendenti, e questa pagina fra le peggiori per tutti e tre.
 * Misurato sul servito il 16.09.2026, prima di scrivere una riga:
 *   · a 360 px la pagina era larga 590 px (600 per i revisori): la tabella a
 *     sette colonne, 558 px, non aveva un riquadro che scorre e allargava
 *     tutto, ponte compreso — ESCI e IMPOSTAZIONI fuori dallo schermo;
 *   · «Chiudi e liquida il periodo», irreversibile, stava a 12 px dal comando
 *     pieno, senza domanda, con lo stesso rosso di «Guarda il periodo»;
 *   · la liquidazione chiusa era un collegamento di 201×20 px con le date ISO;
 *   · 0 celle numeriche su 8 tabulari e a destra, intestazioni centrate;
 *   · i titoli dei registri a 32 px da cio' che precede e 24 da cio' che
 *     introducono: non si legavano al loro registro.
 * ⚠️ Le regole stanno su classi DI QUESTA PAGINA (`.registro-testa`,
 * `table.elenco`, `.liquidazione-chiusa`, `.chiusura-del-periodo`): un
 * incarico e' una pagina, e cio' che qui si e' misurato non si replica altrove
 * per supposizione. `table.elenco` la usa anche la pagina della liquidazione,
 * che ha la stessa tabella ed e' misurata insieme a questa.               */

/* Il saldo del periodo: la cifra per cui si apre la pagina, sul gradino alto
 * della scala e con la moneta. Prima stava dentro una frase a 16 px, senza. */
.saldo-del-periodo {
  display: grid; gap: var(--s2);
  margin: 0 0 var(--s6);
  max-width: var(--misura-di-lettura);
}
.saldo-del-periodo .cifra {
  font-size: var(--t-cifra); font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.saldo-del-periodo .aiuto { color: var(--tenue); font-size: var(--t-piccolo); }

/* Il periodo che tocca una liquidazione chiusa: si dice PRIMA del gesto, non
 * con l'errore dopo. Il tono e' l'ambra («da guardare»), non l'ossido: non e'
 * un guasto, e' un fatto. Il collegamento e' alto un tocco. */
.periodo-chiuso {
  max-width: var(--misura-di-lettura);
  margin: 0 0 var(--s6); padding: var(--s3) var(--s4);
  border-left: var(--segno) solid var(--ambra);
  background: var(--fondo-alto);
}
.periodo-chiuso > a {
  display: inline-flex; align-items: center;
  min-height: var(--tocco-legame); margin-top: var(--s1);
  font-weight: 600;
}

/* La testa di un registro: il titolo sta col SUO registro — 48 sopra, 12
 * sotto — e lo scarico e' un comando terziario, in linea col titolo. */
.intestazione.registro-testa {
  margin-top: var(--s8); margin-bottom: var(--s3);
  gap: var(--s2) var(--s4);
}
.intestazione.registro-testa h2 { margin: 0; }
.intestazione.registro-testa .manca {
  margin: var(--s1) 0 0;
  color: var(--tenue); font-size: var(--t-piccolo);
  font-variant-numeric: tabular-nums;
}
.intestazione.registro-testa > .azione.terziaria { margin-left: auto; }

/* Il registro: sette colonne che si confrontano riga per riga. Le cifre a
 * destra e tabulari, le date e i numeri di documento che non vanno a capo, lo
 * stato del documento elettronico che invece puo' andarci. */
.registro-che-scorre { margin: 0 0 var(--s4); }
/* ⚠️ Il riquadro si raggiunge col tasto Tab (`tabindex="0"`), quindi il fuoco
 * deve vedersi. `contain: paint` del riquadro taglia cio' che dipinge fuori di
 * se': il contorno sta DENTRO, e la prima colonna tiene un'imbottitura che
 * lo lascia respirare. */
.registro-che-scorre:focus-visible { outline: 2px solid var(--carta); outline-offset: -2px; }
table.elenco { width: 100%; border-collapse: collapse; }
table.elenco th, table.elenco td {
  text-align: left; vertical-align: top;
  padding: var(--s2) var(--s3) var(--s2) 0;
  border-bottom: var(--filetto) solid var(--linea);
  font-size: var(--t-piccolo);
}
table.elenco thead th {
  font-family: "IBM Plex Sans", sans-serif;
  font-size: var(--t-minuto); font-weight: 600; color: var(--tenue);
  border-bottom-color: var(--contorno);
  white-space: nowrap;
}
table.elenco .numero { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
table.elenco .quando, table.elenco .codice { white-space: nowrap; font-variant-numeric: tabular-nums; }
/* ⚠️ Lo stato del documento elettronico e' una frase: sta su un blocco che va a
 * capo entro 16rem, cosi' la tabella a 360 px non si allarga per lui. */
table.elenco td.stato > span { display: block; max-width: 16rem; }
table.elenco td.stato .manca { color: var(--fioco); }

/* La chiusura del periodo: una sezione SUA, in fondo ai registri, col filetto
 * dell'ossido — e' l'unico gesto della pagina che non si disfa. Il pulsante
 * puo' andare a capo fra due parole, mai a meta' parola: a 360 px, dentro il
 * filetto, i 304 px del comando non ci stanno su una riga sola. */
.banco > .chiusura-del-periodo {
  margin-top: var(--s8);
  padding: var(--s1) 0 var(--s1) var(--s4);
  border-left: var(--segno) solid var(--ossido-testo);
  max-width: 720px;
}
.chiusura-del-periodo h2 { margin: 0 0 var(--s3); }
.chiusura-del-periodo .spiega { margin: 0 0 var(--s4); }
.chiusura-del-periodo .attenzione {
  max-width: var(--misura-di-lettura); margin: 0 0 var(--s4);
  color: var(--ambra-testo); font-weight: 600;
}
.chiusura-del-periodo form { margin: 0; }
.chiusura-del-periodo .azione {
  white-space: normal; text-align: center;
  padding-block: var(--s2); line-height: 1.2;
}
@media (max-width: 599px) {
  .chiusura-del-periodo .azione { width: 100%; }
}
@container banco (max-width: 699px) {
  .chiusura-del-periodo .azione { width: 100%; }
}

/* Le liquidazioni chiuse: la RIGA e' il collegamento, alta almeno un tocco, con
 * il periodo a sinistra e il saldo a destra. Prima era un elenco numerato del
 * browser con un testo-collegamento di 20 px. */
.liquidazioni-chiuse {
  list-style: none; margin: 0 0 var(--s6); padding: 0;
  max-width: 720px;
  border-top: var(--filetto) solid var(--linea);
}
.liquidazione-chiusa {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: center; column-gap: var(--s4);
  min-height: var(--tocco); padding: var(--s3) var(--s2);
  border-bottom: var(--filetto) solid var(--linea);
  color: var(--carta); text-decoration: none;
}
/* ⚠️ Posizioni ESPLICITE: con il solo `grid-row` sul saldo, l'algoritmo
 * automatico lo piazzava per primo nella colonna 1 e spingeva il periodo e il
 * dettaglio in una terza colonna che nessuno aveva dichiarato (misurato). */
.liquidazione-chiusa .quando { grid-column: 1; grid-row: 1; font-weight: 600; }
.liquidazione-chiusa .dettaglio { grid-column: 1; grid-row: 2; }
.liquidazione-chiusa .saldo {
  grid-column: 2; grid-row: 1 / span 2;
  font-size: var(--t-voce); font-weight: 600;
  font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap;
}
.liquidazione-chiusa .dettaglio { color: var(--tenue); font-size: var(--t-piccolo); }
/* Sul telefono il periodo prende la riga tutta, e il saldo scende accanto al
 * dettaglio. ⚠️ Non e' un gusto: e' una misura. «Dal 01.01.2026 al 31.01.2026»
 * vuole 265 px per stare su una riga sola (284 px in inglese), il saldo ne
 * chiede 99 e il divario 16: 380 px su 312 disponibili dentro un banco da 360.
 * Tenendoli sulla stessa riga il periodo va a capo in mezzo a una data — «Dal
 * 01.01.2026 / al 31.01.2026» — cioe' proprio il numero che si cerca si spezza.
 * Dalla larghezza in cui ci stanno (il banco oltre i 699 px) restano affiancati
 * come sono disegnati. */
@container banco (max-width: 699px) {
  .liquidazione-chiusa .quando { grid-column: 1 / -1; grid-row: 1; }
  .liquidazione-chiusa .dettaglio { grid-column: 1; grid-row: 2; }
  .liquidazione-chiusa .saldo { grid-column: 2; grid-row: 2; }
}
/* ⚠️ L'hover contrasta PIU' del riposo, non meno: il fondo si alza e il periodo
 * si sottolinea; l'inchiostro resta la carta (regola dell'09.09). */
.liquidazione-chiusa:hover { background: var(--fondo-alto); color: var(--carta); }
.liquidazione-chiusa:hover .quando { text-decoration: underline; text-underline-offset: .18em; }
.liquidazione-chiusa:focus-visible { outline: 2px solid var(--carta); outline-offset: -2px; }

/* Il vuoto dei ricevuti porta il gesto che lo riempie: la frase e il comando
 * quieto, uno sotto l'altro. */
.vuoto > .registra-da-qui { margin-top: var(--s4); }

/* ── La scheda della commessa dopo l'audit UX del 15.09 (17.09) ────────────
 * ⚠️ `#disegni` e' dove atterrano il tratto 2 della striscia e il filtro «da
 * guardare»: il filtro ricaricava la pagina dall'inizio e il risultato stava a
 * 2.678 px a 360, tre schermi sotto il dito. Stesso margine del salto di
 * `/economico/`: l'ingombro RESO del ponte piu' un gradino. La sezione porta
 * gia' il margine del banco: la sua intestazione non ne aggiunge un secondo. */
#disegni { scroll-margin-top: calc(var(--ponte-reso, var(--ponte)) + var(--gradino-dell-ancora)); }
.disegni > .intestazione.staccata:first-child { margin-top: 0; }
/* Il banco e' una griglia: i margini non si sommano collassando, e la striscia
   piu' la sezione facevano 64 px di vuoto. Uno dei due basta. */
.ciclo-guscio + .disegni { margin-top: 0; }
/* ⚠️ I due comandi dell'ospite («Rifa' il codice» / «Ritira», uno di pericolo)
 * stavano impilati con 0 px fra i bordi e larghi 104/63: coi guanti un tocco
 * sul confine prende l'altro — e uno chiede conferma, l'altro no. Un gradino
 * fra i due e la stessa larghezza (rilievo di Opus e di Sol, R27). */
.registro.ospiti .riga > .azioni { display: flex; flex-direction: column; gap: var(--s2); align-items: stretch; }
.registro.ospiti .riga > .azioni > form { display: flex; }
.registro.ospiti .riga > .azioni .azione { flex: 1 1 auto; width: 100%; }
/* ⚠️ Il lettore audio nativo seguiva `<meta name="color-scheme" content="dark">`
 * e usciva scuro (rgb ≈77) sulla carta chiara della riga (S4 dell'audit): sulla
 * superficie chiara i controlli nativi sono chiari. */
body.lavoro audio { color-scheme: light; }
/* ⚠️ «Commesse» nell'occhiello era un legame di 65×16 px (Astra R003, Opus P3):
 * il bersaglio cresce a 44 con imbottitura e margine negativo, cosi' la riga
 * non si sposta e il titolo resta dov'era. */
.intestazione .etichetta > a { display: inline-block; padding-block: 14px; margin-block: -14px; }
@media (max-width: 599px) {
  /* ⚠️ Le schede della commessa (`nav.fasi`) uscivano a destra («SOLDI» → «SOL»,
   * bordo a 376 su 360) in uno scorrimento che non si vedeva: sul telefono
   * vanno a capo, DUE PER RIGA e larghe uguali, tutte dentro lo schermo.
   * ⚠️ Il solo `flex-wrap` faceva 3 + 1 («SOLDI» sola nella seconda riga,
   * giudice del giro 1): ogni scheda prende meta' riga (il gap e' 2 px), il
   * testo sta al centro della sua meta' come in una griglia di linguette. */
  .fasi { flex-wrap: wrap; overflow-x: visible; }
  .fasi a { flex: 0 0 calc(50% - var(--s1) / 2); justify-content: center; padding: 0 var(--s2); }
  /* ⚠️ I comandi in testa («Tranche», «Nuovo disegno») partivano da x 38 mentre
   * titolo e blocchi partono da 16: il `.conto` con `margin-left: auto` teneva
   * la larghezza del suo contenuto. Sul telefono prende la riga intera. */
  .intestazione > .conto:has(> .azione) { margin-left: 0; flex: 1 1 100%; }
}
