/* =====================================================================
   LOI — Piattaforma progetti

   Questo foglio è quello di prototype/index.html — il blocco <style>
   nel <head>, portato integralmente. Le stesse classi, gli stessi
   valori: una pagina che usa `.room` o `.qrow` viene identica al
   prototipo, e non c'è nessuna variante "quasi uguale" da tenere
   allineata a mano.

   ATTENZIONE, e vale la pena scriverlo: il prototipo contiene TRE
   blocchi <style>. Gli altri due appartengono a finestre isolate — i
   documenti legali e il report PDF di un appuntamento — e ridefiniscono
   `body` con un `max-width` da foglio stampato. Portarli qui dentro
   stringe l'intera piattaforma in una colonna di 760 pixel. È successo:
   qui va solo il primo.

   Tre differenze rispetto al prototipo, tutte obbligate:

   1. Nessuno stile in linea da nessuna parte. La CSP di §2.3 non
      concede 'unsafe-inline', e questo vale per gli attributi style=
      quanto per i blocchi <style>. Dove il prototipo aggiustava un
      margine sul posto, qui c'è una classe di utilità (in fondo).
   2. Le bandiere del prefisso telefonico venivano da una CDN. Il
      prototipo stesso annotava che l'app reale non deve chiamare una
      CDN a runtime: al loro posto una sigla ISO della stessa misura.
   3. In coda, i componenti che il prototipo non aveva perché non
      prevedeva ancora cronologia e centro notifiche.

   Il giallo resta un segnale, non una superficie (D-06).
   ===================================================================== */

:root{
  --color-brand:#FEDD00;
  --color-background:#FFFFFF;
  --color-surface:#F5F5F5;
  --color-text:#000000;
  --color-text-secondary:#6B6B6B;
  --color-border:#E0E0E0;

  --font: "Graphik", "Graphik LCG", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:24px;
  --s-6:32px; --s-7:48px; --s-8:64px;
  /* Il passo fra due sezioni, come nel prototipo. */
  --s-9:56px;

  /* Due misure che più regole si scambiano, invece di ripetersele:
     l'altezza della barra in alto — a cui si aggancia la sotto-barra
     appiccicosa della pagina progetto — e il margine laterale della
     vista, che si stringe insieme alla finestra. Cambiano nelle soglie
     in fondo al foglio, e chi le usa si adegua da solo. */
  --h-topbar:71px;
  --pad-view:var(--s-6);

  /* Quanto della finestra la tastiera del telefono copre in questo
     momento: zero dappertutto, e il valore vero glielo scrive app.js
     leggendo `visualViewport`. Serve a due cose che vivono sul bordo
     inferiore — il foglio dal basso e la riga «Salva» della finestra a
     tutto schermo — che con `position:fixed` starebbero sotto la
     tastiera invece che sopra: il browser non restringe la finestra di
     layout quando la tastiera si apre, e nessuna misura in CSS lo sa. */
  --tastiera:0px;
}
*{box-sizing:border-box;margin:0;padding:0}
/* scrollbar-gutter riserva sempre lo spazio della scrollbar verticale: senza,
   aprire un menu a comparsa può far comparire la scrollbar, restringere la
   larghezza disponibile e far ricalcolare di colpo griglie auto-fill e
   header — esattamente il "salto" di layout da evitare su tutta la piattaforma. */
html{scroll-behavior:smooth;scrollbar-gutter:stable}
html,body{height:100%}
body{
  font-family:var(--font);
  background:var(--color-background);
  color:var(--color-text);
  font-size:14px;
  line-height:1.45;
  -webkit-font-smoothing:antialiased;
}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid var(--color-text);outline-offset:2px}

/* ---------- fuori dalla vista, dentro l'albero di accessibilità ----------
   Un nome che si ascolta e non si legge. `display:none` toglierebbe il
   testo anche a chi ascolta, ed è il modo in cui un bottone con la sola
   icona diventa un bottone senza nome.

   Serve in due situazioni che sembrano diverse e non lo sono: il nome
   scritto apposta per chi ascolta — le icone della barra in alto, il
   numero delle notifiche non lette — e l'etichetta di una voce di menu
   quando la colonna si stringe e resta la sola icona. Le stesse cinque
   dichiarazioni erano scritte due volte, e la seconda dentro una soglia:
   da lì non si potevano riusare, perché una regola non si eredita
   attraverso una media query.

   Per questo l'etichetta parte nascosta e si rivela dove c'è posto,
   invece del contrario: «c'è posto» è una soglia sola, «non c'è posto»
   ne avrebbe volute due. Il posto c'è sopra 1180 con la barra aperta, e
   sotto 860, dove il marchio passa nella testa della pagina e le voci se
   ne vanno nella barra in fondo — quella regola sta già nella soglia. */
.sr-only,
.brandmark .brandmark-title,
.nav .label{
  position:absolute;width:1px;height:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;
}
/* La stessa soglia scritta sotto — 1180 — letta dall'altro lato: sopra
   di lei, e con la barra non collassata a mano, l'etichetta è testo. */
@media (min-width:1181px){
  .app:not(.side-collapsed) .brandmark .brandmark-title,
  .app:not(.side-collapsed) .nav .label{
    position:static;width:auto;height:auto;overflow:visible;clip-path:none;
  }
}

/* ---------- tipografia ---------- */
/* Su uno schermo stretto 32px sono quattro parole per riga: il titolo
   scende fino a 24 e risale al suo valore appena c'è spazio. */
.t-display{font-weight:900;font-size:clamp(24px,4.5vw,32px);line-height:1.1;letter-spacing:-.02em}
.t-h2{font-weight:900;font-size:clamp(18px,3vw,22px);line-height:1.15;letter-spacing:-.01em}
.t-h3{font-weight:700;font-size:15px;letter-spacing:-.005em}
.t-label{font-weight:500;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-secondary)}
/* Il nome che apre una riga di tabella: pesa più del meta che gli sta
   sotto, ma non è un titolo — Medium, non Bold, e alla dimensione del
   testo corrente. */
.t-medio{font-weight:500}
/* Intestazione di campo, allineata all'etichetta reale del design system
   principale (Input.jsx/Textarea.jsx di loi.design, form "Scrivici"): peso
   regolare, minuscolo, senza letter-spacing — non l'occhiello .t-label
   (maiuscolo/bold/spaziato), che resta per eyebrow di sezione e meta-testi. */
.field-label{display:block;font-weight:400;font-size:12px;color:var(--color-text-secondary)}
.t-meta{font-size:12px;color:var(--color-text-secondary)}
.num{font-weight:900;font-size:11px;letter-spacing:.06em;color:var(--color-text-secondary)}

/* ---------- pill ----------
   Allineato al bottone reale del design system (loi.design/Button.jsx):
   peso 400 (non 500), padding e gap dai suoi token, transizione "all .2s"
   sulla stessa durata di --duration-base, e il pallino disegnato in CSS
   (cerchio con bordo che si riempie in hover) invece del carattere "○". */
/* Regola di design system: un pill non si stira mai, qualunque sia il
   contenitore che lo ospita — un antenato flex-column senza align-items
   esplicito (es. .card) stira di default i figli diretti a piena larghezza
   (align-items:stretch è il default flexbox), ed è già capitato che un
   pill "solitario" (non dentro una .row) ne facesse le spese. Basta fissare
   una larghezza non-auto (fit-content): per spec lo stretch si applica solo
   quando la dimensione sull'asse trasversale è auto, quindi non serve (anzi,
   rompe) forzare anche align-self — l'abbiamo provato: sovrascriveva pure
   l'allineamento centrato voluto nelle toolbar (.toolbar/.row hanno
   align-items:center), disallineando in verticale i pill diretti rispetto a
   quelli annidati in un wrapper. flex:none evita lo shrink in una riga stretta. */
.pill{
  display:inline-flex;align-items:center;gap:6px;
  border:1px solid var(--color-text);border-radius:999px;
  padding:6px 14px;font-weight:400;font-size:12px;
  transition:all .2s ease;
  white-space:nowrap;
  flex:none;width:fit-content;max-width:max-content;
}
.pill::before{content:"";width:6px;height:6px;flex:none;border:1.5px solid currentColor;border-radius:100px;background:transparent;transition:background .2s ease}
.pill--icon::before{display:none}
/* quiet/solid non sono CTA: l'inversione in hover non deve usare il giallo,
   riservato al segnale della pillola primaria (regola invariata da CLAUDE.md). */
