/* bolla: token e componenti. I valori vengono dal design system bolla (tokens.json), i nomi italiani dell'applicazione
   sono legati ognuno al suo token. Il perché di ogni scelta è in DESIGN.md. */

/* Nunito, il carattere del design system: variabile (un file per tutti i pesi), servito dall'applicazione e non da
   Google Fonts, così la pagina resta senza CDN. Solo i sottoinsiemi che scrivono l'italiano. */
@font-face {
  font-family: "Nunito"; font-style: normal; font-display: swap; font-weight: 200 1000;
  src: url(/statici/nunito-latin-ext.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;
}
@font-face {
  font-family: "Nunito"; font-style: normal; font-display: swap; font-weight: 200 1000;
  src: url(/statici/nunito-latin.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;
}

:root {
  /* design system bolla, tema chiaro */
  --surface: #FFFFFF;
  /* la carta del cliente (l'anteprima del PDF, il logo dell'impresa): bianca anche col tema scuro, che non la ridefinisce */
  --carta: #FFFFFF;
  /* la seconda casella della scacchiera della trasparenza (il logo dell'impresa), chiara anche col tema scuro */
  --scacchi: #E4ECEA;
  /* i moduli del QR del secondo fattore, scuri sulla carta anche col tema scuro: un QR chiaro su scuro molte app non lo leggono */
  --qr: #0F2E2C;
  --surface-sunken: #F3F8F7;
  --surface-mint: #E9F5F3;
  --ink: #0F2E2C;
  --ink-muted: #526B68;
  --border: #DCE9E7;
  --border-strong: #6F8C88;
  --primary: #0F2E2C;
  --primary-hover: #1C4845;
  --on-primary: #FFFFFF;
  --accent: #FF7A00;
  --on-accent: #0F2E2C;
  --accent-soft: #FFF0E0;
  --accent-ink: #B04F00;
  --focus: #C45A00;
  --success: #0B6E86;
  --success-soft: #E3F4F8;
  --danger: #B42318;
  --danger-soft: #FDECEA;
  --warning: #9A4F00;
  --warning-soft: #FFF3E3;
  --info: #2451B8;
  --info-soft: #EAF0FD;
  --shadow-card: 0 1px 2px rgba(15, 46, 44, 0.06);
  --shadow-pop: 0 12px 32px rgba(15, 46, 44, 0.14);
  /* le barre agganciate al fondo sul telefono: la stessa ombra dei menu, rivolta verso l'alto */
  --shadow-su: 0 -8px 24px rgba(15, 46, 44, 0.12);
  --velo: rgba(15, 46, 44, 0.35);
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-pill: 999px;
  --font-sans: "Nunito", ui-rounded, "SF Pro Rounded", system-ui, sans-serif;

  /* i nomi dell'applicazione */
  --fondo: var(--surface-sunken);
  --superficie: var(--surface);
  --superficie-2: var(--surface-mint);
  --bordo: var(--border);
  --bordo-forte: var(--border-strong);
  --inchiostro: var(--ink);
  --inchiostro-2: var(--ink-muted);
  --accento: var(--primary);
  --accento-scuro: var(--primary-hover);
  --accento-tenue: var(--surface-mint);
  --manca: var(--ink);
  --errore: var(--danger);
  --errore-tenue: var(--danger-soft);
  --ok: var(--success);
  --ok-tenue: var(--success-soft);
  --ok-scuro: var(--success);
  --r-piccolo: var(--radius-sm);
  --r-campo: var(--radius-md);
  --r-pulsante: var(--radius-pill);
  /* le righe del foglio stanno a 12px e non ai 16 delle card: il filo che le divide segue il raggio, e più tondo si curva */
  --r-riga: var(--radius-md);
  --r-foglio: var(--radius-lg);
  --r-pannello: var(--radius-xl);
  --z-barra: 10;
  --z-azioni: 12;
  --durata: 150ms;
  --curva: cubic-bezier(0.22, 1, 0.36, 1);
  --mono: ui-monospace, SFMono-Regular, Menlo, monospace;
  color-scheme: light;
}
/* Il tema scuro del design system: segue il sistema. Cambiano solo i valori, i nomi restano quelli. */
@media (prefers-color-scheme: dark) {
  :root {
    --surface: #102826;
    --surface-sunken: #0A1C1B;
    --surface-mint: #16302D;
    --ink: #EAF4F2;
    --ink-muted: #9DB8B4;
    --border: #24423F;
    --border-strong: #5A8580;
    --primary: #8FE0D2;
    --primary-hover: #B0EDE3;
    --on-primary: #0A1C1B;
    --accent: #FF8F26;
    --on-accent: #0F2E2C;
    --accent-soft: #3A2512;
    --accent-ink: #FFA552;
    --focus: #FF9A40;
    --success: #5CC8E0;
    --success-soft: #10323A;
    --danger: #FF8A7A;
    --danger-soft: #3A1714;
    --warning: #FFB866;
    --warning-soft: #382510;
    --info: #8FB2FF;
    --info-soft: #172544;
    --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-pop: 0 12px 32px rgba(0, 0, 0, 0.5);
    --shadow-su: 0 -8px 24px rgba(0, 0, 0, 0.5);
    --velo: rgba(0, 0, 0, 0.55);
    color-scheme: dark;
  }
}

/* base */
*, *::before, *::after { box-sizing: border-box; }
/* la barra in alto è sticky: senza questo, andare a un elemento col focus lo nasconde sotto la barra */
html { scroll-padding-top: 80px; }
body {
  margin: 0;
  background: var(--fondo);
  color: var(--inchiostro);
  font: 15px/1.5 var(--font-sans);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3 { text-wrap: balance; }
a { color: var(--accento); }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* Sul telefono bolla si usa come un'app, e niente del browser deve vedersi: né il rettangolo blu del tocco
   (Android), né la pagina che si ricarica tirandola giù dall'alto, né lo zoom del doppio tocco su un pulsante. Il
   tocco lo dicono i componenti stessi (`:active`, sotto), e il :hover c'è solo dove c'è un mouse: col dito
   resterebbe attaccato all'ultima cosa toccata. */
html { -webkit-tap-highlight-color: transparent; overscroll-behavior-y: contain; }
a, button, label, summary, input, select, textarea { touch-action: manipulation; }
/* tenendo il dito su una scheda o sulla freccia, niente anteprima del link né parola selezionata */
.schede, .barra-indietro { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
/* iPhone ingrandisce la pagina entrando in un campo scritto sotto i 16px, e non la rimette com'era: col dito i
   campi sono a 16px, al PC restano a 15 come il testo */
@media (pointer: coarse) {
  input:not([type="checkbox"], [type="radio"], [type="range"]), select, textarea { font-size: max(16px, 1em) !important; }
}
/* il tocco, dove non c'è il mouse: lo stesso colore del passaggio del mouse, finché il dito è giù */
@media (hover: none) {
  .btn:active, .btn-contorno:active, .btn-icona:active, .barra-indietro:active, .vista:active, .pillola:active,
  .menu button:active, .menu a.menu-voce:active, .riga-cruscotto:active, .candidato:active { background: var(--superficie-2); }
  .btn-principale:active { background: var(--primary-hover); }
  .preventivo:active, button.opzione:active { border-color: var(--primary); }
  .riga-rata:active, .riga-utente:active, .riga-attestato:active { background: none; }
}
/* I controlli nativi (radio, checkbox, il triangolo di <details>) e la selezione del testo prendono i colori del
   design system, non il blu del browser. */
:root { accent-color: var(--primary); }
::selection { background: var(--primary); color: var(--on-primary); }
/* L'autocompletamento di Chrome tinge i campi d'azzurro: il fondo resta `--surface`, il testo `--ink`. L'ombra interna
   è l'unico modo di coprirlo; col fuoco si aggiunge l'alone dei campi. */
input:-webkit-autofill { -webkit-text-fill-color: var(--ink); caret-color: var(--ink); box-shadow: inset 0 0 0 100px var(--surface); }
input:-webkit-autofill:focus { box-shadow: inset 0 0 0 100px var(--surface), 0 0 0 3px var(--surface-mint); }
.num { font-variant-numeric: tabular-nums; }
.tenue { color: var(--inchiostro-2); font-size: 14px; }
.codice { font: 12.5px var(--mono); color: var(--inchiostro-2); }
.visivamente-nascosto { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.icona { width: 16px; height: 16px; flex: none; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.caricamento { display: none; }
.htmx-request .caricamento, .htmx-request.caricamento { display: inline; }
[hidden] { display: none !important; }

/* barra in alto */
.barra { position: sticky; top: 0; z-index: var(--z-barra); background: var(--superficie); border-bottom: 1px solid var(--bordo); }
/* larga quanto il contenuto delle pagine (`.pagina`: 880px con 24px di margine): logo e «Esci» stanno a filo del
   foglio, non a 120px oltre i suoi bordi */
.barra-in { max-width: 880px; min-height: 64px; margin: 0 auto; padding: 8px 24px; display: flex; align-items: center; gap: 16px; font-size: 14px; }
/* il ritorno è un pulsante della barra come «Clienti»: la pillola semplice del design system (ghost), alta 44px,
   etichetta a 15px/700 in `--ink`, fondo `--surface-mint` al passaggio. Non più un link grigio piccolo, che accanto ai
   pulsanti sembrava un'altra cosa. */
.barra-indietro { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 16px 0 10px; border-radius: var(--r-pulsante); color: var(--inchiostro); font-size: 15px; font-weight: 700; text-decoration: none; transition: background var(--durata) var(--curva); }
@media (hover: hover) { .barra-indietro:hover { background: var(--superficie-2); } }
.barra-indietro .icona { width: 18px; height: 18px; }
.marchi { display: inline-flex; align-items: center; flex: none; }
/* la «o» di bolla è 76×70; in barra è il solo marchio, alta quanto il testo dei pulsanti le lascia respirare */
.marchio-bolla { width: 26px; height: 24px; flex: none; }
.marchio-barra { display: block; width: 30px; height: 28px; }
/* mentre arriva un'altra pagina la bolla della «o» in barra cerca il centro, da una parte all'altra della fiala (12 per
   parte), finché la pagina nuova non la rimette ferma */
.marchio-barra-bolla { transform-box: fill-box; transform-origin: center; }
.pagina-in-cambio .marchio-barra-bolla { animation: bolla-cerca 1200ms ease-in-out infinite; }
@keyframes bolla-cerca {
  0%, 100% { transform: none; }
  25% { transform: translateX(-12px); }
  75% { transform: translateX(12px); }
}
/* e in cima allo schermo, sopra la pagina (a destra della barra laterale), avanza una linea, veloce all'inizio e
   sempre più lenta: non sa quanto manca, e non arriva mai in fondo da sola. La pagina nuova la toglie */
body::before { content: ""; position: fixed; top: env(safe-area-inset-top, 0px); left: var(--laterale); right: 0; z-index: calc(var(--z-azioni) + 1); height: 3px; background: var(--primary); transform-origin: left; transform: scaleX(0); opacity: 0; pointer-events: none; }
.pagina-in-cambio body::before { opacity: 1; animation: barra-avanza 8s cubic-bezier(0.08, 0.7, 0.2, 1) forwards; }
@keyframes barra-avanza {
  from { transform: scaleX(0.08); }
  to { transform: scaleX(0.94); }
}
/* col movimento ridotto la livella resta storta, ferma, finché la pagina non arriva, e la linea è intera, ferma */
@media (prefers-reduced-motion: reduce) {
  .pagina-in-cambio .marchio-barra-bolla { animation: none; transform: translateX(-12px); }
  .pagina-in-cambio body::before { animation: none; transform: none; }
}
/* il logo intero, largo due volte e mezzo la sua altezza: solo sulla pagina di accesso */
.marchio { display: block; width: 100px; height: 40px; flex: none; }
.marchi + .barra-indietro { margin-left: 0; }

/* avvio: aprendo bolla dalla schermata Home, la «o» grande e la bolla che cerca il centro come in una livella. Il fondo
   è quello della pagina, lo stesso colore dello splash che Android disegna dal manifest, così i due si passano la mano */
.avvio { position: fixed; inset: 0; z-index: calc(var(--z-azioni) + 2); display: grid; place-items: center; background: var(--fondo); }
.avvio-marchio { width: 96px; height: 88px; animation: avvio-fiala 240ms var(--curva) both; }
.avvio-fiala { fill: none; stroke: var(--ink); stroke-width: 16; }
.avvio-bolla { fill: var(--accent); transform-box: fill-box; transform-origin: center; animation: avvio-bolla 900ms cubic-bezier(0.37, 0, 0.63, 1) 120ms both; }
.avvio-via { opacity: 0; transition: opacity 200ms var(--curva); pointer-events: none; }
@keyframes avvio-fiala { from { opacity: 0; transform: scale(0.92); } }
/* la fiala dentro è larga 40, la bolla 16: può correre di 12 per parte. Parte da sinistra, passa il centro, torna
   indietro sempre meno e si ferma: un'oscillazione smorzata, l'ultimo tratto quasi fermo */
@keyframes avvio-bolla {
  0% { transform: translateX(-12px); }
  40% { transform: translateX(7px); }
  65% { transform: translateX(-3px); }
  85% { transform: translateX(1px); }
  100% { transform: none; }
}
@media (prefers-reduced-motion: reduce) { .avvio { display: none; } }
/* L'invito a installare bolla (installa.eta), solo sul telefono aperto dal browser: una pagina di benvenuto sopra la
   pagina, sul suo fondo, che scorre da sola. Il logo intero, il titolo `display` del design system (40/48, 800), il
   perché in `body-l`, la Card coi passi (il numero in una pillola menta, come la voce accesa) e le azioni a tutta
   larghezza sotto il pollice. */
.installa { position: fixed; inset: 0; z-index: calc(var(--z-azioni) + 3); overflow-y: auto; overscroll-behavior: contain; background: var(--fondo); }
html.con-installa body { overflow: hidden; }
.installa-in { display: grid; gap: 24px; max-width: 480px; margin: 0 auto; padding: calc(48px + env(safe-area-inset-top, 0px)) 16px calc(24px + env(safe-area-inset-bottom, 0px)); }
.installa-titolo { margin: 8px 0 0; font-size: 40px; line-height: 48px; font-weight: 800; letter-spacing: -0.02em; text-wrap: balance; }
.installa-titolo:focus { outline: none; }
.installa-perche { margin: -16px 0 0; color: var(--inchiostro-2); font-size: 17px; line-height: 26px; }
.installa-passi { display: grid; gap: 16px; margin: 0; padding: 0; list-style: none; }
.installa-passi li { display: flex; align-items: flex-start; gap: 12px; }
.installa-numero { display: inline-grid; place-items: center; flex: none; width: 28px; height: 28px; border-radius: var(--radius-pill); background: var(--surface-mint); color: var(--ink); font-size: 13px; font-weight: 800; }
.installa-icona { width: 18px; height: 18px; vertical-align: -3px; }
.installa-poi { margin: 16px 0 0; }
.installa-azioni { display: grid; gap: 12px; }
.installa-azioni .btn { width: 100%; justify-content: center; }
/* il marchio in barra porta alla prima pagina: l'anello di focus segue il suo contorno */
a.marchi { border-radius: var(--radius-sm); }
.barra-destra { margin-left: auto; display: flex; align-items: center; gap: 16px; }
/* la «o» nella barra di un preventivo c'è solo sul telefono: al PC sta in cima alla barra laterale */
.barra-destra > .marchi { display: none; }
/* La campanella delle notifiche (campanella.eta, il NotificationBell del design system): in alto a destra, al posto
   della «o», un'icona da 44px che porta all'elenco. Il numero delle non lette in una pillola `--primary`, staccata
   dall'icona da un anello del colore che le sta dietro (`--campanella-fondo`): mai arancione, che è del marchio e
   dell'AI, e mai rossa, che è un errore. Accesa sulla pagina delle notifiche, col fondo menta. */
.campanella { --campanella-fondo: var(--superficie); position: relative; display: inline-grid; place-items: center; flex: none; width: 44px; height: 44px; border-radius: var(--radius-pill); color: var(--inchiostro); text-decoration: none; transition: background var(--durata) var(--curva); }
@media (hover: hover) { .campanella:hover { background: var(--surface-mint); } }
.campanella[aria-current] { background: var(--surface-mint); }
.campanella .icona { width: 22px; height: 22px; }
.campanella-numero { position: absolute; top: 4px; left: 24px; min-width: 20px; height: 20px; padding: 0 5px; border-radius: var(--radius-pill); background: var(--primary); color: var(--on-primary); box-shadow: 0 0 0 2px var(--campanella-fondo); font-size: 12px; font-weight: 800; line-height: 20px; text-align: center; font-variant-numeric: tabular-nums; }
/* sulle pagine principali la campanella non ha una barra dietro: sta sul fondo della pagina */
.barra-principale .campanella, .barra-sezione .campanella { --campanella-fondo: var(--fondo); }
/* L'utente: il cerchio con le iniziali dell'AppHeader del design system, in fondo alla barra laterale. */
.utente-icona { display: inline-grid; place-items: center; width: 36px; height: 36px; flex: none; padding: 0; border: 0; border-radius: 50%; background: var(--surface-mint); color: var(--ink); font-size: 13px; font-weight: 800; line-height: 1; text-decoration: none; }
.stato-salvataggio { display: inline-flex; align-items: center; gap: 6px; color: var(--inchiostro-2); }
.stato-salvataggio::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--ok); }
.stato-salvataggio[data-stato="in-corso"]::before { background: var(--bordo-forte); }
.stato-salvataggio[data-stato="errore"] { color: var(--errore); font-weight: 600; }
.stato-salvataggio[data-stato="errore"]::before { background: var(--errore); }
.totale-barra { font-weight: 800; font-variant-numeric: tabular-nums; }
.da-definire { color: var(--manca); font-weight: 600; }
/* il prezzo del capitolato: sotto «Scegli un prezzo» una nota; con un prezzo lontano più del 20%, nella fonte, in
   `--warning` come la parte che chiede di guardare */
.scarto-capitolato { color: var(--inchiostro-2); font-size: 13px; font-weight: 600; }
.pillola-scarto { color: var(--warning); font-weight: 700; }

/* pagine */
.pagina { max-width: 880px; margin: 0 auto; padding: 24px 24px 96px; }
.pagina-larga, .barra-larga .barra-in { max-width: 1120px; }
.pagina-testa { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; margin: 8px 0 20px; }
/* il profilo: due moduli da una colonna, che a tutta larghezza avrebbero campi lunghi mezzo metro */
.pagina-stretta { max-width: 600px; }
.profilo .riquadro + .riquadro { margin-top: 24px; }
.profilo form { margin: 0; }
/* l'esito buono di un modulo: come l'errore, ma verde e con la spunta; mai il colore da solo */
.fatto { display: flex; align-items: flex-start; gap: 8px; margin: 0; padding: 8px 12px; border-radius: var(--r-campo); background: var(--ok-tenue); color: var(--ok); font-size: 14px; font-weight: 600; }
.fatto::before { content: ""; width: 16px; height: 16px; flex: none; margin-top: 1px; background: currentColor; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat; }
.pagina-testa h1 { margin: 0; font-size: 28px; font-weight: 800; line-height: 36px; letter-spacing: -0.015em; }
.pagina-testa p { margin: 4px 0 0; color: var(--inchiostro-2); max-width: 70ch; }

/* pulsanti */
.btn { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 20px; border: 1.5px solid transparent; border-radius: var(--r-pulsante); background: transparent; color: var(--inchiostro); font-size: 15px; font-weight: 700; white-space: nowrap; text-decoration: none; transition: background var(--durata) var(--curva), border-color var(--durata) var(--curva); }
/* spento, il Button del design system tiene la sua forma al 45%: si vede che c'è, e che adesso non si può */
.btn:disabled { opacity: 0.45; cursor: not-allowed; filter: none; }
@media (hover: hover) { .btn:hover { background: var(--superficie-2); } }
.btn-principale { background: var(--primary); color: var(--on-primary); }
@media (hover: hover) { .btn-principale:hover { background: var(--primary-hover); } }
/* il pulsante secondario del design system, per un'azione che sta da sola su una superficie bianca e altrimenti
   sparirebbe (lo stato vuoto del cliente, «Vedi PDF» finché il preventivo è incompleto): --bordo-forte perché un
   bordo deve arrivare a 3:1 (WCAG 1.4.11) */
.btn-contorno { border: 1.5px solid var(--bordo-forte); background: var(--superficie); color: var(--inchiostro); }
@media (hover: hover) { .btn-contorno:hover { background: var(--superficie-2); } }
.btn-piccolo { min-height: 36px; padding: 0 16px; font-size: 14px; }

.btn-icona { display: inline-grid; place-items: center; width: 36px; height: 36px; padding: 0; border: 0; border-radius: var(--r-pulsante); background: transparent; color: var(--inchiostro-2); }
@media (hover: hover) { .btn-icona:hover { background: var(--superficie-2); color: var(--inchiostro); } }
.link-azione { display: inline-flex; align-items: center; gap: 4px; padding: 6px 4px; border: 0; border-radius: var(--r-piccolo); background: none; color: var(--accento); font-size: 14px; font-weight: 700; }
@media (hover: hover) { .link-azione:hover { text-decoration: underline; text-underline-offset: 3px; } }

/* Isola delle azioni: centrata in basso, galleggia sopra il documento mentre scorre.
   Superficie piena e non vetro. Il vetro è stato provato: su un foglio bianco con testo nero non c'è niente da
   rifrangere, quindi non si vede — l'unica cosa che cambia è che sfuma il testo sottostante, che legge come un
   difetto di resa, e costa lavoro alla GPU a ogni scroll. La forma a pillola e l'ombra bastano a dire "questo
   sta sopra il foglio". */
.azioni-documento {
  position: fixed; bottom: 24px; left: calc(50% + var(--laterale) / 2); transform: translateX(-50%);
  z-index: var(--z-azioni);
  display: flex; align-items: center; gap: 6px;
  /* larga quanto il suo contenuto: con `left: 50%` il browser le darebbe al massimo metà schermo, e il totale andava
     a capo su tre righe accanto a pulsanti a pillola alti 44px */
  width: max-content; max-width: calc(100vw - 32px);
  padding: 6px;
  border: 1px solid var(--bordo);
  border-radius: 999px;
  background: var(--superficie);
  box-shadow: var(--shadow-pop);
}
/* Il totale dentro l'isola: non è un pulsante, è il numero che il documento sta producendo. Paddato a sinistra
   perché respiri dal bordo della pillola, e separato dalle azioni dal loro stesso gap. */
.azioni-documento .totale-barra { padding-left: 8px; font-size: 14px; }
/* i pulsanti seguono la forma dell'isola: un raggio da 8px dentro una pillola lascia quattro angoli storti */
.azioni-documento .btn, .azioni-documento .btn-icona { border-radius: 999px; }
/* il ⋯ è alto e largo quanto gli altri pulsanti dell'isola: un cerchio più piccolo in mezzo a pillole da 44px
   sembrava un pulsante di un'altra famiglia */
.azioni-documento .btn-icona { width: 44px; height: 44px; }
/* dentro l'isola il pulsante non porta un bordo suo: la cornice ce l'ha già l'isola, e due contorni concentrici
   a 6px di distanza leggono come un errore. Lo stato resta detto dal peso (pieno/piatto) e dalla parola. */
.azioni-documento .btn { border: 0; }

/* «Chiedi a Bolla», primo nell'isola: la «o» e le parole, come ogni pulsante dell'isola. Apre la finestra di
   Bolla. È il pulsante dell'AI del design system, l'unico arancione: `--accent` con il testo `--on-accent`, mai
   bianco. La bolla della «o» si fa scura come il tratto, se no sul fondo arancione sparirebbe. */
.btn-chiedi, .btn-ai { gap: 8px; padding: 0 16px 0 12px; background: var(--accent); color: var(--on-accent); --marchio-tratto: var(--on-accent); --marchio-bolla: var(--on-accent); }
.btn-chiedi[aria-expanded="true"] { background: var(--accent); filter: brightness(1.06); }
@media (hover: hover) { .btn-chiedi:hover, .btn-ai:hover { background: var(--accent); filter: brightness(1.06); } }
.btn-chiedi .marchio-bolla, .btn-ai .marchio-bolla { width: 18px; height: 17px; }
/* `.btn-ai` è lo stesso pulsante fuori dall'isola: «Prepara il preventivo», «Ricava dallo storico». Il Button `ai` del
   design system, per le sole azioni che fanno lavorare Bolla, uno per schermata */

/* La finestra di Bolla: sopra l'isola e centrata come lei, sul telefono larga quanto lo schermo. Testa e campo
   restano fermi, scorre la conversazione: la richiesta nuova si scrive sempre nello stesso posto. */
.pannello-bolla {
  position: fixed; inset: auto auto 84px calc(50% + var(--laterale) / 2); translate: -50% 0; margin: 0;
  width: min(560px, calc(100vw - 32px)); max-height: calc(100vh - 160px); padding: 0;
  border: 1px solid var(--bordo); border-radius: var(--r-pannello); background: var(--superficie); color: var(--inchiostro);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}
/* La colonna sta sulla finestra sempre, non solo da aperta: in chiusura il popover non è più `:popover-open` ma resta
   visibile per i 180ms dell'animazione (allow-discrete), e con la sola regola dell'aperta testa, conversazione e campo
   si rimettevano in fila orizzontale mentre sfumavano. */
.pannello-bolla { flex-direction: column; }
.pannello-bolla:popover-open, .pannello-bolla:not([popover]) { display: flex; }
/* Si apre dal pulsante «Chiedi a Bolla»: la finestra nasce lì (app.js mette in --origine-x il punto del pulsante,
   misurato sulla finestra) e cresce verso l'alto, salendo di 24px dall'85% e mettendosi a fuoco. Il contenuto arriva
   un attimo dopo la cornice, così l'occhio segue prima la forma e poi legge. Si chiude verso il pulsante, più in
   fretta: chi chiude ha già deciso. Solo opacità, transform e filter: niente che ricalcoli il layout. Proprietà
   scritte una per una e non con la scorciatoia `transition`: un browser che non conosce `allow-discrete`
   scarterebbe la riga intera. Senza @starting-style (Safari prima della 17.5) si apre e basta. Col movimento
   ridotto la regola generale in fondo al file toglie tutto. */
.pannello-bolla[popover] {
  --curva-apertura: cubic-bezier(0.16, 1, 0.3, 1);
  transform-origin: var(--origine-x, 50%) 100%;
  opacity: 0;
  transform: translateY(12px) scale(0.92);
  filter: blur(2px);
  transition-property: opacity, transform, filter, overlay, display;
  transition-duration: 180ms;
  transition-timing-function: var(--curva);
  transition-behavior: allow-discrete;
}
.pannello-bolla[popover]:popover-open { opacity: 1; transform: none; filter: none; transition-duration: 320ms; transition-timing-function: var(--curva-apertura); }
.pannello-bolla[popover]:popover-open > * { transition: opacity 220ms var(--curva) 90ms; }
@starting-style {
  .pannello-bolla[popover]:popover-open { opacity: 0; transform: translateY(24px) scale(0.85); filter: blur(6px); }
  .pannello-bolla[popover]:popover-open > * { opacity: 0; }
}
/* Senza JavaScript la finestra con una risposta arriva aperta, fuori dal popover (banco-comando.eta): non sta nello
   strato in cima ma dentro l'isola, che con il suo transform fa da riferimento a position: fixed. Contata dal bordo
   dell'isola invece che dallo schermo, la stessa distanza la mette dove starebbe il popover (24 + 60 = 84, e sul
   telefono 16 + 60 = 76). */
.pannello-bolla:not([popover]) { bottom: 60px; }
/* la testa porta il fondo dell'AI del design system (`--accent-soft`): dice di chi è la finestra */
.pannello-bolla-testa { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 12px 10px 20px; background: var(--accent-soft); }
.pannello-bolla h2 { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 17px; font-weight: 800; }
.pannello-bolla h2 .marchio-bolla { width: 18px; height: 17px; }
.conversazione-vuota { margin: 0; padding: 16px; color: var(--inchiostro-2); text-wrap: pretty; }
.scambi { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: grid; gap: 16px; margin: 0; padding: 16px; list-style: none; }
.scambio { display: grid; gap: 8px; }
.scambio p { margin: 0; }
/* chi scrive a destra, Bolla a sinistra con la sua «o»: la forma di una conversazione, senza nomi da leggere */
.scambio-comando { justify-self: end; max-width: 85%; padding: 8px 12px; border-radius: 12px 12px 4px 12px; background: var(--superficie-2); text-wrap: pretty; }
.scambio-risposta { display: flex; align-items: flex-start; gap: 10px; max-width: 92%; }
.scambio-risposta .marchio-bolla { width: 18px; height: 17px; margin-top: 3px; }
.scambio-risposta p:first-child { text-wrap: pretty; }
.scambio-esito { margin-top: 2px !important; color: var(--inchiostro-2); font-size: 13px; }
.pannello-bolla > .errore { margin: 0 16px 12px; }
.pannello-bolla .comando { position: relative; padding: 12px; border-top: 1px solid var(--bordo); }
.comando fieldset { display: flex; gap: 8px; min-width: 0; margin: 0; padding: 0; border: 0; }
.campo-comando { flex: 1; min-width: 0; min-height: 40px; font-size: 15px; }
.comando .btn { min-height: 40px; }
/* La finestra sta dentro l'isola nel DOM (è il suo popover), ma non ne prende la forma: i pulsanti dell'isola
   sono pillole senza bordo, quelli della finestra sono pulsanti di un pannello. */
.azioni-documento .pannello-bolla .btn { border-radius: var(--r-pulsante); }
.azioni-documento .pannello-bolla .btn-contorno { border: 1px solid var(--bordo-forte); }
/* Mentre Bolla lavora il campo non accetta un secondo invio (htmx disabilita il fieldset) e al suo posto si legge
   cosa sta succedendo: niente spinner nel contenuto, uno solo accanto alla frase. */
.comando-attesa { display: none; }
.comando.htmx-request .comando-attesa {
  position: absolute; inset: 12px; display: flex; align-items: center; gap: 10px; margin: 0; padding: 0 12px;
  border-radius: var(--r-campo); background: var(--superficie-2); color: var(--inchiostro-2); font-size: 15px;
}
.comando-attesa .spinner { display: inline-block; width: 14px; height: 14px; }

/* Proposta di Bolla: la barra prende il posto dell'isola, nella stessa posizione, più larga perché deve dire
   cosa si è chiesto e cosa cambia. Non è una pillola: porta due righe di testo, e il raggio dei pannelli. */
.barra-proposta {
  position: fixed; bottom: 16px; left: calc(50% + var(--laterale) / 2); translate: -50% 0; z-index: var(--z-azioni);
  display: grid; gap: 10px; width: min(760px, calc(100vw - 32px)); padding: 14px 16px;
  border: 0; border-radius: var(--r-pannello); background: var(--accent-soft);
  box-shadow: var(--shadow-pop);
}
.barra-proposta p { margin: 0; }
.proposta-testa { display: flex; align-items: flex-start; gap: 10px; }
.proposta-testa .marchio-bolla { width: 18px; height: 17px; margin-top: 2px; }
.proposta-parole { display: grid; gap: 2px; min-width: 0; }
.proposta-comando { color: var(--inchiostro-2); font-size: 14px; }
.proposta-messaggio { font-size: 15px; text-wrap: pretty; }
/* già mandato al cliente: non è un errore, è una cosa da sapere prima di premere */
.proposta-avviso { padding: 6px 12px; border-radius: var(--r-campo); background: var(--superficie); font-size: 14px; }
.barra-proposta .errore { margin: 0; }
.proposta-piede { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.proposta-sintesi { flex: 1 1 260px; font-size: 14.5px; }
.proposta-sintesi b { font-weight: 800; }
.proposta-sintesi:focus-visible { outline-offset: 4px; border-radius: 4px; }
.proposta-azioni { display: flex; gap: 8px; margin-left: auto; }
.proposta-azioni form { margin: 0; }
/* il foglio lascia sotto lo spazio per la barra, che è più alta dell'isola */
.pagina.con-proposta { padding-bottom: 200px; }

/* Le righe della proposta. Ogni stato ha la sua parola nella nota: il colore accompagna, non basta. */
.nota-proposta { grid-column: 1 / -1; margin: 0 0 2px; color: var(--inchiostro-2); font-size: 13px; font-weight: 600; line-height: 1.4; }
.nota-proposta .motivo { font-weight: 400; font-style: italic; }
.nota-nuova { color: var(--accent-ink); }
.nota-tolta { color: var(--errore); }
.riga-doc.proposta-nuova { background: var(--accent-soft); outline: 1.5px dashed var(--accent-ink); outline-offset: -3px; }
@media (hover: hover) { .riga-doc.proposta-nuova:hover { background: var(--accent-soft); outline: 1.5px dashed var(--accent-ink); outline-offset: -3px; } }
.riga-doc.proposta-tolta { background: var(--errore-tenue); }
@media (hover: hover) { .riga-doc.proposta-tolta:hover { background: var(--errore-tenue); } }
/* Barrate e in `--inchiostro-2`, non trasparenti: con l'opacità del mockup il testo scendeva sotto il 4,5:1, e
   quello che si toglie va letto bene quanto quello che resta. */
.proposta-tolta .campo-descrizione { color: var(--inchiostro-2); text-decoration: line-through; }
.proposta-tolta .importo { color: var(--inchiostro-2); text-decoration: line-through; }
.proposta-tolta .calcolo .campo, .proposta-tolta .pillola, .proposta-tolta .selettore { color: var(--inchiostro-2); }
.riga-doc.proposta-cambiata { background: var(--superficie-2); outline: 1.5px solid var(--inchiostro-2); outline-offset: -2px; }
@media (hover: hover) { .riga-doc.proposta-cambiata:hover { background: var(--superficie-2); outline: 1.5px solid var(--inchiostro-2); outline-offset: -2px; } }
@media (hover: hover) { .riga-doc.proposta-invariata:hover { background: transparent; } }
/* sola lettura: i campi si leggono e si raggiungono da tastiera, ma non invitano a scrivere */
.campo[readonly] { cursor: default; }
@media (hover: hover) { .campo[readonly]:hover { background: transparent; } }
@media (hover: hover) { .calcolo .misura .campo-quantita[readonly]:hover { background: var(--superficie); } }
.selettore-fermo { border-color: var(--bordo); background: var(--superficie); cursor: default; }
@media (hover: hover) { .selettore-fermo:hover { border-color: var(--bordo); background: var(--superficie); cursor: default; } }
.pillola-ferma { padding-right: 12px; border-color: var(--bordo); background: var(--superficie); cursor: default; }
@media (hover: hover) { .pillola-ferma:hover { padding-right: 12px; border-color: var(--bordo); background: var(--superficie); cursor: default; } }
.pillola-ferma.pillola-manca { border: 1px dashed var(--bordo-forte); }
.cliente-vuoto { margin: 0; color: var(--inchiostro-2); }
.nota-iva-proposta { margin-bottom: 4px; text-align: right; }

/* campi */
.campo { display: block; width: calc(100% + 12px); margin: 0 -6px; padding: 3px 6px; border: 1px solid transparent; border-radius: var(--r-campo); background: transparent; transition: background var(--durata) var(--curva); }
@media (hover: hover) { .campo:hover { background: var(--superficie-2); } }
/* Col fuoco un campo di testo fa come il TextField del design system: bordo `--ink` e un alone `--surface-mint`.
   L'anello arancio `--focus` è dei pulsanti e degli altri controlli. */
.campo:focus { outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px var(--surface-mint); background: var(--superficie); }
textarea.campo { resize: none; field-sizing: content; min-height: 1.5em; }
.campo-bordato { max-width: 100%; padding: 9px 14px; border: 1.5px solid var(--bordo-forte); border-radius: var(--r-campo); background: var(--superficie); }
.campo-bordato:focus { outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px var(--surface-mint); }
.campo::placeholder, .campo-bordato::placeholder, .aggiungi-campo input::placeholder, .cerca input::placeholder { color: var(--inchiostro-2); }
.cresce { flex: 1; min-width: 240px; }
/* il campo di ricerca è un campo come gli altri: fondo `--surface` e bordo `--border-strong` */
.cerca { display: flex; align-items: center; gap: 8px; padding: 0 14px; border: 1.5px solid var(--bordo-forte); border-radius: var(--r-campo); background: var(--superficie); color: var(--inchiostro-2); }
.cerca input { flex: 1; min-width: 0; padding: 8px 0; border: 0; background: transparent; color: var(--inchiostro); outline: none; }
.cerca:focus-within { border-color: var(--ink); box-shadow: 0 0 0 3px var(--surface-mint); }
.descrizione { display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }
.descrizione textarea { flex: 1; min-width: 260px; resize: vertical; }

/* messaggi */
.errore { display: flex; align-items: flex-start; gap: 8px; margin: 8px 0; padding: 8px 12px; border-radius: var(--r-campo); background: var(--errore-tenue); color: var(--errore); font-size: 14px; font-weight: 600; }
/* Il triangolo sta qui e non nei template: gli errori nascono in undici punti diversi, e un'icona da ricordarsi
   a mano è un'icona che prima o poi manca nel dodicesimo. È l'unica icona che non passa da un <symbol>; la
   maschera le fa seguire currentColor come tutte le altre. Decorativa: il messaggio è nel testo. */
.errore::before { content: ""; width: 16px; height: 16px; flex: none; margin-top: 1px; background: currentColor; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 9v4M12 17h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z'/%3E%3C/svg%3E") center / contain no-repeat; }
.vuoto { margin: 8px 0; color: var(--inchiostro-2); font-size: 14px; }
.vuoto-grande { padding: 32px; text-align: center; color: var(--inchiostro-2); }
.errore-campo:empty { display: none; }

/* foglio ed elenchi */
.foglio { background: var(--superficie); border: 1px solid var(--bordo); border-radius: var(--r-foglio); box-shadow: var(--shadow-card); }
.elenco { list-style: none; margin: 0; padding: 6px 12px; }
.elenco-voce { padding: 14px 12px; border-radius: var(--r-riga); }
.elenco-voce + .elenco-voce { box-shadow: 0 -1px 0 var(--bordo); }
.elenco-testa { display: grid; grid-template-columns: 1fr auto auto; gap: 4px 20px; align-items: center; }
.elenco-titolo { color: var(--inchiostro); font-weight: 700; text-decoration: none; }
@media (hover: hover) { a.elenco-titolo:hover { color: var(--accento); text-decoration: underline; text-underline-offset: 3px; } }
/* il numero accompagna il titolo senza competerci: stessa riga, peso normale, inchiostro secondario */
.elenco-numero { margin-left: 8px; font-size: 13px; color: var(--inchiostro-2); }
.elenco-meta { color: var(--inchiostro-2); font-size: 13.5px; }
/* il nome è l'appiglio con cui si ritrova un preventivo mesi dopo, non un dettaglio come la data */
.elenco-cliente { color: var(--inchiostro); font-weight: 700; }
.elenco-importo { font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }
/* L'elenco dei preventivi: una scheda per preventivo, cliccabile per intero. Da ferma dice che si apre (bordo e
   freccia in un cerchio, come le proposte di prezzo); al passaggio o col fuoco il bordo diventa `--primary` e il
   cerchio si riempie. */
.preventivi { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.preventivo {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: 4px 20px;
  padding: 16px 16px 16px 20px; border: 1px solid var(--bordo); border-radius: var(--r-foglio);
  background: var(--superficie); box-shadow: var(--shadow-card); color: var(--inchiostro); text-decoration: none;
  transition: border-color var(--durata) var(--curva), background var(--durata) var(--curva);
}
.preventivo:focus-visible { border-color: var(--primary); }
@media (hover: hover) { .preventivo:hover { border-color: var(--primary); } }
.preventivo:focus-visible .opzione-vai { background: var(--primary); color: var(--on-primary); }
@media (hover: hover) { .preventivo:hover .opzione-vai { background: var(--primary); color: var(--on-primary); } }
@media (hover: hover) { .preventivo:hover .opzione-vai .icona { transform: translateX(1px); } }
.preventivo-corpo { display: grid; gap: 4px; min-width: 0; }
.preventivo-testa { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.preventivo-titolo { font-size: 16px; font-weight: 700; line-height: 1.35; }
.preventivo-numero { font-size: 13px; color: var(--inchiostro-2); }
.preventivo-importo { font-size: 16px; font-weight: 700; text-align: right; white-space: nowrap; }
.preventivo .opzione-vai { width: 32px; height: 32px; }
/* lo stato del preventivo: l'etichetta a pillola del design system (StatusBadge), sempre con la parola */
.stato { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px; border-radius: var(--r-pulsante); font-size: 12.5px; font-weight: 700; white-space: nowrap; }
.stato-punto { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.stato-neutro { background: var(--surface-mint); color: var(--ink-muted); }
.stato-info { background: var(--info-soft); color: var(--info); }
.stato-ok { background: var(--ok-tenue); color: var(--ok); }
/* da sollecitare: il trattamento di «da definire», lavoro da fare e non allarme (DESIGN.md, Colors) */
.stato-da-fare { border: 1px dashed var(--bordo-forte); background: var(--superficie); color: var(--manca); }
/* da controllare (un accettato senza condizioni di pagamento): lo stato `warning` del design system */
.stato-attenzione { background: var(--warning-soft); color: var(--warning); }
/* un avviso che non ferma (il coordinatore del POS con più imprese): lo stato warning, non l'errore */
.avviso-attenzione { margin: 0; padding: 8px 12px; border-radius: var(--r-campo); background: var(--warning-soft); color: var(--warning); font-size: 14px; font-weight: 600; }
/* scaduto (un attestato): lo stato `danger` del design system, con la parola */
.stato-errore { background: var(--danger-soft); color: var(--danger); }
/* scritto da Bolla e non ancora rivisto (un modello di lavoro ricavato dallo storico): lo stato `bozza-ai` del design
   system, arancio chiaro con la fiala al posto del punto; dopo la conferma perde il segno arancione */
.stato-ai { background: var(--accent-soft); color: var(--accent-ink); --marchio-tratto: var(--accent-ink); --marchio-bolla: var(--accent-ink); }
.stato-ai .marchio-bolla { width: 14px; height: 13px; }
/* Il riepilogo degli esiti sotto il titolo dell'elenco: le cifre in neretto, il resto come la riga sopra */
.pagina-testa .riepilogo-esiti { color: var(--inchiostro); }
.riepilogo-esiti .num { font-weight: 700; font-variant-numeric: tabular-nums; }
/* Le viste dell'elenco: pillole-link in fila, quella aperta piena come lo stato aperto delle pillole */
.viste { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px; }
.vista {
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 14px;
  border: 1px solid var(--bordo); border-radius: var(--r-pulsante); background: var(--superficie);
  color: var(--inchiostro); font-size: 14px; font-weight: 700; text-decoration: none;
}
@media (hover: hover) { .vista:hover { background: var(--superficie-2); } }
.vista[aria-current="page"] { border-color: var(--accento); background: var(--superficie-2); }
.vista-conteggio { color: var(--inchiostro-2); font-weight: 600; font-variant-numeric: tabular-nums; }
.pannello:empty { display: none; }
.pannello { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--bordo); }
.azioni { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

/* tabella delle righe di un preventivo storico */
.tabella { width: 100%; border-collapse: collapse; font-size: 14px; }
/* intestazioni di colonna nello stile `label` del design system: maiuscolo spaziato */
.tabella th { padding: 8px; border-bottom: 1px solid var(--bordo); color: var(--inchiostro-2); font-size: 12px; font-weight: 800; line-height: 16px; letter-spacing: 0.06em; text-transform: uppercase; text-align: left; }
.tabella td { padding: 7px 8px; border-bottom: 1px solid var(--bordo); vertical-align: top; }
.tabella .num { text-align: right; }
.tabella .descr { white-space: pre-line; }
.tabella tfoot td { border-bottom: 0; font-weight: 800; }

/* opzioni cliccabili: fonti di prezzo e risultati della ricerca */
.gruppo { margin: 14px 0 4px; color: var(--inchiostro-2); font-size: 12px; font-weight: 800; line-height: 16px; letter-spacing: 0.06em; text-transform: uppercase; }
/* Ogni proposta è un pulsante che si fa riconoscere da fermo: un bordo, e la freccia in un cerchio accanto al
   prezzo. Al passaggio (o col fuoco) il bordo si fa `--primary` e il cerchio si riempie: la scelta è quella. */
.opzione { display: grid; grid-template-columns: 1fr auto; gap: 2px 16px; align-items: center; width: 100%; margin-top: 6px; padding: 10px 12px; border: 1px solid transparent; border-radius: var(--r-campo); background: transparent; text-align: left; }
button.opzione { border-color: var(--bordo); background: var(--superficie); transition: border-color var(--durata) var(--curva), background var(--durata) var(--curva); }
button.opzione:focus-visible { border-color: var(--primary); background: var(--surface-mint); }
@media (hover: hover) { button.opzione:hover { border-color: var(--primary); background: var(--surface-mint); } }
.opzione-prezzo { grid-row: span 3; display: inline-flex; align-items: center; gap: 10px; font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }
.opzione-vai { display: inline-grid; place-items: center; width: 28px; height: 28px; flex: none; border-radius: 50%; background: var(--surface-mint); color: var(--primary); transition: background var(--durata) var(--curva), color var(--durata) var(--curva); }
.opzione-vai .icona { transition: transform var(--durata) var(--curva); }
button.opzione:focus-visible .opzione-vai { background: var(--primary); color: var(--on-primary); }
@media (hover: hover) { button.opzione:hover .opzione-vai { background: var(--primary); color: var(--on-primary); } }
@media (hover: hover) { button.opzione:hover .opzione-vai .icona { transform: translateX(1px); } }
.opzione-dettaglio, .opzione-motivo { color: var(--inchiostro-2); font-size: 12.5px; }
/* il prezzo ha un'unità diversa da quella della riga: si può usare, ma cambia l'unità della riga (da controllare) */
.opzione-avviso { color: var(--warning); font-size: 12.5px; font-weight: 600; }
.opzione.non-applicabile { color: var(--inchiostro-2); }
.opzione.non-applicabile .opzione-prezzo { font-weight: 400; }

/* banco: il documento */
/* la testata è la carta intestata: a sinistra che lavoro è, a destra per chi. Le colonne si stirano alla stessa
   altezza, così il filo che le divide è un divisore di colonne e non un trattino appeso al blocco del cliente. */
.foglio-testa { display: flex; padding: 32px 40px 16px; }
.testa-lavoro { flex: 1; min-width: 0; }
.foglio-origine { color: var(--inchiostro-2); font-size: 13px; }
/* come i campi del cliente: il titolo è una riga del documento, non una casella. Il padding verticale di
   `.campo` lo staccava dall'origine di 6px più del disegno. */
.campo-titolo { margin-top: 2px; padding-top: 0; padding-bottom: 0; font-size: 28px; font-weight: 800; line-height: 1.3; letter-spacing: -0.015em; }
/* cliente: il destinatario, come sui preventivi di carta. Si vede perché sta lì e perché è incolonnato, non per
   uno sfondo suo: dentro un foglio bianco un riquadro grigio è una toppa. Larghezza fissa, così un titolo lungo
   non stringe il blocco, e lo sfondo dei campi al passaggio del mouse è largo quanto la colonna — si legge come
   un blocco invece che come una striscia lunga quanto il foglio. */
.cliente { flex: none; width: 300px; padding-left: 20px; border-left: 1px solid var(--bordo); }
.cliente-etichetta { margin-bottom: 3px; color: var(--inchiostro-2); font-size: 12px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; }
/* Con un cliente, i suoi dati si leggono come su carta: il nome in `body-strong` più grande, poi indirizzo e
   recapiti in `--inchiostro-2`, uno per riga (in 300px affiancarli spezzerebbe l'email a metà). «Modifica», un
   pulsante ghost piccolo, sta sulla riga dell'etichetta. */
.cliente-testa { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: -8px 0 2px; }
.cliente-testa .cliente-etichetta { margin: 0; }
.cliente .btn.cliente-modifica { margin: 0 -12px 0 0; }
.cliente-nome { margin: 0; font-size: 16px; line-height: 24px; font-weight: 700; color: var(--inchiostro); overflow-wrap: anywhere; }
.cliente-riga { margin: 0; font-size: 14.5px; line-height: 22px; color: var(--inchiostro-2); overflow-wrap: anywhere; }
.cliente-recapito { font-size: 14px; }
/* In modifica, i TextField del design system: l'etichetta (14px/700) sempre visibile sopra, il campo alto 44px con
   bordo `border-strong` e `radius-md`, al fuoco il bordo `ink` con l'alone; il segnaposto è solo un esempio. */
.cliente-aperto { display: grid; gap: 12px; align-content: start; }
.cliente-aperto .cliente-etichetta { margin: 0; }
.campo-ds { display: grid; gap: 6px; min-width: 0; }
.campo-ds label { font-size: 14px; line-height: 20px; font-weight: 700; color: var(--inchiostro); }
.campo-ds input { width: 100%; min-height: 44px; padding: 0 14px; font-size: 15px; }
.campo-ds input::placeholder { color: var(--inchiostro-2); }
.cliente-aperto .btn.cliente-fatto { justify-self: start; margin: 2px 0 0; }
/* lo stato vuoto è il primo passo, non una nota a margine: un pulsante con un bordo visibile */
.cliente .btn { margin-top: 8px; }
/* Quando è partito e a chi: un fatto, non un'azione. Peso e colore di una didascalia. */
.invio-stato {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--inchiostro-2);
  overflow-wrap: anywhere;
}
/* la riga dell'IVA porta un selettore invece di una cifra: le sue celle respirano un po' meno delle altre, e il
   selettore si allinea a destra con gli importi della colonna */
.riepilogo .riga-iva td { padding-top: 2px; padding-bottom: 2px; }
/* niente allineamento a destra del contenuto: il chevron sta a filo destro come in ogni selettore, ed è la
   cella del riepilogo ad allineare a destra la scatola intera */
.selettore-iva { min-width: 12ch; }
.nota-iva td { color: var(--inchiostro-2); font-size: 13px; }
.righe { list-style: none; margin: 0; padding: 0 16px; }
.riga-vuota { padding: 24px; color: var(--inchiostro-2); text-align: center; }
.righe:has(.riga-doc) .riga-vuota { display: none; }
.riga-doc { position: relative; display: grid; grid-template-columns: 1fr auto 32px; gap: 4px 16px; padding: 14px 16px 14px 24px; }
/* il filo tra le righe è un bordo dritto, come nella tabella QuoteItems: un'ombra seguiva gli angoli arrotondati
   della riga e disegnava una curva in cima a ognuna */
.riga-doc + .riga-doc { border-top: 1px solid var(--bordo); }
@media (hover: hover) { .riga-doc:hover { background: var(--surface-sunken); } }
.riga-doc.aperta { background: var(--surface-mint); box-shadow: inset 0 0 0 1px var(--bordo); }
/* la testata compatta e le azioni in fondo alla riga aperta sono del telefono (sotto, nella media query) */
.riga-compatta, .azioni-riga-aperta { display: none; }
.campo-descrizione { font-size: 15.5px; }
.calcolo { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 4px; color: var(--inchiostro-2); font-size: 14px; }
/* quantità e unità a larghezza fissa: su tutte le righe il "×" e la pillola restano incolonnati, e il numero non
   dipende dal supporto di field-sizing (senza, un input torna alla larghezza di default di ~20 caratteri) */
.calcolo .campo { display: inline-block; width: 7ch; margin: 0; color: var(--inchiostro); }
/* Quantità e unità sono una misura sola: un gruppo unico, diviso da un filo, invece di due controlli che si
   somigliano e non si toccano. Il bordo destro della quantità è quello sinistro del selettore: uno solo, non due
   appiccicati. */
.misura { display: inline-flex; align-items: stretch; }
.calcolo .misura .campo-quantita {
  width: 6ch; min-height: 40px; padding: 0 8px; text-align: right;
  border: 1.5px solid var(--bordo-forte); border-right: 0; border-radius: var(--r-campo) 0 0 var(--r-campo);
  background: var(--superficie);
}
@media (hover: hover) { .calcolo .misura .campo-quantita:hover { background: var(--superficie-2); } }
.calcolo .misura .campo-quantita:focus { outline: none; border-color: var(--ink); box-shadow: inset -1px 0 0 var(--ink), 0 0 0 3px var(--surface-mint); background: var(--superficie); position: relative; }
.misura .selettore { min-height: 40px; border: 1.5px solid var(--bordo-forte); border-radius: 0 var(--r-campo) var(--r-campo) 0; }
/* in sola lettura (una proposta di Bolla) i campi si leggono ma non si toccano: il bordo leggero, non quello dei
   campi da compilare */
.calcolo .misura .campo-quantita[readonly], .misura .selettore-fermo, .pillola.pillola-ferma { border-color: var(--bordo); }
.pillola.pillola-ferma.pillola-manca { border-color: var(--bordo-forte); }
@media (hover: hover) { .pillola.pillola-ferma:hover { background: var(--superficie); } }
.importo { padding-top: 3px; font-size: 15.5px; font-weight: 700; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.riga-doc.manca .importo { color: var(--inchiostro-2); font-weight: 400; }
.riga-doc .altro { transition: opacity var(--durata); }
@media (hover: hover) {
  .riga-doc .altro { opacity: 0; }
  .riga-doc:focus-within .altro, .riga-doc .altro:focus-visible { opacity: 1; }
  .riga-doc:hover .altro { opacity: 1; }
}
/* La maniglia sta nella fascia libera a sinistra, in posizione assoluta: lo spazio c'è già (i 24px di padding
   della riga) e così le descrizioni,
   che sono la parte stretta della riga, non perdono un pixel di larghezza. */
/* -16px e non -2: la scatola da 32px arrivava sopra la descrizione, e cliccando la prima lettera si prendeva
   la maniglia invece del campo. Il conto va fatto sulla textarea, non sulla colonna: `.campo` ha `margin: 0 -6px`,
   quindi il testo comincia sei pixel prima del suo posto. A -16 la maniglia finisce due pixel prima del testo, e
   il padding di `.righe` (16px) la ospita per intero. */
.presa { position: absolute; left: -16px; top: 12px; display: grid; place-items: center; width: 32px; height: 32px; color: var(--inchiostro-2); cursor: grab; transition: opacity var(--durata); }
.presa:active { cursor: grabbing; }
/* stessa visibilità del ⋯: quaranta righe restano calme invece di riempirsi di appigli */
@media (hover: hover) {
  .presa { opacity: 0; }
  .riga-doc:focus-within .presa { opacity: 1; }
  .riga-doc:hover .presa { opacity: 1; }
}
/* la riga presa si stacca dal foglio; il posto dove cadrà si vede in negativo */
.riga-presa { background: var(--superficie); box-shadow: var(--shadow-pop); }
.riga-fantasma { opacity: 1; background: var(--accento-tenue); }
.riga-fantasma > * { visibility: hidden; }
/* Al PC le righe sono la tabella QuoteItems del design system: colonne con le loro intestazioni (Descrizione,
   Quantità, Prezzo, Totale), una riga per lavorazione, i numeri incolonnati a destra, un filo dritto tra una riga e
   l'altra. Il markup è quello del telefono, dove la riga resta compatta e si apre sul posto: qui corpo e calcolo si
   sciolgono (`display: contents`) e i loro pezzi prendono ciascuno la sua colonna. La fonte del prezzo scende sotto
   il campo, come l'aiuto di un TextField. */
.righe-testa { display: none; }
@media (min-width: 721px) and (not ((pointer: coarse) and (max-height: 500px))) {
  .foglio { --colonne-righe: minmax(0, 1fr) 152px 184px 108px 32px; }
  .righe-testa {
    display: grid; grid-template-columns: var(--colonne-righe); column-gap: 16px; align-items: end;
    margin-top: 8px; padding: 10px 20px 10px 32px; border-bottom: 1px solid var(--bordo);
    color: var(--inchiostro-2); font-size: 12px; line-height: 16px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
  }
  .righe-testa > :last-child { grid-column: 4; text-align: right; }
  .righe { padding: 0; }
  .riga-doc {
    grid-template-columns: var(--colonne-righe); grid-auto-flow: row dense; column-gap: 16px; row-gap: 6px; align-items: center;
    padding: 12px 20px 12px 32px;
  }
  .riga-doc:has(.pillola-fonte) { padding-bottom: 32px; }
  .riga-doc .riga-corpo, .riga-doc .calcolo { display: contents; }
  .riga-doc > .nota-proposta { grid-column: 1 / -1; }
  .riga-doc .campo-descrizione { grid-column: 1; }
  .riga-doc .calcolo > [aria-hidden="true"] { display: none; }
  .riga-doc .misura { grid-column: 2; }
  .riga-doc .misura .campo-quantita { width: auto; flex: 1; min-width: 0; }
  .riga-doc .misura .selettore { flex: none; }
  .riga-doc .pillola { grid-column: 3; position: relative; width: 100%; min-width: 0; }
  .riga-doc .pillola .num { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .riga-doc .pillola-fonte { position: absolute; left: 1px; top: calc(100% + 5px); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; line-height: 18px; }
  .riga-doc .pillola-punto { display: none; }
  .riga-doc .da-definire { grid-column: 2; font-size: 13px; }
  .riga-doc .scarto-capitolato { grid-column: 3; padding-left: 1px; }
  .riga-doc .errore-campo { grid-column: 1 / -1; }
  .riga-doc .errore-campo:empty { display: none; }
  .riga-doc .importo { grid-column: 4; padding: 0; }
  .riga-doc .altro { grid-column: 5; }
  .riga-doc .fonti { grid-column: 1 / -1; }
  .presa { left: 0; top: 16px; }
}
/* sugli schermi larghi il foglio del banco si allarga: una tabella di quattro colonne a 880px lascia alla
   descrizione, che è la parte che si legge, meno di un terzo della riga */
@media (min-width: 1100px) and (not ((pointer: coarse) and (max-height: 500px))) {
  .pagina:has(> .foglio > .righe), .pagina-documenti { max-width: 1040px; }
  body:has(.pagina > .foglio > .righe) .barra-in, body:has(.pagina-documenti) .barra-in { max-width: 1040px; }
  .foglio { --colonne-righe: minmax(0, 1fr) 172px 208px 116px 32px; }
}
.fonti:empty { display: none; }
.fonti { grid-column: 1 / -1; margin-top: 10px; padding-top: 12px; border-top: 1px solid var(--bordo); }
/* il perché di un prezzo corretto, in testa al pannello delle fonti: un riquadro chiaro col bordo, che si stacca
   dal fondo della riga aperta; «Usa …» va a capo quando non ci sta */
.perche-prezzo { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin: 0 0 12px; padding: 10px 12px; border: 1px solid var(--bordo); border-radius: var(--r-piccolo); background: var(--superficie); font-size: 14px; line-height: 1.45; }
.perche-prezzo p { flex: 1 1 36ch; margin: 0; text-wrap: pretty; }
.opzione-dettaglio b, .opzione .codice b { color: var(--inchiostro); font-weight: 700; }
@media (pointer: coarse) { .perche-prezzo .link-azione { min-height: 44px; } }
.prezzo-manuale { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--bordo); font-size: 14px; }
.prezzo-manuale input { width: 9em; text-align: right; }

/* Il prezzo della riga: si preme per sceglierne un altro. Ha la forma di un campo del design system (TextField:
   bordo `border-strong`, `radius-md`), non di una pillola, che nel design system è dei pulsanti, delle chip e delle
   tab: è un valore, e si sceglie. Al passaggio il fondo `surface-mint`; aperto, il bordo `ink` con l'alone, come un
   campo col fuoco. Il nome della classe è rimasto quello di prima: lo usano app.js e gli scambi del server. */
.pillola { display: inline-flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 40px; padding: 0 10px 0 12px; border: 1.5px solid var(--bordo-forte); border-radius: var(--r-campo); background: var(--superficie); color: var(--inchiostro); font-size: 15px; font-weight: 600; text-align: left; transition: border-color var(--durata), background var(--durata), box-shadow var(--durata); }
.pillola .num { font-weight: 700; }
.pillola-fonte { color: var(--inchiostro-2); font-weight: 600; }
/* la parte della fonte che cambia il numero: la correzione imparata dai preventivi mandati (spec prezzi imparati) */
.pillola-correzione { color: var(--inchiostro); font-weight: 700; }
.pillola .icona { flex: none; color: var(--inchiostro-2); }
@media (hover: hover) { .pillola:hover { background: var(--superficie-2); } }
.pillola[aria-expanded="true"] { border-color: var(--ink); box-shadow: 0 0 0 3px var(--surface-mint); background: var(--superficie); }
.pillola .icona { transition: transform var(--durata) var(--curva); }
.pillola[aria-expanded="true"] .icona { transform: rotate(180deg); }
.pillola-manca { border: 1.5px dashed var(--bordo-forte); color: var(--manca); font-weight: 700; }
.appena-applicata .pillola { animation: evidenzia 1s var(--curva); }
@keyframes evidenzia { from { border-color: var(--ink); background: var(--superficie-2); } }
/* Dopo «Applica» la riga intera, non solo il prezzo: un comando può aver cambiato la descrizione o la misura.
   Più lungo del prezzo singolo, perché le righe accese possono essere più d'una e vanno trovate con lo sguardo. */
.riga-doc.appena-applicata[data-da-comando] { animation: evidenzia-riga 1.6s var(--curva); }
@keyframes evidenzia-riga { from { background: var(--accento-tenue); } }

/* spinner sulla pillola mentre la ricerca dei prezzi è in corso (htmx aggiunge .htmx-request all'elemento che
   fa la richiesta): sostituisce il chevron, non il contenuto del pannello (vedi .segnaposto, DESIGN.md) */
.spinner { display: none; width: 16px; height: 16px; flex: none; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: girare 0.7s linear infinite; }
.pillola.htmx-request .icona { display: none; }
.pillola.htmx-request .spinner { display: inline-block; }
/* lo stesso spinner su un pulsante che aspetta una risposta lenta (passo 2: la lettura della descrizione);
   .btn è già inline-flex con il suo gap, qui basta far comparire lo spinner */
.btn.in-corso .spinner { display: inline-block; }
/* L'attesa di un'azione (app.js, DESIGN.md «Attesa»): passata la soglia, lo spinner entra nel controllo premuto,
   dopo la sua parola. Nei pulsanti a pillola c'è già il gap; nel menu ⋯ le voci sono blocchi allineati a sinistra,
   e lo spinner va a filo destro come il chevron di un selettore. */
.in-attesa { cursor: progress; }
.in-attesa > .spinner { display: inline-block; }
.menu button.in-attesa { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
/* Gli altri tasti, fermi finché l'azione non risponde. Si vedono fermi solo passata la soglia (app.js mette
   `.pagina-in-attesa` sulla radice), come lo spinner. Nessuna trasparenza (DESIGN.md, Colors): il testo passa a
   `--inchiostro-2`, i pulsanti pieni a `--superficie-2`, e al passaggio non si accende niente. */
[data-bloccato] { cursor: not-allowed; }
html.pagina-in-attesa [data-bloccato],
@media (hover: hover) { html.pagina-in-attesa [data-bloccato]:hover { color: var(--inchiostro-2); } }
html.pagina-in-attesa :is(.btn-principale, .btn-chiedi, .btn-ai)[data-bloccato] {
  border-color: transparent; background: var(--superficie-2);
  --marchio-tratto: var(--inchiostro-2); --marchio-bolla: var(--inchiostro-2);
}
@media (hover: hover) { html.pagina-in-attesa [data-bloccato]:not(.btn-principale, .btn-chiedi, .btn-ai):hover { background: transparent; text-decoration: none; } }
html.pagina-in-attesa .btn-contorno[data-bloccato] { border-color: var(--bordo); background: var(--superficie); }
/* Senza rete (app.js): i tasti che chiedono qualcosa al server, fermi come durante un'attesa, ma subito e finché la
   rete non torna. Toccati dicono perché, nel segno «Senza rete» della barra. */
html.senza-rete [data-fermo-rete] { cursor: not-allowed; color: var(--inchiostro-2); }
html.senza-rete :is(.btn-principale, .btn-chiedi, .btn-ai)[data-fermo-rete] {
  border-color: transparent; background: var(--superficie-2);
  --marchio-tratto: var(--inchiostro-2); --marchio-bolla: var(--inchiostro-2);
}
@media (hover: hover) { html.senza-rete [data-fermo-rete]:not(.btn-principale, .btn-chiedi, .btn-ai):hover { background: transparent; text-decoration: none; } }
html.senza-rete .btn-contorno[data-fermo-rete] { border-color: var(--bordo); background: var(--superficie); }
/* il segno in barra: lo StatusBadge, che non va a capo e non si stringe */
.rete-assente { flex: none; white-space: nowrap; }
.barra-in > .rete-assente { margin-left: auto; }
.rete-assente-testa { margin-bottom: 8px; }
/* senza rete il banco non salva niente: il suo «Salvato» lascia il posto al segno */
html.senza-rete .stato-salvataggio { display: none; }
/* il pulsante di conferma dell'invio, mentre manda: lo spinner e «Invio in corso…» al posto della destinazione */
.menu .invia-conferma { display: flex; align-items: center; gap: 8px; }
.invia-conferma .invio-attesa { display: none; }
.invia-conferma.htmx-request .invio-testo { display: none; }
.invia-conferma.htmx-request .invio-attesa, .invia-conferma.htmx-request .spinner { display: inline-block; }
.invia-conferma:disabled { cursor: progress; }
@keyframes girare { to { transform: rotate(360deg); } }

/* segnaposto del pannello delle fonti e dei risultati di "Aggiungi": righe grigie con leggera pulsazione */
.segnaposto { display: grid; gap: 8px; padding: 8px 10px; }
.segnaposto-riga { height: 40px; border-radius: var(--r-campo); background: var(--bordo); animation: pulsare 1.4s ease-in-out infinite; }
.segnaposto-riga:nth-child(2) { animation-delay: 0.15s; }
.segnaposto-riga:nth-child(3) { animation-delay: 0.3s; }
@keyframes pulsare { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } }
/* Lo scheletro di una pagina del menu che sta arrivando (app.js, «Il menu è immediato»): la sua forma — titolo,
   schede, righe — in blocchi grigi che pulsano piano come i segnaposto dei prezzi. Gli stessi contenitori della
   pagina vera (`.riquadro`, `.foglio`), così quando arriva niente salta. Col movimento ridotto restano fermi. */
.sk { border-radius: var(--radius-sm); background: var(--bordo); animation: pulsare 1.4s ease-in-out infinite; }
.sk-titolo { height: 32px; margin: 2px 0 10px; }
.sk-sottotitolo { width: 40%; height: 20px; margin-bottom: 18px; }
.sk-riga { height: 14px; margin: 8px 0; }
.sk-campo { max-width: 420px; height: 44px; margin-bottom: 16px; border-radius: var(--r-campo); }
.sk-area { height: 140px; margin-top: 20px; border-radius: var(--r-campo); }
.sk-riga-doc { padding: 12px 24px; border-top: 1px solid var(--bordo); }
.sk-voce { display: grid; gap: 4px; margin-bottom: 12px; padding: 18px 20px; border: 1px solid var(--bordo); border-radius: var(--radius-lg); background: var(--superficie); }
.sk-voce .sk:nth-child(2), .riquadro .sk:nth-child(3) { animation-delay: 0.15s; }
.cruscotto-griglia .riquadro + .riquadro .sk { animation-delay: 0.3s; }
/* il titolo che prende il fuoco dopo la navigazione (per i lettori di schermo) non si disegna l'anello */
main h1[tabindex="-1"]:focus { outline: none; }

/* menu ⋯ (popover nativo, posizionato da app.js) */
.menu[popover] { position: fixed; inset: auto; margin: 0; overflow-y: auto; min-width: 190px; padding: 6px; border: 1px solid var(--bordo); border-radius: var(--r-campo); background: var(--superficie); box-shadow: var(--shadow-pop); }
.menu button { display: block; width: 100%; padding: 8px 10px; border: 0; border-radius: var(--r-piccolo); background: transparent; font-size: 14px; text-align: left; }
@media (hover: hover) { .menu button:hover { background: var(--superficie-2); } }
/* una voce del menu che porta a un'altra pagina (il contratto): un link, che si presenta come le voci pulsante */
.menu a.menu-voce { display: block; padding: 8px 10px; border-radius: var(--r-piccolo); color: var(--inchiostro); font-size: 14px; text-decoration: none; }
@media (hover: hover) { .menu a.menu-voce:hover { background: var(--superficie-2); } }
.menu .pericolo { color: var(--errore); }
.menu .scelta.pericolo { background: var(--errore-tenue); font-weight: 600; }
/* un filo fra ciò che si può rifare e ciò che non si può: l'eliminazione non deve stare attaccata alle altre voci */
/* «Vedi PDF» come voce del menu: è del telefono, dove la barra in basso non ha posto per il pulsante */
.menu-pdf { display: none; }
/* al PC «Vedi PDF» sta nel menu quando nell'isola c'è un altro passo (banco-passo.eta) */
.azioni-documento:not(:has(#azioni-pdf)) .menu .menu-pdf { display: block; padding: 8px 10px; border-radius: var(--r-piccolo); color: var(--inchiostro); font-size: 14px; text-decoration: none; }
@media (hover: hover) { .azioni-documento:not(:has(#azioni-pdf)) .menu .menu-pdf:hover { background: var(--superficie-2); } }
.azioni-passo { display: contents; }
.menu-reinvia { display: none; }
.menu-riga { height: 1px; margin: 6px -6px; border: 0; background: var(--bordo); }
/* Riga di spiegazione dentro un popover di conferma: dice cosa sta per succedere, non è una voce da premere. */
.menu-nota {
  margin: 0;
  padding: 6px 10px 8px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--inchiostro-2);
  max-width: 32ch;
}

/* selettore di una scelta da un elenco chiuso: pulsante come un campo in linea, listbox in un popover nativo
   posizionato da app.js come il menu ⋯ (stessa funzione di posizionamento) */
/* Si fa riconoscere come controllo anche da fermo: bordo e chevron sempre visibili, come la pillola del prezzo
   che sta sulla stessa riga e fa lo stesso mestiere. Prima il bordo era trasparente e il chevron compariva solo
   al passaggio del mouse: su un computer, a riposo, «A corpo» era indistinguibile da un'etichetta — e chi usa
   questo strumento conosce il mestiere, non il software.
   `--bordo` e non `--bordo-forte`: a identificare il controllo (WCAG 1.4.11) basta il chevron, che sta in
   `--inchiostro-2` a 6,35:1, e un bordo più marcato di quello del prezzo rovescerebbe la gerarchia della riga. */
.selettore {
  display: inline-flex; align-items: center; justify-content: space-between; gap: 8px;
  min-height: 32px; padding: 0 8px;
  border: 1px solid var(--bordo); border-radius: var(--r-campo);
  background: var(--superficie); color: var(--inchiostro); font-size: inherit;
  transition: border-color var(--durata) var(--curva), background var(--durata) var(--curva);
}
/* Larghezza fissa, non minima: con `min-width` la scatola cresceva col testo, «A corpo» diventava più larga di
   «mq», e il per e i prezzi finivano a x diverse da una riga all'altra. 11ch tiene l'etichetta più lunga senza
   troncarla. Il vuoto che resta attorno a «mq» è costante, e un vuoto costante si legge come una colonna; era
   quello variabile a sembrare un difetto. */
.selettore-um { width: 11ch; }
.selettore-testo { display: inline-block; max-width: 10ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.selettore[aria-expanded="true"] { border-color: var(--accento); background: var(--accento-tenue); }
@media (hover: hover) { .selettore:hover { border-color: var(--accento); background: var(--accento-tenue); } }
.selettore:focus-visible { outline: 2px solid var(--focus); outline-offset: 0; background: var(--superficie); }
.selettore .icona { width: 14px; height: 14px; flex: none; transition: transform var(--durata) var(--curva); }
/* il chevron gira quando l'elenco è aperto, come nella pillola: dice che quello che si vede sotto viene da qui */
.selettore[aria-expanded="true"] .icona { transform: rotate(180deg); }
.listbox-scelta[popover] { position: fixed; inset: auto; margin: 0; min-width: 150px; max-height: 60vh; overflow-y: auto; padding: 6px; border: 1px solid var(--bordo); border-radius: var(--r-campo); background: var(--superficie); box-shadow: var(--shadow-pop); list-style: none; }
.listbox-scelta li { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: var(--r-piccolo); font-size: 14px; color: var(--inchiostro); cursor: pointer; }
@media (hover: hover) { .listbox-scelta li:hover { background: var(--accento-tenue); } }
/* opzione attiva da tastiera: il focus del DOM resta sulla listbox (pattern "button + listbox"), quindi il browser
   non disegna nessun anello sull'opzione. Il bordo pieno la distingue dal passaggio del mouse e arriva al 3:1. */
.listbox-scelta li.opzione-attiva { background: var(--accento-tenue); box-shadow: inset 0 0 0 2px var(--accento); }
.listbox-scelta .icona-spunta { color: var(--accento); visibility: hidden; }
.listbox-scelta li[aria-selected="true"] .icona-spunta { visibility: visible; }
/* I suggerimenti sotto un campo di testo (il nome dell'attestato): la stessa listbox, agganciata al campo e larga
   come lui. Anche sul telefono resta sotto il campo e non diventa il foglio dal basso: il fuoco è nel campo, la
   tastiera è aperta, e un foglio dal basso starebbe sotto la tastiera. */
.campo-suggerito { position: relative; }
.suggerimenti { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 30; max-height: min(296px, 45vh); margin: 0; overflow-y: auto; padding: 6px; border: 1px solid var(--bordo); border-radius: var(--r-campo); background: var(--superficie); box-shadow: var(--shadow-pop); list-style: none; overscroll-behavior: contain; }
.suggerimenti mark { background: none; color: inherit; font-weight: 700; }

/* Finestra modale (<dialog>): la conferma del preventivo. Il design system la vuole `radius-lg` con `shadow-pop`, il
   titolo in `title-3`. Testa e piede restano fermi, scorre il corpo: «Conferma preventivo» non finisce mai sotto il
   bordo dello schermo. Il velo è quello dei fogli del telefono. Esc la chiude (il browser), il clic fuori no: dentro
   c'è un modulo, e un clic scappato non lo deve buttare. */
.finestra {
  width: min(600px, calc(100vw - 32px)); max-height: calc(100dvh - 48px); padding: 0;
  border: 1px solid var(--bordo); border-radius: var(--radius-lg); background: var(--superficie); color: var(--inchiostro);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}
.finestra[open] { display: flex; flex-direction: column; }
.finestra::backdrop { background: var(--velo); }
/* Si apre crescendo appena, come i popover: solo opacità e transform. Col movimento ridotto la regola generale in
   fondo al file toglie tutto. */
.finestra {
  opacity: 0; transform: translateY(8px) scale(0.98);
  transition-property: opacity, transform, overlay, display;
  transition-duration: 180ms; transition-timing-function: var(--curva); transition-behavior: allow-discrete;
}
.finestra[open] { opacity: 1; transform: none; }
.finestra::backdrop { opacity: 0; transition-property: opacity, overlay, display; transition-duration: 180ms; transition-behavior: allow-discrete; }
.finestra[open]::backdrop { opacity: 1; }
@starting-style {
  .finestra[open] { opacity: 0; transform: translateY(8px) scale(0.98); }
  .finestra[open]::backdrop { opacity: 0; }
}
/* Senza JavaScript arriva aperta dal server, non modale: sta nel flusso della pagina, sopra l'isola. */
.finestra[open]:not(:modal) { position: fixed; inset: 24px 0 auto; z-index: calc(var(--z-azioni) + 1); margin: 0 auto; }
.modulo-finestra { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.finestra-testa { padding: 20px 24px 12px; }
.finestra-testa h2 { margin: 0; font-size: 17px; font-weight: 700; line-height: 24px; }
.finestra-sottotitolo { margin: 2px 0 0; color: var(--inchiostro-2); font-size: 13px; font-weight: 600; }
.finestra-corpo { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: grid; gap: 20px; padding: 4px 24px 20px; }
/* La conferma guidata (banco-conferma.eta): tre passi, uno alla volta. Il passo si dice a parole sotto il titolo, in
   `--inchiostro-2` come il sottotitolo e in 700: il design system non ha un componente a passi. Senza JavaScript i
   passi stanno tutti uno sotto l'altro, e restano «Annulla» e il pulsante finale. */
.passo { display: grid; gap: 20px; align-content: start; }
.finestra-passo { display: none; margin: 8px 0 0; color: var(--inchiostro-2); font-size: 13px; font-weight: 700; }
.passo-nav { display: none; }
.passo-titolo { display: none; margin: 0; font-size: 14px; font-weight: 700; }
@media (scripting: none) { .passo-titolo { display: block; } }
@media (scripting: enabled) {
  .modulo-finestra[data-passo] .finestra-passo { display: block; }
  .modulo-finestra[data-passo="1"] .passo:not(.passo-1),
  .modulo-finestra[data-passo="2"] .passo:not(.passo-2),
  .modulo-finestra[data-passo="3"] .passo:not(.passo-3) { display: none; }
  .modulo-finestra .passo-nav { display: inline-flex; }
  .modulo-finestra:not([data-passo="3"]) .passo-fine { display: none; }
  .modulo-finestra:not([data-passo="1"]) .passo-annulla { display: none; }
}
.finestra-piede { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 24px 16px; border-top: 1px solid var(--bordo); background: var(--superficie); }
/* La proposta della passkey dopo l'accesso (passkey-proposta.eta): una finestra corta, una domanda e due risposte. */
.finestra-stretta { width: min(440px, calc(100vw - 32px)); }
.proposta-passkey-testo { margin: 0; color: var(--inchiostro-2); }
/* Il totale su cui si calcolano le rate: `amount` del design system, e accanto su cosa è calcolato. È il numero che
   si sta accettando, quindi sta in cima, prima dei campi. */
.conferma-totale { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; margin: 0; padding: 12px 16px; border-radius: var(--r-campo); background: var(--superficie-2); }
.conferma-totale strong { font-size: 20px; font-weight: 800; letter-spacing: -0.01em; }
.conferma-totale-etichetta { font-size: 12px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--inchiostro-2); }
.conferma-totale-nota { color: var(--inchiostro-2); font-size: 13px; font-weight: 600; }
/* voci da definire: il trattamento di «da definire», lavoro da fare e non allarme; la parola lo dice */
.avviso { margin: -8px 0 0; padding: 8px 12px; border: 1px dashed var(--bordo-forte); border-radius: var(--r-campo); font-size: 14px; }
/* Un campo del modulo come il TextField del design system: etichetta sopra, sempre visibile. */
.campo-modulo { display: grid; gap: 6px; min-width: 0; margin: 0; padding: 0; border: 0; }
.campo-modulo > label, .campo-modulo > legend { padding: 0; margin-bottom: 0; font-size: 14px; font-weight: 700; }
.campo-modulo > legend { margin-bottom: 6px; }
.campo-modulo .errore { margin: 0; }
.campo-modulo textarea { width: 100%; resize: vertical; }
.campo-data { width: 12em; min-height: 44px; }
/* Il campo data (app.js, DESIGN.md «Campo data»): il TextField con la data all'italiana e, dentro a destra, il pulsante
   del calendario. Il calendario è il popover dei menu: la testa col mese e le frecce, i giorni a pillola (oggi con
   l'anello, il giorno scelto in `--primary`), «Oggi» e «Togli» in fondo. */
.campo-data-ds { display: flex; align-items: center; gap: 4px; min-height: 44px; padding: 0 4px 0 0; border: 1.5px solid var(--bordo-forte); border-radius: var(--r-campo); background: var(--superficie); }
.campo-data-ds:focus-within { border-color: var(--ink); box-shadow: 0 0 0 3px var(--surface-mint); }
.campo-data-ds:has([aria-invalid="true"]) { border-color: var(--errore); }
.campo-data-testo { flex: 1; min-width: 0; padding: 9px 0 9px 12px; border: 0; background: transparent; color: inherit; font: inherit; font-variant-numeric: tabular-nums; outline: none; }
.campo-data-apri { flex: none; width: 36px; height: 36px; }
.campo-data-ds + .errore { margin: 8px 0 0; }
.calendario[popover] { position: fixed; inset: auto; margin: 0; padding: 12px; border: 1px solid var(--bordo); border-radius: var(--r-campo); background: var(--superficie); box-shadow: var(--shadow-pop); color: var(--inchiostro); }
.calendario-testa { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.calendario-mese { margin: 0; font-weight: 800; }
.calendario-mese::first-letter { text-transform: uppercase; }
.icona-avanti { transform: rotate(180deg); }
.calendario-settimana, .calendario-giorni { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; }
.calendario-settimana span { padding: 4px 0; color: var(--inchiostro-2); font-size: 12px; font-weight: 800; letter-spacing: 0.06em; }
.calendario-giorno { aspect-ratio: 1; min-height: 36px; padding: 0; border: 0; border-radius: var(--radius-pill); background: transparent; color: var(--inchiostro); font: inherit; font-variant-numeric: tabular-nums; cursor: pointer; transition: background var(--durata) var(--curva); }
@media (hover: hover) { .calendario-giorno:not(:disabled):hover { background: var(--superficie-2); } }
.calendario-giorno.oggi { box-shadow: inset 0 0 0 1.5px var(--bordo-forte); font-weight: 700; }
.calendario-giorno[aria-pressed="true"] { background: var(--primary); color: var(--on-primary); font-weight: 800; }
.calendario-giorno:disabled { color: var(--bordo-forte); cursor: not-allowed; }
.calendario-giorno:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.calendario-piede { display: flex; justify-content: space-between; gap: 8px; margin-top: 8px; }
.facoltativo { margin-left: 4px; color: var(--inchiostro-2); font-weight: 600; font-size: 13px; }
.aiuto-campo { color: var(--inchiostro-2); font-size: 13px; }
/* un campo col suo errore: il bordo `--danger`, come vuole il TextField; il messaggio sotto dice come correggere */
.finestra [aria-invalid="true"].campo-bordato, .con-suffisso:has([aria-invalid="true"]) { border-color: var(--errore); }
.opzione-radio:has(input[aria-invalid="true"]) { border-color: var(--errore); }
/* Il suffisso del TextField («%»): un campo solo, con l'unità dentro il bordo. Si scrive solo il numero. */
.con-suffisso { display: flex; align-items: center; gap: 4px; padding: 0 12px 0 0; border: 1.5px solid var(--bordo-forte); border-radius: var(--r-campo); background: var(--superficie); }
.con-suffisso:focus-within { border-color: var(--ink); box-shadow: 0 0 0 3px var(--surface-mint); }
.con-suffisso input { flex: 1; min-width: 0; padding: 9px 0 9px 12px; border: 0; background: transparent; text-align: right; font-variant-numeric: tabular-nums; outline: none; }
.suffisso { color: var(--inchiostro-2); font-weight: 600; }
/* la rete (rete.eta): il ricarico è un numero breve, il campo non va a tutta larghezza; alto quanto i campi */
.rete-ricarico-campo { max-width: 160px; min-height: 44px; }
.rete-ricarico .fatto { justify-self: start; }
.riga-rete-richiesta .riga-cruscotto-azione { margin: 0; }
/* Le rate: una riga per rata, a colonne come le righe del documento. L'importo è calcolato, non si scrive: è testo,
   in cifre tabulari e a destra, come ogni importo. */
.schemi-rate { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 4px; }
/* colonne in px e non in em: l'intestazione è a 12px e le righe a 15, e in em non starebbero una sotto l'altra */
.rate-testa, .rata { display: grid; grid-template-columns: minmax(0, 1fr) 96px 128px 64px; gap: 8px; align-items: center; }
.rate-testa { font-size: 12px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--inchiostro-2); }
.rate-testa span:nth-child(n+2), .rata-importo { text-align: right; }
.rate-elenco { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.rata .campo-bordato { width: 100%; min-height: 44px; }
.con-suffisso input { min-height: 41px; }
.rata-importo { font-weight: 700; }
.rata-togli { justify-self: end; min-height: 36px; }
.rata-errore { grid-column: 1 / -1; }
.rate-piede { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* sotto la colonna degli importi: a destra resta la colonna di «Togli» */
.rate-somma { margin: 0 72px 0 0; color: var(--inchiostro-2); font-weight: 700; }
.rate-somma[data-sbagliata] { color: var(--errore); }
/* le rate di scorta sono per chi non ha JavaScript; con JavaScript ci sono «Aggiungi una rata» e gli schemi */
.rata-scorta { display: none; }
@media (scripting: none) {
  .rata-scorta { display: grid; }
  .schemi-rate, .rata-aggiungi, .rata-togli { display: none; }
}
/* Le due schede di un preventivo, «Preventivo | Documenti»: le pillole-link delle viste, sopra il foglio e sopra la
   Card dei documenti. */
.schede-preventivo { margin-bottom: 16px; }
/* Le schede delle sezioni a più pagine (profilo-schede.eta: Profilo, Squadra e sicurezza; impresa-schede.eta: un'impresa
   nell'amministrazione), le stesse pillole-link. In un'impresa la «o» non sta sulla riga delle schede, e il ⋯ resta
   accanto al nome anche sul telefono. Sul telefono stanno su una riga sola che scorre di lato. Nel Profilo, pagina principale, si fermano prima della «o»
   nell'angolo in alto a destra, centrate in altezza con lei: la «o» ha il centro a 42px dal bordo (20 + 8 + 14), la
   pillola alta 36 lo ha a 16 + 8 + 18. Squadra e sicurezza sul telefono è una pagina dentro il Profilo: sotto la
   freccia, come «Preventivo | Documenti». */
.schede-sezione { margin-bottom: 16px; }
@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  .schede-sezione { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; gap: 6px; }
  .barra-principale + .pagina .schede-sezione { margin-top: 8px; margin-right: 40px; }
  .schede-sezione .vista { flex: none; padding-inline: 12px; }
  .schede-sezione::-webkit-scrollbar { display: none; }
  /* la «o» sta già sulla riga delle schede: il titolo ha tutta la larghezza, e il pulsante accanto scende sotto */
  .barra-principale + .pagina .schede-sezione ~ .pagina-testa { padding-right: 0; }
  .pagina .schede-sezione:not(.schede-impresa) ~ .pagina-testa > div:first-child { flex-basis: 100%; }
}
.solo-telefono { display: none; }
@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  .solo-telefono { display: block; }
  .profilo .solo-telefono { margin-bottom: 24px; }
  .profilo .solo-telefono .riquadro-flush { padding-top: 0; }
}
.sk-scheda { width: 120px; height: 36px; border-radius: var(--r-pulsante); }
/* il foglio vuoto della Dashboard e dell'elenco: due righe di testo e «Nuovo preventivo», al centro come quello vero */
.vuoto-grande .sk { margin-inline: auto; }
.sk-pulsante { width: 170px; height: 44px; margin-top: 18px; border-radius: var(--r-pulsante); }
/* L'anteprima del PDF (anteprima.eta): il foglio bianco del cliente, anche col tema scuro, largo quanto un A4 e
   rimpicciolito sul telefono (app.js misura l'iframe e dà al riquadro la sua altezza; prima vale la forma dell'A4). */
.anteprima-foglio {
  position: relative; overflow: hidden; width: 100%; max-width: 796px; aspect-ratio: 210 / 297; margin: 0 auto;
  border: 1px solid var(--bordo); border-radius: var(--r-foglio); background: var(--carta); box-shadow: var(--shadow-card);
}
.anteprima-foglio iframe { position: absolute; top: 0; left: 0; width: 794px; height: 1123px; border: 0; transform-origin: 0 0; }
/* «Condividi» o «Scarica» (anteprima.eta, vedi-documento.eta): sugli schermi da toccare si condivide, come in
   un'app; app.js mette `senza-condividi` dove il browser non sa condividere un file. Deciso qui e non dopo, perché la
   parola non cambi sotto gli occhi quando la pagina è già arrivata. */
[data-condividi] .solo-condividi { display: none; }
@media (pointer: coarse) {
  html:not(.senza-condividi) [data-condividi] .solo-condividi { display: revert; }
  html:not(.senza-condividi) [data-condividi] .solo-scarica { display: none; }
}
.anteprima-avviso, .pagina-anteprima > .errore { max-width: 794px; margin: 0 auto 12px; }
.anteprima-avviso { color: var(--inchiostro-2); font-size: 14px; font-weight: 600; }
/* Una foto tra i documenti (vedi-documento.eta): il nome e da dove viene sopra, la foto intera sotto */
.vedi-testa { margin-bottom: 16px; }
.vedi-testa h1 { margin: 0; font-size: 20px; font-weight: 800; line-height: 1.3; overflow-wrap: anywhere; }
.vedi-testa p { margin: 4px 0 0; color: var(--inchiostro-2); font-size: 14px; }
/* Un PDF tra i documenti: le pagine una sotto l'altra, fogli bianchi come quello dell'anteprima (PDF.js le disegna
   in app.js). Finché non arriva c'è la forma di un A4. */
.vedi-pdf { display: flex; flex-direction: column; gap: 16px; }
.vedi-pagina {
  width: 100%; max-width: 796px; margin: 0 auto; overflow: hidden;
  border: 1px solid var(--bordo); border-radius: var(--r-foglio); background: var(--carta); box-shadow: var(--shadow-card);
}
.vedi-pagina-attesa { aspect-ratio: 210 / 297; }
.vedi-pagina canvas { display: block; width: 100%; height: auto; }
.vedi-pdf-fallito { margin: 0; color: var(--inchiostro-2); font-size: 15px; }
.vedi-immagine { display: block; max-width: 100%; height: auto; margin: 0 auto; border-radius: var(--r-foglio); background: var(--superficie); box-shadow: var(--shadow-card); }
/* I documenti del preventivo, nella loro pagina: una Card del design system con le righe della Dashboard
   (`.riga-cruscotto`). Il pulsante «Carica un documento» è il secondario piccolo: il campo del file è nascosto
   dentro l'etichetta, e l'anello del fuoco lo porta l'etichetta, che è ciò che si vede. */
.carica-documento { flex: none; }
.carica-documento .btn { cursor: pointer; }
.carica-documento .btn:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }
.carica-senza-js, .solo-senza-js { display: none; }
@media (scripting: none) {
  .carica-documento { display: flex; gap: 8px; }
  .carica-senza-js, .solo-senza-js { display: inline-flex; }
}
#errore-documenti:empty { display: none; }
#errore-documenti .errore { margin: 16px 24px 0; }
/* il ⋯ del documento sta sopra il link che copre la riga, e si vede sempre: sul telefono non c'è il passaggio */
.riga-documento .btn-icona { color: var(--inchiostro-2); }
/* il documento appena caricato si accende e si spegne, come un prezzo appena applicato */
.riga-documento.appena-caricato { animation: evidenzia-riga 1.6s var(--curva); }
/* le condizioni di pagamento nel pannello del cliente, sotto «Accettato il…» */
.pagamento-stato { text-wrap: pretty; }

/* aggiungi una lavorazione */
.aggiungi { margin: 8px 40px 0; }
.aggiungi-campo { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border: 1px dashed var(--bordo-forte); border-radius: var(--r-riga); color: var(--inchiostro-2); }
.aggiungi-campo:focus-within { border-color: var(--ink); border-style: solid; box-shadow: 0 0 0 3px var(--surface-mint); }
.aggiungi-campo input { flex: 1; min-width: 0; border: 0; background: transparent; color: var(--inchiostro); outline: none; }
.aggiungi-risultati:empty { display: none; }
.aggiungi-risultati { margin-top: 6px; padding: 6px; border: 1px solid var(--bordo); border-radius: var(--r-riga); }

/* riepilogo */
.riepilogo { display: flex; justify-content: flex-end; padding: 20px 40px 32px; }
.riepilogo table { border-collapse: collapse; font-size: 15px; font-variant-numeric: tabular-nums; }
.riepilogo td { padding: 3px 0 3px 32px; text-align: right; }
.riepilogo td:first-child { padding-left: 0; color: var(--inchiostro-2); text-align: left; }
.riepilogo .da-definire td { color: var(--manca); font-weight: 600; }
/* il totale è il numero più visibile della schermata: `amount-l` del design system */
.riepilogo .totale td { padding-top: 10px; color: var(--inchiostro); font-size: 32px; font-weight: 800; line-height: 40px; letter-spacing: -0.02em; }

/* revisione dei set di valutazione */
.voce-rev-testa { display: grid; grid-template-columns: 56px 1fr 170px 150px; gap: 12px; align-items: start; }
.freq { font-weight: 700; }
.stato-verifica { font-size: 13.5px; font-weight: 600; }
.stato-verifica.ok { color: var(--ok); }
.stato-verifica.no { color: var(--errore); }
.stato-verifica.attesa { color: var(--inchiostro-2); }
.avanzamento { display: flex; align-items: center; gap: 12px; }
.avanzamento-traccia { width: 200px; height: 6px; overflow: hidden; border-radius: 3px; background: var(--superficie-2); }
.avanzamento-traccia span { display: block; height: 100%; background: var(--accento); }
.candidato { display: grid; grid-template-columns: 24px 1fr; gap: 8px; padding: 10px; border: 1px solid transparent; border-radius: var(--r-campo); }
@media (hover: hover) { .candidato:hover { background: var(--superficie-2); } }
.candidato:has(input:checked) { border-color: var(--accento); background: var(--accento-tenue); }
.candidato-descr { font-size: 13.5px; white-space: pre-line; }

/* Il nuovo preventivo: la chat con Bolla (guidato.eta, DESIGN.md «Nuovo preventivo: la chat»). La forma di «Chiedi a
   Bolla» nel banco: chi scrive a destra, in una bolla `--superficie-2`; Bolla a sinistra con la sua «o», il testo
   sul fondo della pagina. In fondo, fermo sopra le schede, il posto per rispondere. Finite le domande si va dritti
   alla bozza, nel banco. */
.pagina.pagina-chat { max-width: 760px; padding-bottom: 16px; }
/* la chat riempie lo schermo: con pochi messaggi il posto per rispondere sta comunque in fondo */
.chat { display: flex; flex-direction: column; min-height: calc(100dvh - 56px); }
/* la chat nuova ha la barra con la freccia (65 px) e il margine della pagina (24): senza toglierli la pagina è più alta
   dello schermo, e aprendosi in fondo nasconde il titolo sotto la barra */
.barra-interna + .pagina-chat .chat { min-height: calc(100dvh - 105px); }
.chat-testa { margin-bottom: 20px; }
.chat-testa h1 { margin: 0; font-size: 28px; font-weight: 800; line-height: 36px; letter-spacing: -0.015em; }
.chat-numero { color: var(--inchiostro-2); font-size: 16px; font-weight: 700; letter-spacing: 0; }
/* per chi è il preventivo, sotto il titolo: una riga di contesto, non un riquadro che rubi la scena */
.per-cliente { margin: 4px 0 0; color: var(--inchiostro-2); font-size: 14px; }
.per-cliente strong { color: var(--inchiostro); font-weight: 600; }
.chat-messaggi { flex: 1; display: flex; flex-direction: column; gap: 16px; margin: 0; padding: 0 0 20px; list-style: none; }
.msg { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }
.msg-corpo { display: grid; gap: 6px; min-width: 0; }
.msg-corpo > p { margin: 0; text-wrap: pretty; }
.msg-bolla { max-width: 92%; }
.msg-bolla > .marchio-bolla { flex: none; width: 22px; height: 20px; margin-top: 2px; }
.msg-nota { color: var(--inchiostro-2); font-size: 14px; }
/* chi scrive: a destra, la bolla del messaggio, e sotto l'azione per cambiarlo */
.msg-tu { flex-direction: column; align-items: flex-end; gap: 4px; align-self: flex-end; max-width: 85%; }
.msg-tu .msg-corpo { padding: 10px 14px; border-radius: 16px 16px 4px 16px; background: var(--superficie-2); }
.msg-testo { white-space: pre-line; overflow-wrap: anywhere; }
/* la conversazione del preventivo (rete-conversazione.eta): le altre imprese a sinistra, col nome sopra, nel fumetto
   bordato della Card; sotto ogni messaggio quando, e il collega che l'ha scritto */
/* i propri messaggi nel fumetto pieno, col colore dell'azione principale: si distinguono dagli altri a colpo d'occhio */
.conversazione .msg-tu .msg-corpo { background: var(--primary); color: var(--on-primary); }
.conversazione .msg-tu .msg-quando { text-align: right; }
.conversazione .msg-autore { color: var(--accent-ink); }
.msg-impresa { flex-direction: column; align-items: flex-start; gap: 4px; align-self: flex-start; max-width: 85%; }
.msg-impresa .msg-corpo { padding: 10px 14px; border: 1px solid var(--bordo); border-radius: 16px 16px 16px 4px; background: var(--superficie); }
.msg-autore { margin: 0 4px; color: var(--inchiostro); font-size: 13px; font-weight: 700; }
.msg-quando { margin: 0 4px; color: var(--inchiostro-2); font-size: 12.5px; }
.conversazione .chat-testa .occhiello { margin: 0 0 4px; color: var(--inchiostro-2); font-size: 12px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; }
.msg-azione { padding: 2px 4px; border: 0; background: none; color: var(--inchiostro-2); font-size: 13px; font-weight: 700; text-decoration: none; cursor: pointer; }
@media (hover: hover) { .msg-azione:hover { color: var(--inchiostro); text-decoration: underline; text-underline-offset: 3px; } }
.chat-cambia { display: contents; }
.msg-largo { max-width: 100%; }
.msg-largo .msg-corpo { flex: 1; }
.msg-errore .errore { margin: 0; }
/* la domanda di adesso: la frase che si deve leggere, un po' più grande delle altre */
.domanda-ai { margin: 0; font-size: 18px; font-weight: 600; line-height: 1.4; text-wrap: pretty; }
.etichetta-chiarimento { width: fit-content; padding: 2px 10px; border-radius: 999px; background: var(--accent-soft); color: var(--accent-ink); font-size: 13px; font-weight: 700; }
/* il tipo che l'AI ha letto nella descrizione: il chip dell'AI del design system */
.proposto { margin-right: 4px; padding: 1px 8px; border-radius: var(--r-pulsante); background: var(--accent-soft); color: var(--accent-ink); font-size: 13px; font-weight: 700; white-space: nowrap; }
/* «So già»: quello che Bolla ha capito, in pillole che si toccano per cambiarlo */
.so-gia { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 13.5px; }
.so-gia-titolo { margin-right: 2px; color: var(--inchiostro-2); }
.pillola-so { min-height: 32px; padding: 0 12px; border: 1px solid var(--bordo); border-radius: 999px; background: var(--superficie); font-size: 13.5px; }
@media (hover: hover) { .pillola-so:hover { border-color: var(--accento); background: var(--accento-tenue); } }
/* i puntini di Bolla mentre pensa: solo durante una risposta (la mette app.js, e htmx con la sua richiesta) */
.msg-scrive { display: none; }
.chat.chat-in-attesa .msg-scrive, .chat:has(.chat-scrivi.htmx-request) .msg-scrive, html.pagina-in-attesa .chat .msg-scrive { display: flex; }
.puntini { display: inline-flex; gap: 4px; padding: 8px 0; }
.puntini span { width: 7px; height: 7px; border-radius: 50%; background: var(--inchiostro-2); opacity: 0.35; }
@media (prefers-reduced-motion: no-preference) {
  .puntini span { animation: puntino 1.2s ease-in-out infinite; }
  .puntini span:nth-child(2) { animation-delay: 0.15s; }
  .puntini span:nth-child(3) { animation-delay: 0.3s; }
}
@keyframes puntino { 30% { opacity: 1; transform: translateY(-2px); } 60% { opacity: 0.35; transform: none; } }
/* il messaggio appena mandato, prima della risposta: già al suo posto, un poco più chiaro */
.msg-in-volo .msg-corpo { opacity: 0.7; }
/* Il posto per rispondere: in fondo alla chat, fermo in basso mentre si scorre. Le risposte rapide sopra il campo */
.chat-scrivi { position: sticky; bottom: 0; z-index: 2; display: grid; gap: 10px; margin: 0 -8px; padding: 12px 8px calc(12px + env(safe-area-inset-bottom)); background: linear-gradient(to bottom, transparent, var(--fondo) 16px); }
.chat-scrivi .errore { margin: 0; }
/* `--riga-chat`: l'altezza dei pulsanti nel campo (40 px, 44 col dito). Il campo di testo vuoto, o con una riga, è alto
   uguale: il testo sta a metà dei pulsanti. Con più righe cresce, e i pulsanti restano in fondo, accanto all'ultima. */
.chat-campo { --riga-chat: 40px; min-width: 0; display: flex; align-items: flex-end; gap: 8px; padding: 6px 6px 6px 16px; border: 1.5px solid var(--bordo-forte); border-radius: 24px; background: var(--superficie); transition: border-color var(--durata) var(--curva), box-shadow var(--durata) var(--curva); }
.chat-campo:focus-within { border-color: var(--inchiostro); box-shadow: 0 0 0 3px var(--surface-mint); }
/* la larghezza è fissata (width: 0 e flex: 1, cioè lo spazio che resta): field-sizing allarga solo le misure lasciate
   libere, e così il campo cresce in altezza e mai in larghezza, anche con una parola lunga che non va a capo da sola
   (un indirizzo, un codice). Quella si spezza dove capita. */
.campo-chat { flex: 1 1 0; width: 0; min-width: 0; overflow-wrap: anywhere; min-height: var(--riga-chat); max-height: 40vh; padding: calc((var(--riga-chat) - 1.45em) / 2) 0; border: 0; outline: 0; background: none; color: var(--inchiostro); font: inherit; font-size: 16px; line-height: 1.45; resize: none; field-sizing: content; }
.campo-chat::placeholder { color: var(--inchiostro-2); }
/* vuoto, il campo è una riga sola: il segnaposto non lo allarga (con field-sizing il campo si misurerebbe anche su di
   lui) e, se non ci sta, finisce coi puntini. Cresce solo col testo scritto, fino a 40vh */
.campo-chat:placeholder-shown { field-sizing: fixed; height: var(--riga-chat); overflow: hidden; }
.campo-chat:placeholder-shown::placeholder { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-manda { flex: none; min-height: var(--riga-chat); padding: 0 16px 0 12px; }
/* La voce: il microfono è il pulsante icona del design system, dentro il campo accanto al pulsante per mandare.
   Registrando il campo lascia il posto a «Ti ascolto», col punto `--danger` che pulsa e i secondi, e il microfono
   diventa il quadrato pieno per fermare (l'azione principale di quel momento, `--primary`); trascrivendo, lo spinner. */
.chat-voce { flex: none; width: var(--riga-chat); height: var(--riga-chat); }
.chat-voce .icona { width: 20px; height: 20px; }
.chat-voce .spinner { width: 18px; height: 18px; }
.chat-ascolto { flex: 1; display: flex; align-items: center; gap: 8px; min-width: 0; min-height: var(--riga-chat); color: var(--inchiostro); font-size: 16px; font-weight: 600; }
.ascolto-punto { flex: none; width: 10px; height: 10px; border-radius: 50%; background: var(--danger); }
.ascolto-tempo { color: var(--inchiostro-2); font-variant-numeric: tabular-nums; }
.ascolto-annulla { margin-left: auto; }
.chat-campo.in-ascolto .campo-chat, .chat-campo.in-ascolto .chat-manda { display: none; }
.chat-campo.in-ascolto .chat-voce { background: var(--primary); color: var(--on-primary); transition: background var(--durata) var(--curva); }
.chat-campo.in-trascrizione .chat-voce .icona { display: none; }
.chat-campo.in-trascrizione .chat-voce .spinner { display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
  .chat-campo.in-ascolto .ascolto-punto { animation: ascolto 1.2s ease-in-out infinite; }
}
@keyframes ascolto { 50% { opacity: 0.35; } }
.chat-manda .icona { width: 18px; height: 18px; }
.rapide { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; border: 0; }
.rapida { min-height: 36px; padding: 0 14px; border: 1.5px solid var(--bordo-forte); border-radius: var(--r-pulsante); background: var(--superficie); font-size: 14px; font-weight: 600; }
@media (hover: hover) { .rapida:hover { border-color: var(--accento); background: var(--accento-tenue); } }
/* il tipo segnato (proposto dalla descrizione, o scelto prima): pieno come lo stato attivo del design system */
.rapida-scelta { border-color: var(--accento); background: var(--accento-tenue); }
/* «Non lo so» e «Altro» non sono risposte come le altre: tratteggiate, come la pillola senza prezzo */
.rapida-neutra { border-style: dashed; color: var(--inchiostro-2); }
.chat-meta { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 12px; margin: 0; color: var(--inchiostro-2); font-size: 13.5px; }
.chat-meta:only-child { justify-content: flex-end; }
.mancano { color: var(--inchiostro-2); font-size: 13.5px; }
.chat-azioni { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 0; }
/* le lavorazioni lette da Bolla (guidato.eta, «Altro»): pillole spuntate una sotto l'altra, col testo che va a capo */
.lavorazioni-lette { display: grid; gap: 12px; margin-top: 8px; }
.lavorazioni-elenco { display: grid; gap: 8px; margin: 0; padding: 0; border: 0; min-width: 0; }
.lavorazioni-elenco .opzione-radio { justify-content: flex-start; padding-block: 8px; line-height: 20px; border-radius: var(--r-campo); }
.lavorazioni-elenco .opzione-radio:has(input:checked) { font-weight: 600; }
.lavorazioni-elenco input { flex: none; }
/* Il capitolato (nuovo-capitolato-file.eta): le voci lette sotto il messaggio di bolla, coi capitoli sopra. */
.nuovo-preventivo .pannello-ai ~ .riquadro, .nuovo-preventivo .riquadro + .riquadro { margin-top: 24px; }
.capitolato-capitolo { margin: 8px 0 0; color: var(--ink-muted); }
/* la scelta di «Nuovo preventivo» e del capitolato: una Card con le sole righe, senza testata sopra */
.nuovo-preventivo .riquadro-flush { padding-top: 0; }
.nuovo-preventivo .riquadro-corpo:empty { display: none; }
.nuovo-preventivo .riquadro-flush .riga-cruscotto:first-child { border-top: 0; }
.capitolato-capitolo:first-of-type { margin-top: 0; }
.lavorazione-misura { color: var(--inchiostro-2); font-weight: 400; }
/* L'ultimo messaggio, la bozza pronta: l'AiPanel del design system (`--accent-soft`, `radius-xl`, l'occhiello in
   `--accent-ink`, il segno della fiala in un cerchio `--superficie`). La linea in fondo, in `--accent` (è di Bolla),
   si riempie nel tempo che manca al passaggio al banco (ATTESA_BOZZA in app.js). */
.msg-proposta { display: block; }
.pannello-ai { display: grid; gap: 16px; padding: 20px 24px; border-radius: var(--r-pannello); background: var(--accent-soft); color: var(--inchiostro); }
.pannello-ai-testa { display: flex; align-items: center; gap: 12px; }
.pannello-ai-segno { display: inline-grid; place-items: center; flex: none; width: 36px; height: 36px; border-radius: 999px; background: var(--superficie); }
.pannello-ai-segno .marchio-bolla { width: 20px; height: 18px; }
.pannello-ai-occhiello { margin: 0; color: var(--accent-ink); font-size: 12px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; }
.pannello-ai h2 { margin: 0; font-size: 17px; font-weight: 800; line-height: 24px; }
.pannello-ai-corpo { margin: 0; }
.pannello-ai-azioni { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
.pannello-ai-nota { color: var(--inchiostro-2); font-size: 14px; }
.pannello-ai-avanza { height: 4px; overflow: hidden; border-radius: 2px; background: var(--superficie); }
.pannello-ai-avanza span { display: block; height: 100%; background: var(--accent); transform-origin: left; transform: scaleX(0); }
@media (prefers-reduced-motion: no-preference) {
  .pannello-ai-avanza span { animation: bozza-avanza 2.4s linear forwards; }
  .msg-proposta { animation: bozza-entra 320ms cubic-bezier(0.16, 1, 0.3, 1) both; }
}
@media (prefers-reduced-motion: reduce) { .pannello-ai-avanza { display: none; } }
@keyframes bozza-avanza { to { transform: scaleX(1); } }
@keyframes bozza-entra { from { opacity: 0; transform: translateY(12px) scale(0.98); } }
.aiuto { max-width: 65ch; margin: 0 0 20px; color: var(--inchiostro-2); }
.campi { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 20px 24px; }
.campo-guidato { min-width: 0; margin: 0; padding: 0; border: 0; }
.campo-guidato > label, .campo-guidato > legend { display: block; margin-bottom: 6px; padding: 0; font-size: 14px; font-weight: 700; }
.con-unita { display: flex; align-items: center; gap: 8px; }
.con-unita input { width: 9em; text-align: right; }
.campo-guidato small { display: block; margin-top: 4px; color: var(--inchiostro-2); font-size: 12.5px; }
/* selettore più specifico di `.campo-guidato small`, che altrimenti vincerebbe sul colore. Il valore l'ha letto
   l'AI dalla descrizione: testo arancio del design system (`--accent-ink`) */
.campo-guidato .da-descrizione { color: var(--accent-ink); font-size: 12.5px; font-weight: 600; }
/* la lettura della descrizione non è riuscita: una riga tenue, non un riquadro d'errore */
.lettura-fallita { margin: 0 0 16px; color: var(--inchiostro-2); font-size: 14px; }
.opzioni-radio { display: flex; flex-wrap: wrap; gap: 8px; }
.opzione-radio { display: inline-flex; align-items: center; gap: 8px; min-height: 36px; padding: 0 14px; border: 1.5px solid var(--bordo-forte); border-radius: var(--r-pulsante); background: var(--superficie); cursor: pointer; }
.opzione-radio:has(input:checked) { border-color: var(--accento); background: var(--accento-tenue); color: var(--inchiostro); font-weight: 700; }
.opzione-radio:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }
/* un solo indicatore di focus (quello dell'etichetta sopra): il radio nativo non ne mostra un secondo */
.opzione-radio input:focus-visible { outline: none; }
.scheda-nome { font-weight: 700; }

/* La prima pagina: due schede, che stanno in una schermata. A sinistra, più larga, quello che c'è da fare; a destra
   come vanno i preventivi. Ogni blocco è una Card del design system (`.riquadro`): `--surface`, bordo `--border`,
   `radius-lg`, `shadow-card`, titolo `title-2`, sottotitolo `small` in `--ink-muted`. */
.cruscotto-griglia { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 24px; align-items: start; }
/* la colonna di destra: le notifiche sopra l'andamento */
.cruscotto-colonna { display: grid; gap: 24px; min-width: 0; }
.riquadro-nota-azioni { display: flex; justify-content: flex-start; padding: 12px 8px 16px; border-top: 1px solid var(--bordo); }
/* senza preventivi la Dashboard è il benvenuto: le notifiche, se ci sono, gli stanno sopra */
.cruscotto > .riquadro-notifiche { margin-bottom: 24px; }
/* la pagina delle notifiche: avanti e indietro tra le pagine di trenta */
.notifiche-pagine { display: flex; justify-content: center; gap: 8px; margin-top: 16px; }
/* una Card senza testa: le righe partono dal bordo di sopra */
.notifiche-pagina .riquadro-flush { padding-top: 0; }
.notifiche-pagina .riquadro-flush .riga-cruscotto:first-child { border-top: 0; }
.riquadro { min-width: 0; overflow: hidden; border: 1px solid var(--bordo); border-radius: var(--radius-lg); background: var(--superficie); box-shadow: var(--shadow-card); }
/* testa e corpo come `bo-card-head` e `bo-card-body`: 20px 24px sopra, il corpo 20px 24px 24px */
.riquadro-testa { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 20px 24px 0; }
.riquadro h2 { margin: 0; font-size: 20px; line-height: 28px; font-weight: 800; letter-spacing: -0.01em; }
.riquadro-sotto { margin: 2px 0 0; color: var(--inchiostro-2); font-size: 13px; line-height: 18px; font-weight: 600; }
.riquadro-testa .btn { flex: none; }
.riquadro-corpo { padding: 20px 24px 24px; }
/* la variante `flush` della Card: le righe vanno da bordo a bordo, e il loro padding sta dentro la riga */
.riquadro-flush { padding: 16px 0 0; }
/* una Card fatta di sole righe, senza testa (la conversazione nella pagina della richiesta): niente spazio né riga sopra */
.riquadro > .riquadro-flush:first-child { padding-top: 0; }
.riquadro > .riquadro-flush:first-child .riga-cruscotto:first-child { border-top: 0; }
.riquadro-vuoto { margin: 0; color: var(--inchiostro-2); }
/* Una riga: che preventivo (titolo e dettagli), poi quello che la riga ha da dire (etichetta, importo, un pulsante
   quando l'azione non è aprire) e la freccia in un cerchio delle schede dell'elenco. Cliccabile per intero: il
   titolo è il link e si stende sulla riga; il pulsante ci sta sopra. Al passaggio il fondo `--surface-mint` e il
   cerchio pieno, come le schede dell'elenco; col fuoco da tastiera l'anello è della riga. */
.righe-cruscotto { margin: 0; padding: 0; list-style: none; }
.riga-cruscotto { position: relative; display: flex; align-items: center; gap: 12px; min-height: 64px; padding: 12px 20px 12px 24px; border-top: 1px solid var(--bordo); transition: background var(--durata) var(--curva); }
@media (hover: hover) { .riga-cruscotto:hover { background: var(--superficie-2); } }
.riga-cruscotto:focus-within .opzione-vai { background: var(--primary); color: var(--on-primary); }
@media (hover: hover) { .riga-cruscotto:hover .opzione-vai { background: var(--primary); color: var(--on-primary); } }
.riga-cruscotto:has(.riga-cruscotto-titolo:focus-visible) { outline: 2px solid var(--focus); outline-offset: -2px; }
.riga-cruscotto-corpo { display: grid; flex: 1; gap: 2px; min-width: 0; }
.riga-cruscotto-titolo { color: var(--inchiostro); font-weight: 700; text-decoration: none; overflow-wrap: anywhere; }
/* una notifica già letta: il titolo meno pesante, così le nuove si vedono anche senza leggere l'etichetta */
.riga-letta .riga-cruscotto-titolo { font-weight: 600; }
.riga-cruscotto-titolo:focus-visible { outline: none; }
.riga-cruscotto-titolo::after { content: ""; position: absolute; inset: 0; }
/* un titolo che non è un link (una voce, un prezzo da applicare) non copre la riga: dentro ci sono campi da toccare */
span.riga-cruscotto-titolo::after { content: none; }
.riga-cruscotto-meta { color: var(--inchiostro-2); font-size: 13px; line-height: 18px; font-weight: 600; overflow-wrap: anywhere; }
.riga-cruscotto .stato { flex: none; }
.riga-cruscotto-azione { position: relative; z-index: 1; flex: none; }
.riga-cruscotto .opzione-vai { width: 32px; height: 32px; }

/* Gli attestati (lavoratore.eta): le righe della Dashboard, ma la riga non è un link (non apre niente di suo): il nome
   è testo, il file un link nella riga dei dettagli, e sotto, chiuso, il modulo del rinnovo a tutta larghezza. */
.attestati .riquadro + .riquadro, .attestati .fatto + .riquadro { margin-top: 24px; }
/* l'avviso della revisione appena aperta, sopra il foglio; poi le revisioni passate sotto i documenti, un'altra Card */
.avviso-revisione { margin: 0 0 16px; }
.pagina-documenti .riquadro + .riquadro { margin-top: 24px; }
/* i dati del contratto, il terzo passo della conferma: un gruppo di campi come gli altri */
.contratto-campi { gap: 12px; }
/* La finestra del POS (banco-pos.eta). L'impresa appaltatrice serve solo a una subappaltatrice: scelta
   «Appaltatrice», il campo sparisce. Le lavorazioni sono pillole come le altre scelte, ma i nomi del POS sono lunghi e
   vanno a capo: la pillola cresce in altezza e il testo resta a sinistra. */
.modulo-finestra:has(input[name="ruolo"][value="APPALTATRICE"]:checked) .pos-appaltatrice { display: none; }
.pos-figura-nuova { display: none; gap: 12px; margin-top: 12px; padding-left: 12px; border-left: 2px solid var(--bordo); }
.pos-figura:has(.pos-figura-scegli-nuova:checked) .pos-figura-nuova { display: grid; }
.pos-gruppo .opzione-radio, .passo-1 .opzione-radio { padding-block: 7px; line-height: 20px; }
.pos-attestati { display: grid; gap: 8px; margin: -8px 0 0; padding: 0; list-style: none; font-size: 14px; }
.pos-attestati li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 12px; }
.pos-proposte { margin: 0; }
.pos-altre { display: grid; gap: 20px; }
.pos-altre > summary { justify-self: start; list-style: none; }
.pos-altre > summary::-webkit-details-marker { display: none; }
.pos-altre[open] > summary { margin-bottom: 0; }
/* il riepilogo dello scadenziario chiude con quello che manca in grassetto, come un totale */
.andamento-totale { margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--bordo); }
.andamento-totale dt { color: var(--inchiostro); font-weight: 700; }
/* lo scadenziario: una riga per rata, divise da un filo come le righe della Dashboard, ma senza freccia (la riga non
   porta altrove): che rata è e quanto, lo StatusBadge, e a destra la scadenza e «Segna incassata» */
/* Lo scadenziario (pagamenti-rate.eta): il riepilogo e le rate, due Card una sotto l'altra. Una rata è una riga
   della Dashboard che non si apre: niente fondo al passaggio; sotto quanto e lo stato, «Scade il» e «Segna
   incassata» su una riga loro, a destra. Una rata incassata ha solo il menu ⋯. */
.pagamenti .riquadro + .riquadro { margin-top: 24px; }
.riga-rata { flex-wrap: wrap; row-gap: 12px; }
@media (hover: hover) { .riga-rata:hover { background: none; } }
/* il titolo non è un link: senza il velo che rende cliccabile la riga, che coprirebbe la data e i pulsanti */
.riga-rata .riga-cruscotto-titolo::after { content: none; }
.riga-rata-azioni { display: flex; flex-basis: 100%; flex-wrap: wrap; align-items: end; justify-content: flex-end; gap: 12px; margin: 0; }
.riga-rata-scade { margin-right: auto; }
.riga-rata-scade label { font-size: 14px; font-weight: 700; }
.attestati .fatto { margin-bottom: 16px; }
/* l'amministrazione (amministrazione.eta, impresa.eta): le Card una sotto l'altra, come la squadra */
.amministrazione .riquadro + .riquadro, .amministrazione .fatto + .riquadro, .amministrazione .errore + .riquadro, .amministrazione .pannello-ai + .riquadro, .amministrazione .fatto + .pannello-ai { margin-top: 24px; }
.amministrazione .riquadro-testa .btn-icona { flex: none; }
.amministrazione > .fatto, .amministrazione > .errore { margin-bottom: 16px; }
.amministrazione .riquadro-testa .btn { flex: none; }
.amministrazione .pagina-testa > div:first-child { flex: 1; min-width: 0; }
.impresa-stato, .storico-impresa { display: grid; gap: 16px; }
.impresa-stato p, .storico-impresa p { margin: 0; }
/* lo storico caricato: quanti preventivi e righe, e sotto, più piano, quando e come sta la ricerca */
.storico-conti { font-weight: 700; }
.storico-quando { color: var(--inchiostro-2); font-size: 14px; }
/* le righe di un modello di lavoro: il prezzo dallo storico a destra, come l'importo di un preventivo nell'elenco;
   senza prezzo «da definire», come nel banco. Sul telefono va sotto, allineato alle parole */
.riga-modello .riga-cruscotto-titolo { font-weight: 600; }
.riga-modello-prezzo { flex: none; font-weight: 700; font-variant-numeric: tabular-nums; text-align: right; }
.riga-modello-prezzo.da-definire { color: var(--manca); font-weight: 600; }
/* salva e prova, affiancati come i pulsanti di un modulo */
.azioni-modulo { display: flex; flex-wrap: wrap; gap: 8px; }
.impresa-stato form { margin: 0; }
/* il logo dell'impresa, su bianco come sulla carta del cliente, alto quanto sul preventivo */
.logo-impresa { display: grid; gap: 16px; }
/* sulla scacchiera, il segno di ogni programma d'immagini per «qui è trasparente» */
.logo-anteprima {
  display: flex; align-items: center; justify-content: center; min-height: 96px; padding: 16px; border: 1px solid var(--bordo); border-radius: var(--r-campo);
  background: repeating-conic-gradient(var(--scacchi) 0 25%, var(--carta) 0 50%) 0 0 / 16px 16px;
}
.logo-sfondo { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 0; color: var(--inchiostro-2); font-size: 14px; font-weight: 600; }
.logo-togli { justify-self: start; }
.logo-anteprima img { display: block; max-width: 100%; max-height: 72px; }
/* un utente: il nome non apre niente (la riga non è un link), le azioni stanno nel ⋯ */
@media (hover: hover) { .riga-utente:hover { background: none; } }
/* il link d'accesso appena creato, una volta sola: cosa è, il link da copiare, e che lo manda chi l'ha creato */
.link-accesso { display: grid; gap: 8px; padding-bottom: 8px; }
.link-accesso .campo-bordato { width: 100%; min-height: 44px; font-size: 14px; }
.aggiungi-utente { border-top: 1px solid var(--bordo); }
.aggiungi-utente h3 { margin: 0; }
/* la squadra (squadra.eta, lavoratore.eta): le Card una sotto l'altra, come negli attestati */
.squadra .riquadro + .riquadro, .squadra .fatto + .riquadro, .rete .riquadro + .riquadro, .rete .fatto + .riquadro { margin-top: 24px; }
.squadra .fatto, .rete .fatto { margin-bottom: 16px; }
/* il titolo prende la riga; sul telefono le azioni (Accetta e prepara, ⋯) vanno sotto invece di stringerlo */
.rete .pagina-testa > div:first-child { flex: 1 1 320px; min-width: 0; }
.rete .errore + .riquadro { margin-top: 16px; }
/* la richiesta di prezzo (rete-nuova.eta, rete-richiesta.eta): le Card una sotto l'altra, i campi in colonna */
.modulo-richiesta .riquadro + .riquadro { margin-top: 24px; }
.modulo-campi { display: grid; gap: 16px; }
.modulo-campi textarea { resize: vertical; }
.modulo-piede { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin-top: 24px; }
.dati-richiesta { display: grid; gap: 12px; margin: 0; }
.dati-richiesta > div { display: grid; grid-template-columns: 136px 1fr; gap: 12px; }
.dati-richiesta dt { color: var(--inchiostro-2); font-size: 14px; font-weight: 600; }
.dati-richiesta dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.dato-nascosto { color: var(--inchiostro-2); font-style: italic; }
.dato-nota { white-space: pre-line; }
.voce-quantita { flex: none; color: var(--inchiostro-2); white-space: nowrap; }
.riga-voce-richiesta .riga-cruscotto-titolo { white-space: normal; }
/* il preventivo dell'edile: le richieste mandate, sotto il foglio */
.banco-rete { margin-top: 24px; }
.proposta-rete { margin-top: 24px; }
.pos-rete-azioni { display: flex; flex-wrap: wrap; gap: 8px; }
.sicurezza-esenzione { justify-self: start; margin-top: 4px; }
.avvisi-impresa { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px; }
.voci-cambiate { display: grid; gap: 12px; }
.applica-prezzi { display: grid; gap: 16px; }
.prezzi-rete-righe { display: grid; gap: 12px; }
.prezzi-rete-righe .righe-cruscotto { border-block: 1px solid var(--bordo); }
.prezzi-rete-al-posto { margin: 0; color: var(--inchiostro-2); font-size: 14px; }
.prezzi-rete-al-posto s { text-decoration-thickness: 1px; }
.prezzi-rete-totale { margin: 0; color: var(--inchiostro-2); }
.prezzi-rete-totale strong, .prezzo-rete { color: var(--inchiostro); }
.ricarico-riga { margin-top: 6px; }
.ricarico-riga > summary { width: fit-content; color: var(--inchiostro-2); font-size: 13px; font-weight: 700; cursor: pointer; }
.ricarico-riga[open] > summary { margin-bottom: 6px; }
.voci-cambiate-titolo { margin: 0; }
.voci-cambiate .righe-cruscotto { border: 1px solid var(--bordo); border-radius: var(--r-campo); }
.voci-cambiate .aiuto-campo { margin: 0; }
.squadra .riquadro-testa .btn { flex: none; }
.squadra .pagina-testa > div:first-child { flex: 1; min-width: 0; }
.riga-attestato { flex-wrap: wrap; }
@media (hover: hover) { .riga-attestato:hover { background: none; } }
.riga-attestato .riga-cruscotto-titolo::after { content: none; }
.riga-attestato .riga-cruscotto-meta a { color: var(--inchiostro); font-weight: 700; }
.attestato-modifica { flex-basis: 100%; }
.attestato-modifica > summary { list-style: none; width: fit-content; cursor: pointer; }
.attestato-modifica > summary::-webkit-details-marker { display: none; }
.attestato-modifica[open] > summary { margin-bottom: 12px; }
.riquadro-rinnovi { margin-bottom: 24px; }
/* i moduli degli attestati: etichetta sopra, come TextField del design system; le due date affiancate */
.modulo-attestato { display: grid; gap: 16px; margin: 0; }
.campo-etichettato { display: grid; gap: 6px; min-width: 0; }
.campo-etichettato > label { font-size: 14px; font-weight: 700; }
.campo-etichettato .campo-bordato { width: 100%; min-height: 44px; }
.facoltativo { color: var(--inchiostro-2); font-weight: 600; }
.campi-affiancati { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
.etichetta-campo { font-size: 14px; font-weight: 700; }
/* le domande di un modello per il foglio del sopralluogo (impresa-modello-cantiere.eta): ogni domanda è un gruppo, con
   sopra quella del percorso guidato, divisi da una linea */
.cantiere-domanda { display: grid; gap: 12px; min-width: 0; margin: 0; padding: 0 0 16px; border: 0; border-bottom: 1px solid var(--bordo); }
.cantiere-domanda > legend { padding: 0; margin-bottom: 12px; color: var(--inchiostro-2); font-size: 13px; font-weight: 600; }
.cantiere-domanda:last-of-type { padding-bottom: 0; border-bottom: 0; }
.modulo-cantiere-azioni { display: flex; flex-wrap: wrap; gap: 8px; }
/* il file dell'attestato: il componente di «Carica un documento» (il secondario piccolo, il campo nascosto dentro,
   l'anello del fuoco sull'etichetta) e accanto il nome del file scelto, o che cosa si può scegliere */
.scegli-file { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; min-width: 0; }
.scegli-file .btn { cursor: pointer; }
.scegli-file .btn:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }
.scegli-file-nome { min-width: 0; color: var(--inchiostro-2); font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
.scegli-file-nome.scelto { color: var(--inchiostro); }
.notifiche { display: grid; gap: 12px; }
.notifiche p { margin: 0; }
.notifiche-home { color: var(--inchiostro-2); font-size: 14px; }
.notifiche-azioni { display: flex; flex-wrap: wrap; gap: 8px; }
.notifiche-azioni:not(:has(button:not([hidden]))) { display: none; }
@media (max-width: 480px) { .campi-affiancati { grid-template-columns: 1fr; } }
/* «Mostra altre N cose da fare»: un pulsante ghost piccolo sotto le prime sei, che apre le altre sul posto */
.altri-compiti > summary { margin: 8px 18px; list-style: none; }
.altri-compiti > summary::-webkit-details-marker { display: none; }
.altri-compiti > summary .icona { width: 16px; height: 16px; transition: transform var(--durata) var(--curva); }
.altri-compiti[open] > summary .icona { transform: rotate(180deg); }
.altri-compiti .altri-chiudi, .altri-compiti[open] .altri-apri { display: none; }
.altri-compiti[open] .altri-chiudi { display: inline; }
/* l'elenco aperto sta sopra il pulsante che lo chiude: le righe restano in fila con le prime */
.altri-compiti[open] { display: flex; flex-direction: column-reverse; }
.riquadro-nota { margin: 0; padding: 4px 24px 16px; color: var(--inchiostro-2); font-size: 13px; font-weight: 600; }
/* Come va: il riepilogo del QuoteTotals, righe etichetta-valore con le cifre a destra. Una sola riga in grande
   (`amount-l`), il lavoro preso: è l'unico numero grande della pagina. */
.andamento { display: grid; gap: 8px; margin: 0; }
.andamento-riga { display: flex; align-items: baseline; justify-content: space-between; gap: 24px; }
.andamento dt { color: var(--inchiostro-2); }
.andamento dd { margin: 0; font-weight: 700; text-align: right; }
.andamento-grande { margin-bottom: 4px; padding-bottom: 12px; border-bottom: 1px solid var(--bordo); }
.andamento-grande dt { color: var(--inchiostro); font-weight: 800; }
.andamento-grande dd { font-size: 32px; line-height: 40px; font-weight: 800; letter-spacing: -0.02em; }
/* Il grafico dei lavori accettati per mese: una serie, colonne `--primary` larghe al massimo 24px, angoli tondi da 4px
   in cima e dritte sulla linea di base. Il valore scritto solo sul mese più alto e su questo; gli altri nel
   suggerimento, al passaggio o col fuoco da tastiera. Testi in inchiostro, mai nel colore della colonna. */
.grafico { margin: 24px 0 0; }
.grafico-titolo { font-size: 12px; line-height: 16px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--inchiostro-2); }
.colonne { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px; margin: 12px 0 0; padding: 0; list-style: none; }
.colonna { position: relative; display: flex; flex-direction: column; align-items: center; gap: 4px; border-radius: var(--radius-sm); cursor: default; }
.colonna-valore { height: 16px; font-size: 12px; line-height: 16px; font-weight: 700; color: var(--inchiostro); white-space: nowrap; }
.colonna-valore-nascosto { visibility: hidden; }
.colonna-area { display: flex; align-items: flex-end; justify-content: center; align-self: stretch; height: 120px; border-bottom: 1px solid var(--bordo-forte); }
.colonna-barra { width: 24px; max-width: 70%; border-radius: 4px 4px 0 0; background: var(--primary); transition: background var(--durata) var(--curva); }
.colonna:focus-visible .colonna-barra { background: var(--primary-hover); }
@media (hover: hover) { .colonna:hover .colonna-barra { background: var(--primary-hover); } }
.colonna-mese { font-size: 12px; font-weight: 600; color: var(--inchiostro-2); }
.colonna-attuale .colonna-mese { color: var(--inchiostro); font-weight: 800; }
.colonna::after {
  content: attr(data-suggerimento);
  position: absolute; bottom: calc(100% + 6px); left: 50%; translate: -50% 0; z-index: 1;
  padding: 6px 10px; border-radius: var(--radius-sm); background: var(--ink); color: var(--surface);
  font-size: 13px; font-weight: 600; white-space: nowrap; box-shadow: var(--shadow-pop);
  opacity: 0; pointer-events: none; transition: opacity var(--durata) var(--curva);
}
/* ai bordi il suggerimento si allinea alla colonna invece di uscire dalla scheda */
.colonna:first-child::after, .colonna:nth-child(2)::after { left: 0; translate: 0 0; }
.colonna:last-child::after, .colonna:nth-last-child(2)::after { left: auto; right: 0; translate: 0 0; }
.colonna:focus-visible::after { opacity: 1; }
@media (hover: hover) { .colonna:hover::after { opacity: 1; } }
/* Sotto i 900px una colonna sola: prima quello che c'è da fare, poi come va. */
@media (max-width: 900px) {
  .cruscotto-griglia { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  .riquadro-testa { padding: 16px 16px 0; }
  .riquadro-corpo { padding: 16px; }
  .riquadro-flush { padding: 12px 0 0; }
  .altri-compiti > summary { margin: 8px 10px; }
  .riquadro-nota { padding: 4px 16px 16px; }
  /* la riga va a capo: sopra il preventivo e la freccia, sotto l'etichetta, l'importo e il pulsante */
  .riga-cruscotto { flex-wrap: wrap; padding: 12px 12px 12px 16px; }
  .riga-cruscotto-corpo { flex: 1 1 calc(100% - 44px); }
  .riga-cruscotto .opzione-vai { order: 1; }
  .riga-cruscotto .stato, .riga-cruscotto-azione { order: 2; }
  .riga-modello-prezzo { flex-basis: 100%; text-align: left; }
  /* un attestato: il ⋯ in alto a destra al posto della freccia, sotto lo stato, poi «Rinnova o correggi» */
  .riga-attestato .riga-cruscotto-corpo { flex-basis: calc(100% - 56px); }
  .riga-attestato .riga-cruscotto-azione { order: 1; }
  .riga-attestato .attestato-modifica { order: 3; }
  /* una rata: sopra quanto (col ⋯ a destra, se è incassata), sotto lo stato, poi «Scade il» e «Segna incassata» */
  .riga-rata-incassata .riga-cruscotto-corpo { flex-basis: calc(100% - 56px); }
  .riga-rata .riga-cruscotto-azione { order: 0; }
  .riga-rata .stato { order: 1; }
  .riga-rata-azioni { order: 2; }
  /* il titolo e il pulsante non stanno sulla stessa riga: il pulsante scende sotto, a tutta larghezza */
  .documenti .riquadro-testa { flex-wrap: wrap; }
  .documenti .carica-documento, .documenti .carica-documento .btn { width: 100%; justify-content: center; }
  .squadra .riquadro-testa { flex-wrap: wrap; }
  .squadra .riquadro-testa > .btn { width: 100%; justify-content: center; }
  .amministrazione .riquadro-testa { flex-wrap: wrap; }
  /* il ⋯ resta accanto al titolo, come nella scheda: va a capo solo un pulsante con le parole */
  .amministrazione .riquadro-testa:has(> .btn-icona) { flex-wrap: nowrap; }
  .amministrazione .riquadro-testa > .btn { width: 100%; justify-content: center; }
  /* un utente: il ⋯ in alto a destra al posto della freccia, sotto lo stato, come un attestato */
  .riga-utente .riga-cruscotto-corpo { flex-basis: calc(100% - 56px); }
  .riga-utente .riga-cruscotto-azione { order: 1; }
  .riga-passkey .riga-cruscotto-corpo { flex-basis: calc(100% - 56px); }
  .riga-passkey .riga-cruscotto-azione { order: 1; }
  #errore-documenti .errore { margin: 12px 16px 0; }
  /* il ⋯ del documento resta accanto alla freccia: da solo sulla riga di sotto sembrava un avanzo */
  .riga-documento .riga-cruscotto-corpo { flex-basis: calc(100% - 100px); }
  .riga-documento .btn-icona { order: 0; }
  .andamento-grande dd { font-size: 28px; line-height: 36px; }
}

/* rubrica dei clienti: stesso elenco dei preventivi, con il campo di ricerca sopra */
.cerca-rubrica { max-width: 420px; margin: 0 0 16px; }
/* l'indirizzo è il secondo dato del contatto, non un metadato come la data: grande quanto basta per leggerlo */
.rubrica-indirizzo { margin-top: 2px; color: var(--inchiostro-2); font-size: 14.5px; }
/* i recapiti stanno sotto l'indirizzo, più piccoli: servono quando si apre il contatto, non per scorrere l'elenco */
.rubrica-recapiti { margin-top: 2px; color: var(--inchiostro-2); font-size: 13.5px; overflow-wrap: anywhere; }
.rubrica-usato { margin-top: 2px; color: var(--inchiostro-2); font-size: 13px; }
.rubrica-indirizzo, .rubrica-recapiti, .rubrica-usato { display: block; }
/* la scheda del cliente: le Card una sotto l'altra, come negli attestati */
.scheda-cliente .riquadro + .riquadro, .scheda-cliente .fatto + .riquadro { margin-top: 24px; }
.scheda-cliente .fatto { margin-bottom: 16px; }
.scheda-cliente .pagina-testa h1, .scheda-cliente .pagina-testa p { overflow-wrap: anywhere; }
/* I sopralluoghi (sopralluogo-nuovo.eta, sopralluogo.eta; mockup docs/superpowers/specs/mockup/2026-10-01-sopralluogo.html).
   Il nuovo: due Card una sotto l'altra e il pulsante; «Che lavoro è» si apre scegliendo Altro. */
.modulo-sopralluogo { display: grid; gap: 24px; margin: 0; }
.campi-sopralluogo { display: grid; gap: 16px; }
.scelta-lavoro { min-width: 0; margin: 0; padding: 0; border: 0; }
.scelta-lavoro .errore { margin: 8px 0 0; }
.campo-altro { display: none; }
.campo-altro.aperto, .modulo-sopralluogo:has(input[name="modello"][value="altro"]:checked) .campo-altro { display: grid; }
/* il foglio: in testa il giorno, il lavoro, chi e dove; «Salvato» in alto a destra */
.foglio-sopralluogo .riquadro + .riquadro { margin-top: 24px; }
.foglio-sopralluogo .pagina-testa h1 { overflow-wrap: anywhere; }
.pagina-testa .occhiello { margin: 0 0 4px; color: var(--inchiostro-2); font-size: 12px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; }
.pagina-testa .sopralluogo-dati { display: grid; gap: 6px; margin: 8px 0 0; color: var(--inchiostro-2); }
.sopralluogo-dati span { display: inline-flex; align-items: center; gap: 8px; min-width: 0; overflow-wrap: anywhere; }
.sopralluogo-dati .icona { flex: none; width: 16px; height: 16px; }
.sopralluogo-dati a { color: inherit; font-weight: 600; }
.salvato { display: inline-flex; align-items: center; gap: 6px; color: var(--inchiostro-2); font-size: 13px; font-weight: 600; }
.salvato .icona { width: 14px; height: 14px; }
/* la voce della lista di controllo: il segno (vuoto, o la spunta quando c'è la risposta), la cosa, il campo sotto */
.controllo { display: grid; grid-template-columns: 28px 1fr; gap: 4px 12px; padding: 14px 24px; border-top: 1px solid var(--bordo); }
.controllo:first-child { border-top: 0; }
.controllo-segno { display: inline-grid; place-items: center; width: 24px; height: 24px; margin-top: 1px; border: 1.5px solid var(--bordo-forte); border-radius: var(--radius-pill); color: var(--on-primary); }
.controllo-segno .icona { width: 14px; height: 14px; visibility: hidden; }
.controllo-fatto .controllo-segno { border-color: var(--primary); background: var(--primary); }
.controllo-fatto .controllo-segno .icona { visibility: visible; }
.controllo-cosa { font-weight: 700; }
.controllo-aiuto { grid-column: 2; color: var(--inchiostro-2); font-size: 13px; line-height: 18px; }
.controllo-campo { grid-column: 2; margin: 6px 0 0; }
.controllo-errore { grid-column: 2; margin: 4px 0 0; }
.con-unita { display: flex; align-items: center; gap: 8px; }
.con-unita .campo-bordato { width: 120px; min-height: 40px; }
.con-unita [aria-invalid="true"].campo-bordato { border-color: var(--errore); }
.con-unita span { color: var(--inchiostro-2); font-weight: 600; }
/* lo StatusBadge `ai` nella testa di una Card: a destra, e non si stringe */
.riquadro-testa > .stato { flex: none; }
/* la risposta del cliente: un campo largo quanto la riga */
.campo-cliente .campo-bordato { width: 100%; min-height: 40px; }
/* una cosa da non dimenticare: tutta la riga si tocca, e il segno si riempie */
.controllo-spunta { cursor: pointer; }
.controllo-spunta:has(input:focus-visible) .controllo-segno { outline: 2px solid var(--focus); outline-offset: 2px; }
.controllo-spunta.controllo-fatto .controllo-cosa { color: var(--inchiostro-2); }
/* gli appunti: il campo grande, e mentre si detta «Ti ascolto» sopra, come nella chat */
.appunti-campo { display: grid; gap: 8px; margin: 0; }
.appunti-campo .chat-ascolto { min-height: 36px; }
.appunti { display: block; width: 100%; min-height: 150px; resize: vertical; }
.appunti-campo .errore { margin: 0; }
.detta.in-trascrizione .spinner { display: inline-block; }
.detta.in-trascrizione .icona-voce { display: none; }
/* le foto: le miniature in quattro colonne, «Scatta» nella testa della Card */
.foto { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin: 0; padding: 0; list-style: none; }
.foto a { display: block; }
.foto img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; border: 1px solid var(--bordo); border-radius: var(--radius-md); background: var(--superficie-2); }
.foto-vuoto { margin: 0; color: var(--inchiostro-2); }
.scatta { cursor: pointer; }
.scatta:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }
.scatta.in-corso { pointer-events: none; }
.scatta.in-corso .icona { display: none; }
#foto-sopralluogo .riquadro-testa form { flex: none; margin: 0; }
/* una foto ancora nel telefono: la si vede già, più chiara, finché non parte */
.foto-in-coda img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; border: 1px dashed var(--bordo-forte); border-radius: var(--radius-md); opacity: 0.6; }
/* «Senza rete»: le righe di «Lavori», coi sopralluoghi che il telefono ha */
.senza-rete .preventivi { margin-bottom: 24px; }
.senza-rete-vuoto { margin: 0 0 24px; color: var(--inchiostro-2); }
/* il foglio lascia sotto lo spazio per l'isola, con «Prepara il preventivo» e il ⋯ */
.foglio-sopralluogo { padding-bottom: 120px; }
/* «Prepara il preventivo»: la Proposta di Bolla in cima e le Card sotto; ogni cosa capita col suo valore a destra e da
   dove viene sotto */
.modulo-prepara { display: grid; gap: 24px; margin: 0; }
.letto { display: grid; grid-template-columns: 1fr auto; gap: 2px 12px; padding: 12px 24px; border-top: 1px solid var(--bordo); }
.letto:first-child { border-top: 0; }
.letto-valore { font-weight: 700; text-align: right; }
.letto-fonte { grid-column: 1 / -1; color: var(--inchiostro-2); font-size: 13px; }
.pagina-testa-azioni { display: flex; align-items: center; gap: 8px; }
/* il TextField con l'errore: bordo `--danger` e il messaggio subito sotto */
.campo-etichettato [aria-invalid="true"].campo-bordato { border-color: var(--errore); }
.campo-etichettato .errore { margin: 0; }
.manca-q { color: var(--manca); font-weight: 600; }
.pillola-statica { cursor: default; }
@media (hover: hover) { .pillola-statica:hover { border-color: var(--bordo); background: var(--superficie); } }
@media (hover: hover) { .pillola-manca.pillola-statica:hover { border: 1px dashed var(--bordo-forte); background: var(--superficie); } }

/* pagina di accesso: un foglio solo, come la carta intestata del preventivo */
.accesso { min-height: 100vh; min-height: 100dvh; display: grid; place-items: center; padding: 24px 16px; }
.accesso-foglio { width: 100%; max-width: 400px; padding: 36px 36px 32px; background: var(--superficie); border: 1px solid var(--bordo); border-radius: var(--r-foglio); box-shadow: var(--shadow-card); }
.accesso-marchi { margin-bottom: 28px; }
.accesso-foglio h1 { margin: 0 0 20px; font-size: 28px; font-weight: 800; line-height: 36px; letter-spacing: -0.015em; }
.accesso-form { display: grid; gap: 16px; }
.accesso-form .errore { margin: 0; }
.accesso-campo label { display: block; margin-bottom: 6px; font-size: 14px; font-weight: 700; }
/* 16px e non 15: sotto, Safari su iPhone ingrandisce la pagina quando il campo prende il fuoco */
.accesso-campo input { width: 100%; min-height: 44px; font-size: 16px; }
.accesso-campo input[aria-invalid="true"] { border-color: var(--errore); }
.con-mostra { position: relative; }
.con-mostra input { padding-right: 96px; }
.con-mostra .btn { position: absolute; right: 4px; top: 50%; translate: 0 -50%; min-height: 34px; font-size: 13.5px; color: var(--inchiostro-2); }
.accesso-invia { width: 100%; justify-content: center; min-height: 44px; font-size: 15px; margin-top: 4px; }
.accesso-nota { margin: 20px 0 0; font-size: 13.5px; color: var(--inchiostro-2); }
/* il link d'accesso (benvenuto.eta): una frase sotto il titolo, e la regola della password sotto il campo */
.accesso-testo { margin: -8px 0 20px; color: var(--inchiostro-2); }
.accesso-campo .accesso-nota { margin-top: 6px; }
/* il secondo passaggio con una passkey: «Usa la passkey» prima, il codice sotto, come seconda strada */
.accesso-passkey { display: grid; gap: 12px; }
.accesso-passkey .errore { margin: 0; }
.accesso-oppure { margin: 24px 0 12px; font-size: 14px; color: var(--inchiostro-2); }
/* all'accesso «Entra con Face ID» viene prima del modulo: «Oppure con email e password» chiude il suo blocco */
.accesso-passkey-prima { margin-bottom: 4px; }
.accesso-passkey-prima .accesso-oppure { margin: 12px 0 8px; }
/* le passkey nel Profilo: le righe, poi il codice e il pulsante che ne aggiunge una */
.passkey-aggiungi { display: grid; gap: 16px; }
.passkey-aggiungi > .errore { margin: 0; }
.passkey-corpo { display: grid; gap: 16px; }
.passkey-corpo .fatto, .passkey-crea .fatto { margin: 0; }
.passkey-crea { display: grid; gap: 16px; }
/* le righe delle passkey sopra il modulo: il bordo le separa da lui, e il titolo non è un link */
.riquadro-flush + .passkey-corpo { border-top: 1px solid var(--bordo); }
.riga-passkey .riga-cruscotto-titolo::after { content: none; }
/* il secondo passaggio dell'amministratore (accesso-codice.eta): il QR su carta, la chiave da ricopiare, il codice */
.accesso-qr { display: grid; place-items: center; margin-bottom: 16px; padding: 12px; background: var(--carta); border: 1px solid var(--bordo); border-radius: var(--r-campo); color: var(--qr); }
.accesso-qr svg { display: block; width: 100%; max-width: 208px; height: auto; }
.accesso-segreto { margin-bottom: 20px; }
.accesso-segreto input { font-size: 14px; letter-spacing: 0.04em; }
.accesso-campo .accesso-cifre { font-variant-numeric: tabular-nums; letter-spacing: 0.2em; }
.accesso-esci { margin-top: 8px; }
.accesso-esci .btn { padding: 0; min-height: 36px; font-size: 13.5px; color: var(--inchiostro-2); }
@media (max-width: 480px) {
  /* sul telefono il foglio è la pagina, come il foglio del banco sotto i 720px */
  /* sul telefono il foglio resta una card, con 16px di margine ai lati come le altre pagine; si stringe il dentro */
  .accesso { padding: 16px; }
  .accesso-foglio { padding: 28px 20px 24px; }
}

@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  .barra-in { padding: 8px 16px; gap: 10px; }
  /* Sotto i 720px la barra non ci sta più con tutto: il ritorno resta la sola freccia, che è un gesto che si
     capisce da solo, e l'etichetta va ai lettori di schermo invece di sparire. Si toglie la parola meno
     necessaria, non quella che dice a quanto siamo. Per la stessa ragione «Nuovo preventivo» resta «Nuovo». */
  .indietro-testo, .nuovo-testo { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  /* resta la sola freccia: un cerchio da 44px, come gli altri pulsanti a icona */
  .barra-indietro { width: 44px; padding: 0; justify-content: center; }
  .barra-destra .btn { white-space: nowrap; }
  /* Dentro un preventivo la «o» sta a destra di «Salvato», nello stesso punto delle pagine principali: la barra è
     alta come la loro riga del titolo, e freccia, «Salvato» e «o» stanno sulla stessa linea di mezzo. */
  .barra-destra > .marchi { display: inline-flex; padding: 8px; margin-right: -8px; }
  .barra-destra > .campanella { margin-right: -8px; }
  /* Le sezioni restano la sola icona, e la parola va ai lettori di schermo come «preventivo» in «Nuovo» */
  /* A 360 px la «o», il ritorno, «Salvato», «Clienti», «Nuovo» e l'utente sforavano di una decina di pixel: si
     tolgono spazi, non parole né bersagli da 44 px. */
  @media (max-width: 380px) {
    .barra-in { gap: 6px; }
    .barra-destra { gap: 4px; }
    .stato-salvataggio { font-size: 13px; }
    .barra-destra .btn-principale { padding: 0 14px; }
    /* Con «Inizio» tra le sezioni la «o» è una seconda strada per lo stesso posto: sotto i 380px, dove sul banco
       la barra sforava di 18px, cede il posto lei, non una parola né un bersaglio da 44px. */
    .barra-in > .marchi { display: none; }
  }
  /* Nell'isola del telefono non c'è posto per le parole: resta la «o», e «Chiedi a Bolla» va ai lettori di schermo,
     come «preventivo» in «Nuovo» nella barra. */
  .chiedi-testo { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  /* La pagina tiene 16px di margine ai lati, come la barra sopra: il foglio resta una card, con bordo e angoli, e
     titoli, ricerca e messaggi stanno allineati al suo bordo. Il foglio a filo dello schermo sembrava tagliato. */
  .foglio-testa, .riepilogo { padding-left: 16px; padding-right: 16px; }
  /* due colonne da 300px non ci stanno: il cliente scende sotto il titolo a tutta larghezza, e il filo che
     divideva le colonne diventa il filo che le separa in verticale */
  .foglio-testa { display: block; }
  .cliente { width: auto; margin-top: 20px; padding-top: 14px; padding-left: 0; border-left: 0; border-top: 1px solid var(--bordo); }
  .aggiungi { margin: 8px 16px 0; }
  .righe { padding: 0 4px; }
  /* Il margine sinistro resta quello della maniglia, che qui è sempre visibile: con 12px come gli altri lati i
     sei punti finirebbero sopra la prima parola della descrizione invece di stare nel margine. */
  .riga-doc { padding: 12px 12px 12px 28px; }
  .riga-doc .altro { opacity: 1; }
  /* Qui il conto è un altro: `.righe` ha 4px di padding invece di 16, quindi la maniglia non può sporgere o
     uscirebbe dal foglio. Ci sta perché la riga ha 28px di padding a sinistra, e il disco da 32px può
     sovrapporsi alla colonna senza che l'icona, larga 16 e centrata, tocchi il testo. */
  .presa { opacity: 1; left: -2px; }
  /* sul telefono l'importo scende sotto il titolo, e la freccia resta a destra a metà altezza */
  .preventivo { grid-template-columns: minmax(0, 1fr) auto; padding: 14px 12px 14px 16px; }
  .preventivo-importo { grid-row: 2; grid-column: 1; text-align: left; }
  .preventivo .opzione-vai { grid-row: 1 / span 2; grid-column: 2; }
  .elenco-testa { grid-template-columns: 1fr auto; }
  .elenco-testa > :nth-child(3) { grid-column: 1 / -1; }
  .voce-rev-testa { grid-template-columns: 40px 1fr; }
  .voce-rev-testa > :nth-child(n+3) { grid-column: 2; }
  .tabella { display: block; overflow-x: auto; }
}

/* Col dito serve un bersaglio di almeno 44 px (WCAG 2.5.5, e la mano di chi lavora in cantiere). Si allarga l'area
   toccabile; dove il disegno deve restare piccolo cresce il padding, non l'aspetto. Solo con `pointer: coarse`:
   col mouse la densità di oggi resta quella giusta. */
@media (pointer: coarse) {
  .btn, .btn-icona, .rapida, .pillola, .selettore, .opzione-radio, .pillola-so, .menu button, .menu a, .barra-indietro, .vista { min-height: 44px; }
  .btn-icona, .barra-indietro, .btn-chiedi { min-width: 44px; justify-content: center; }
  .utente-icona { width: 44px; height: 44px; }
  /* i campi che stanno da soli (cerca, comando, risposta, accesso): quelli dentro le righe del banco li misura il banco */
  .cerca input, .campo-comando, .accesso-campo input { min-height: 44px; }
  /* «Mostra» sta dentro il campo della password: il campo cresce quanto serve a tenerlo a 44 px con 4 px di aria */
  .accesso-campo .con-mostra input { min-height: 52px; }
  .con-mostra .btn { min-height: 44px; }
  /* Nell'elenco dei preventivi si tocca la voce intera, non il solo titolo: il titolo è un link di una o due righe,
     alto 22 o 41 px, e la voce non ha altri controlli. Il link si stende sulla voce con un velo trasparente. */
  .elenco-voce:has(> .elenco-testa a.elenco-titolo) { position: relative; }
  a.elenco-titolo::after { content: ""; position: absolute; inset: 0; }
  /* La chat del nuovo preventivo: «Modifica» e «Cambia» sotto i messaggi sono parole piccole, e il link ad «Altro»
     sta in una frase. L'area toccabile cresce col padding e il margine negativo la compensa. */
  .msg-azione { min-height: 44px; margin: -8px 0; padding: 0 8px; }
  .chat-campo { --riga-chat: 44px; }
  /* con viewport-fit=cover, in orizzontale la tacca starebbe sopra il testo: la pagina si scosta come farebbe Safari */
  body { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
}
/* Sotto i 16 px Safari su iPhone ingrandisce la pagina quando un campo prende il fuoco, e non la rimette a posto.
   Il titolo del preventivo è un campo più grande di così, e resta com'è. */
@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  input, textarea, select, .campo:not(.campo-titolo), .campo-bordato { font-size: 16px; }
  /* indirizzo, telefono, email e stato della preparazione sono il dato che si cerca, non un'etichetta di servizio:
     sul telefono si leggono alla misura del testo. Il numero e le date restano piccoli. */
  .rubrica-indirizzo, .rubrica-recapiti, .elenco-meta { font-size: 15px; }
  /* la barra in alto tocca il bordo dello schermo: nell'app aggiunta alla schermata Home ci passerebbe l'ora sopra */
  .barra { padding-top: env(safe-area-inset-top); }
}

/* Il banco sul telefono (proposta C del mockup 2026-09-24-telefono). Chiusa, ogni riga è una testata di due righe
   di testo: la descrizione, e sotto misura × prezzo · fonte; a destra l'importo. Toccandola si apre sul posto, una
   alla volta (app.js), con i controlli di sempre messi in colonna e in fondo le azioni che sul desktop stanno nel
   menu ⋯. Maniglia e ⋯ non ci sono: trascinare col dito una riga alta mezzo schermo litiga con lo scorrimento. */
@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  .presa, .riga-doc .altro, .riga-doc > .importo { display: none; }
  .riga-doc { display: block; padding: 0; }
  .riga-doc:not(.aperta-telefono) > .riga-corpo, .riga-doc:not(.aperta-telefono) > .fonti, .riga-doc:not(.aperta-telefono) > .azioni-riga-aperta { display: none; }
  .riga-compatta {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "descrizione importo" "sommario chevron";
    align-items: baseline; gap: 2px 8px; width: 100%; min-height: 44px; padding: 12px;
    border: 0; border-radius: var(--r-riga); background: none; text-align: left; -webkit-tap-highlight-color: transparent;
  }
  /* col dito il :hover resta attaccato alla riga appena toccata: qui non dice niente */
  @media (hover: hover) { .riga-doc:hover { background: transparent; } }
  .riga-compatta:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
  .riga-compatta:active { background: var(--superficie-2); }
  /* il contenuto ha un contenitore suo per lo scambio OOB, ma per la griglia non esiste */
  .compatta { display: contents; }
  .compatta-descrizione {
    grid-area: descrizione; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
    overflow: hidden; overflow-wrap: anywhere; font-size: 16px; line-height: 1.35; color: var(--inchiostro);
  }
  .compatta-importo { grid-area: importo; font-size: 16px; font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
  .riga-doc.manca .compatta-importo { color: var(--inchiostro-2); font-weight: 400; }
  .compatta-sommario { grid-area: sommario; color: var(--inchiostro-2); font-size: 14px; line-height: 1.4; text-wrap: pretty; }
  /* quello che manca si vede come nella pillola e accanto alla quantità: stesso inchiostro, stesso peso */
  .compatta-sommario.sommario-manca { color: var(--manca); font-weight: 600; }
  .compatta-chevron { grid-area: chevron; align-self: start; margin-top: 2px; color: var(--inchiostro-2); rotate: -90deg; transition: rotate var(--durata) var(--curva); }
  .nota-proposta { margin: 0; padding: 12px 12px 0; }

  /* Aperta: il bordo d'accento dice quale riga si sta toccando. Della testata resta l'importo in alto a destra;
     descrizione e sommario restano al lettore di schermo, nel nome del pulsante che richiude. */
  .riga-doc.aperta-telefono, .riga-doc.aperta-telefono.aperta { margin: 6px 0; padding: 0 12px 12px; border-radius: var(--r-riga); box-shadow: inset 0 0 0 2px var(--accento); }
  /* il fondo tinto delle fonti aperte (desktop) qui lo fa già il bordo; quello di una riga della proposta resta */
  .riga-doc.aperta-telefono.aperta { background: var(--superficie); }
  /* la riga aperta ha già il suo contorno: niente filo sopra di lei né sotto */
  .riga-doc.aperta-telefono, .riga-doc.aperta-telefono + .riga-doc { border-top: 0; }
  .aperta-telefono .riga-compatta { grid-template-areas: "importo chevron"; padding: 12px 0 8px; }
  .aperta-telefono .compatta-descrizione, .aperta-telefono .compatta-sommario { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .aperta-telefono .compatta-importo { justify-self: end; }
  .aperta-telefono .compatta-chevron { rotate: 180deg; }
  .aperta-telefono .campo-descrizione { width: 100%; min-height: 64px; margin: 0; padding: 8px 10px; line-height: 1.4; }
  .aperta-telefono .campo-descrizione:not([readonly]) { border-color: var(--bordo-forte); background: var(--superficie); }
  .aperta-telefono .calcolo { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 8px 12px; margin-top: 10px; }
  /* il «×» tra la misura e il prezzo, che qui stanno su due righe */
  .aperta-telefono .calcolo > [aria-hidden="true"] { display: none; }
  .aperta-telefono .misura .campo-quantita, .aperta-telefono .misura .selettore { min-height: 44px; }
  .aperta-telefono .misura .campo-quantita { width: 8ch; }
  /* il prezzo con la sua fonte su una riga intera: il chevron in fondo a destra, la fonte subito dopo il prezzo */
  .aperta-telefono .pillola { grid-column: 1 / -1; order: 1; justify-content: space-between; width: 100%; min-height: 44px; padding: 0 12px 0 14px; font-size: 15px; white-space: nowrap; }
  .aperta-telefono .pillola-fonte { min-width: 0; margin-right: auto; overflow: hidden; text-overflow: ellipsis; }
  .aperta-telefono .fonti { margin-top: 12px; }
  .aperta-telefono .prezzo-manuale input { min-height: 44px; }
  .azioni-riga-aperta { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
  .azioni-riga-aperta .btn { min-height: 44px; font-size: 15px; }
  .azioni-riga-aperta .btn-icona { width: 44px; height: 44px; border: 1px solid var(--bordo-forte); color: var(--inchiostro); }
  .icona-su { rotate: -90deg; }
  .icona-giu { rotate: 90deg; }
  .azioni-riga-aperta .pericolo { color: var(--errore); }
  .azioni-riga-aperta .scelta { background: var(--errore-tenue); font-weight: 600; }
  /* la conferma è larga: prende il posto delle frecce, come nel menu prende quello di «Elimina riga» */
  .azioni-riga-aperta:has(.scelta:not([hidden])) [data-azione] { display: none; }
  .azioni-riga-aperta [data-fatto] { margin-left: auto; padding: 0 20px; }
  /* «Aggiungi una lavorazione» è un campo solo, e col dito si tocca tutto il riquadro */
  .aggiungi-campo { padding-top: 0; padding-bottom: 0; }
  .aggiungi-campo input { min-height: 44px; }
}

/* La finestra della conferma sul telefono: un foglio che sale dal fondo a tutta larghezza, come la finestra di Bolla
   (DESIGN.md, «Fogli dal basso»). Le rate vanno su due righe: quando sopra, quota, importo e «Togli» sotto. */
@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  .finestra { width: 100%; max-width: 100%; max-height: 92dvh; margin: auto 0 0; border-width: 1px 0 0; border-radius: var(--radius-lg) var(--radius-lg) 0 0; transform: translateY(24px); }
  .finestra[open] { transform: none; }
  @starting-style { .finestra[open] { transform: translateY(24px); } }
  .finestra[open]:not(:modal) { inset: auto 0 0; }
  .finestra-testa { padding: 16px 16px 8px; }
  .finestra-corpo { padding: 4px 16px 16px; }
  .finestra-piede { padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); }
  .finestra-piede .btn { flex: 1; justify-content: center; }
  .rate-testa { display: none; }
  .rata { grid-template-columns: 96px minmax(0, 1fr) auto; padding-bottom: 8px; border-bottom: 1px solid var(--bordo); }
  .rata > .rata-campo:first-child { grid-column: 1 / -1; }
  .rate-somma { margin-right: 0; }
}

/* Il selettore dell'unità (e dell'IVA) sul telefono: un elenco che si apre sotto il pulsante copriva la riga di
   sotto, e sembrava che il contenuto fosse sparito. Qui sale dal basso a tutta larghezza, col velo sul resto, e
   le opzioni si toccano col pollice. La posizione la dà il CSS: app.js non la calcola (posizionaPopover). */
@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  .listbox-scelta[popover] { position: fixed; left: 0; right: 0; bottom: 0; top: auto; width: 100%; max-width: none; max-height: 60vh; margin: 0; padding: 8px 8px calc(8px + env(safe-area-inset-bottom)); border-width: 1px 0 0; border-radius: var(--r-pannello) var(--r-pannello) 0 0; box-shadow: var(--shadow-su); transition: translate 220ms var(--curva); }
  @starting-style { .listbox-scelta[popover]:popover-open { translate: 0 100%; } }
  .listbox-scelta[popover]::backdrop { background: var(--velo); }
  .listbox-scelta li { min-height: 48px; padding: 0 16px; gap: 12px; font-size: 16px; }
  /* 16px nei campi: sotto, Safari su iPhone ingrandisce la pagina al fuoco */
  .campo-ds input { font-size: 16px; }
}

/* Sul telefono l'isola resta un'isola, come sul desktop: una pillola centrata che galleggia a 16 px dal fondo (più il
   margine della barra di sistema dell'iPhone), larga quanto il suo contenuto: [«o»] [⋯] [Manda al cliente]. Il totale
   non ci sta accanto alle azioni, e resta nel riepilogo in fondo al foglio. «Vedi PDF» entra nel menu ⋯, come le
   altre azioni che non sono la principale. La barra della proposta galleggia allo stesso modo; la finestra di Bolla,
   che si apre, sale dal fondo a tutta larghezza. */
@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  .azioni-documento { bottom: calc(16px + env(safe-area-inset-bottom)); }
  .azioni-documento .totale-barra { display: none; }
  /* la pagina ha in fondo lo spazio dell'isola (16 + 44 + 2 × 6 + il bordo) e un po' d'aria: l'ultima riga non ci finisce sotto */
  .pagina { padding: 16px 16px calc(96px + env(safe-area-inset-bottom)); }
  .btn-chiedi { width: 44px; height: 44px; padding: 0; justify-content: center; }
  .azioni-documento .btn-principale { padding: 0 18px; font-size: 15px; white-space: nowrap; }
  /* la secondaria entra nel menu ⋯ (Vedi PDF, contratto, POS e pagamenti ci sono già): sull'isola resta il passo */
  .azioni-passo .passo-secondaria { display: none; }
  .menu-reinvia { display: block; }
  .menu .menu-pdf { display: flex; align-items: center; width: 100%; min-height: 44px; padding: 8px 10px; border-radius: var(--r-piccolo); color: var(--inchiostro); font-size: 15px; text-decoration: none; }
  .menu .menu-pdf:active { background: var(--superficie-2); }
  .menu button, .menu a.menu-voce { font-size: 15px; }

  /* La finestra di Bolla è un foglio dal basso, come il selettore dell'unità, alta fino all'85% dello schermo: `dvh`
     e non `vh`, perché su iPhone `vh` conta anche la barra degli indirizzi e il campo finirebbe sotto. Nasce dal
     centro del fondo, con l'animazione di sempre. La barra sparisce mentre è aperta: due cose fisse una sull'altra
     non dicono quale conta. Resta visibile la finestra, che nel DOM le sta dentro.
     Con la tastiera aperta Safari su iPhone non restringe la pagina, la copre: `--tastiera` (quanto ne copre) e
     `--vista-alta` (quanto se ne vede) li scrive app.js da visualViewport, e la finestra sale e si accorcia. */
  .pannello-bolla[popover], .pannello-bolla:not([popover]) { left: 0; right: 0; bottom: var(--tastiera, 0px); top: auto; translate: none; width: 100%; max-width: none; max-height: min(85dvh, calc(var(--vista-alta, 100dvh) - 16px)); border-width: 1px 0 0; border-radius: var(--r-pannello) var(--r-pannello) 0 0; box-shadow: var(--shadow-su); }
  /* un foglio che sale dal fondo scende dove è venuto, invece di rimpicciolirsi verso il centro come la finestra del desktop */
  .pannello-bolla[popover] { transform-origin: 50% 100%; transform: translateY(100%); filter: none; }
  @starting-style { .pannello-bolla[popover]:popover-open { transform: translateY(100%); filter: none; } }
  /* il velo entra ed esce con la finestra, invece di comparire e sparire di colpo mentre lei ancora si muove */
  .pannello-bolla[popover]::backdrop {
    background: var(--velo); opacity: 0;
    transition-property: opacity, overlay, display; transition-duration: 180ms; transition-timing-function: var(--curva);
    transition-behavior: allow-discrete;
  }
  .pannello-bolla[popover]:popover-open::backdrop { opacity: 1; transition-duration: 320ms; }
  @starting-style { .pannello-bolla[popover]:popover-open::backdrop { opacity: 0; } }
  .azioni-documento:has(.pannello-bolla:popover-open), .azioni-documento:has(.pannello-bolla:not([popover])) { visibility: hidden; }
  /* l'isola torna quando il foglio è sceso, non mentre gli passa davanti: sparisce subito, ricompare dopo i 180ms */
  .azioni-documento { transition: visibility 0s linear 180ms; }
  .azioni-documento:has(.pannello-bolla:popover-open) { transition-delay: 0s; }
  .pannello-bolla { visibility: visible; }
  .pannello-bolla .comando { padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
  .campo-comando, .comando .btn { min-height: 44px; }

  /* La barra della proposta: agganciata come l'isola, e bassa. Il comando su una riga e la risposta di Bolla su due,
     poi i puntini; toccandoli si leggono interi (app.js). Il lettore di schermo li legge sempre interi. */
  .barra-proposta { left: 16px; right: 16px; bottom: calc(16px + env(safe-area-inset-bottom)); translate: none; width: auto; gap: 8px; padding: 12px 14px; }
  .proposta-parole { cursor: pointer; -webkit-tap-highlight-color: transparent; }
  .proposta-comando { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; line-clamp: 1; overflow: hidden; }
  .proposta-messaggio { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; line-height: 1.4; }
  .proposta-intera .proposta-comando, .proposta-intera .proposta-messaggio { -webkit-line-clamp: none; line-clamp: none; }
  .proposta-piede { gap: 8px; }
  .proposta-sintesi { flex-basis: 100%; }
  .proposta-azioni { width: 100%; }
  /* ognuno largo quanto la sua parola più lo spazio che avanza: a metà per uno, a 360 px «Applica le modifiche»
     andava a capo */
  .proposta-azioni form { flex: 1 1 auto; }
  .proposta-azioni .btn { width: 100%; min-height: 44px; padding: 0 12px; justify-content: center; font-size: 15px; white-space: nowrap; }
  /* lo spazio della barra a riposo (comando, due righe di risposta, riassunto, pulsanti) più un po' d'aria */
  .pagina.con-proposta { padding-bottom: calc(216px + env(safe-area-inset-bottom)); }
}


/* Senza JavaScript la testata compatta non apre niente, e toccare la proposta non ne toglie i puntini: una proposta
   arrivata col modulo vero (banco-comando.eta) si deve poter leggere intera prima di applicarla. Le righe restano
   aperte com'erano prima del telefono, con l'importo sotto, e la proposta intera. */
@media (max-width: 720px) and (scripting: none), (pointer: coarse) and (max-height: 500px) and (scripting: none) {
  .riga-compatta { display: none; }
  .riga-doc { padding: 12px; }
  .riga-doc:not(.aperta-telefono) > .riga-corpo, .riga-doc > .importo { display: block; }
  .riga-doc > .importo { margin-top: 6px; text-align: right; }
  .proposta-comando, .proposta-messaggio { -webkit-line-clamp: none; line-clamp: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
  /* senza movimento la riga appena cambiata si accende e basta; app.js la spegne dopo un momento */
  .riga-doc.appena-applicata[data-da-comando] { background: var(--accento-tenue); }
  .spinner { border: none; }
  .spinner::before { content: "…"; }
}

/* Sul telefono bolla è un'app (DESIGN.md, «Sul telefono»). Sulle pagine principali la navigazione scende in basso,
   nella barra delle schede, e in alto resta la sola «o»: le sezioni e il cerchio dell'utente sono diventati schede,
   «Nuovo preventivo» il cerchio al centro. Dentro un preventivo le schede non ci sono: in alto la freccia con la
   parola, come un'app che è entrata in una pagina, e in basso l'isola. Al PC le schede non si vedono: c'è la barra
   laterale. */
.schede { display: none; }
@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  .barra-indietro-app { width: auto; margin-left: -8px; padding: 0 14px 0 6px; font-size: 16px; }
  .barra-indietro-app .icona { width: 24px; height: 24px; }

  /* Sulle pagine principali niente barra in alto: con la sola «o» era una striscia vuota. La «o» resta, nell'angolo
     in alto a destra sulla riga del titolo, e scorre via con la pagina; porta alla Dashboard e, mentre arriva
     un'altra pagina, la sua bolla cerca il centro come prima. La linea del cambio pagina è già sul bordo dello
     schermo. Dentro un preventivo la barra resta: lì porta la freccia indietro e lo stato del salvataggio. */
  .barra-principale { position: absolute; top: env(safe-area-inset-top); right: 0; padding-top: 0; background: none; border-bottom: 0; }
  .barra-principale .barra-in { min-height: 0; padding: 20px 8px 0 0; }
  .barra-principale .marchi { padding: 8px; }
  .barra-principale + .pagina { padding-top: calc(16px + env(safe-area-inset-top)); }
  .barra-principale + .pagina .pagina-testa, .barra-principale + .pagina .chat-testa { padding-right: 48px; }
  /* la campanella è larga quanto la «o» col suo margine (44px), ma il numero sporge di qualche pixel a sinistra */
  .barra-principale:has(.campanella) + .pagina .pagina-testa, .barra-principale:has(.campanella) + .pagina .chat-testa { padding-right: 56px; }

  .schede {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-azioni);
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    padding: 4px 4px calc(4px + env(safe-area-inset-bottom));
    background: var(--superficie); border-top: 1px solid var(--bordo); box-shadow: var(--shadow-su);
  }
  /* il posto per rispondere della chat sta sopra le schede, non sotto */
  body:has(.schede) .chat-scrivi { bottom: calc(64px + env(safe-area-inset-bottom)); padding-bottom: 12px; }
  /* lo schermo meno il margine in alto (16 px), quello in basso (16) e le schede (64) */
  .chat { min-height: calc(100dvh - 96px - env(safe-area-inset-top) - env(safe-area-inset-bottom)); }
  /* e con la barra della freccia in alto (65 px) */
  .barra-interna + .pagina-chat .chat { min-height: calc(100dvh - 161px - env(safe-area-inset-top) - env(safe-area-inset-bottom)); }
  .chat-testa h1 { font-size: 24px; line-height: 32px; }
  .msg-bolla, .msg-tu { max-width: 100%; }
  .chat-manda-parola { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .chat-manda { width: var(--riga-chat); padding: 0; justify-content: center; }
  /* l'ultima riga di ogni pagina non finisce sotto le schede */
  body:has(.schede) { padding-bottom: calc(64px + env(safe-area-inset-bottom)); }
  .scheda {
    position: relative; display: flex; flex-direction: column; align-items: center; gap: 2px; min-height: 56px; padding-top: 4px;
    color: var(--inchiostro-2); font-size: 12px; font-weight: 700; line-height: 16px; text-decoration: none; -webkit-tap-highlight-color: transparent;
  }
  /* la scheda della pagina in cui si è, come nelle app del telefono: icona e parola in `--primary` e più spesse, le
     altre chiare e sottili. Non solo il colore: cambiano anche il tratto e il peso della parola */
  .scheda > .icona { width: 26px; height: 26px; margin: 3px 0; stroke-width: 1.7; }
  .scheda[aria-current] { color: var(--primary); font-weight: 800; }
  .scheda[aria-current] > .icona { stroke-width: 2.4; }
  .scheda-avatar { display: grid; place-items: center; width: 28px; height: 28px; margin: 2px 0; border-radius: 50%; background: var(--surface-mint); color: var(--ink); font-size: 11px; font-weight: 800; }
  .scheda[aria-current] > .scheda-avatar { box-shadow: 0 0 0 2px var(--superficie), 0 0 0 4px var(--inchiostro); }
  /* «Nuovo» è un cerchio pieno che sale un poco sopra la barra: il bordo del colore della barra lo stacca dal filo */
  .scheda-piu {
    box-sizing: content-box; display: grid; place-items: center; width: 44px; height: 44px; margin-top: -20px;
    border: 4px solid var(--superficie); border-radius: 50%; background: var(--primary); color: var(--on-primary);
  }
  .scheda-piu .icona { width: 24px; height: 24px; stroke-width: 2.4; }
  /* la parola «Nuovo» resta del colore delle altre: accesa sembrerebbe la pagina in cui si è, e a distinguerla basta il cerchio */
  /* la scheda toccata aspetta la sua pagina: lo spinner prende il posto dell'icona, come nelle sezioni al PC */
  .scheda > .spinner { order: -1; width: 24px; height: 24px; margin: 4px 0; }
  .scheda.in-attesa > .icona, .scheda.in-attesa > .scheda-avatar { display: none; }
  .scheda-nuovo > .spinner { position: absolute; top: 4px; left: 50%; translate: -50% 0; width: 20px; height: 20px; margin: 0; color: var(--on-primary); }
  .scheda-nuovo.in-attesa .scheda-piu .icona { visibility: hidden; }
}

/* La barra laterale, al PC (laterale.eta): il menu fisso a sinistra di un'applicazione, stretto alle sole icone a ogni
   larghezza (le parole nel `title`, al passaggio del mouse, e ai lettori di schermo). La voce in cui si è si accende
   come le schede del telefono, col colore e col tratto, più un filo sul bordo sinistro: niente pillola.
   `--laterale` è la sua larghezza, e ci si centrano l'isola, la finestra di Bolla e la linea che avanza; vale solo
   sulle pagine che la barra ce l'hanno (non l'accesso, non lo strumento di valutazione). */
:root { --laterale: 0px; }
.laterale { display: none; }
@media (min-width: 721px) and (not ((pointer: coarse) and (max-height: 500px))) {
  body:has(> .laterale) { --laterale: 76px; padding-left: var(--laterale); }
  /* in alto, al PC, le pagine principali non hanno una barra: il titolo grande è in testa alla pagina, e la campanella
     sta in alto a destra sulla sua riga (la prima della pagina: il titolo, o le schede dove ci sono), senza fondo né
     filo, e scorre via con la pagina come sul telefono. La «o» no: al PC sta in cima alla barra laterale. */
  .barra-principale, .barra-sezione { position: absolute; top: 44px; left: var(--laterale); right: 0; background: none; border-bottom: 0; pointer-events: none; }
  /* sulle pagine a schede (Profilo, Squadra e sicurezza) la prima riga sono le pillole, più in alto del titolo */
  .barra-sezione, .barra-principale:has(+ .pagina > .viste:first-child) { top: 36px; }
  /* larga quanto la pagina sotto, così la campanella sta a filo del suo bordo destro e non dello schermo */
  .barra-principale .barra-in, .barra-sezione .barra-in { min-height: 0; padding: 0 24px; justify-content: flex-end; }
  .barra-principale:has(+ .pagina-larga) .barra-in, .barra-sezione:has(+ .pagina-larga) .barra-in { max-width: 1120px; }
  .barra-principale:has(+ .pagina-stretta) .barra-in, .barra-sezione:has(+ .pagina-stretta) .barra-in { max-width: 600px; }
  .barra-principale .campanella, .barra-sezione .campanella { pointer-events: auto; margin-right: -8px; }
  .barra-principale .marchi, .barra-sezione .marchi, .barra-sezione .barra-indietro { display: none; }
  .barra-principale + .pagina, .barra-sezione + .pagina { padding-top: 40px; }
  /* il titolo, e il pulsante che gli sta accanto, lasciano il posto alla campanella */
  .barra-principale:has(.campanella) + .pagina .pagina-testa, .barra-principale:has(.campanella) + .pagina .chat-testa, .barra-sezione:has(.campanella) + .pagina > :first-child { padding-right: 64px; }
  .laterale {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: var(--z-barra); width: var(--laterale);
    display: flex; flex-direction: column; gap: 2px; padding: 20px 12px 16px; overflow-y: auto;
    background: var(--superficie); border-right: 1px solid var(--bordo);
  }
  .laterale-marchio { display: flex; align-items: center; justify-content: center; min-height: 44px; margin-bottom: 16px; border-radius: var(--radius-sm); }
  .laterale-o { display: block; width: 36px; height: 33px; }
  .laterale-nuovo { width: 48px; height: 48px; margin: 0 auto 20px; padding: 0; justify-content: center; }
  .laterale-nuovo .icona { width: 20px; height: 20px; stroke-width: 2.4; }
  .laterale-nuovo.in-attesa > .icona { display: none; }
  .laterale-testo { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .laterale-voci { display: flex; flex-direction: column; gap: 2px; }
  .voce {
    position: relative; display: flex; align-items: center; justify-content: center; gap: 12px; min-height: 48px; padding: 0 12px;
    border-radius: var(--radius-md); color: var(--inchiostro-2); font-size: 15px; font-weight: 700; text-decoration: none;
    transition: color var(--durata) var(--curva);
  }
  @media (hover: hover) { .voce:hover { color: var(--inchiostro); } }
  .voce .icona { width: 22px; height: 22px; stroke-width: 1.8; }
  .voce[aria-current] { color: var(--primary); font-weight: 800; }
  .voce[aria-current] .icona { stroke-width: 2.4; }
  .voce[aria-current]::before { content: ""; position: absolute; left: -12px; top: 12px; bottom: 12px; width: 4px; border-radius: 0 4px 4px 0; background: var(--primary); }
  /* chi è dentro sta in fondo, lontano dalle sezioni: è un posto dove si va di rado */
  .voce-sicurezza { margin-top: auto; }
  .voce-sicurezza + .voce-utente { margin-top: 8px; }
  .voce-utente { margin-top: auto; }
  .voce-utente[aria-current] .utente-icona { box-shadow: 0 0 0 2px var(--superficie), 0 0 0 4px var(--primary); }
  /* la voce toccata aspetta la sua pagina: lo spinner al posto dell'icona, e la barra non si sposta */
  .voce > .spinner { order: -1; width: 22px; height: 22px; }
  .voce.in-attesa > .icona, .voce.in-attesa > .utente-icona { display: none; }
}

/* Il passaggio da una pagina all'altra (app.js, «La navigazione è immediata»), come in un'app. Il verso lo dà la
   profondità: entrare in un preventivo è una spinta, la pagina nuova arriva da destra e quella di prima arretra un
   poco e si scurisce; tornare indietro è il movimento opposto, con la pagina che se ne va sopra l'altra. Cambiare
   sezione è una dissolvenza incrociata, le due pagine insieme: niente istante vuoto in mezzo. Dallo scheletro alla
   pagina vera, che è già al suo posto, basta una dissolvenza breve. La barra laterale, le schede e la barra in alto
   restano ferme: cambia la voce accesa, non la cornice. Sul telefono la spinta è a tutta larghezza, come su iPhone;
   al PC un accenno, perché una pagina larga che attraversa lo schermo a ogni clic sarebbe troppo. Sono View
   Transitions: anche le pagine caricate per intero (un modulo, una ricarica) sfumano. Col movimento ridotto niente,
   e chi non le conosce cambia pagina di colpo, come prima. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  .schede { view-transition-name: schede; }
  /* la barra del preventivo e la «o» delle pagine principali sono due cose diverse: con lo stesso nome la «o»
     nell'angolo del telefono diventava la barra a tutta larghezza, allargandosi sullo schermo, e al ritorno si
     restringeva. La «o» resta ferma tra le sezioni; entrando e uscendo da un preventivo va con la sua pagina */
  .barra-interna { view-transition-name: barra; }
  .barra-principale { view-transition-name: barra-principale; }
  html[data-transizione="avanti"] .barra-principale, html[data-transizione="indietro"] .barra-principale { view-transition-name: none; }
  .laterale { view-transition-name: laterale; }
  /* tra le due facce di un preventivo le sue schede restano ferme, come quelle in basso tra le sezioni */
  html[data-transizione^="faccia-"] .schede-preventivo { view-transition-name: schede-preventivo; }
  html[data-transizione^="faccia-"] .schede-sezione { view-transition-name: schede-sezione; }
  ::view-transition-group(schede), ::view-transition-group(barra), ::view-transition-group(barra-principale), ::view-transition-group(laterale), ::view-transition-group(schede-preventivo), ::view-transition-group(schede-sezione) { animation-duration: 220ms; }
  ::view-transition-old(root) { animation: 160ms var(--curva) both pagina-esce; }
  ::view-transition-new(root) { animation: 240ms var(--curva) 40ms both pagina-entra; }
  html[data-transizione="avanti"]::view-transition-old(root) { animation: 340ms cubic-bezier(0.32, 0.72, 0, 1) both spinta-esce; }
  html[data-transizione="avanti"]::view-transition-new(root) { animation: 340ms cubic-bezier(0.32, 0.72, 0, 1) both spinta-entra; }
  html[data-transizione="indietro"]::view-transition-old(root) { z-index: 1; animation: 300ms cubic-bezier(0.32, 0.72, 0, 1) both ritorno-esce; }
  html[data-transizione="indietro"]::view-transition-new(root) { animation: 300ms cubic-bezier(0.32, 0.72, 0, 1) both ritorno-entra; }
  /* tra le sezioni si scorre come tra le schede, verso quella toccata: le due pagine insieme, sfumando */
  html[data-transizione="destra"]::view-transition-old(root) { animation: 300ms cubic-bezier(0.32, 0.72, 0, 1) both scorri-via-sinistra; }
  html[data-transizione="destra"]::view-transition-new(root) { animation: 300ms cubic-bezier(0.32, 0.72, 0, 1) both scorri-da-destra; }
  html[data-transizione="sinistra"]::view-transition-old(root) { animation: 300ms cubic-bezier(0.32, 0.72, 0, 1) both scorri-via-destra; }
  html[data-transizione="sinistra"]::view-transition-new(root) { animation: 300ms cubic-bezier(0.32, 0.72, 0, 1) both scorri-da-sinistra; }
  /* tra «Preventivo» e «Documenti» si scorre di lato, verso la scheda toccata, a ogni larghezza: le schede sono in fila */
  html[data-transizione="faccia-destra"]::view-transition-old(root) { animation: 300ms cubic-bezier(0.32, 0.72, 0, 1) both faccia-via-sinistra; }
  html[data-transizione="faccia-destra"]::view-transition-new(root) { animation: 300ms cubic-bezier(0.32, 0.72, 0, 1) both faccia-da-destra; }
  html[data-transizione="faccia-sinistra"]::view-transition-old(root) { animation: 300ms cubic-bezier(0.32, 0.72, 0, 1) both faccia-via-destra; }
  html[data-transizione="faccia-sinistra"]::view-transition-new(root) { animation: 300ms cubic-bezier(0.32, 0.72, 0, 1) both faccia-da-sinistra; }
  html[data-transizione="sostituisci"]::view-transition-old(root) { animation: 120ms linear both pagina-esce; }
  html[data-transizione="sostituisci"]::view-transition-new(root) { animation: 160ms linear both svela; }
}
@keyframes pagina-esce { to { opacity: 0; } }
@keyframes pagina-entra { from { opacity: 0; transform: scale(0.985); } }
@keyframes svela { from { opacity: 0; } }
/* al PC la barra laterale è verticale: tra le sezioni il contenuto scorre appena in su o in giù, verso la voce */
@keyframes scorri-da-destra { from { opacity: 0; transform: translateY(20px); } }
@keyframes scorri-via-sinistra { to { opacity: 0; transform: translateY(-12px); } }
@keyframes scorri-da-sinistra { from { opacity: 0; transform: translateY(-20px); } }
@keyframes scorri-via-destra { to { opacity: 0; transform: translateY(12px); } }
/* tra le facce di un preventivo, al PC: un accenno di lato */
@keyframes faccia-da-destra { from { opacity: 0; transform: translateX(24px); } }
@keyframes faccia-via-sinistra { to { opacity: 0; transform: translateX(-12px); } }
@keyframes faccia-da-sinistra { from { opacity: 0; transform: translateX(-24px); } }
@keyframes faccia-via-destra { to { opacity: 0; transform: translateX(12px); } }
/* al PC: un accenno di spinta */
@keyframes spinta-entra { from { opacity: 0; transform: translateX(32px); } }
@keyframes spinta-esce { to { opacity: 0; transform: translateX(-16px); } }
@keyframes ritorno-esce { to { opacity: 0; transform: translateX(32px); } }
@keyframes ritorno-entra { from { opacity: 0; transform: translateX(-16px); } }
/* sul telefono: la spinta a tutta larghezza, e la pagina sotto che arretra di un terzo e si scurisce; tra le schede lo
   scorrimento di lato, per un quarto di schermo, come far scorrere le schede col dito */
@media (max-width: 720px), (pointer: coarse) and (max-height: 500px) {
  /* il nuovo sopralluogo: il pulsante largo quanto il telefono, sotto le Card */
  .azioni-sopralluogo .btn { width: 100%; justify-content: center; }
  @keyframes scorri-da-destra { from { opacity: 0; transform: translateX(25%); } }
  @keyframes scorri-via-sinistra { to { opacity: 0; transform: translateX(-25%); } }
  @keyframes scorri-da-sinistra { from { opacity: 0; transform: translateX(-25%); } }
  @keyframes scorri-via-destra { to { opacity: 0; transform: translateX(25%); } }
  @keyframes faccia-da-destra { from { opacity: 0; transform: translateX(25%); } }
  @keyframes faccia-via-sinistra { to { opacity: 0; transform: translateX(-25%); } }
  @keyframes faccia-da-sinistra { from { opacity: 0; transform: translateX(-25%); } }
  @keyframes faccia-via-destra { to { opacity: 0; transform: translateX(25%); } }
  @keyframes spinta-entra { from { transform: translateX(100%); } }
  @keyframes spinta-esce { to { transform: translateX(-30%); filter: brightness(0.92); } }
  @keyframes ritorno-esce { to { transform: translateX(100%); } }
  @keyframes ritorno-entra { from { transform: translateX(-30%); filter: brightness(0.92); } }
}