.pill--quiet{border-color:var(--color-border);color:var(--color-text-secondary)}
.pill--solid{background:var(--color-text);border-color:var(--color-text);color:#fff}
.pill[disabled]{opacity:.4;pointer-events:none}
.pill--sm{padding:4px 10px;font-size:11px}
.pill--sm::before{width:5px;height:5px}
/* Terziaria: azioni minori o rischiose (es. elimina) — nessun bordo, nessun
   pallino, un filo di sottolineatura solo in hover: non deve competere
   visivamente con le azioni primarie/secondarie della stessa riga. Unica
   variante che resta diversa dal bottone reale (che il pallino lo mostra
   sempre): lì non condivide la riga con altre azioni come qui in tabella. */
.pill--tertiary{border-radius:0;border-color:transparent;padding:6px 2px;color:var(--color-text-secondary);text-decoration:underline;text-decoration-color:var(--color-border);text-underline-offset:3px}
.pill--tertiary::before{display:none}
.pill--tertiary:focus-visible{background:none;border-color:transparent;color:var(--color-text);text-decoration-color:currentColor}

/* ---------- badge stato ---------- */
.badge{
  display:inline-block;padding:4px 10px;border-radius:999px;
  font-size:11px;font-weight:500;letter-spacing:.04em;
  border:1px solid var(--color-border);color:var(--color-text-secondary);
  background:var(--color-background);white-space:nowrap;
}
.badge--active{background:var(--color-brand);border-color:var(--color-brand);color:var(--color-text);font-weight:700}
.badge--done{border-color:var(--color-text);color:var(--color-text)}
/* Segnala che non tutti gli ambienti del progetto sono alla stessa fase —
   il badge mostra il segnale più avanzato, questo evita che nasconda chi è
   rimasto indietro. Icona neutra (nessun colore nuovo in palette), il
   dettaglio sta nel title al passaggio del mouse. */
.stato-flag{display:inline-flex;vertical-align:middle;margin-left:4px;color:var(--color-text-secondary);cursor:default}
/* Avanzamento ordini: shade dello stesso giallo, non colori diversi — e
   sempre a riempimento pieno, mai un misto di bordo-solo e pieno. */
.badge--st0{background:#FFF9E0;border-color:#FFF9E0;color:var(--color-text)}
.badge--st1{background:#FFEE99;border-color:#FFEE99;color:var(--color-text)}
.badge--st2{background:#FCE45C;border-color:#FCE45C;color:var(--color-text)}

/* ---------- layout ---------- */
.app{display:none;min-height:100vh;min-height:100dvh;grid-template-columns:236px 1fr;transition:grid-template-columns .16s ease}
.app.is-on{display:grid}
.app.side-collapsed{grid-template-columns:84px 1fr}

.side{
  background:var(--color-surface);
  border-right:1px solid var(--color-border);
  padding:var(--s-5) var(--s-4);
  display:flex;flex-direction:column;gap:var(--s-6);
  position:sticky;top:0;height:100vh;height:100dvh;
  /* Su un portatile schermo-corto le voci possono superare l'altezza
     della finestra: la barra scorre per conto suo invece di tagliare le
     ultime voci fuori dallo schermo, dove non si raggiungono. */
  overflow-y:auto;overscroll-behavior:contain;
  transition:padding .16s ease;
}
.side-collapsed .side{padding-left:var(--s-3);padding-right:var(--s-3)}
.brandmark{position:relative;display:flex;align-items:center;gap:var(--s-2)}
.brandmark-mark{width:28px;height:28px;display:flex;flex:none}
.brandmark-title{font-weight:700;font-size:16px;color:var(--color-text)}
.side-head{display:flex;align-items:center;gap:var(--s-2)}
.side-collapsed .side-head{justify-content:center}

/* Freccetta di collasso: a metà altezza, incollata al bordo destro della
   sidebar, come in molti editor (metà dentro, metà fuori). */
.side-toggle{
  position:absolute;top:50%;right:-13px;transform:translateY(-50%);
  width:26px;height:26px;border-radius:50%;
  background:var(--color-background);border:1px solid var(--color-border);
  display:flex;align-items:center;justify-content:center;color:var(--color-text);
  box-shadow:0 1px 4px rgba(0,0,0,.12);z-index:11;
}
.side-collapsed .side-toggle svg{transform:rotate(180deg)}

.nav{display:flex;flex-direction:column;gap:1px}
.nav a{
  position:relative;
  display:flex;align-items:center;gap:10px;
  padding:9px var(--s-3);font-size:13px;font-weight:500;
  border-left:2px solid transparent;color:var(--color-text-secondary);
}
.nav a.is-on{color:var(--color-text);font-weight:700;border-left-color:var(--color-brand);background:var(--color-background)}
.side-collapsed .nav a{justify-content:center;padding:9px 0}
.nav a svg{flex:none}


.main{min-width:0}
/* Griglia a tre colonne (non flex) apposta: con tb-left/tb-right a larghezza
   variabile (breadcrumb, icone) un flex "centra nello spazio residuo" fa
   ballare il centro ogni volta che uno dei due lati cambia lunghezza. Due
   colonne di uguale ampiezza restano sempre uguali fra loro, quindi la
   colonna centrale resta ancorata al centro reale della barra, non a un
   centro che si sposta.
   La centrale non si misura però sul contenuto: `auto` la lasciava larga
   quanto il campo, cioè la ventina di caratteri di default di un input.
   Prende una quota della barra e cresce con la finestra, fino a un tetto
   oltre il quale un campo di ricerca è solo un rettangolo vuoto. I lati
   sono `minmax(0,1fr)` per potersi stringere invece di spingere la barra
   in overflow — la sinistra fino a zero, perché le briciole vanno a capo;
   la destra fino al proprio contenuto e non oltre, perché le tre icone e
   l'avatar non hanno un modo di stringersi: sotto quella misura non si
   restringevano, uscivano dalla barra. */
.topbar{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(240px,620px) minmax(max-content,1fr);
  align-items:center;gap:var(--s-4);
  padding:var(--s-4) var(--s-6);border-bottom:1px solid var(--color-border);
  position:sticky;top:0;background:var(--color-background);z-index:10;
}
.tb-left{display:flex;align-items:center;gap:var(--s-4);min-width:0}
.tb-center{display:flex;justify-content:center;min-width:0}
.tb-right{display:flex;align-items:center;gap:var(--s-2);justify-self:end}
/* Il campo riempie la colonna che gli è stata assegnata. */
#search-wrap{width:100%}
.tb-center .searchbar{width:100%}
.crumbs{display:flex;align-items:center;gap:var(--s-2);font-size:12px;color:var(--color-text-secondary);flex-wrap:wrap}
/* Tre parti della barra esistono solo sul telefono: il marchio (che qui
   sta nel menu laterale), il bottone che apre la ricerca (qui il campo è
   già aperto) e il passo indietro delle briciole (qui c'è il percorso
   intero). Nascoste, non sono colonne: la griglia della barra resta di
   tre anche con cinque figli. */
.topbar .tb-marchio,.topbar .tb-cerca,.topbar .crumb-su{display:none}
.view{padding:var(--pad-view);max-width:1180px}
.head{margin-bottom:var(--s-6)}
.head .t-label{margin-bottom:var(--s-2)}

/* ---------- header: icone, avatar, dropdown ---------- */
.rel{position:relative}
.icon-btn{
  display:inline-flex;align-items:center;justify-content:center;
  width:38px;height:38px;border-radius:50%;color:var(--color-text);
  position:relative;transition:background .14s ease;flex:none;
}
.icon-btn .dot{position:absolute;top:6px;right:7px;width:8px;height:8px;border-radius:50%;background:var(--color-brand);border:2px solid var(--color-background)}
.avatar{
  width:30px;height:30px;border-radius:50%;background:var(--color-text);color:#fff;
  display:inline-flex;align-items:center;justify-content:center;font-weight:700;font-size:11px;
}
.dropdown{
  position:absolute;top:calc(100% + 10px);right:0;width:300px;background:var(--color-background);
  border:1px solid var(--color-border);z-index:20;max-height:70vh;overflow:auto;display:none;
  box-shadow:0 10px 28px rgba(0,0,0,.10);
}
.dropdown.is-on{display:block}
/* Il pannello risultati può essere più largo del campo che lo apre, per
   ospitare bene i dati — ancorato al centro del campo, non al suo bordo. */
.dropdown--search{left:50%;right:auto;transform:translateX(-50%);width:480px;max-width:80vw}
.dropdown-head{padding:var(--s-4) var(--s-4) var(--s-3);border-bottom:1px solid var(--color-border);font-weight:700;font-size:13px}
.dropdown-item{display:block;width:100%;text-align:left;padding:var(--s-3) var(--s-4);border-bottom:1px solid var(--color-border)}
.dropdown-item:last-child{border-bottom:0}

/* ---------- ricerca ---------- */
.searchbar{display:flex;align-items:center;gap:var(--s-2);border:1px solid var(--color-border);border-radius:999px;padding:8px 14px;color:var(--color-text-secondary)}
.searchbar input{border:0;background:none;font:inherit;flex:1;color:var(--color-text);min-width:0}
.searchbar input:focus{outline:0}
.search-group{padding:var(--s-3) var(--s-4) var(--s-1);font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--color-text-secondary)}
.search-hit{display:flex;justify-content:space-between;gap:var(--s-2);width:100%;text-align:left;padding:var(--s-2) var(--s-4);border-bottom:1px solid var(--color-border)}
/* Larga almeno quanto la riga di filtri sotto (Tutti i progetti/Stato/Esito
   e simili) — a 180px il placeholder più lungo ("Cerca progetto, luogo,
   cliente…") non ci stava. Stesso campo su tutte le pagine elenco, un solo
   posto da correggere. */
/* `max-width` accanto a `width`: senza, i 420px valgono anche su uno
   schermo da 390 e non è il campo a uscire — è la pagina intera ad
   allargarsi, portando fuori dallo schermo il bordo destro di ogni card
   e di ogni tabella. Il sintomo si vedeva ovunque, la causa era qui. */
.searchmini{display:flex;align-items:center;gap:var(--s-2);border-bottom:1px solid var(--color-border);padding:6px 2px;color:var(--color-text-secondary);width:420px;max-width:100%;flex:0 1 auto}
.searchmini input{border:0;background:none;font:inherit;flex:1;color:var(--color-text);min-width:0}
.searchmini input:focus{outline:0}

/* ---------- toolbar uniforme (griglia costante fra pagine) ---------- */
.toolbar{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;margin-bottom:var(--s-5);min-height:38px}

/* ---------- titoli di sezione: più affordance fra i blocchi di una pagina ---------- */
.section-title{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-4);flex-wrap:wrap}
/* Il titolo di sotto-sezione non porta più la riga nera sotto: bastava
   il peso del carattere a dire che comincia qualcosa, e in una pagina
   con tre o quattro sezioni quelle righe diventavano un reticolo.
   Tolto il bordo, però, lo stacco fra una sezione e l'altra deve
   arrivare dallo spazio: 56, il passo di sezione del ritmo verticale.
   `* +` e non un margine sempre presente, perché il primo titolo di
   una pagina (o di una `.sezione-progetto`) non ha niente sopra da cui
   staccarsi — è la stessa eccezione dichiarata per `.field + .field`. */
* + .section-title{margin-top:var(--s-9)}
.section-title .num{font-size:13px}
.section-title h2{margin:0}

/* ---------- card ---------- */
.grid{display:grid;gap:var(--s-4)}
.grid--3{grid-template-columns:repeat(auto-fill,minmax(min(280px,100%),1fr))}
.grid--2{grid-template-columns:repeat(auto-fill,minmax(min(340px,100%),1fr))}
.card{
  border:1px solid var(--color-border);background:var(--color-background);
  padding:var(--s-5);display:flex;flex-direction:column;gap:var(--s-3);
  transition:border-color .14s ease;text-align:left;
}
.card-top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s-3)}
.card-foot{margin-top:auto;padding-top:var(--s-3);border-top:1px solid var(--color-border);
  display:flex;justify-content:space-between;align-items:center;gap:var(--s-3)}

/* ---------- righe ambiente / accordion ---------- */
.room{border:1px solid var(--color-border);margin-bottom:var(--s-4)}
.room-head{display:flex;align-items:center;gap:var(--s-4);padding:var(--s-4) var(--s-5);background:var(--color-surface);cursor:pointer;flex-wrap:wrap}
.room-head .t-h3{flex:1}
.room-head .chev{color:var(--color-text-secondary);transition:transform .16s ease;flex:none}
.room.is-open .chev{transform:rotate(180deg)}
.room-body{display:none;padding:var(--s-4) var(--s-5);flex-direction:column;gap:var(--s-2)}
.room.is-open .room-body{display:flex}
.qrow{
  display:grid;grid-template-columns:1fr auto auto auto;gap:var(--s-4);align-items:center;
  padding:var(--s-3) 0;border-bottom:1px solid var(--color-border);
}
.qrow:last-child{border-bottom:0}
/* Riga con una sola azione in coda (es. "Progetti da fatturare"): senza
   le colonne dei numeri l'azione resterebbe a metà riga. */
.qrow--azione{grid-template-columns:1fr auto}
.amount{font-weight:700;font-variant-numeric:tabular-nums}

/* ---------- tabella ---------- */
table{width:100%;border-collapse:collapse}
/* Stessa tabella (stesse colonne), stessa larghezza ovunque compaia — con
   table-layout:auto (il default) le colonne si allargano in base al
   contenuto DI QUELLA pagina, quindi "Voce"/"Azienda"/ecc. finiscono larghe
   in modo diverso in Progetti, Ordini e nel dettaglio ordine a seconda di
   cosa c'è scritto lì, invece di restare coerenti. table-layout:fixed +
   larghezze esplicite sulle colonne "corte" fissano lo schema una volta
   sola; "Voce" resta senza larghezza propria e assorbe lo spazio residuo. */
.tbl-ordine{table-layout:fixed}
.tbl-ordine th:nth-child(2),.tbl-ordine td:nth-child(2){width:140px}
.tbl-ordine th:nth-child(3),.tbl-ordine td:nth-child(3){width:170px}
.tbl-ordine th:nth-child(4),.tbl-ordine td:nth-child(4){width:150px}
.tbl-ordine th:nth-child(5),.tbl-ordine td:nth-child(5){width:190px}
/* La colonna azione eredita white-space:nowrap da .num-cell (serve per gli
   importi tabulari), ma qui dentro ci stanno due pill affiancati ("Registra
   aggiornamento" + "Elimina") che non entrano in una riga sola a larghezza
   fissa: forzavano la tabella (e quindi la pagina) in scroll orizzontale.
   Vanno a capo su due righe, restando dentro la larghezza fissa. */
.tbl-ordine td:nth-child(5){white-space:normal}
.tbl-ordine td:nth-child(5) .pill{margin:2px 0 2px 6px}
/* Stessa cosa per la tabella voci del preventivo: compare sia in vPreventivo()
   sia — senza intestazione — dentro "Scelta definitiva" nella pagina progetto.
   "Voce" resta flessibile, Q.tà/Prezzo/Totale/azione hanno larghezza fissa. */
.tbl-voci{table-layout:fixed}
.tbl-voci th:nth-child(2),.tbl-voci td:nth-child(2){width:90px}
.tbl-voci th:nth-child(3),.tbl-voci td:nth-child(3){width:110px}
.tbl-voci th:nth-child(4),.tbl-voci td:nth-child(4){width:110px}
.tbl-voci th:nth-child(5),.tbl-voci td:nth-child(5){width:170px}
.tbl-voci td:nth-child(5){white-space:normal}
.tbl-voci td:nth-child(5) .pill{margin:2px 0 2px 6px}
/* La somma delle colonne fisse è la larghezza sotto la quale "Voce" —
   l'unica colonna senza misura propria — si riduce a quel che avanza, e
   quel che avanza diventa presto una lettera per riga. Le due tabelle si
   fermano lì e scorrono dentro `.tabella-scroll`, che le avvolge
   entrambe ovunque compaiano. Non è una regola da telefono: succede già
   in una finestra da mezzo schermo su un portatile, ed è da lì che il
   problema si è visto. */
.tbl-ordine{min-width:780px}
.tbl-voci{min-width:620px}
th{
  text-align:left;font-size:11px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;
  color:var(--color-text-secondary);padding:var(--s-3) var(--s-3);border-bottom:1px solid var(--color-text);
}
td{padding:var(--s-4) var(--s-3);border-bottom:1px solid var(--color-border);vertical-align:middle;overflow-wrap:break-word}

/* Intestazione che ordina. Il colore pieno la distingue dalle intestazioni
   inerti — che restano grigie — senza aggiungere un altro segnale: in una
   riga di etichette tutte uguali, quelle su cui si può agire devono
   dirlo da sole. La freccia compare solo sulla colonna attiva. */
th a{display:inline-flex;align-items:center;gap:4px;color:inherit}
th a[aria-sort]{color:var(--color-text);font-weight:700}
th a svg{flex:none}
.num-cell th a,th.num-cell a{justify-content:flex-end}
td.num-cell{font-variant-numeric:tabular-nums;text-align:right;font-weight:700;white-space:nowrap}
tr.is-total td{border-bottom:0;font-weight:900;padding-top:var(--s-4)}

/* ---------- tracking: solo lo stato attuale, il resto in un tooltip ---------- */
.track{position:relative;display:inline-block}
.track-tip{
  display:none;flex-direction:column;gap:4px;position:absolute;top:calc(100% + 6px);left:0;
  background:var(--color-text);color:#fff;padding:8px 10px;border-radius:6px;font-size:11px;
  z-index:20;box-shadow:0 8px 20px rgba(0,0,0,.2);
  /* Le tappe stanno su una riga ciascuna, larghe quanto la più lunga:
     `nowrap` le teneva così ma a 390 usciva dallo schermo. Il tetto è
     la finestra meno i margini della vista. */
  width:max-content;max-width:calc(100vw - 2 * var(--s-4));
}
.track-tip span{white-space:normal}
.track:focus-within .track-tip{display:flex}
.track-tip span{opacity:.55}
.track-tip span.done{opacity:.85;text-decoration:line-through}
.track-tip span.now{opacity:1;font-weight:700}
.note{font-size:12px;color:var(--color-text-secondary);margin-top:var(--s-2);padding-left:var(--s-3);border-left:2px solid var(--color-brand)}

/* ---------- visibilità ---------- */
.vis{display:inline-flex;align-items:center;gap:var(--s-2);font-size:11px;color:var(--color-text-secondary)}
.vis span:last-child{display:inline-block;width:92px;text-align:left}
.switch{width:34px;height:18px;border:1px solid var(--color-text);border-radius:999px;position:relative;background:var(--color-background);flex:none}
.switch i{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:var(--color-text);transition:transform .16s ease}
.switch.on{background:var(--color-brand);border-color:var(--color-brand)}
.switch.on i{transform:translateX(16px)}

/* ---------- briefing giornaliero: box compatto con spunta ---------- */
.briefing-box{border:1px solid var(--color-border);background:var(--color-surface);padding:0 var(--s-4)}
.briefing-row{display:grid;grid-template-columns:auto 1fr auto;gap:var(--s-3);align-items:center;padding:7px 0;border-bottom:1px solid var(--color-border)}
.briefing-row:last-child{border-bottom:0}
/* Una riga sola per voce: il testo tronca con ellissi invece di andare a
   capo, min-width:0 è necessario perché un figlio di grid altrimenti non si
   restringe mai sotto la sua larghezza di contenuto naturale. */
.briefing-row-testo{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-align:left}
.briefing-row-testo .t-meta{display:inline}
.briefing-check{width:18px;height:18px;border:1.5px solid var(--color-border);border-radius:50%;display:flex;align-items:center;justify-content:center;flex:none;color:#fff;transition:background .14s ease,border-color .14s ease}
.briefing-check.is-on{background:var(--color-brand);border-color:var(--color-brand);color:var(--color-text)}
/* Il segno di spunta esiste sempre nel markup ma è invisibile finché non è
   completato — passando sopra un cerchietto ancora vuoto appare comunque, a
   suggerire cosa succede cliccando (spunta fantasma, non è ancora fatto). */
.briefing-check svg{opacity:0;transition:opacity .14s ease}
.briefing-check.is-on svg{opacity:1}

/* ---------- tessere con immagine di sfondo (schede brand) ---------- */
.tessere{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(240px,100%),1fr));gap:2px}
.tessera{
  aspect-ratio:4/5;position:relative;overflow:hidden;display:flex;align-items:flex-end;
  padding:var(--s-4);color:#fff;text-align:left;
}
.tessera span{position:relative;z-index:2;font-weight:700;font-size:13px;letter-spacing:.02em}
.tessera em{position:relative;z-index:2;display:block;font-style:normal;font-size:11px;opacity:.75;letter-spacing:.06em;text-transform:uppercase}
.tessera::after{content:"";position:absolute;inset:0;background:linear-gradient(transparent 30%,rgba(0,0,0,.72));z-index:1}
.tessera::before{content:"";position:absolute;inset:0;transition:transform .5s ease}

.tessera-riga{display:flex;align-items:center;gap:var(--s-4);border:1px solid var(--color-border);padding:var(--s-4);margin-bottom:var(--s-2);text-align:left;width:100%;transition:border-color .14s ease}
.tessera-mini{width:52px;height:52px;flex:none;object-fit:cover}
/* L'elenco della vetrina nel pannello: la riga porta la miniatura, il
   testo e le azioni; sotto 860 le azioni vanno a capo sotto il testo. */
.vetrina-testo{flex:1;min-width:0}
.vetrina-azioni{flex:none}
/* L'elenco si riordina trascinando (D-63). La maniglia è il solo punto
   da cui un dito solleva la riga — `touch-action:none` lì e non sulla
   riga, così il resto della riga fa ancora scorrere la pagina. Col
   mouse si prende la riga dove capita: il cursore lo dice. */
[data-ordina] .tessera-riga{position:relative;background:var(--color-background);cursor:grab}
[data-ordina].ordinando,[data-ordina].ordinando .tessera-riga{cursor:grabbing;user-select:none;-webkit-user-select:none}
.maniglia{flex:none;display:flex;align-items:center;justify-content:center;width:24px;height:40px;margin:-8px 0;color:var(--color-text-secondary);cursor:grab;touch-action:none;position:relative}
.tessera-riga.trascinata{z-index:2;border-color:var(--color-text);box-shadow:0 8px 24px rgba(0,0,0,.14)}

/* ---------- gallery vera (Foto, Render, Moodboard): foto + didascalia, non link ---------- */
.gallery-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(220px,100%),1fr));gap:var(--s-4)}
.gal-card{border:1px solid var(--color-border);text-align:left;overflow:hidden;transition:border-color .14s ease;background:var(--color-background)}
.gal-thumb{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;background:var(--color-surface)}
/* Un PDF o un DWG non ha anteprima: al suo posto un riquadro con
   l'icona del documento, delle stesse proporzioni, così la griglia non
   si scompone quando le due cose stanno una accanto all'altra. */
.gal-thumb--file{display:flex;align-items:center;justify-content:center;
  color:var(--color-text-secondary)}
.gal-card-info{padding:var(--s-3) var(--s-4) var(--s-4)}
.gal-card-title{font-weight:700;font-size:13px}

/* ---------- lightbox: vista full screen navigabile ---------- */
.lightbox-overlay{position:fixed;inset:0;background:rgba(0,0,0,.92);z-index:60;display:flex;align-items:center;justify-content:center;flex-direction:column;padding:var(--s-6);touch-action:pan-y pinch-zoom}
.lightbox-img{max-width:min(92vw,1100px);max-height:70vh;object-fit:contain;box-shadow:0 20px 60px rgba(0,0,0,.5)}
.lightbox-img--placeholder{width:min(92vw,1100px);height:70vh;
  display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.6)}
.lightbox-close{position:absolute;top:var(--s-5);right:var(--s-5);color:#fff;padding:8px}
.lightbox-nav{position:absolute;top:50%;transform:translateY(-50%);color:#fff;padding:12px}
.lightbox-nav--prev{left:var(--s-5)}
.lightbox-nav--next{right:var(--s-5)}
/* Il contenitore delle due frecce: da scrivania non c'è — `contents` lo
   toglie dal disegno e le frecce restano assolute ai bordi — e sotto
   520 diventa la riga sotto la foto. */
.lightbox-frecce{display:contents}
.lightbox-caption{margin-top:var(--s-5);text-align:center;color:#fff;max-width:70ch;
  display:flex;flex-direction:column;gap:var(--s-2);align-items:center}
.lightbox-caption-titolo{font-weight:700}
/* Sul nero il grigio dei metadati sparisce: qui vale il bianco velato. */
.lightbox-caption .t-meta{color:rgba(255,255,255,.7)}
.lightbox-caption .pill{border-color:rgba(255,255,255,.4);color:#fff}

/* ---------- navigazione interna al progetto: sub-menu, non pulsanti ---------- */
.subnav{
  display:flex;gap:var(--s-6);flex-wrap:wrap;margin-bottom:var(--s-6);
  position:sticky;top:var(--h-topbar);background:var(--color-background);padding:var(--s-3) 0;z-index:4;border-bottom:1px solid var(--color-border);
}
.subnav a{
  font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--color-text-secondary);padding-bottom:6px;border-bottom:2px solid transparent;
}
.subnav a.active{color:var(--color-text);border-bottom-color:var(--color-brand)}
[id^="sez-"]{scroll-margin-top:calc(var(--h-topbar) + 80px)}

/* ---------- card a bassa enfasi ----------
   La sezione "Progetto e documenti" aveva anche un titolo più piccolo e
   grigio degli altri: in una pagina lunga come quella del progetto due
   misure di titolo si leggono come due gerarchie, e quella sezione non
   sta un gradino sotto le altre. Restano le card sommesse, che è dove
   la bassa enfasi ha senso. */
.section-title-icon{color:var(--color-text-secondary);display:flex;flex:none}
.card--quiet{background:var(--color-surface);border-color:transparent;box-shadow:none}

/* ---------- modale ---------- */
/* align-items:flex-start (non center) apposta: se il contenuto del modale
   cambia altezza (es. Azienda ↔ Privato nel form cliente), il bordo
   superiore resta fermo — solo quello inferiore si allarga o si stringe. */
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.4);display:none;align-items:flex-start;justify-content:center;z-index:50;padding:var(--s-5);overflow-y:auto}
.modal-overlay.is-on{display:flex;padding-top:8vh}
.modal-box{background:var(--color-background);border:1px solid var(--color-border);max-width:600px;min-width:min(320px,100%);min-height:340px;width:100%;padding:var(--s-6);max-height:86vh;overflow:auto}
/* Titolo della finestra e croce sulla stessa riga, la croce ai margini
   del testo e non appesa all'angolo della scatola. */
.modale-testa{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s-4)}
.modale-chiudi{color:var(--color-text-secondary);display:flex;padding:var(--s-1);flex:none}
/* Un blocco preso dalla pagina porta con sé i propri margini: dentro
   la finestra l'ultimo non deve lasciarne uno appeso sotto. */
.modal-box > *:last-child{margin-bottom:0}
.check-row{display:flex;align-items:flex-start;gap:var(--s-3);padding:var(--s-4);border:1px solid var(--color-text);margin-top:var(--s-4)}
/* `.field + .field` non copre questo caso: sopra c'è una casella, non
   un campo, e «Orario di invio» finiva incollato al riquadro. */
.check-row + .field{margin-top:var(--s-5)}
.check-row.warn{border-color:#b4881f;background:#fffbea}

/* ---------- caricamento file: trascina o clicca ---------- */
.dropzone{border:1px dashed var(--color-border);padding:var(--s-6) var(--s-5);text-align:center;cursor:pointer;color:var(--color-text-secondary);transition:border-color .14s ease,background .14s ease}
.dropzone.over{border-color:var(--color-text);background:var(--color-surface);color:var(--color-text)}
.dz-list{display:flex;flex-wrap:wrap;gap:6px;margin-top:14px;justify-content:center}
.dz-chip{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--color-border);border-radius:999px;padding:5px 6px 5px 12px;font-size:12px;background:var(--color-background)}
.dz-chip button{display:inline-flex;color:var(--color-text-secondary)}

/* ---------- conferma ---------- */
.toast{
  position:fixed;left:50%;bottom:28px;transform:translateX(-50%) translateY(20px);
  background:var(--color-text);color:#fff;padding:12px 20px;border-radius:999px;
  font-size:13px;font-weight:500;opacity:0;pointer-events:none;
  transition:opacity .18s ease, transform .18s ease;z-index:60;
}
.toast.is-on{opacity:1;transform:translateX(-50%) translateY(0)}

/* ---------- login ---------- */
/* La schermata di accesso (D-62): a sinistra la vetrina — una foto
   per progetto, a tutto schermo, una per volta — e a destra il modulo.
   Le foto le sceglie il team LOI dal pannello di amministrazione. */
.login{
  min-height:100vh;min-height:100dvh;display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,520px);
}
.login.is-off{display:none}
.login-scena{position:relative;overflow:hidden;background:var(--color-text);min-height:100dvh}
.diapositiva{position:absolute;inset:0;margin:0;opacity:0;transition:opacity 1.2s ease}
.diapositiva.is-on{opacity:1}
.diapositiva img{width:100%;height:100%;object-fit:cover;display:block}
/* La didascalia sta sopra una sfumatura scura che parte a metà foto,
   così il bianco regge su qualsiasi immagine. */
.diapositiva figcaption{
  position:absolute;left:0;right:0;bottom:0;padding:var(--s-8) var(--s-7) var(--s-7);
  background:linear-gradient(transparent,rgba(0,0,0,.7));color:#fff;
  display:flex;flex-direction:column;gap:4px;
}
.diapositiva figcaption strong{font-weight:700;font-size:18px}
.diapositiva figcaption span{font-size:13px;opacity:.85}
/* Senza foto la scena è scura e dice cosa manca: il posto è quello della
   foto dello showroom, e la stessa scena la ha LOI OS (D-65). */
.login-scena--vuota{display:flex;align-items:center;justify-content:center;padding:var(--s-7);background:var(--color-text)}
.login-segnaposto{color:rgba(255,255,255,.55);font-size:12px;font-weight:500;letter-spacing:.08em;text-transform:uppercase}
.login-lato{display:flex;align-items:center;padding:var(--s-8) var(--s-7)}
.login-form{display:flex;flex-direction:column;gap:var(--s-5);width:100%}
.login-form .claim{color:var(--color-text-secondary);font-size:14px;max-width:38ch}
.login-marchio{width:44px;height:44px;display:flex}
.field{display:flex;flex-direction:column;gap:var(--s-2)}
/* Due campi impilati non si toccano: fra l'uno e l'altro corre il passo
   da 16 del ritmo verticale. Dentro `.form-grid` lo spazio lo dà già la
   griglia (margin-bottom su ogni campo) e la regola si annulla, invece
   di sommarsi. Qui lo spazio lo prende chi sta sotto e non chi sta sopra,
   unica eccezione al ritmo verticale: `+` è il solo selettore che dice a
   un campo se ne ha un altro accanto senza dipendere da `:has()`. */
.field + .field{margin-top:var(--s-4)}
/* Allineato al vero campo del sito loi.design (form "Scrivici"): riga sottile
   sotto al campo, non un box; a fuoco diventa nero, non giallo — il giallo
   nel design system principale è un segnale isolato (CTA, stato attivo), mai
   usato come feedback di focus su ogni campo di un form. */
.field input{border:0;border-bottom:1px solid var(--color-border);padding:10px 0;font-size:15px;background:none}
.field input:focus{outline:0;border-bottom-color:var(--color-text)}
.field input[disabled]{color:var(--color-text-secondary)}
.field textarea{border:0;border-bottom:1px solid var(--color-border);padding:10px 0;font-size:15px;background:none;font-family:inherit;color:inherit;width:100%;resize:vertical;min-height:80px}
.field textarea:focus{outline:0;border-bottom-color:var(--color-text)}
.field select{border:0;border-bottom:1px solid var(--color-border);padding:10px 0;font-size:15px;background:none;font-family:inherit;color:inherit;width:100%}

/* ---------- password: occhiello + contatore di sicurezza, ovunque ---------- */
.pw-wrap{position:relative}
.pw-wrap input{padding-right:32px;width:100%}
.pw-eye{position:absolute;right:0;top:50%;transform:translateY(-50%);color:var(--color-text-secondary);display:flex;padding:4px}
.pw-strength{display:flex;align-items:center;gap:var(--s-2);margin-top:8px}
.pw-strength-bar{flex:1;height:4px;background:var(--color-border);border-radius:2px;overflow:hidden}
.pw-strength-fill{display:block;height:100%;width:0;background:var(--color-text);transition:width .16s ease}

/* ---------- avatar caricabile ---------- */
.avatar-upload{position:relative;width:84px;height:84px;flex:none}
.avatar-upload-img{
  display:flex;align-items:center;justify-content:center;width:84px;height:84px;border-radius:50%;
  background:var(--color-text);color:#fff;font-weight:700;font-size:24px;overflow:hidden;
}
.avatar-upload-btn{
  position:absolute;bottom:0;right:0;width:30px;height:30px;border-radius:50%;
  background:var(--color-background);border:1px solid var(--color-border);
  display:flex;align-items:center;justify-content:center;box-shadow:0 1px 4px rgba(0,0,0,.15);color:var(--color-text);
}
.field select:focus{outline:0;border-bottom-color:var(--color-text)}

/* ---------- indirizzo: suggerimenti da OpenStreetMap ----------
   L'elenco esce dal flusso e si appoggia sotto al campo, come ogni altro
   pannello a comparsa della piattaforma: dentro un `.form-grid` occupare
   spazio vero sposterebbe di colpo tutti i campi della riga accanto. */
.ind-wrap{position:relative}
/* Bordo, padding e fuoco li dà già `.field input`: qui serve solo che il
   campo riempia il contenitore che lo avvolge. */
.ind-wrap>input{width:100%}
.ind-list{
  position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:20;
  background:var(--color-background);border:1px solid var(--color-border);
  box-shadow:0 10px 28px rgba(0,0,0,.10);max-height:280px;overflow:auto;
}
.ind-opt{display:flex;flex-direction:column;gap:2px;width:100%;text-align:left;
  padding:var(--s-2) var(--s-4);border-bottom:1px solid var(--color-border)}
.ind-opt-riga{font-size:14px}
/* Il nome completo di un luogo è lungo quanto vuole: sta su una riga
   sola e si tronca, invece di allargare il pannello. */
.ind-opt .t-meta{overflow:hidden;text-overflow:ellipsis;max-width:100%}
.ind-opt.is-on{background:var(--color-surface)}
/* L'attribuzione a OpenStreetMap: piccola, in coda, ma sempre presente —
   è la condizione a cui quei dati si usano. */
.ind-attrib{padding:var(--s-2) var(--s-4);font-size:12px;color:var(--color-text-secondary);border-top:1px solid var(--color-border)}

/* ---------- telefono: prefisso (bandiera SVG, cercabile) + numero, un campo solo ---------- */
.tel-combo{display:flex;align-items:center;border-bottom:1px solid var(--color-border)}
.tel-combo:focus-within{border-bottom-color:var(--color-text)}
.tel-combo>input{border:0;padding:10px 0;font-size:15px;background:none;flex:1;min-width:0}
.tel-combo>input:focus{outline:0}
.tel-prefix{flex:none;position:relative}
/* `line-height:normal` come dentro un `input`: col 1.45 del body la riga
   del prefisso era alta 22px contro i 18 del campo accanto, e il
   telefono restava due pixel più basso degli altri campi della griglia
   — bordo inferiore compreso. */
.tel-prefix-trigger{display:flex;align-items:center;gap:8px;padding:10px 4px 10px 0;color:inherit;font-size:15px;line-height:normal}
/* Al posto della bandiera (che veniva da una CDN, vietata dalla CSP) una
   sigla ISO: stessa larghezza, stesso peso visivo, nessuna dipendenza. */
.tel-prefix-trigger .fi,.tel-prefix-opt .fi{width:22px;height:14px;flex:none;display:inline-flex;
  align-items:center;justify-content:center;background:var(--color-surface);border-radius:2px;
  box-shadow:0 0 0 1px rgba(0,0,0,.08);font-size:8px;font-weight:700;letter-spacing:.04em;
  color:var(--color-text-secondary);text-transform:uppercase}
.tel-prefix-val{white-space:nowrap;margin-right:2px}
/* `display:flex` qui vinceva sul `display:none` di `.dropdown` — questa
   regola viene dopo — e il menu dei prefissi restava aperto senza che
   nessuno lo avesse aperto: un riquadro «Cerca paese o prefisso…»
   sospeso sopra la pagina, in ogni form con un telefono. La direzione
   della colonna vale sempre; a comparire è solo quando è `.is-on`. */
/* Ancorato al bordo sinistro del bottone e non a quello destro come gli
   altri `.dropdown`: il prefisso sta all'inizio del campo, spesso a
   pochi pixel dal bordo della pagina, e un pannello da 300px che cresce
   verso sinistra da lì finisce fuori dallo schermo. */
.tel-prefix-menu{min-width:260px;padding:0;flex-direction:column;left:0;right:auto}
.tel-prefix-menu.is-on{display:flex}
/* Selettore lungo per necessità: `.field input` (una classe e un tipo)
   vince su `.tel-prefix-search` (una classe sola) anche stando prima nel
   file, e gli imponeva `padding:10px 0` — il testo appiccicato al bordo
   sinistro del pannello — più la riga nera del proprio focus, che qui
   diventava una barra scura larga quanto il pannello. Dentro un menu già
   aperto sul campo giusto, quel segnale di fuoco non dice niente: resta
   la sottile riga di separazione dall'elenco. */
.tel-prefix-menu .tel-prefix-search{border:0;border-bottom:1px solid var(--color-border);
  padding:10px 12px;font-size:13px;width:100%;font-family:inherit;background:none}
.tel-prefix-menu .tel-prefix-search:focus{outline:0;border-bottom-color:var(--color-border)}
.tel-prefix-list{max-height:240px;overflow:auto;padding:6px}
.tel-prefix-opt{display:flex;align-items:center;gap:10px}
.field-error{color:#b3413e;font-size:11px;margin-top:4px}


/* ---------- select per i filtri: stesso stile pill del resto ---------- */
.select-filter{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  border:1px solid var(--color-border);border-radius:999px;color:var(--color-text-secondary);
  padding:7px 30px 7px 16px;font-weight:500;font-size:12px;font-family:inherit;
  background:var(--color-background) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23787878' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 14px center;
  cursor:pointer;transition:border-color .14s ease,color .14s ease;
}
.select-filter:focus{outline:0;border-color:var(--color-brand)}

/* ---------- filtro a checkbox multi-selezione ---------- */
.filtro-check{position:relative;display:inline-block}
.filtro-check-list{position:absolute;top:calc(100% + 6px);left:0;background:var(--color-background);border:1px solid var(--color-border);box-shadow:0 8px 20px rgba(0,0,0,.10);z-index:30;padding:8px;min-width:200px;max-height:280px;overflow:auto}
.filtro-check-opt{display:flex;align-items:center;gap:8px;padding:6px 4px;font-size:13px;cursor:pointer;white-space:nowrap}
.filtro-check-opt input{margin:0}
.filtro-check-clear{margin-top:4px;font-size:11px;color:var(--color-text-secondary);text-decoration:underline;padding:4px}

/* ---------- viste personalizzate: un solo selettore a comparsa ---------- */
/* Una riga di tabella che si apre da qualsiasi punto: il collegamento
   resta sul nome per la tastiera, il resto della riga risponde al
   clic — come nel prototipo, dove la riga aveva un onclick suo. */
/* Titolo di scheda con i suoi badge sulla stessa riga, e la riga di
   azioni che le segue: nel prototipo erano due `style` in linea. */
/* Cronologia: tipo, fatto, e a destra se il cliente lo vede. Tre
   colonne fisse come nel prototipo, allineate in alto perché il testo
   di un'attività può occupare più righe del suo badge. */
.qrow--storico{grid-template-columns:minmax(0,118px) minmax(0,1fr) minmax(0,150px);align-items:start}
.qrow--storico .badge{width:fit-content}
.tl-testo{font-weight:500}

.row--titolo{gap:10px}
.row--azioni{margin-top:var(--s-4);gap:var(--s-2)}
.max-64ch{max-width:64ch}

/* Il grigio del passaggio del mouse sta sotto `(hover:hover)`, dove un
   puntatore c'è: al tocco una riga di tabella non dava nessun ritorno —
   si toccava un nome e per un istante non succedeva niente, senza sapere
   se il dito avesse preso o fosse scivolato. `:active` dura quanto il
   dito resta giù, quindi non resta incollato come farebbe l'hover. */
.riga-cliccabile{cursor:pointer}
.riga-cliccabile:active{background:var(--color-surface)}

.vista-switcher,.modo-switcher{flex:none}
.vista-menu{min-width:220px;padding:6px}
.vista-item{display:flex;align-items:center;gap:8px;width:100%;text-align:left;padding:8px 10px;font-size:13px;border-radius:4px;color:var(--color-text)}
.vista-item svg{flex:none}
.vista-item.on{font-weight:700}
.vista-item-row{display:flex;align-items:center}
.vista-item-row .vista-item{flex:1}
.vista-item-x{padding:6px;color:var(--color-text-secondary);flex:none}
.vista-item--new{border-top:1px solid var(--color-border);margin-top:4px;padding-top:10px;font-weight:500}

/* ---------- kanban ---------- */
.kanban{display:flex;gap:16px;overflow-x:auto;padding-bottom:8px}
.kanban-col{flex:0 0 260px;background:var(--color-surface);border-radius:4px;padding:12px;min-height:80px}
.kanban-col.over{outline:2px dashed var(--color-brand);outline-offset:-2px}
.kanban-col-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
.kanban-card{background:var(--color-background);border:1px solid var(--color-border);border-radius:4px;padding:10px;margin-bottom:8px;cursor:grab;text-align:left;width:100%}
.kanban-card:active{cursor:grabbing}

/* ---------- calendario ---------- */
.cal-head{display:flex;align-items:center;margin-bottom:16px}
/* Le due griglie — intestazione dei giorni e celle — scorrono insieme
   dentro un unico contenitore: separate, su uno schermo stretto i nomi
   dei giorni finirebbero sopra una colonna che non è la loro. */
.cal-scroll{overflow-x:auto;overscroll-behavior-x:contain}
.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:1px;background:var(--color-border)}
.cal-grid--head{margin-bottom:1px}
.cal-cell-label{background:var(--color-background);padding:6px 8px;font-size:11px;font-weight:700;color:var(--color-text-secondary);text-transform:uppercase;min-width:0;overflow:hidden}
.cal-cell{background:var(--color-background);min-height:96px;padding:6px;display:flex;flex-direction:column;gap:3px;min-width:0;overflow:hidden}
.cal-cell--empty{background:var(--color-surface)}
.cal-cell--oggi{box-shadow:inset 0 0 0 2px var(--color-brand)}
.cal-day{font-size:11px;color:var(--color-text-secondary);font-weight:700}
.cal-chip{display:block;width:100%;min-width:0;box-sizing:border-box;text-align:left;font-size:10.5px;padding:3px 5px;border-radius:3px;background:var(--color-surface);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cal-chip--richiamo{background:#fdf0c8}
.cal-chip--consegna{background:#e4e4e4}

/* ---------- griglia dei form: sempre al massimo 2 colonne ---------- */
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 var(--s-4)}
.form-grid .field{margin-bottom:var(--s-4)}
.form-grid .field + .field{margin-top:0}
.form-grid .span2{grid-column:1/-1}

/* ---------- select con ricerca ---------- */
.combo{position:relative}
.combo input{border:0;border-bottom:1px solid var(--color-border);padding:10px 0;font-size:15px;background:none;width:100%;font-family:inherit;color:inherit}
.combo input:focus{outline:0;border-bottom-color:var(--color-text)}
.combo--clearable input{padding-right:26px}
.combo-clear{position:absolute;right:0;top:50%;transform:translateY(-50%);color:var(--color-text-secondary);display:flex;padding:4px}
.combo-list{position:absolute;top:calc(100% + 4px);left:0;right:0;background:var(--color-background);border:1px solid var(--color-border);max-height:200px;overflow:auto;z-index:30;box-shadow:0 8px 20px rgba(0,0,0,.10)}
.combo-opt{display:block;width:100%;text-align:left;padding:9px 12px;font-size:13px}
.combo-opt.new{border-top:1px solid var(--color-border);font-weight:700}

/* ---------- wizard per step ---------- */

/* ---------- dashboard ---------- */
.kpi{border:1px solid var(--color-border);padding:var(--s-5);display:flex;flex-direction:column;gap:6px;text-align:left;width:100%;transition:border-color .14s ease}
button.kpi{cursor:pointer}
.kpi .v{font-weight:900;font-size:28px;letter-spacing:-.01em}

/* ---------- riepilogo compatto (briefing dashboard) ---------- */
.kpi-compact{display:flex;align-items:center;justify-content:space-between;width:100%;text-align:left;padding:10px 2px;border-bottom:1px solid var(--color-border);transition:border-color .14s ease}
.kpi-compact:last-child{border-bottom:0}
.kpi-compact-v{font-weight:900;font-size:18px;letter-spacing:-.01em}

/* ---------- report: barre orizzontali, niente librerie di grafici ---------- */
.report-bar-row{display:flex;align-items:center;gap:var(--s-3);margin-bottom:12px}
.report-bar-label{width:170px;max-width:34%;flex:none;font-size:12px;color:var(--color-text-secondary)}
.report-bar-track{flex:1;height:10px;background:var(--color-surface);border-radius:4px;overflow:hidden}
.report-bar-fill{display:block;height:100%;background:var(--color-text)}
.report-bar-value{width:32px;flex:none;text-align:right;font-weight:700;font-size:12px}
.roles{display:flex;gap:var(--s-2);flex-wrap:wrap}
.roles button{border:1px solid var(--color-border);padding:8px 14px;border-radius:999px;font-size:12px;font-weight:500;color:var(--color-text-secondary)}
.roles button.on{background:var(--color-brand);border-color:var(--color-brand);color:var(--color-text);font-weight:700}

.empty{border:1px dashed var(--color-border);padding:var(--s-7);text-align:center;color:var(--color-text-secondary)}
.divider{height:1px;background:var(--color-border);margin:var(--s-6) 0}
.stack{display:flex;flex-direction:column;gap:var(--s-2)}
.row{display:flex;gap:var(--s-3);align-items:center;flex-wrap:wrap}
.spacer{flex:1}

/* Lo scorrimento animato di `html` è movimento come le transizioni:
   chi lo ha spento non lo vuole neanche quando tocca un'ancora. */
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}html{scroll-behavior:auto}}

/* =====================================================================
   AGGIUNTE — quello che il prototipo non aveva
   ===================================================================== */


/* ---------- centro notifiche (§18) ---------- */
.notifica{display:flex;align-items:flex-start;gap:var(--s-4);
  padding:var(--s-4) 0;border-bottom:1px solid var(--color-border)}
.notifica:last-child{border-bottom:0}
.notifica-testo{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--s-1)}
.notifica--nuova{border-left:2px solid var(--color-brand);padding-left:var(--s-4)}
.notifica-errore{color:#b3413e}

/* ---------- pagina stretta: accesso, attivazione, secondo fattore ---------- */
.stretta{max-width:520px;margin:0 auto;padding:var(--s-8) var(--s-5)}
.stretta .mark{width:40px;height:40px;display:flex;margin-bottom:var(--s-6)}
.stretta h1{margin-bottom:var(--s-2)}
.stretta .intro{color:var(--color-text-secondary);margin-bottom:var(--s-6);max-width:46ch}

/* ---------- segreto TOTP e codici di recupero ---------- */
.segreto{border:1px solid var(--color-border);background:var(--color-surface);
  padding:var(--s-4);font-size:15px;word-break:break-all;margin:var(--s-4) 0}
.codici{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(140px,100%),1fr));gap:var(--s-2);margin:var(--s-4) 0}
.codici li{list-style:none;border:1px solid var(--color-border);padding:var(--s-3);text-align:center;font-size:14px}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;letter-spacing:.06em}

/* ---------- avvisi in pagina ---------- */
.avviso{border:1px solid var(--color-text);padding:var(--s-4);margin-bottom:var(--s-5);font-size:13px}
.avviso--attenzione{border-color:#b4881f;background:#fffbea}

/* ---------- documenti legali ---------- */
.legale{max-width:720px;margin:0 auto;padding:var(--s-7) var(--s-5) var(--s-8);line-height:1.55}
.legale h1{font-size:22px;font-weight:900;margin-bottom:var(--s-1)}
.legale h2{font-size:15px;font-weight:700;margin:var(--s-6) 0 var(--s-2);padding-top:var(--s-4);border-top:1px solid var(--color-border)}
.legale p{margin-bottom:var(--s-3)}
.legale .meta{color:var(--color-text-secondary);font-size:12px;margin-bottom:var(--s-6)}
.legale table{margin:var(--s-3) 0;font-size:13px}
.legale td{padding:var(--s-2);vertical-align:top}
.legale .foot{margin-top:var(--s-7);font-size:11px;color:var(--color-text-secondary)}

/* ---------- tabelle in orizzontale su schermi stretti ---------- */
.tabella-scroll{overflow-x:auto;max-width:100%;overscroll-behavior-x:contain}

/* ---------- avatar nella barra in alto ----------
   Senza questo, `.icon-btn` impone 38×38 al bottone e comprime l'avatar
   che ci sta dentro. */
.icon-btn--avatar{width:auto;height:auto}
.dropdown--profilo{width:240px}
/* Coda legale del menu profilo: i due documenti su una riga sola, in
   corpo minore, staccati dalle voci di sopra da un filo di bordo. Non
   sono azioni e non hanno il peso delle altre voci. */
.dropdown-legale{padding:var(--s-3) var(--s-4);border-top:1px solid var(--color-border);
  background:var(--color-surface);font-size:11px;line-height:1.5;color:var(--color-text-secondary)}

/* ---------- celle con più azioni ----------
   `.num-cell` impone `white-space:nowrap` per gli importi tabulari, ma
   due pillole affiancate in una cella stretta forzerebbero la tabella in
   scroll orizzontale: qui vanno a capo e prendono il loro margine. */
td.azioni{white-space:normal}
td.azioni .pill{margin:2px 6px 2px 0}

/* ---------- righe di consenso e di preferenza ----------
   Un elenco di scelte con la loro spiegazione sotto: le tre caselle
   dell'attivazione (informativa, termini, marketing) e gli interruttori
   delle notifiche. Diverso da `.check-row`, che è il box bordato per una
   singola conferma che deve pesare. */
.consenso{display:flex;align-items:flex-start;gap:var(--s-3);
  padding:var(--s-3) 0;border-bottom:1px solid var(--color-border)}
.consenso:last-child{border-bottom:0}
.consenso input[type="checkbox"]{margin-top:3px;flex:none;width:auto}
.consenso label{font-size:13px;line-height:1.5}
.consenso a{text-decoration:underline;text-underline-offset:3px}
.consenso .t-meta{display:block;margin-top:2px}

/* Il numero che chiede attenzione in panoramica. Non rosso — la palette
   non lo prevede (brief §8.4) — ma l'ambra già usata per gli avvisi. */
.kpi-compact-v--attenzione{color:#957019}

/* =====================================================================
   UTILITÀ — sostituiscono gli attributi style= del prototipo
   Una classe per ogni aggiustamento che lì stava in linea. Non sono
   una libreria di utilità: sono esattamente i casi che servivano.
   ===================================================================== */

/* ---------- ritmo verticale ----------
   Il prototipo distribuiva questi margini in linea, caso per caso. Sono
   tre soli valori, e sono questi: 24 fra un blocco e il successivo, 16
   fra un titolo (o la riga che introduce) e ciò che introduce, 56 fra
   una sezione e l'altra. Usare 32 dappertutto — com'era — rendeva la
   pagina più ariosa del prototipo e il ritmo irregolare, perché 32
   incontrava i 24 delle righe di azione.

   Vale la regola dell'unico proprietario: lo spazio fra due blocchi lo
   mette chi sta sopra, con `.blocco`; una riga di azioni che segue un
   blocco usa `.row--alto`, e quando i due si incontrano il margine
   collassa sullo stesso valore invece di sommarsi. */
.blocco{margin-bottom:var(--s-5)}
.blocco-titolo{margin-bottom:var(--s-4)}
.row--alto{margin-top:var(--s-5)}

/* Due passi più larghi, entrambi presi dal prototipo: 32 per un blocco
   che chiude un'area della pagina (il riepilogo in panoramica), 40 per
   un gruppo dentro una galleria. */
.blocco--largo{margin-bottom:var(--s-6)}
.gruppo{margin-bottom:40px}

/* L'ultimo blocco di una pagina o di una sezione non lascia un margine
   appeso: uscirebbe dal contenitore senza creare spazio, e sommandosi a
   quello della sezione renderebbe il distacco diverso dagli altri. */
.view > *:last-child,
.sezione-progetto > *:last-child{margin-bottom:0}
.row--stretto{gap:var(--s-2)}
.t-meta--normale{font-weight:400;text-transform:none;letter-spacing:0}
.t-meta--unica-riga{white-space:nowrap}
.testo-bianco{color:#fff}
.max-12ch{max-width:12ch}
.max-38ch{max-width:38ch}
.max-44ch{max-width:44ch}
.mt-2{margin-top:var(--s-2)}
.mt-4{margin-top:var(--s-4)}
.filtro-inline{display:inline-flex;align-items:center;gap:var(--s-2);font-size:12px;color:var(--color-text-secondary)}
.filtro-inline input{width:auto}
.campo-file{border:1px dashed var(--color-border);padding:var(--s-3);font-size:13px}

/* ---------- traduzione degli style= che nel prototipo stavano in linea ----------
   Una classe per ciascuno dei casi realmente presenti nel markup del
   prototipo, con lo stesso valore: il risultato a schermo è identico,
   ma passa dal foglio di stile come richiede la CSP. */
/* Il prototipo scriveva flex:1 in linea su ogni intestazione di sezione:
   `margin:0` arriva dalla regola sopra, questa aggiunge la crescita. */
.section-title h2{margin:0;flex:1}
.flex-1{flex:1}
.qrow--due{grid-template-columns:1fr auto}
.link-titolo{text-align:left}
.row--fine{gap:10px;flex-wrap:wrap;justify-content:flex-end}
.sotto-blocco{margin-top:16px;padding-top:16px;border-top:1px solid var(--color-border)}
.sezione-progetto{margin-bottom:var(--s-9)}
.scelta-alternative{margin:4px 0 8px 20px;padding-left:12px;border-left:2px solid var(--color-border)}
.scelta-azione{margin:0 0 12px 20px}

/* Ogni scelta registrata in appuntamento è una scheda a sé — sfondo
   pieno, non un filo di separazione: con più righe una sotto l'altra
   restano distinte anche a colpo d'occhio. */
.scheda-scelta{background:var(--color-surface);border:1px solid var(--color-border);
  padding:16px;margin-top:14px}
.scheda-scelta--alternativa{margin:6px 0 20px 24px;padding-left:12px;background:transparent;
  border:none;border-left:2px solid var(--color-border)}
.max-720{max-width:720px}

.login-nota{max-width:44ch}

/* Il pannello del modulo è giallo (D-65): il colore principale, come nel
   sito e in LOI OS, di cui questa schermata è la gemella. Il giallo qui è
   una superficie e non un segnale, quindi ogni grigio pensato per il
   bianco — righe dei campi, etichette, bordi dei pulsanti — diventa un
   nero più o meno tenue: un grigio su giallo non si legge. Vale solo
   dentro `.login-lato`: nel resto della piattaforma il giallo resta un
   segnale e niente cambia. */
.login-lato{background:var(--color-brand)}
.login-lato .claim,
.login-lato .t-meta,
.login-lato .field-label{color:rgba(0,0,0,.72)}
.login-lato .field input{border-bottom-color:rgba(0,0,0,.4)}
.login-lato .field input:focus{border-bottom-color:var(--color-text)}
.login-lato .pw-eye{color:rgba(0,0,0,.6)}
.login-lato .pw-eye:hover{color:var(--color-text)}
.login-lato .pill--quiet{border-color:rgba(0,0,0,.5);color:var(--color-text)}
.login-lato .pill--quiet:hover{border-color:var(--color-text)}
.login-lato a{color:var(--color-text);text-decoration:underline;text-underline-offset:3px}
.login-lato .avviso{background:rgba(255,255,255,.6)}
.login-lato .field-error{color:#8a1f1c}
/* Il cerchio del marchio è giallo come lo sfondo: un anello nero lo
   ridisegna, lo stesso trattamento del sito quando il giallo non sta su
   una superficie neutra. */
.login-lato .login-marchio svg{overflow:visible}
.login-lato .login-marchio svg>path:first-child{stroke:var(--color-text);stroke-width:6}

/* ---------- navigazione senza ricaricare ----------
   Una barra sottile in cima mentre la pagina arriva. Non una rotella al
   centro: il contenuto vecchio resta leggibile fino alla sostituzione, e
   un velo sopra lo renderebbe inutilizzabile per mezzo secondo. */
body::after{
  content:"";position:fixed;top:0;left:0;height:2px;width:0;
  background:var(--color-brand);z-index:100;
  transition:width .3s ease,opacity .2s ease;opacity:0;pointer-events:none;
}
body.in-caricamento::after{width:70%;opacity:1}
/* Il cursore dice che qualcosa sta succedendo anche se la barra è breve. */
body.in-caricamento{cursor:progress}

/* Riepilogo e "Da fare oggi" affiancati a metà, come in panoramica nel
   prototipo: i dati e le cose da fare si leggono insieme. */
.grid--meta{grid-template-columns:1fr 1fr;gap:var(--s-8);align-items:start}
.briefing-vuoto{padding:8px 0}

/* Una voce spuntata resta leggibile ma si fa da parte. */
.briefing-row--fatta .briefing-row-testo{color:var(--color-text-secondary);text-decoration:line-through}

/* Il modulo del nuovo progetto è stretto come nel prototipo: un campo
   largo quanto lo schermo invita a scriverci dentro un tema. */
.form-grid--stretta{max-width:640px}

.testo-forte{color:var(--color-text);font-weight:700}
/* Una scadenza passata: l'ocra del prototipo, che segnala senza allarmare.
   Il rosso non è in palette, e un pagamento in ritardo non è un guasto. */
/* Come TESTO l'ocra del prototipo si ferma a 3.24 di contrasto su bianco,
   sotto il 4.5 che serve a un testo normale — ed è proprio il testo che
   dice "questa fattura è scaduta". Scurita quel tanto che basta (4.56),
   resta la stessa ocra e non diventa un allarme. Come bordo o come
   sfondo il valore originale va bene e resta dov'è: lì la soglia è 3. */
.testo-attenzione{color:#957019}
.kanban-card-nome{font-weight:500;font-size:13px}
.cal-mese{margin:0 12px}

.vista-nome{margin-left:5px}
.filtri-multipli{display:contents}

/* La misura del prototipo per il testo della zona sensibile: una riga
   lunga quanto lo schermo si legge male proprio dove conta capire cosa
   sta per succedere. */
.zona-sensibile-testo{max-width:52ch;margin-bottom:12px}

/* ---------- accessibilità da tastiera ----------
   Il collegamento di salto: fuori dallo schermo finché non riceve il
   fuoco, dove diventa un normale pulsante in alto a sinistra. Non
   `display:none`, che lo toglierebbe anche dall'ordine di tabulazione e
   quindi dalla portata di chi deve usarlo. */
.salta{
  position:absolute;left:var(--s-4);top:-64px;z-index:200;
  background:var(--color-background);color:var(--color-text);
  border:1px solid var(--color-text);padding:10px 16px;
  font-size:13px;font-weight:500;transition:top .12s ease;
}
.salta:focus{top:var(--s-4)}
/* Il contenuto riceve il fuoco dopo il salto, ma non è un controllo:
   il contorno lo direbbe a torto. Il salto si sente lo stesso, perché
   la lettura riparte da lì. */
.main:focus{outline:0}

/* I campi spengono il contorno di sistema per tenersi la propria riga
   sotto — che però risponde anche al fuoco da tastiera, dove serve un
   segno più forte. `:focus-visible` lo restituisce a chi naviga con il
   tasto Tab e lo lascia spento per chi ha appena cliccato dentro. */
.field input:focus-visible,
.field textarea:focus-visible,
.field select:focus-visible,
.searchbar input:focus-visible,
.searchmini input:focus-visible,
.combo input:focus-visible,
.tel-combo>input:focus-visible,
.tel-prefix-search:focus-visible,
.select-filter:focus-visible{outline:2px solid var(--color-text);outline-offset:2px}

/* ---------- barra in fondo e foglio dal basso ----------
   Esistono solo sul telefono: qui sono spenti, e la soglia a 860 li
   accende insieme allo spegnimento del menu laterale. Le misure stanno
   là, con le altre regole della stessa soglia.

   Il velo non ha bisogno di una soglia: lo scopre app.js, e app.js lo
   scopre solo dove i fogli esistono. Sta sotto al foglio (45) e alla
   barra in fondo (46), che deve restare visibile e toccabile — è il
   difetto per cui il foglio «Altro» faceva sparire la navigazione senza
   restituirla. */
.barra-sotto{display:none}
.foglio{display:none}
.velo-foglio{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:44}

/* Dietro una finestra o un foglio la pagina non si scorre: il velo dice
   che quella parte è spenta, e una pagina che scorre lo smentisce.
   `scrollbar-gutter:stable` su `html` tiene lo spazio della barra di
   scorrimento anche adesso, quindi la larghezza non salta. */
body.senza-scroll{overflow:hidden}
/* Safari iOS ignora `overflow:hidden` sul documento: lì a fermare il
   dito è `bloccaScroll()` in app.js, che intercetta `touchmove` fuori
   dal foglio e dalla finestra. Questa regola resta per tutti gli altri. */

/* Un accordo concordato con un singolo soggetto, fuori dalle regole
   generali del programma. Non è uno stato ma un'eccezione: bordo pieno e
   nessun riempimento, così si nota senza competere con i badge di stato. */
.badge--deroga{border-color:var(--color-text);color:var(--color-text);font-weight:700;margin-left:6px}

/* =====================================================================
   IL PASSAGGIO DEL MOUSE

   Tutto quel che segue vale solo dove un puntatore c'è davvero. Su uno
   schermo che si tocca il passaggio del mouse non esiste: il browser lo
   simula al tocco, e lo stato resta incollato al controllo appena
   toccato — una card col bordo nero, una riga grigia, un cerchietto già
   spuntato — finché non se ne tocca un altro. Un ritorno visivo che
   racconta il passato invece del presente.

   `(hover:hover)` chiede del dispositivo di puntamento principale, non
   della larghezza: un portatile con lo schermo touch resta un
   portatile, e queste regole gli restano. Nessuna di loro porta
   informazione — colori di bordo, sfondi di riga, una foto che cresce
   di un filo — quindi togliendole al tocco non si perde niente. Quel
   che invece serve a chi tocca sta fuori da qui: `:focus-visible` per
   la tastiera, `:active` per il ritorno immediato del dito, e
   `.track:focus-within` per il dettaglio dell'avanzamento.

   Stanno tutte insieme e non sparse accanto ai loro componenti per non
   ripetere la stessa condizione quaranta volte, e nell'ordine in cui il
   foglio le scriveva: fra `.card` e `.card--quiet`, o fra `.pill` e
   `.pill--quiet`, chi vince dipende ancora da chi viene dopo.
   ===================================================================== */
@media (hover:hover){
  .pill:hover::before{background:currentColor}
  .pill:hover{background:var(--color-brand);border-color:var(--color-brand);color:var(--color-text)}
  .pill--quiet:hover{background:none;color:var(--color-text);border-color:var(--color-text)}
  .pill--solid:hover{background:var(--color-background);color:var(--color-text);border-color:var(--color-text)}
  .pill--tertiary:hover{background:none;border-color:transparent;color:var(--color-text);text-decoration-color:currentColor}
  .stato-flag:hover{color:var(--color-text)}
  .side-toggle:hover{border-color:var(--color-text)}
  .nav a:hover{color:var(--color-text)}
  .crumbs button:hover{color:var(--color-text);text-decoration:underline}
  .crumb-su:hover{color:var(--color-text)}
  .icon-btn:hover{background:var(--color-surface)}
  .dropdown-item:hover{background:var(--color-surface)}
  .search-hit:hover{background:var(--color-surface)}
  .card:hover{border-color:var(--color-text)}
  th a:hover{color:var(--color-text)}
  .track:hover .track-tip{display:flex}
  .briefing-check:hover{border-color:var(--color-text)}
  .briefing-check:hover svg{opacity:1}
  .tessera:hover::before{transform:scale(1.04)}
  .tessera-riga:hover{border-color:var(--color-text)}
  .maniglia:hover{color:var(--color-text)}
  .gal-card:hover{border-color:var(--color-text)}
  .lightbox-close:hover{opacity:.7}
  .lightbox-nav:hover{opacity:.7}
  .lightbox-caption .pill:hover{border-color:#fff}
  .subnav a:hover{color:var(--color-text);border-bottom-color:var(--color-border)}
  .card--quiet:hover{border-color:var(--color-border)}
  .modale-chiudi:hover{color:var(--color-text)}
  .dropzone:hover{border-color:var(--color-text);background:var(--color-surface);color:var(--color-text)}
  .dz-chip button:hover{color:var(--color-text)}
  .pw-eye:hover{color:var(--color-text)}
  .avatar-upload-btn:hover{border-color:var(--color-text)}
  .ind-opt:hover{background:var(--color-surface)}
  .select-filter:hover{color:var(--color-text);border-color:var(--color-text)}
  .riga-cliccabile:hover{background:var(--color-surface)}
  .vista-item:hover{background:var(--color-surface)}
  .vista-item-x:hover{color:var(--color-text)}
  .combo-clear:hover{color:var(--color-text)}
  .combo-opt:hover{background:var(--color-surface)}
  button.kpi:hover{border-color:var(--color-text)}
  .kpi-compact:hover{border-color:var(--color-text)}
  .dropdown-legale a:hover{color:var(--color-text);text-decoration:underline}
  .link-titolo:hover{text-decoration:underline;text-underline-offset:3px}
}

/* =====================================================================
   IL DITO NON TRASCINA

   Due modalità dell'elenco progetti chiedono un puntatore preciso e non
   ci sono su un dispositivo che si tocca. Il kanban sposta le schede
   con il drag and drop nativo (`dragstart`/`drop`), che al tocco non
   parte affatto: sarebbe una vista dove si guarda e basta, senza che
   niente lo dica. Il calendario chiede 640 pixel di larghezza minima e
   scrive i suoi appuntamenti a 10,5px: a 390 è una griglia da scorrere
   in due direzioni per leggere sigle.

   La condizione è del dispositivo di puntamento, non della larghezza:
   una finestra stretta su un portatile ha ancora un mouse, e lì le due
   modalità funzionano. Chi la scelta la nasconde è questo blocco; chi
   arriva con un indirizzo che le chiede lo riporta alla lista è
   app.js, che legge la stessa condizione da `matchMedia`.
   ===================================================================== */
@media (pointer:coarse){
  .vista-item[data-puntatore="fine"]{display:none}
}

/* =====================================================================
   ADATTAMENTO ALLA LARGHEZZA

   Tutte le soglie stanno qui, in fondo e in ordine dalla più larga alla
   più stretta. Non è ordine per gusto: una soglia usa selettori della
   stessa specificità delle regole di base, quindi vince solo se le
   viene dopo. Sparse per il foglio — e prima lo erano, in due punti
   distanti — il fatto che una funzioni dipende da quanto in basso è
   finita la regola che deve correggere, che è un modo di funzionare
   per combinazione.

   Le soglie sono quattro:
   · 1180 — portatile: la barra laterale diventa una guida di icone;
   · 1024 — finestra a mezzo schermo: le coppie di colonne si impilano;
   ·  860 — tablet e telefono: la navigazione passa in orizzontale;
   ·  520 — telefono stretto: margini e pannelli si stringono.

   Nessuna delle quattro nasconde nulla che altrove si possa fare: una
   pagina stretta è la stessa piattaforma in un'altra forma.
   ===================================================================== */

/* ---------- 1180: portatile ----------
   Fra 860 e 1180 la piattaforma restava nella sua forma da scrivania:
   236 pixel di menu sempre aperti e, tolti i margini, una vista che
   scendeva sotto i 700 — dove una tabella di ordini non ci sta più. È
   la misura di una finestra non a tutto schermo su un portatile da 15",
   cioè il caso normale, non un caso limite. La barra si riduce alla
   colonna di icone — la stessa del collasso manuale — e i 152 pixel
   recuperati vanno al contenuto. */
@media (max-width:1180px){
  :root{--pad-view:var(--s-5)}
  .app.is-on{grid-template-columns:84px 1fr}
  .side{padding-left:var(--s-3);padding-right:var(--s-3)}
  .side-head{justify-content:center}
  /* Il bottone di collasso non ha più niente da collassare. */
  .side-toggle{display:none}
  .nav a{justify-content:center;padding:9px 0}
  .grid--meta{gap:var(--s-6)}
}

/* ---------- 1024: finestra a mezzo schermo ----------
   Due colonne affiancate qui valgono meno di una sola leggibile: il
   riepilogo e "Da fare oggi" si impilano, e le tabelle a colonne fisse
   cominciano a scorrere dentro il loro contenitore (la soglia ce
   l'hanno già scritta addosso, non serve ripeterla). */
@media (max-width:1024px){
  .grid--meta{grid-template-columns:1fr;gap:var(--s-6)}
  .topbar{padding:var(--s-4) var(--s-5)}
  .qrow--storico{grid-template-columns:minmax(0,100px) minmax(0,1fr) minmax(0,130px)}
  .dropdown--search{width:min(480px,calc(100vw - 2 * var(--s-5)))}
}

/* ---------- 860: tablet e telefono ---------- */
@media (max-width:860px){
  /* ---------- la testa della pagina ----------
     Prima era impilata su tre righe — briciole, ricerca, icone — e per
     questo non appiccicosa: tenerne un quinto di schermo fisso avrebbe
     lasciato il resto da leggere in uno spiraglio. Ora è una riga sola
     alta 56 (marchio a sinistra, icone a destra) più una riga alta 44
     che tiene o le briciole ridotte al passo indietro o il campo di
     ricerca: mai le due insieme, perché stanno nella stessa area della
     griglia. Cento pixel in tutto, e può restare in vista.
     `--h-topbar` non è una misura ripetuta a mano: la sotto-barra del
     progetto la legge per agganciarsi sotto la testa. Su una pagina di
     primo livello, dove un passo indietro non esiste, la riga di sotto
     non c'è e la testa vale 56: la sotto-barra vive solo dentro un
     progetto, che un genitore ce l'ha sempre. */
  /* L'altezza della barra in fondo, zona di sistema compresa: la
     usano il contenuto, il toast, la finestra modale e il foglio dal
     basso, che devono tutti fermarsi al suo bordo superiore. Era
     scritta per esteso in tre punti. */
  :root{--h-topbar:100px;--h-barra:calc(56px + env(safe-area-inset-bottom))}
  /* Il passo fra due sezioni scende da 56 a 40: su 660 pixel di altezza
     56 era quasi un decimo dello schermo di bianco. Il rapporto con il
     passo di blocco (24) resta: una sezione stacca più di un blocco. */
  :root{--s-9:40px}
  .topbar{
    position:sticky;top:0;
    padding:0 var(--s-4);gap:0 var(--s-3);
    grid-template-columns:auto minmax(0,1fr);
    grid-template-areas:"marchio azioni" "sotto sotto";
  }
  .topbar .tb-marchio{grid-area:marchio;display:flex;min-height:56px}
  .tb-right{grid-area:azioni;justify-self:end}
  .tb-left{grid-area:sotto;min-width:0}
  .tb-center{grid-area:sotto;width:100%;min-height:44px;display:none;align-items:center}
  .topbar .tb-cerca{display:inline-flex}

  /* Il campo si apre al posto delle briciole, a tutta larghezza: sono
     la stessa riga, e la testa non cambia altezza aprendolo. */
  .topbar.cerca-aperta .tb-left{display:none}
  .topbar.cerca-aperta .tb-center{display:flex}

  /* Del percorso resta il solo passo indietro. La catena intera non
     entra in una riga, e quel che si cerca sul telefono è tornare al
     genitore, non rileggere da dove si è passati. */
  .crumbs{display:none}
  .topbar .crumb-su{
    display:flex;align-items:center;gap:6px;min-height:44px;
    font-size:13px;color:var(--color-text-secondary);
  }

  .app.is-on{grid-template-columns:1fr}
  .app.side-collapsed{grid-template-columns:1fr}
  /* `min-width:0` non è un dettaglio: `.side` è un elemento di griglia,
     e un elemento di griglia si allarga al proprio contenuto se non gli
     si dice il contrario. Con le voci di navigazione in riga faceva 800px
     su uno schermo da 390, e `overflow-x:auto` non entrava mai in
     funzione — la barra non scorreva, era la pagina intera a essere più
     larga dello schermo. Ogni card e ogni tabella finivano tagliate a
     destra, e la causa non era in nessuna delle due. */
  .side{position:static;height:auto;flex-direction:row;align-items:center;gap:var(--s-4);overflow-x:auto;overflow-y:visible;min-width:0;padding:var(--s-3) var(--s-4)}
  .side-head{display:none}
  .side-toggle{display:none}
  .nav{flex-direction:row}
  .nav a{border-left:0;border-bottom:2px solid transparent;white-space:nowrap;justify-content:flex-start;padding:9px var(--s-3)}
  .nav a.is-on{border-left:0;border-bottom-color:var(--color-brand)}
  /* In orizzontale l'etichetta torna a vedersi: la guida di icone
     serviva a stringere una colonna, e qui non c'è più una colonna. */
  .brandmark .brandmark-title,
  .nav .label{position:static;width:auto;height:auto;overflow:visible;clip-path:none}

  /* Stessa pagina in colonna: la vetrina sopra, alta poco più di metà
     schermo, e il modulo sotto con il marchio in cima. `minmax(0,1fr)`
     e non `1fr`: la colonna deve poter scendere sotto la larghezza
     minima del modulo, o il modulo sfora a destra. */
  .login{grid-template-columns:minmax(0,1fr)}
  .login-scena{min-height:52dvh}
  .diapositiva figcaption{padding:var(--s-7) var(--s-4) var(--s-5)}
  .login-scena--vuota{padding:var(--s-5) var(--s-4)}
  .login-lato{padding:var(--s-6) var(--s-4)}
  .login-form{min-width:0}
  .view{padding:var(--s-5) var(--s-4)}
  .qrow{grid-template-columns:1fr;gap:var(--s-2)}
  .dropdown, .dropdown--search{position:fixed;top:auto;right:var(--s-4);left:var(--s-4);width:auto;transform:none}
  /* `top:auto` lascia il menu dove starebbe nel flusso, cioè in cima al
     documento: finché la testa era immobile andava bene, perché in cima
     c'era anche lei. Ora che resta in vista, i due menu che si aprono
     da lì si agganciano al suo bordo, altrimenti si aprono fuori dallo
     schermo appena la pagina è scorsa di un dito. */
  .dropdown--profilo,.dropdown--search{top:56px}
  /* Il pannello dei prefissi no: `position:fixed` con `top:auto` lo
     inchioda al punto dello schermo dove il campo si trovava
     all'apertura, e scorrendo la pagina resta lì, sospeso a metà,
     staccato dal campo che lo ha aperto. Resta attaccato al suo
     bottone, largo quanto lo schermo concede. */
  .tel-prefix-menu{position:absolute;top:calc(100% + 10px);left:0;right:auto;
    width:min(300px,calc(100vw - 2 * var(--s-4)))}
  .form-grid{grid-template-columns:1fr}
  .form-grid .span2{grid-column:auto}

  /* Il campo prende la riga intera invece della sua misura da scrivania. */
  .searchmini{width:100%}

  /* ---------- la sotto-barra del progetto sta su una riga ----------
     Sei voci in maiuscolo con 32 pixel di spazio fra l'una e l'altra
     non stanno in 390: andavano a capo su tre righe, e restando
     appiccicate si mangiavano un altro centinaio di pixel prima del
     contenuto. È lo stesso trattamento della navigazione — una riga
     sola che scorre, nessuna voce spezzata — e la voce attiva la
     riporta in vista app.js, come faceva già per le sezioni.

     I margini negativi la portano a filo dello schermo, dentro il
     padding che la vista ha già: quel che scorre deve poter uscire dal
     bordo, altrimenti l'ultima voce sembra l'ultima che c'è. Non
     allargano la pagina, perché è lei stessa a scorrere.

     Le voci diventano alte 40: era una fila di bersagli da 22, cioè
     sotto i 24 di WCAG 2.5.8, e la barra resta della stessa altezza
     perché quei pixel li restituisce il padding che tolgo. */
  .subnav{
    flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;gap:var(--s-5);
    scrollbar-width:none;-webkit-overflow-scrolling:touch;
    padding:var(--s-1) var(--s-4);
    margin-left:calc(var(--s-4) * -1);margin-right:calc(var(--s-4) * -1);
  }
  .subnav::-webkit-scrollbar{display:none}
  /* La riga della vetrina: maniglia, miniatura e testo sulla prima
     riga, le azioni sotto — a 390 non c'è posto per tutto in fila. */
  .vetrina-elenco .tessera-riga{flex-wrap:wrap}
  .vetrina-azioni{flex-basis:100%;justify-content:flex-end}
  .subnav a{
    flex:none;white-space:nowrap;display:flex;align-items:center;
    min-height:40px;padding-bottom:0;
  }

  /* ---------- le barre degli strumenti sono chip che scorrono ----------
     Con `flex-wrap:wrap` a 390 pixel diventavano tre o quattro righe di
     pillole prima dell'elenco: è la resa giusta su schermo largo, dove
     lo spazio avanza, e la peggiore qui, dove non c'è comunque. Una
     barra di soli filtri diventa una riga sola che scorre, come le chip
     di un'app nativa.

     Quella che porta la ricerca no: il campo prende già la riga intera
     (qui sopra), e in una riga che scorre si porterebbe dietro tutto il
     resto fuori dallo schermo. Resta a capo, e quel che le rimane è un
     pulsante o due — l'azione principale è salita nel titolo. Che una
     barra la ricerca ce l'abbia lo dice il suo contenuto: `:has()` è il
     solo modo di leggerlo senza appendere una classe a mano su ognuna
     delle pagine che una barra la scrivono. */
  .toolbar:not(:has(.searchmini)){
    flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;
    scrollbar-width:none;-webkit-overflow-scrolling:touch;
  }
  .toolbar:not(:has(.searchmini))::-webkit-scrollbar{display:none}
  .toolbar > *{flex:none}
  /* Lo spazio elastico spingeva a destra l'azione principale, che ora
     sta nella riga del titolo. In una riga che scorre resterebbe un
     vuoto da attraversare col dito per arrivare al filtro dopo. */
  .toolbar .spacer{display:none}

  /* ---------- l'azione principale sale nella riga del titolo ----------
     «Nuovo progetto», «Nuova fattura», «Invita cliente»: è la cosa per
     cui si è aperta la pagina, e stava in fondo a una barra che va a
     capo. Sale accanto all'`h1`, dove nessun filtro la può spingere
     giù. A spostarla è app.js — il nodo è quello che il server ha già
     scritto, con i suoi gestori attaccati — e questa classe la mette
     lui sulla testa che la riceve. Sopra 860 non esiste, e la barra
     resta quella di prima. */
  .head--azione{
    display:grid;grid-template-columns:minmax(0,1fr) auto;
    align-items:center;column-gap:var(--s-3);
  }
  /* Il titolo divide la riga con l'azione; quel che gli sta sotto —
     la frase che spiega la pagina — riprende la larghezza intera,
     perché sotto l'azione non c'è più niente. */
  .head--azione > *{grid-column:1 / -1}
  .head--azione > :first-child{grid-column:1}
  .head--azione > .azione-titolo{grid-column:2;grid-row:1;justify-self:end}

  /* ---------- le tabelle elenco diventano schede ----------
     Una tabella che scorre in orizzontale porta fuori dallo schermo la
     prima colonna, cioè il nome: quel che si stava cercando sparisce
     appena si scorre per leggere il resto. La forma giusta la usa già
     la pagina ordini, dove ogni ordine è un blocco con un titolo e i
     suoi dati sotto. Qui ci si arriva senza un secondo markup: la
     tabella resta una tabella, il `thead` sparisce e ogni cella stampa
     da sé l'etichetta della colonna, che `tabellaEtichettata()` le ha
     appeso in `data-etichetta`.

     `[hidden]` va ridichiarato: `display:block` su `tr` è più
     specifico della regola del browser che nasconde un elemento
     nascosto, e senza questa riga ogni modulo di modifica — che sta in
     una riga nascosta finché non lo si apre — comparirebbe aperto
     dentro la scheda. */
  .tbl-schede,.tbl-schede tbody,.tbl-schede tr,.tbl-schede td{display:block}
  .tbl-schede thead{display:none}
  .tbl-schede tr[hidden]{display:none}
  .tbl-schede tr{border:1px solid var(--color-border);padding:var(--s-4);margin-bottom:var(--s-3)}
  .tbl-schede td{border:0;padding:0;margin-top:var(--s-2)}
  .tbl-schede td::before{
    content:attr(data-etichetta);display:block;margin-bottom:2px;
    font-size:11px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;
    color:var(--color-text-secondary);
  }
  /* Senza etichetta sono il titolo della scheda e le azioni: il primo
     non ha bisogno di dichiarare di essere un nome, le seconde non sono
     un dato. */
  .tbl-schede td:not([data-etichetta])::before{display:none}
  /* Un campo dentro una cella porta già la sua etichetta nel `label`:
     la cella non la stampa una seconda volta sopra. */
  .tbl-schede td:has(.field-label)::before{display:none}
  .tbl-schede td:first-child{margin-top:0}
  /* L'importo resta a destra, sulla riga della sua etichetta: in una
     pila di schede è il numero che si confronta fra una e l'altra, e
     incolonnato si legge. La cella numerica porta un valore solo,
     quindi `space-between` non ha altro da spargere. */
  .tbl-schede td.num-cell{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-4)}
  .tbl-schede td.num-cell::before{margin-bottom:0}
  /* La riga del totale è una scheda anche lei, ma non è un elemento
     dell'elenco: il fondo grigio la distingue senza aggiungere parole. */
  .tbl-schede tr.is-total{background:var(--color-surface)}

  /* ---------- le due tabelle a colonne fisse ----------
     `.tbl-ordine` e `.tbl-voci` non diventano schede: dentro le loro
     celle ci sono i form di riga, e una scheda li impilerebbe fuori
     dalla forma che hanno. Restano tabelle che scorrono, ma la prima
     colonna — il nome della voce — resta ferma a sinistra mentre il
     resto passa: senza, si scorre fino all'avanzamento e non si sa più
     di cosa sia. Il fondo è pieno perché il resto della riga le passa
     sotto, e il filo a destra dice dov'è il taglio.

     Quel filo obbliga le due tabelle a `border-collapse:separate`: con
     i bordi fusi non è più la cella a disegnarli ma la tabella, e
     restano al loro posto mentre la cella scorre via — la prima
     colonna si stacca e il taglio resta indietro. Con `border-spacing`
     a zero la resa non cambia di un pixel, perché i bordi qui stanno
     su un lato solo e non hanno niente da fondere. */
  .tbl-ordine,.tbl-voci{border-collapse:separate;border-spacing:0}
  .tbl-ordine th:first-child,.tbl-ordine td:first-child,
  .tbl-voci th:first-child,.tbl-voci td:first-child{
    position:sticky;left:0;z-index:1;
    background:var(--color-background);border-right:1px solid var(--color-border);
  }

  /* Sette colonne su 390 pixel fanno celle da 40: il calendario scorre
     per intero — intestazione e celle insieme — invece di ridurre ogni
     giorno a una scheggia. Le tabelle fanno già così per conto loro. */
  .cal-grid{min-width:640px}

  /* Le barre del report: l'etichetta non si mangia la barra. */
  .report-bar-label{width:120px;max-width:40%}

  /* ---------- quel che si tocca ----------
     Su un telefono il tocco non ha il puntatore fine del mouse. WCAG
     2.5.8 chiede 24 pixel, il pollice ne vuole 44, e sotto quella
     misura si sbaglia bersaglio invece di sbagliare intenzione.

     Le pillole crescono davvero: sono l'azione principale di ogni
     riga, e 44 di altezza non cambia niente di come sono disegnate —
     il bordo resta a filo del testo perché il contenuto sta al centro.
     `min-height` e non padding, così vale anche per `.pill--sm`, che
     lo alzava per conto suo. */
  .pill{min-height:44px}
  .icon-btn{width:44px;height:44px}
  /* L'interruttore di visibilità è un bottone con la sua etichetta
     accanto: quel che si tocca è tutta la riga, non il cursore. */
  .vis{min-height:44px}
  /* La riga del briefing cresce fino a 44 perché il cerchietto della
     spunta ci arrivi senza debordare in quella sopra e in quella sotto:
     un'area allargata che invade la riga vicina sposta l'errore invece
     di toglierlo. 18 di cerchietto più 13 sopra e 13 sotto. */
  .briefing-row{padding:13px 0}

  /* ---------- i controlli a icona: l'area cresce, il disegno no ----------
     Un interruttore alto 18 e una croce da 24 sono piccoli di proposito
     — ingrandirli vorrebbe dire ridisegnare la pagina intorno a loro —
     quindi a crescere è solo quel che intercetta il dito: uno
     pseudo-elemento trasparente che deborda oltre i bordi del
     controllo. Non occupa spazio nel flusso e non si vede.

     Il controllo deve essere posizionato, altrimenti il riquadro si
     aggancia all'antenato posizionato più vicino e finisce altrove.
     `.pw-eye` e `.combo-clear` lo sono già — stanno dentro il campo —
     e riceverne un secondo li staccherebbe da lì.

     Lo scostamento si conta dal bordo INTERNO, non da quello esterno:
     `inset` su un elemento assoluto parte dal riquadro dentro il bordo
     del contenitore, quindi su un controllo che un bordo ce l'ha — il
     cursore, il cerchietto — l'area esce due pixel più stretta di
     quanto la sottrazione direbbe. Le misure qui sotto lo tengono già
     in conto: sono state lette dal browser, non calcolate a mano.

     Il lato che confina con un altro bersaglio non si allarga. Due aree
     sovrapposte spostano l'errore invece di toglierlo, e su una di
     queste lo peggiorerebbero: la croce che toglie una vista salvata sta
     appiccicata al bottone che la applica, e sta dopo di lui nel
     documento — dieci pixel di debordo e un dito che voleva aprire una
     vista la cancella. Dove il vicino è vicino l'area cresce in altezza
     e si ferma in larghezza: 44 per 32 preso bene vale più di 44 per 44
     che prende anche quello di fianco. */
  .briefing-check,.vista-item-x,.modale-chiudi,.dz-chip button,th a{position:relative}
  .switch::after,.briefing-check::after,.vista-item-x::after,.modale-chiudi::after,
  .pw-eye::after,.combo-clear::after,.dz-chip button::after,th a::after,.maniglia::after{
    content:"";position:absolute;inset:-11px;
  }
  /* La maniglia è già alta 40: cresce solo in larghezza, fino al bordo
     della riga a sinistra e non sopra la miniatura a destra. */
  .maniglia::after{inset:-2px -6px -2px -16px}
  /* Il cursore è 34 per 18, il cerchietto della spunta 18 per 18: a
     entrambi 11 per lato non basta in altezza. Il cerchietto non si
     allarga a sinistra oltre il rientro del riquadro né a destra fin
     dentro il testo della voce, che è un collegamento suo. */
  .switch::after{inset:-14px -6px}
  .briefing-check::after{inset:-15px -7px -15px -15px}
  /* Croce di un allegato, croce di una vista salvata e intestazione che
     ordina: tutte e tre hanno un vicino a pochi pixel. */
  .dz-chip button::after,th a::after{inset:-14px -10px}
  .vista-item-x::after{inset:-10px -8px -10px 0}

  /* ---------- la barra in fondo ----------
     Il menu laterale lascia il posto a una barra fissa sul bordo
     inferiore, dove arriva il pollice. Le voci hanno tutte la stessa
     larghezza — una griglia a colonne uguali, non flex, così «Altro»
     non è più stretto di «Panoramica». La voce attiva ha il filo
     giallo sopra, lo stesso segnale del bordo sinistro nel menu
     laterale, spostato sul lato che qui tocca il contenuto.
     `env(safe-area-inset-bottom)` è lo spazio della barra di sistema
     degli iPhone senza tasto: senza, le etichette ci finiscono sotto. */
  .side{display:none}
  .barra-sotto{
    display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
    position:fixed;left:0;right:0;bottom:0;z-index:46;
    background:var(--color-background);border-top:1px solid var(--color-border);
    padding-bottom:env(safe-area-inset-bottom);
  }
  .barra-sotto a,.barra-sotto button{
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
    min-height:56px;padding:6px 4px 8px;
    font-size:11px;font-weight:500;line-height:1.2;color:var(--color-text-secondary);
    border-top:2px solid transparent;margin-top:-1px;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  .barra-sotto a svg,.barra-sotto button svg{flex:none}
  .barra-sotto .is-on{color:var(--color-text);font-weight:700;border-top-color:var(--color-brand)}
  .barra-sotto button[aria-expanded="true"]{color:var(--color-text)}

  /* Il contenuto e il toast si tengono sopra la barra: 56 di barra più
     un passo di respiro, più la zona di sistema. */
  .main{padding-bottom:calc(var(--h-barra) + var(--s-5))}
  .toast{bottom:calc(var(--h-barra) + var(--s-4))}
  .modal-overlay{padding-bottom:calc(var(--h-barra) + var(--s-4))}

  /* ---------- il foglio dal basso ----------
     Un pannello ancorato al bordo del bottone che lo apre funziona con
     un puntatore e non con un pollice: se il bottone sta a destra il
     pannello esce dallo schermo, e un `position:fixed` con `top:auto`
     resta appeso dove il bottone si trovava all'apertura, staccato da
     tutto. Sotto 860 quel che si apre da un bottone si apre invece dal
     basso, dove il pollice arriva: è D-48 — una finestra sua per ogni
     azione — nella forma che il telefono usa.

     Una regola sola per tutti: la classe la mette app.js sul pannello
     che in questo momento è aperto, qualunque sia il meccanismo con cui
     si apre (`is-on` per i menu, `hidden` per gli elenchi). Aggiungere
     un pannello a questo trattamento è aggiungere un selettore
     all'elenco che sta in `app.js`, non riscrivere queste misure.

     Il fondo è il bordo SUPERIORE della barra in fondo, non quello
     dello schermo: il foglio «Altro» arrivava fino in fondo e copriva
     la navigazione con area propria e opaca — la barra spariva e non
     c'era modo di riaverla, perché il gestore ignora di proposito i
     tocchi dentro il foglio. Con la tastiera aperta il fondo è il suo
     bordo, altrimenti il foglio ci finisce sotto.

     `max-height` in `dvh` e non in `vh`: su iOS `vh` misura la finestra
     con le barre del browser ritratte, cioè più di quel che si vede. */
  .foglio-giu{
    position:fixed;inset:auto 0 max(var(--h-barra),var(--tastiera)) 0;
    width:auto;min-width:0;max-width:none;
    /* Fino al 60% dello schermo, ma mai oltre lo spazio fra la testa
       della pagina e la tastiera, meno un campo: `dvh` misura la
       finestra di layout, che su iOS non si restringe con la tastiera,
       e il foglio dei suggerimenti di indirizzo si apre proprio mentre
       si scrive — a 60dvh copriva il campo in cui si stava scrivendo.
       I 72 pixel lasciati sopra sono un'etichetta e il suo campo. */
    max-height:min(60dvh,calc(100dvh - var(--tastiera) - var(--h-topbar) - 72px));
    margin:0;padding:0;overflow:auto;overscroll-behavior:contain;transform:none;
    background:var(--color-background);border:0;border-top:1px solid var(--color-border);
    box-shadow:0 -12px 28px rgba(0,0,0,.14);z-index:45;
  }
  /* Il nome dell'azione che ha aperto il foglio e la croce, come nella
     finestra modale: un foglio comparso dal basso deve dire di cosa è,
     e come si chiude. Resta in vista mentre l'elenco scorre. */
  .foglio-testa{
    position:sticky;top:0;z-index:1;
    display:flex;align-items:center;justify-content:space-between;gap:var(--s-4);
    padding:var(--s-3) var(--s-4);
    background:var(--color-background);border-bottom:1px solid var(--color-border);
    font-weight:700;font-size:13px;
  }
  /* L'area di tocco è 44 senza che la croce cresca: il padding la
     allarga, il margine negativo restituisce lo spazio alla riga. */
  .foglio-chiudi{
    display:flex;color:var(--color-text-secondary);
    padding:var(--s-3);margin:calc(var(--s-3) * -1);
  }
  /* Le righe di un foglio si toccano col pollice, non si puntano: nel
     pannello da scrivania una casella di filtro è alta 28 pixel, e in
     un foglio largo quanto lo schermo diventa una riga da sbagliare.
     Il rientro laterale è quello della riga di testa, così l'elenco e
     il suo nome stanno incolonnati. */
  .foglio-giu .filtro-check-opt,
  .foglio-giu .vista-item,
  .foglio-giu .filtro-check-clear{min-height:44px;padding:var(--s-3) var(--s-4)}
  .foglio-voce{display:flex;align-items:center;gap:var(--s-3);min-height:52px;font-size:14px}
  .foglio-voce svg{flex:none;color:var(--color-text-secondary)}
  .foglio-voce[aria-current="page"]{font-weight:700;border-left:2px solid var(--color-brand)}

  /* Sotto i 16px, iOS Safari zooma la pagina al fuoco del campo e non
     torna indietro all'uscita. Vale per ogni campo, compresi quelli che
     lo ereditano con `font:inherit` (`.searchbar input`, `.searchmini
     input`) o lo dichiarano con una classe (`.field input`,
     `.tel-prefix-search`): senza `!important` quelle regole, più
     specifiche, vincerebbero comunque su questa. */
  input, select, textarea{font-size:16px!important}
  /* Quando un foglio si apre sopra un campo che ha il fuoco, app.js
     porta il campo appena sotto la testa: questo è il margine che lo
     tiene fuori da lei. */
  input, select, textarea{scroll-margin-top:calc(var(--h-topbar) + var(--s-3))}
  /* La sigla del prefisso era a 8px in una scatola da 22 per 14: sotto
     ogni soglia di lettura. La scatola cresce con lei. */
  .tel-prefix-trigger .fi,.tel-prefix-opt .fi{width:30px;height:18px;font-size:11px}
  /* ---------- la finestra modale e la tastiera ----------
     Fra 520 e 860 la finestra è ancora una scatola nel velo, e con la
     tastiera aperta «Salva» ci finiva sotto: il velo si ferma sopra la
     tastiera, e la scatola non supera lo spazio che resta — 8vh sopra,
     barra e margine sotto. Sotto 520 la finestra è la schermata e la
     regola di là riscrive entrambe. */
  .modal-overlay{bottom:var(--tastiera)}
  .modal-box{max-height:calc(100dvh - var(--tastiera) - 8vh - var(--h-barra) - var(--s-4))}
  /* ---------- le card a piena larghezza ----------
     In una colonna sola, una card con bordo su quattro lati e 24 di
     padding era una scatola con margini doppi: 16 di vista più 24. Le
     card di elenco prendono la forma delle righe di una lista, un filo
     sotto e basta; quelle di sintesi restano scatole, più strette. */
  .grid:has(> .card:not(.card--quiet)){gap:0}
  .grid > .card:not(.card--quiet){border-width:0 0 1px;padding:var(--s-4) 0}
  .kpi,.card--quiet{padding:var(--s-4)}
}

/* ---------- 520: telefono stretto ----------
   Qui non cambia la struttura — è già una colonna sola — ma le misure
   scritte in pixel: i margini della vista, il riquadro della finestra
   modale (che sotto i 368 usciva dallo schermo di lato) e i pannelli a
   comparsa ancorati al bordo sinistro del loro bottone. */
@media (max-width:520px){
  :root{--pad-view:var(--s-4)}
  .view{padding:var(--s-5) var(--pad-view)}

  /* ---------- la finestra prende tutto lo schermo ----------
     A 390 una finestra con i suoi margini, il suo bordo e `max-height`
     a 86vh dentro un velo che scorre a sua volta è una scatola dentro
     una scatola, e nessuna delle due sa chi debba scorrere. Qui la
     finestra è la schermata: nessun margine, nessun bordo, e a scorrere
     è lei sola — il velo non scorre affatto, altrimenti le due righe
     appiccicose non avrebbero un contenitore a cui attaccarsi.

     Il fondo del velo è il bordo della tastiera, non quello dello
     schermo: `position:fixed` non lo sa da sé, e senza questa riga la
     riga «Salva» resta sotto la tastiera esattamente come prima. */
  .modal-overlay{padding:0;bottom:var(--tastiera);align-items:stretch;overflow:hidden}
  .modal-overlay.is-on{padding:0}
  .modal-box{
    max-width:none;min-width:0;min-height:0;height:100%;max-height:none;
    border:0;padding:var(--s-5);overflow:auto;overscroll-behavior:contain;
  }
  /* Titolo e azioni restano ai due bordi mentre il modulo scorre in
     mezzo: su uno schermo alto 844 con la tastiera aperta il modulo è
     più lungo di quel che si vede, e «Salva» non deve essere una cosa
     da cercare. I margini negativi le portano a filo della finestra,
     dentro il padding che la scatola ha già.

     Lo scostamento è il padding cambiato di segno e non zero: un
     elemento appiccicato si ferma al bordo del CONTENUTO di chi scorre,
     non al suo bordo esterno, e con `top:0` la riga di testa restava
     ferma 24 pixel più in basso — sopra di lei si vedeva scorrere il
     modulo. */
  .modal-box > .modale-testa{
    position:sticky;top:calc(var(--s-5) * -1);z-index:2;
    margin:calc(var(--s-5) * -1) calc(var(--s-5) * -1) var(--s-4);
    padding:var(--s-4) var(--s-5);
    background:var(--color-background);border-bottom:1px solid var(--color-border);
  }
  /* Solo la riga di azioni della finestra, non una qualsiasi annidata
     nel modulo: figlia della scatola o del modulo che la scatola
     contiene, e ultima. */
  .modal-box > .row--alto:last-child,
  .modal-box > .row--azioni:last-child,
  .modal-box > * > .row--alto:last-child,
  .modal-box > * > .row--azioni:last-child{
    position:sticky;bottom:calc(var(--s-5) * -1);z-index:2;
    margin:var(--s-4) calc(var(--s-5) * -1) calc(var(--s-5) * -1);
    padding:var(--s-4) var(--s-5) calc(var(--s-4) + env(safe-area-inset-bottom));
    background:var(--color-background);border-top:1px solid var(--color-border);
  }

  /* Il ripiego di quando i pannelli non sono fogli — cioè con
     JavaScript spento: un foglio dal basso è largo quanto lo schermo, e
     questo massimo lo rimpicciolirebbe tenendolo attaccato a sinistra. */
  .filtro-check-list:not(.foglio-giu),
  .vista-menu:not(.foglio-giu),
  .tel-prefix-menu:not(.foglio-giu){max-width:calc(100vw - var(--s-6))}
  .stretta{padding:var(--s-6) var(--s-4)}
  .legale{padding:var(--s-6) var(--s-4)}
  .toolbar{gap:var(--s-2)}
  .cal-cell{min-height:76px}
  .lightbox-overlay{padding:var(--s-4)}
  /* Le frecce stavano sopra la foto, ai bordi: qui scendono in una riga
     sotto di lei, e la didascalia dopo. Sfogliare col dito lo fa app.js. */
  .lightbox-frecce{display:flex;justify-content:center;gap:var(--s-6);order:2;margin-top:var(--s-4)}
  .lightbox-nav{position:static;transform:none}
  .lightbox-caption{order:3}
  /* La galleria a una colonna era una foto per schermata: due colonne
     fisse, con la didascalia più piccola. */
  .gallery-grid{grid-template-columns:repeat(2,1fr);gap:var(--s-2)}
  .gal-card-info{padding:var(--s-2) var(--s-3) var(--s-3)}
  .gal-card-title{font-size:12px}
}
